cirnogodot/Scripts/Components/Actors/PlayerDamageReceiver.cs

150 lines
4.3 KiB
C#
Raw Normal View History

2025-03-01 14:08:31 +01:00
using System;
2025-03-11 17:58:46 +01:00
using Cirno.Scripts.Components.FSM;
2025-03-01 14:08:31 +01:00
using Godot;
namespace Cirno.Scripts.Components.Actors;
public partial class PlayerDamageReceiver : Area2D
{
[Export]
public bool Enabled { get; set; } = false;
[Export]
public bool Invulnerable { get; private set; } = false;
[Export] public BulletOwner BulletGroup { get; set; } = BulletOwner.Player;
[Export]
private ActorResourceProvider _healthProvider;
[Export]
private ActorResourceProvider _shieldProvider;
2025-03-03 17:55:53 +01:00
[Export] public StringName AcidGroupName { get; private set; } = "Acid";
2025-03-01 14:08:31 +01:00
[Signal]
public delegate void HealthChangedEventHandler(float newValue, float maxValue);
2025-03-03 10:58:20 +01:00
[Signal]
public delegate void HealthDecreasedEventHandler(float value, float newValue, float maxValue);
2025-03-01 14:08:31 +01:00
[Signal]
public delegate void ShieldChangedEventHandler(float newValue, float maxValue);
2025-03-03 10:58:20 +01:00
[Signal]
public delegate void ShieldDecreasedEventHandler(float value, float newValue, float maxValue);
2025-03-01 14:08:31 +01:00
[Signal]
public delegate void DeathEventHandler();
public float CurrentHealth
{
get => _healthProvider.CurrentResource;
set => _healthProvider.CurrentResource = value;
}
public float CurrentShield
{
get => _shieldProvider.CurrentResource;
set => _shieldProvider.CurrentResource = value;
}
2025-03-11 17:58:46 +01:00
private IStateMachine<PlayerState, CharacterBody2D> _stateMachine;
2025-03-01 14:08:31 +01:00
2025-03-11 17:58:46 +01:00
public void Init(IStateMachine<PlayerState, CharacterBody2D> machine)
2025-03-01 14:08:31 +01:00
{
2025-03-11 17:58:46 +01:00
_stateMachine = machine;
2025-03-10 14:23:28 +01:00
Invulnerable = GlobalState.Instance.SessionSettings.GodMode;
2025-03-01 14:08:31 +01:00
_healthProvider.ResourceChanged += ((value, maxValue) =>
{
2025-03-03 09:20:11 +01:00
//if (!Enabled) return;
2025-03-03 10:58:20 +01:00
Hud.Instance?.UpdateHealth(value, maxValue);
2025-03-01 14:08:31 +01:00
EmitSignal(SignalName.HealthChanged, value, maxValue);
});
2025-03-03 10:58:20 +01:00
_healthProvider.ResourceDecreased += (value, newValue, maxValue) =>
{
EmitSignal(SignalName.HealthDecreased, value, newValue, maxValue);
};
_shieldProvider.ResourceDecreased += (value, newValue, maxValue) =>
{
EmitSignal(SignalName.ShieldDecreased, value, newValue, maxValue);
};
2025-03-01 14:08:31 +01:00
_shieldProvider.ResourceChanged += ((value, maxValue) =>
{
2025-03-03 09:20:11 +01:00
//if (!Enabled) return;
2025-03-03 10:58:20 +01:00
Hud.Instance?.UpdateShield(value, maxValue);
2025-03-01 14:08:31 +01:00
EmitSignal(SignalName.ShieldChanged, value, maxValue);
});
_healthProvider.ResourceDepleted += () =>
{
2025-03-03 09:20:11 +01:00
//if (!Enabled) return;
2025-03-01 14:08:31 +01:00
EmitSignal(SignalName.Death);
};
}
2025-03-03 09:20:11 +01:00
public void RefillHealth()
{
_healthProvider.FillResource();
}
public void RefillShield()
{
_shieldProvider.FillResource();
}
2025-03-01 14:08:31 +01:00
private void _on_damage_hitbox_area_entered(Area2D area)
{
if (!Enabled) return;
if (Invulnerable) return;
2025-03-03 17:55:53 +01:00
if (area.IsInGroup(AcidGroupName))
{
// Handle acid death
AcidDeath();
return;
}
2025-03-01 14:08:31 +01:00
if (area is not Bullet bullet || bullet.BulletOwner == BulletGroup) return;
this.Hit(bullet.Damage, bullet.DamageType);
bullet.RequestCollisionDestruction();
}
2025-03-03 17:55:53 +01:00
private void AcidDeath()
{
if (!Enabled) return;
GD.Print("Acid death");
2025-03-11 17:58:46 +01:00
_stateMachine.SetState(PlayerState.Drowning);
//_healthProvider.CurrentResource = 0;
2025-03-03 17:55:53 +01:00
}
2025-03-01 14:08:31 +01:00
public void Hit(float damage, DamageType type = DamageType.Neutral)
{
if (!Enabled) return;
if (CurrentShield > 0 && type is not DamageType.Explosive or DamageType.Acid)
{
// Reduce shield
//PlayShieldAnimation(); // Let this be handled by event
CurrentShield -= damage;
if (CurrentShield < 0)
{
CurrentHealth -= Math.Abs(CurrentShield);
CurrentShield = 0;
}
}
else
{
if (type is DamageType.Fire)
{
CurrentHealth -= damage * 2;
}
else
{
CurrentHealth -= damage;
}
//Blink(); // Let this be handled by event
}
if (!(CurrentHealth <= 0)) return;
}
}