using Godot; /// /// Gerenciador de turnos, o senhor do tempo. /// public partial class TurnManager : RefCounted { public int TurnCount { get; private set; } = 0; private Map map; private MapData Map_Data { get => map.Map_Data; } private Player Player { get => Map_Data.Player; } /// /// As ações do jogador ficam em uma fila e são executadas quando /// possível dentro das regras do senhor do tempo. /// private Godot.Collections.Array playerActionQueue = []; public TurnManager(Map map) { this.map = map; } /// /// Insere uma ação na fila de ações do jogador. /// /// public void InsertPlayerAction(Action playerAction) { playerActionQueue.Add(playerAction); } /// /// Computa um turno. /// /// Um turno segue a seguinte ordem lógica /// 1. Todos os atores recebem energia com base nas suas velocidades. /// 2. O jogador performa ações enquanto sua energia permitir /// 3. Os outros atores performam suas ações enquanto sua energia permitir. /// public void Tick() { // Se o jogador puder agir mas a fila de ações estiver vazia, // não computamos o turno. if (playerActionQueue.Count == 0 && Player.Energy > 0) { return; } Vector2I previousPlayerPos = Player.GridPosition; // Início do turno, o jogador recebe um pouco de energia. if (Player.Energy <= 0) { StartTurn(); } // Primeiro executamos a ação do jogador, se ele puder. if (playerActionQueue.Count > 0 && Player.Energy > 0) { Action action = playerActionQueue[0]; playerActionQueue.RemoveAt(0); action.Perform(); } // Se o jogador ainda tem energia, ele poderá fazer // mais um turno sem interrupções. if (Player.Energy <= 0) { // Depois computamos os turnos dos outros atores. HandleEnemyTurns(); map.UpdateFOV(Player.GridPosition); } // Por fim, se o jogador mudou de lugar, atualizamos seu campo de visão. if (Player.GridPosition != previousPlayerPos) { map.UpdateFOV(Player.GridPosition); } } /// /// Método executado no início do turno. /// private void StartTurn() { TurnCount++; // Recarregamos a energia de todos os atores. foreach (Actor actor in Map_Data.Actors) { if (actor.IsAlive) { actor.RechargeEnergy(); } } } /// /// Executa turnos para cada ator no mapa. /// private void HandleEnemyTurns() { foreach (Actor actor in Map_Data.Actors) { if (actor is Player) continue; // Se o ator for um inimigo e estiver vivo, deixamos // que sua IA faça um turno. if (actor is Enemy enemy && enemy.IsAlive) { // O inimigo poderá fazer quantos turnos sua energia deixar. while (enemy.Energy > 0) { enemy.Soul.Perform(); } } } } }