newlon/scripts/components/Entity.cs
2025-07-08 00:05:23 +05:00

156 lines
3.4 KiB
C#

using Godot;
using Godot.Collections;
using Newlon.Systems.Effects;
namespace Newlon.Components;
[GlobalClass]
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
}