blob: 01efc186a4ce403bee8ef80bb1a82c86ba871c40 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
using Godot;
/// <summary>
/// Gerenciador de turnos, o senhor do tempo.
/// </summary>
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; }
/// <summary>
/// As ações do jogador ficam em uma fila e são executadas quando
/// possível dentro das regras do senhor do tempo.
/// </summary>
private Godot.Collections.Array<Action> playerActionQueue = [];
public TurnManager(Map map) {
this.map = map;
}
/// <summary>
/// Insere uma ação na fila de ações do jogador.
/// </summary>
/// <param name="playerAction"></param>
public void InsertPlayerAction(Action playerAction) {
playerActionQueue.Add(playerAction);
}
/// <summary>
/// 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.
/// </summary>
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();
}
bool actionResult = true;;
// Primeiro executamos a ação do jogador, se ele puder.
if (playerActionQueue.Count > 0 && Player.Energy > 0) {
Action action = playerActionQueue[0];
playerActionQueue.RemoveAt(0);
actionResult = action.Perform();
}
// Se a ação do jogador for gratuita ou se o jogador ainda possuir energia,
// ele poderá fazer mais um turno sem interrupções.
if (actionResult && 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);
}
}
/// <summary>
/// Método executado no início do turno.
/// </summary>
private void StartTurn() {
TurnCount++;
// Recarregamos a energia de todos os atores.
foreach (Entity entity in Map_Data.Entities) {
if (entity is Actor actor && actor.IsAlive) {
actor.RechargeEnergy();
}
}
}
/// <summary>
/// Executa turnos para cada ator no mapa.
/// </summary>
private void HandleEnemyTurns() {
foreach (Entity entity in Map_Data.Entities) {
if (entity is Player) continue;
// Se o ator for um inimigo e estiver vivo, deixamos
// que sua IA faça um turno.
if (entity is Enemy enemy && enemy.IsAlive) {
// O inimigo poderá fazer quantos turnos sua energia deixar.
while (enemy.Energy > 0) {
enemy.Soul.Perform();
}
}
}
}
}
|