using Godot;
using TheLegendOfGustav.Map;
using TheLegendOfGustav.Utils;
namespace TheLegendOfGustav.Entities.Actors;
///
/// A classe de ator define um personagem no jogo.
///
[GlobalClass]
public partial class Actor : Entity
{
#region Fields
private int mp;
private int hp;
private int energy;
#endregion
#region Constructors
public Actor(Vector2I initialPosition, MapData map, ActorDefinition definition) : base(initialPosition, map, definition)
{
SetDefinition(definition);
}
#endregion
#region Signals
///
/// Sinal emitido toda vez que o HP mudar.
///
/// Novo HP
/// Quantidade máxima de HP.
[Signal]
public delegate void HealthChangedEventHandler(int hp, int maxHp);
///
/// Sinal emitido se o ator morrer.
///
[Signal]
public delegate void DiedEventHandler();
#endregion
#region Properties
///
/// Se o ator está vivo.
///
public bool IsAlive { get => Hp > 0; }
///
/// Utilizado no sistema de turnos.
/// Enquanto o ator tiver energia, ele poderá realizar turnos.
///
public int Energy
{
get => energy;
set
{
if (value > Speed)
{
energy = Speed;
}
else
{
energy = value;
}
}
}
///
/// Taxa de recarga de energia.
///
public int Speed { get => Definition.Speed; }
///
/// HP máximo do ator.
///
public int MaxHp { get; private set; }
///
/// HP atual do ator.
///
public int Hp
{
get => hp;
set
{
// Esta propriedade impede que o HP seja maior que o máximo.
hp = int.Clamp(value, 0, MaxHp);
EmitSignal(SignalName.HealthChanged, Hp, MaxHp);
if (hp <= 0)
{
Die();
}
}
}
///
/// Máximo de mana do ator.
///
public int MaxMp { get; private set; }
///
/// Mana atual do ator.
///
public int Mp
{
get => mp;
set
{
mp = int.Clamp(value, 0, MaxMp);
}
}
///
/// Estatística de ataque
///
public int Atk { get; private set; }
///
/// Estatística de defesa.
///
public int Def { get; private set; }
///
/// Estatística mental.
///
public int Men { get; private set; }
///
/// A definição do ator possui caracterísitcas padrões que definem
/// o ator em questão.
///
private ActorDefinition Definition
{
get;
set;
}
#endregion
#region Methods
///
/// Executado uma vez por turno,
///
public void RechargeEnergy()
{
Energy += Speed;
}
///
/// Move o ator para uma localização. Veja MovementAction.
///
/// Vetor que parte da posição do ator até o seu destino.
public void Walk(Vector2I offset)
{
// Cada ator tem um peso no sistema de pathfinding.
// Sempre que ele se mover, removemos seu peso da posição antiga
MapData.UnregisterBlockingEntity(this);
GridPosition += offset;
// E colocamos na próxima.
MapData.RegisterBlockingEntity(this);
// Este peso influencia o algoritmo de pathfinding.
// Atores evitam caminhos bloqueados. por outros atores.
}
///
/// Recupera uma quantidade de HP do ator.
///
/// HP para recuperar
/// Quanto HP foi realmente recuperado.
public int Heal(int amount)
{
int neoHp = Hp + amount;
if (neoHp > MaxHp) neoHp = MaxHp;
int recovered = neoHp - Hp;
Hp = neoHp;
return recovered;
}
///
/// Aplica uma definição de NPC para o ator.
/// Se o ator for um boneco de barro, este método é como um
/// sopro de vida.
///
/// A definição do ator.
public virtual void SetDefinition(ActorDefinition definition)
{
base.SetDefinition(definition);
Definition = definition;
Type = definition.Type;
MaxHp = definition.Hp;
Hp = definition.Hp;
MaxMp = definition.Mp;
Mp = definition.Mp;
Atk = definition.Atk;
Def = definition.Def;
Men = definition.Men;
}
public virtual void Die()
{
//⠀⠀⠀⠀⢠⣤⣤⣤⢠⣤⣤⣤⣤⣄⢀⣠⣤⣤⣄⠀⠀⠀⢀⣠⣤⣤⣄⠀⣤⣤⠀⠀⣠⣤⣤⣤⣤⣤⡄⢠⣤⣤⣤⣄⠀⠀
//⠀⠀⠀⠀⠈⢹⣿⠉⠈⠉⣿⣿⠉⠉⢾⣿⣉⣉⠙⠀⠀⢀⣾⡟⠉⠉⣿⣧⢸⣿⡄⢠⣿⠏⣿⣿⣉⣉⡁⢸⣿⡏⢉⣿⡷⠀
//⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⣿⣿⠀⠀⠈⠿⠿⣿⣿⡀⠀⠸⣿⡇⠀⠀⣾⣿⠀⢿⣿⣸⡿⠀⣿⣿⠿⠿⠇⢸⣿⣿⣿⣿⠀⠀
//⠀⠀⠀⠀⢠⣼⣿⣤⠀⠀⣿⣿⠀⠀⢷⣦⣤⣼⡿⠁⠀⠀⠹⣿⣤⣴⡿⠋⠀⠘⣿⣿⠃⠀⣿⣿⣤⣤⡄⢸⣿⡇⠙⢿⣦⡀
//⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⠀⠀⠀⠀⠀⠀⢀⣰⣶⣶⣶⣿⣿⣿⣿⣷⣶⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⠿⠛⠛⠻⢿⣿⣿⣿⣿⣿⣿⣿⣶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⠀⠀⠀⢀⢾⣿⣿⣿⣿⠟⠁⠀⠀⠀⠀⠀⠈⠉⠉⠉⠻⢿⢿⣿⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⠀⠀⢠⠏⢸⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠿⢻⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⠀⢀⠇⠀⠈⠿⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⢀⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⡸⠀⠀⠀⠀⠀⠀⠀⠀⡼⠛⠳⣄⡀⠀⠐⢿⣦⡀⠀⠀⠀⢠⠃⠀⣸⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⢠⠇⠀⠀⠀⠀⠀⠀⠀⠀⠉⠀⠀⠀⠉⣳⠟⠒⠻⣿⣦⡀⠀⡘⠀⢰⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⢀⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⠃⢠⣄⡀⠈⠙⢿⡌⠁⠀⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⣄⣈⢻⡿⠃⢰⠟⠲⣼⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⠀⡰⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⡶⢴⠋⠀⠀⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⡴⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠞⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⡴⢟⠒⠀⠀⠀⠀⢰⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠏⠀⠀⠈⠉⣿⠇⠀⢀⡎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⣷⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠠⣤⣤⣀⢰⠏⠉⠙⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣠⠴⠢⠦⠽⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⣿⣿⣿⣷⡄⣀⡀⠈⠉⠋⢹⠋⠁⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//⠿⠿⠿⠿⠿⠦⠈⠀⠀⠀⠸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
string deathMessage;
if (MapData.Player == this)
{
deathMessage = "Você morreu!";
}
else
{
deathMessage = $"{DisplayName} morreu!";
}
MessageLogData.Instance.AddMessage(deathMessage);
Texture = Definition.deathTexture;
BlocksMovement = false;
Type = EntityType.CORPSE;
DisplayName = $"Restos mortais de {DisplayName}";
MapData.UnregisterBlockingEntity(this);
EmitSignal(SignalName.Died);
}
#endregion
}