using System; using Cirno.Scripts.Components.FSM; 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; [Export] public StringName AcidGroupName { get; private set; } = "Acid"; [Signal] public delegate void HealthChangedEventHandler(float newValue, float maxValue); [Signal] public delegate void HealthDecreasedEventHandler(float value, float newValue, float maxValue); [Signal] public delegate void ShieldChangedEventHandler(float newValue, float maxValue); [Signal] public delegate void ShieldDecreasedEventHandler(float value, float newValue, float maxValue); [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; } private IStateMachine _stateMachine; public void Init(IStateMachine machine) { _stateMachine = machine; Invulnerable = GlobalState.Instance.SessionSettings.GodMode; _healthProvider.ResourceChanged += ((value, maxValue) => { //if (!Enabled) return; Hud.Instance?.UpdateHealth(value, maxValue); EmitSignal(SignalName.HealthChanged, value, maxValue); }); _healthProvider.ResourceDecreased += (value, newValue, maxValue) => { EmitSignal(SignalName.HealthDecreased, value, newValue, maxValue); }; _shieldProvider.ResourceDecreased += (value, newValue, maxValue) => { EmitSignal(SignalName.ShieldDecreased, value, newValue, maxValue); }; _shieldProvider.ResourceChanged += ((value, maxValue) => { //if (!Enabled) return; Hud.Instance?.UpdateShield(value, maxValue); EmitSignal(SignalName.ShieldChanged, value, maxValue); }); _healthProvider.ResourceDepleted += () => { //if (!Enabled) return; EmitSignal(SignalName.Death); }; } public void RefillHealth() { _healthProvider.FillResource(); } public void RefillShield() { _shieldProvider.FillResource(); } private void _on_damage_hitbox_area_entered(Area2D area) { if (!Enabled) return; if (Invulnerable) return; if (area.IsInGroup(AcidGroupName)) { // Handle acid death AcidDeath(); return; } if (area is not Bullet bullet || bullet.BulletOwner == BulletGroup) return; this.Hit(bullet.Damage, bullet.DamageType); bullet.RequestCollisionDestruction(); } private void AcidDeath() { if (!Enabled) return; GD.Print("Acid death"); _stateMachine.SetState(PlayerState.Drowning); //_healthProvider.CurrentResource = 0; } 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; } }