using System.Collections.Generic; using Godot; using Newlon.Systems.Effects; namespace Newlon.Components.Zombies; public partial class RuntimeZombieData : Node2D, IEntity, ILocalTimescale, IEffectHandler { [Signal] public delegate void OnHPChangedEventHandler(int deltaHP, Node origin); [Signal] public delegate void OnDamagedEventHandler(); [Signal] public delegate void OnLocalTimescaleChangedEventHandler(int currentTimescale); [Export] private int _hp; [Export] private int _maxHP; [Export] private Armor _armor; [Export] private AudioStream garlicSound; [Export] private AudioStream freezeSound; private float _localTimescale = 1.0f; public int Hp => _hp; public int MaxHp => _maxHP; public bool AbleToEat = true; public float LocalTimescale { get => _localTimescale; set { _localTimescale = value; EmitSignal(SignalName.OnLocalTimescaleChanged,_localTimescale); } } public override void _Ready() { _hp = _maxHP; // Effect timers setup for(int i = 0; i < Utility.EffectSlotCount; i++) { var timer = new Timer() {Autostart = false, OneShot = true}; _effectSlotTimers[i] = timer; AddChild(timer); int current_index = i; timer.Timeout += () => {EndEffectAtSlot(current_index);}; } } public void Heal(int amount,Node origin) { if(_armor != null) { _hp += _armor.Heal(amount); } else _hp += amount; EmitSignal(SignalName.OnHPChanged,amount,origin); if (MaxHp > 0) { _hp = MaxHp; } } public void TakeDamage(int amount, Node origin, Utility.DamageTypes damageType = Utility.DamageTypes.PHYSICAL) { if (_armor != null) { _hp -= _armor.RecieveDamage(amount); } else _hp -= amount; EmitSignal(SignalName.OnHPChanged,-amount, origin); EmitSignal(SignalName.OnDamaged); if (_hp <= 0) { QueueFree(); } } #region Effects system private readonly Effect[] _activeEffectSlots = new Effect[Utility.EffectSlotCount]; private readonly Timer[] _effectSlotTimers = new Timer[Utility.EffectSlotCount]; // Effect handling public void GiveEffect(Effect what) { int slot = (int)what.Slot; if (_activeEffectSlots[slot] == null) { switch (what.Slot) { case Utility.EffectSlots.FREEZE: AudioSequencer.Play("zombie_freeze", freezeSound); var settings = new ChannelSettings(); settings.restartTreshold = -1; AudioSequencer.ChangeSettings("zombie_freeze",settings); break; case Utility.EffectSlots.GARLIC: AudioSequencer.Play("zombie_garlic", garlicSound); break; } } if (_activeEffectSlots[slot] != null) { _effectSlotTimers[slot].Stop(); _activeEffectSlots[slot].Exit(this); } _effectSlotTimers[slot].WaitTime = what.Duration; _effectSlotTimers[slot].Start(); what.Enter(this); _activeEffectSlots[slot] = what; } public void EndEffect(Effect what) { what.Exit(this); _activeEffectSlots[(int)what.Slot] = null; } public void ProcessEffects() { for(int i = 0; i < Utility.EffectSlotCount; i++) _activeEffectSlots[i]?.Process(this); } private void EndEffectAtSlot(int slot) { _activeEffectSlots[slot].Exit(this); _activeEffectSlots[slot] = null; } #endregion }