155 lines
3.4 KiB
C#
155 lines
3.4 KiB
C#
using Godot;
|
|
using Godot.Collections;
|
|
using Newlon.Systems.Effects;
|
|
|
|
namespace Newlon.Components;
|
|
|
|
public partial class Entity : Node2D
|
|
{
|
|
#region Health points
|
|
[Export] public float MaxHP;
|
|
public float HP;
|
|
[Signal] public delegate void OnHPChangedEventHandler(int deltaHP, Node origin);
|
|
[Signal] public delegate void OnDamagedEventHandler();
|
|
|
|
public virtual void TakeDamage(float amount, Node origin)
|
|
{
|
|
HP -= amount;
|
|
EmitSignal(SignalName.OnHPChanged, -amount, origin);
|
|
EmitSignal(SignalName.OnDamaged);
|
|
if (HP <= 0)
|
|
{
|
|
KillByDamage();
|
|
}
|
|
}
|
|
|
|
public virtual void Heal(float amount, Node origin)
|
|
{
|
|
EmitSignal(SignalName.OnHPChanged, amount, origin);
|
|
HP += amount;
|
|
}
|
|
|
|
public virtual void KillByDamage()
|
|
{
|
|
Kill();
|
|
}
|
|
|
|
public virtual void Kill()
|
|
{
|
|
QueueFree();
|
|
}
|
|
|
|
|
|
#endregion
|
|
#region Brain
|
|
public virtual void DisableBrain()
|
|
{
|
|
GetNode<AnimationPlayer>("AnimationPlayer").ProcessMode = ProcessModeEnum.Always;
|
|
GetNode<AnimationTree>("AnimationTree").ProcessMode = ProcessModeEnum.Always;
|
|
ProcessMode = ProcessModeEnum.Disabled;
|
|
}
|
|
|
|
public virtual void EnableBrain()
|
|
{
|
|
GetNode<AnimationPlayer>("AnimationPlayer").ProcessMode = ProcessModeEnum.Inherit;
|
|
GetNode<AnimationTree>("AnimationTree").ProcessMode = ProcessModeEnum.Inherit;
|
|
ProcessMode = ProcessModeEnum.Inherit;
|
|
}
|
|
#endregion
|
|
#region Effects
|
|
[Export] private Array<Effect> _effectImmunities = new();
|
|
private readonly Dictionary<string,Effect> _activeEffectSlots = new();
|
|
private readonly Dictionary<string,Timer> _effectSlotTimers = new();
|
|
|
|
[Signal] public delegate void EffectStartedEventHandler(Effect what);
|
|
[Signal] public delegate void EffectEndedEventHandler(Effect what);
|
|
[Signal] public delegate void EffectContinuedEventHandler(Effect what);
|
|
|
|
|
|
public virtual void GiveEffect(Effect what)
|
|
{
|
|
if (_effectImmunities.Contains(what))
|
|
{
|
|
return;
|
|
}
|
|
|
|
string slot = what.Slot;
|
|
if (_activeEffectSlots.ContainsKey(slot) == false)
|
|
{
|
|
InitSlot(slot);
|
|
}
|
|
|
|
if (what == _activeEffectSlots[slot])
|
|
{
|
|
EmitSignal(SignalName.EffectContinued, what);
|
|
}
|
|
else
|
|
{
|
|
EmitSignal(SignalName.EffectStarted, what);
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
private void InitSlot(string key)
|
|
{
|
|
_activeEffectSlots.Add(key, null);
|
|
|
|
var timer = new Timer() { Autostart = false, OneShot = true };
|
|
AddChild(timer);
|
|
timer.Timeout += () => { EndEffectAtSlot(key); };
|
|
|
|
_effectSlotTimers.Add(key, timer);
|
|
|
|
}
|
|
|
|
public void EndEffect(Effect what)
|
|
{
|
|
EndEffectAtSlot(what.Slot);
|
|
}
|
|
|
|
public void ProcessEffects()
|
|
{
|
|
foreach(string key in _activeEffectSlots.Keys)
|
|
_activeEffectSlots[key]?.Process(this);
|
|
}
|
|
|
|
private void EndEffectAtSlot(string slot)
|
|
{
|
|
_activeEffectSlots[slot].Exit(this);
|
|
_activeEffectSlots[slot] = null;
|
|
|
|
EmitSignal(SignalName.EffectEnded, _activeEffectSlots[slot]);
|
|
|
|
}
|
|
#endregion
|
|
#region LocalTimescale
|
|
private float _localTimescale = 1.0f;
|
|
[Signal] public delegate void OnLocalTimescaleChangedEventHandler(float scale);
|
|
public float LocalTimescale
|
|
{
|
|
get => _localTimescale;
|
|
set
|
|
{
|
|
_localTimescale = value;
|
|
EmitSignal(SignalName.OnLocalTimescaleChanged, _localTimescale);
|
|
}
|
|
}
|
|
#endregion
|
|
#region Godot overrides
|
|
public override void _Ready()
|
|
{
|
|
HP = MaxHP;
|
|
}
|
|
#endregion
|
|
}
|