using System; 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; [Signal] public delegate void HealthChangedEventHandler(float newValue, float maxValue); [Signal] public delegate void ShieldChangedEventHandler(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; } public void Init() { _healthProvider.FillResource(); _shieldProvider.FillResource(); _healthProvider.ResourceChanged += ((value, maxValue) => { if (!Enabled) return; EmitSignal(SignalName.HealthChanged, value, maxValue); }); _shieldProvider.ResourceChanged += ((value, maxValue) => { if (!Enabled) return; EmitSignal(SignalName.ShieldChanged, value, maxValue); }); _healthProvider.ResourceDepleted += () => { if (!Enabled) return; EmitSignal(SignalName.Death); }; } private void _on_damage_hitbox_area_entered(Area2D area) { if (!Enabled) return; if (Invulnerable) return; if (area is not Bullet bullet || bullet.BulletOwner == BulletGroup) return; this.Hit(bullet.Damage, bullet.DamageType); bullet.RequestCollisionDestruction(); } 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; } }