forked from smccourtb/bones
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.gd
297 lines (251 loc) · 10.2 KB
/
main.gd
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
extends Node
signal roll_phase_begin
signal roll_phase_end
signal target_phase_begin
signal target_phase_end
signal combat_phase_begin
signal combat_phase_end
var rerolls: int = 2
var round_num: int = 1
var turn_owner: bool = false # if true player turn, false: enemy
# node references
onready var units = $UI/Units
onready var players = $UI/Units/HBoxContainer/PlayerBattlers
onready var enemies = $UI/Units/HBoxContainer/EnemyBattlers
onready var reroll_button = $UI/Reroll
onready var end_phase_button = $UI/EndPhase
onready var undo_button = $UI/Undo
onready var win_message = $UI/WinMessage
# although this is the main script right now, much of this will be moved to
# "battle" script in the future
func setup_signals() -> void:
# these signals control the flow of the phases of battle
connect("roll_phase_begin", self, "_on_rollPhase_begin")
connect("roll_phase_end", self, "_on_rollPhase_end")
connect("target_phase_end", self, "_on_targetPhase_end")
connect("target_phase_begin", self, "_on_targetPhase_begin")
connect("combat_phase_begin", self, "_on_combatPhase_begin")
connect("combat_phase_end", self, "_on_combatPhase_end")
units.connect("actions_selected", self, "_on_ActionsSelected")
func _ready() -> void:
setup_signals()
reroll_button.set_text("%s (%s)" % [tr("LABEL_REROLL"), str(rerolls)])
win_message.set_text(tr("LABEL_WIN_MESSAGE"))
randomize()
# TODO: add an "{ begin / end } { current_phase } Phase" button to call this
# and the other phases. One button for all logic.
emit_signal("roll_phase_begin")
func _physics_process(_delta: float) -> void:
# debugging purposes. Updates the phase and whose turn it is
units.turn_label.text = "Player Turn" if turn_owner else "Enemy Turn"
units.phase_label.text = "Phase: " + Global.get_turn_phase_name()
end_phase_button.set_text("End %s Phase" % [Global.get_turn_phase_name().to_lower().capitalize()])
# hides button unless its players roll phase
reroll_button.visible = Global.turn_phase == Global.TurnPhase.ROLL and turn_owner
end_phase_button.visible = Global.turn_phase != Global.TurnPhase.COMBAT
undo_button.visible = Global.turn_phase != Global.TurnPhase.COMBAT
if Global.turn_phase == Global.TurnPhase.ROLL and turn_owner:
end_phase_button.set_disabled(!check_if_die_done_rolling())
if not turn_owner:
end_phase_button.set_disabled(true)
undo_button.set_disabled(true)
if units.action_stack.empty():
undo_button.set_disabled(true)
if Global.turn_phase == Global.TurnPhase.TARGET and turn_owner:
if units.target_stack.empty():
undo_button.set_disabled(true)
else:
undo_button.set_disabled(false)
func set_reroll(amount) -> void:
# subtracts the amount provided from reroll.
rerolls += amount
if rerolls <= 0:
reroll_button.set_disabled(true)
rerolls = 0
if get_reroll() + amount > 2:
rerolls = 2
reroll_button.set_text("Reroll (" + str(rerolls) + ")")
reroll_button.set_disabled(rerolls < 1)
func get_reroll() -> int:
return rerolls
func _on_rollPhase_begin() -> void:
print("ENTERING ROLL PHASE")
Global.turn_phase = Global.TurnPhase.ROLL
# begins game as enemy turn
# loops through all units for whosever turn it is and rolls their die
if turn_owner:
for player in players.get_children():
player.roll_die()
else:
# TODO: if an enemy dies, the game gets held up here waiting for a dead
# enemy to roll their die. FIXME
# temp solution right here. not tested yet
for enemy in enemies.get_children():
if is_instance_valid(enemy):
enemy.roll_die()
else: continue
func _on_rollPhase_end() -> void:
print("EXITING ROLL PHASE")
# officially ends the roll phase and beings the target phase
emit_signal("target_phase_begin")
func _on_targetPhase_begin() -> void:
print("ENTERING TARGET PHASE")
# updates the debug "phase" label
Global.turn_phase = Global.TurnPhase.TARGET
# loops through all player units, checks if there are any misses and sets the
# target to null but still triggers the target selected signal so it can increase
# the count for the signal actions_selected
if turn_owner:
for player in players.get_children():
if player.action_choice.name == "Miss":
player.emit_signal("target_selected", null)
# sets target_selected variable
player.set_target_selected(true)
if not turn_owner:
# for enemies, loop through all of them and for the ones that have not
# missed choose a random target
for enemy in enemies.get_children():
# it doesnt matter if they roll a miss or not. its handled inside the
# function choose_target() AND set_enemy_target(). It doesn't matter
# because it loops through all chooses a target if it can and then
# moves on regardless. With the player you need to wait for input.
if not enemy.action_choice.name == "Miss":
enemy.choose_target()
# triggers the end of target phase
emit_signal("target_phase_end")
func _on_targetPhase_end() -> void:
# so these are different because the enemy first rolls, chooses their actions,
# and chooses their targets before the player does anything. So it sets the
# turn owner to the player, then triggers the beginning of the roll phase to
# let the player do the saem thing. When it gets back here as the players turn,
# its time to begin combat. As of right now. The player goes first.
print("EXITING TARGET PHASE")
if turn_owner:
emit_signal("combat_phase_begin")
else:
turn_owner = not turn_owner
emit_signal("roll_phase_begin")
func _on_combatPhase_begin() -> void:
print("ENTERING COMBAT PHASE")
Global.turn_phase = Global.TurnPhase.COMBAT
if turn_owner:
# loops through all player units and checks if they have a target, then
# puts them in this characters array.
var characters = []
for player in players.get_children():
if player.target:
characters.append(player)
# then it loops through that characters array and checks if its disabled
# variable is set to true. This isnt used right now. I was using it for
# when somebody died but now i just free the node. I am leaving it because
# I may have status effects in the future and disabled will be handy
for character in characters:
if not character.disabled:
# slides the the whole character control node forward
character.action_tween_start()
# slides the the characters target node forward
character.target.action_tween_start()
yield(get_tree().create_timer(.5), "timeout")
# performs its action that it chose in the roll phase
# also plays its appropriate animation
character.action()
yield(get_tree().create_timer(1.0), "timeout")
# slides both characters back to their original spots
character.action_tween_end()
if is_instance_valid(character.target):
character.target.action_tween_end()
yield(get_tree().create_timer(1.5), "timeout")
# swaps over to the enemy and starts combat phase over
turn_owner = not turn_owner
emit_signal("combat_phase_begin")
else:
for enemy in enemies.get_children():
# does the same thing as above but in one line and doesnt create a
# new array
if enemy.target and not enemy.disabled:
enemy.action()
# # gives it a little room to breathe between combats
# TODO: add the same thing as above here possibly put it into
# a function
yield(get_tree().create_timer(2.0), "timeout")
emit_signal("combat_phase_end")
func _on_combatPhase_end() -> void:
print("EXITING COMBAT PHASE")
# Just a clean up function that performs the resets for everything to prepare
# for the next round, if there is no winner
round_num +=1 # <- no functionality to that yet
# resets rerolls
set_reroll(2)
# sets turn_owner to enemy
turn_owner = false
# TODO: make a reset function for units and just call that here instead
units.enemy_actions_selected = 0
units.player_actions_selected = 0
units.player_targets_selected = 0
units.action_stack = []
units.target_stack = []
# reset each unit (character) on both sides so they get set back to the
# beginning of combat state.
# TODO: move this to $Units it makes more sense to have this there than main.
for unit in units.unit_refs:
# should update unit_refs to remove the references but this works
if is_instance_valid(unit):
unit.reset()
# this is just thrown in to signify combat is over. All placeholder stuff
if check_for_win():
win_message.show()
set_pause_mode(true)
else:
emit_signal("roll_phase_begin")
func _on_ActionsSelected() -> void:
# this is an odd situation becuase its separate from the other logic
# used in the other turn phase functions. emitted from units.gd
# called when all actions(die) on either side are selected
if not turn_owner: # if enemy turn
yield(get_tree().create_timer(1.0), "timeout")
emit_signal("roll_phase_end")
func check_for_win() -> bool:
# we could use get_nodes_in_group("enemies") but we already have the
# reference
if enemies.get_children().size() > 0:
return false
return true
func _on_Reroll_pressed() -> void:
# subtract 1 reroll action from total rerolls
set_reroll(-1)
# roll all available player dice
var dice = get_tree().get_nodes_in_group("die")
for die in dice:
# this is just me guessing at values
# would be nice make it feel a bit more 'realistic'
die.set_gravity_scale(4)
die.apply_impulse(die.translation, Vector3(randi() % 5 + .5, randi() % 5 + .5, randi() % 5 + .5))
yield(get_tree().create_timer(.1), "timeout")
die.set_physics_process(true)
func check_if_die_done_rolling():
for i in players.get_children():
if not is_instance_valid(i.die) or i.die.stopped:
return true
return false
func _on_EndPhase_pressed() -> void:
var turn_phase = Global.get_turn_phase_name()
if turn_phase == "ROLL": # and all die have "stopped"
# check all players if they have selected an action
# if not set the selection
for i in players.get_children():
if not i.action_choice:
i.die.emit_signal("die_selected", i.die.actions[i.die.roll])
elif turn_phase == "TARGET":
emit_signal("target_phase_end")
func _on_Undo_pressed() -> void:
if Global.turn_phase == Global.TurnPhase.ROLL:
var x = units.action_stack.pop_back()
units.player_actions_selected -= 1
x.ui_animation_player.play_backwards("show_action_container")
x.action_choice = null
x.add_child(x.die)
x.die.set_scale(Vector3(1,1,1))
elif Global.turn_phase == Global.TurnPhase.TARGET:
var x = units.target_stack.pop_back()
units.player_targets_selected -= 1
x.set_target(false)