-
Notifications
You must be signed in to change notification settings - Fork 0
/
gameplay.gd
434 lines (345 loc) · 11.1 KB
/
gameplay.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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
extends Node
#variables
#reference to the game log
# These define which numbers are used as the placeholders for
# the Max Zero and Question cards respectively.
var MAX_ZERO_VALUE = 100
var QUESTION_VALUE = 99
var DEFAULT_STARTING_BID = -16
var CHALLENGE_WAIT_TIME: float = 4 # in seconds
var deck = []
@export var currentPlayer: Node
var isFirstTurnOfRound = true
var currentBid = -16
var middleCard = 0
var allCardsVisible = false
var cardDealtFromQuestion = 0
@export var playerTemplate: PackedScene #The template for a new player.
var gameLog
# Called when the node enters the scene tree for the first time.
func _ready():
randomize()
gameLog = $UICanvas/GameLog/VBoxContainer/GameLogText
$UICanvas/OpenMenuButton.grab_focus()
var newPlayer
#print(str($/root/GlobalVariables.playerCount))
# Create the right number of players as children.
# Reparent them all to PlayerGrid.
# Make the first player in the list the player whose turn it is.
# Make sure the first player to be created is a human.
for i in range($/root/GlobalVariables.playerCount + 1):
newPlayer = playerTemplate.instantiate()
#newPlayer.reparent($PlayerGrid)
$PlayerGrid.add_child(newPlayer)
if i == 0:
newPlayer.isHumanPlayer = true
newPlayer.isUIPlayer = true
newPlayer.updateName("Player")
else:
newPlayer.updateName("Comp" + str(i))
$PlayerGrid.move_child($PlayerGrid/MiddleCard, -1)
currentPlayer = players()[0]
#print(players()[0])
setUpRound()
startTurn()
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
var playerToUse = currentPlayer
for p in players():
if p.isUIPlayer:
playerToUse = p
$UICanvas/TotalVisibleToPlayer.text = "Total visible: " + playerToUse.totalKnownToPlayerAsString()
pass
func livingPlayers():
# Returns a list of all living players.
# Use len(livingPlayers()) to get living player count.
return players().filter(func(player): return player.isAlive())
func players():
# Returns a list of all players.
return $PlayerGrid.get_children().filter(func(player): return player.is_in_group("Player"))
func nextLivingPlayer(player):
# Get the next living player after a specific player.
# This and lastLivingPlayer exist instead of just using lastLivingPlayerNew
# because I made them before writing nextLivingPlayerNew.
return nextLivingPlayerNew(player, true)
func lastLivingPlayer(player):
# Get the previous living player after a specific player.
return nextLivingPlayerNew(player, false)
func nextLivingPlayerNew(player, direction):
# Return the next living player in a direction.
# true = forward/in turn order
# false = backward/against turn order
# This doesn't use livingPlayers() just in case player is dead.
var index = players().find(player)
var currentPlayerNLP = player
var indexChange = 1
if direction:
indexChange = 1
else:
indexChange = -1
if len(livingPlayers()) < 2:
"""
Error checking: If there's one or less living players,
don't bother cycling through the list.
Just return the same player as the input.
I don't think this would ever be an issue.
"""
return player
else:
while true:
# Change the index in the specified direction,
# making sure it doesn't go out of bounds.
# Then if the player at that index is alive, return them.
index += indexChange
index = wrapi(index, 0, len(players()))
currentPlayerNLP = players()[index]
if currentPlayerNLP.isAlive():
return currentPlayerNLP
func setUpRound():
# Resets everything for a new round.
# However, this doesn't automatically start the turn.
allCardsVisible = false
makeDeck()
dealOutCards()
resetPeeks()
currentBid = DEFAULT_STARTING_BID
isFirstTurnOfRound = true
$PlayerGrid/MiddleCard.card = middleCard
func makeDeck():
# Creates a fresh deck.
deck.clear()
deck.append(-10)
deck.append(-5)
for i in range(11):
deck.append(i)
deck.append(15)
deck.append(20)
deck.append(MAX_ZERO_VALUE)
deck.append(QUESTION_VALUE)
deck.shuffle()
func dealOutCards():
# Deals the top cards from the deck out to each living player.
# Also to the middle as well as a spot reserved for if ? is in play.
var i = 0
for player in players():
if player.isAlive():
player.card = deck[i]
i += 1
else:
player.card = 0
middleCard = deck[i]
i += 1
cardDealtFromQuestion = deck[i]
pass
func resetPeeks():
# Resets whether players peeked.
for player in players():
player.canChallengeThisRound = true
if player.isAlive():
player.canSeeMiddleCard = false
else:
player.canSeeMiddleCard = true
func cardTranslated(cardNumber):
# Expresses a card number as text.
# Used by the game log.
if cardNumber == MAX_ZERO_VALUE:
return "Max 0"
elif cardNumber == QUESTION_VALUE:
return "?"
else:
return str(cardNumber)
func startTurn():
# Start a turn without changing whose turn it is.
#print(currentPlayer)
if currentPlayer.isHumanPlayer:
# show the interface and set the minimum bid to the current + 1
#$UICanvas/BidInput.min_value = currentBid + 1
$UICanvas/PlayerUI/BidInput.value = currentBid + 1
showPlayerUI()
pass
else:
# call the script for the AI turn
currentPlayer.startAITurn()
pass
func nextPlayersTurn():
#print(nextLivingPlayer(currentPlayer).get_name())
currentPlayer = nextLivingPlayer(currentPlayer)
startTurn()
func lastPlayerNewTurn():
currentPlayer = lastLivingPlayer(currentPlayer)
startTurn()
func specificPlayerStartTurn(player):
# Have a specific player start a turn.
currentPlayer = player
startTurn()
func raiseBid(newBid):
# Called by a player script whenever the bid is raised.
#print($PlayerGrid.get_children())
currentBid = newBid
currentPlayer.canChallengeThisRound = true
isFirstTurnOfRound = false
#update the game log
#$UICanvas/GameLog/VBoxContainer/GameLogText.add_text(currentPlayer.get_name() + " raised the bid to " + str(newBid) + ".")
gameLog.addText(currentPlayer.get_name() + " raised the bid to " + str(newBid) + ".")
nextPlayersTurn()
#print(str(newBid))
func cardTotal():
# Returns the total of all cards in play.
var total = 0
var maxCard = -16
var questionFound = false
var maxZeroFound = false
for p in livingPlayers():
if p.card == MAX_ZERO_VALUE:
maxZeroFound = true
elif p.card == QUESTION_VALUE:
questionFound = true
else:
if p.card > maxCard:
maxCard = p.card
total += p.card
if middleCard == MAX_ZERO_VALUE:
maxZeroFound = true
elif middleCard == QUESTION_VALUE:
questionFound = true
else:
if middleCard > maxCard:
maxCard = middleCard
total += middleCard
if questionFound:
if cardDealtFromQuestion == MAX_ZERO_VALUE:
maxZeroFound = true
else:
if cardDealtFromQuestion > maxCard:
maxCard = cardDealtFromQuestion
total += cardDealtFromQuestion
if maxZeroFound:
total -= maxCard
return total
func challengerWins():
# Return whether or not the challenging player wins.
return currentBid > cardTotal()
func resolveChallenge():
# Resolve a challenge.
# If the player who lost is dead after the challenger,
# the player after them takes the next turn.
$ChallengeTimer.start()
# The timer is used for the coroutine in startChallenge().
# Basically it's there to make sure that the game pauses to wait out the challenge.
# Setting allCardsVisible to true makes it so that players can see all cards
# until the start of the next round.
allCardsVisible = true
var challenger = currentPlayer
var bidder = lastLivingPlayer(currentPlayer)
var questionSeen = false
# Tell the game log what all the cards were.
gameLog.addText(challenger.get_name() + " challenged " + bidder.get_name() + "'s bid of " + str(currentBid) + ".")
gameLog.addText("The total was " + str(cardTotal()) + ".")
# actually say the card names here
gameLog.addText("The middle card was " + cardTranslated(middleCard))
if middleCard == QUESTION_VALUE:
questionSeen = true
for p in players():
if p.isAlive():
gameLog.addText(p.get_name() + " had " + cardTranslated(p.card))
if p.card == QUESTION_VALUE:
questionSeen = true
if questionSeen:
gameLog.addText("The card drawn from ? was " + cardTranslated(cardDealtFromQuestion))
#Resolve the challenge.
if challengerWins():
gameLog.addText(challenger.get_name() + " won the challenge.")
gameLog.addText("---")
challenger.openEye()
bidder.loseEye()
#setUpRound()
if bidder.isAlive():
#specificPlayerStartTurn(bidder)
currentPlayer = bidder
else:
if len(livingPlayers()) <= 1:
victory(challenger)
else:
#specificPlayerStartTurn(challenger)
currentPlayer = challenger
else:
# if the bidder wins
gameLog.addText(bidder.get_name() + " won the challenge.")
gameLog.addText("---")
bidder.openEye()
challenger.loseEye()
#setUpRound()
if challenger.isAlive():
#specificPlayerStartTurn(challenger)
currentPlayer = challenger
else:
if len(livingPlayers()) <= 1:
victory(bidder)
else:
currentPlayer = nextLivingPlayer(challenger)
#startTurn()
pass
func startChallenge():
#Calls resolveChallenge(), then waits a while before starting the next turn.
resolveChallenge()
await $ChallengeTimer.timeout
# Only start the turn if more than one player is still alive.
# Before I fixed this, there was an amusing bug where the winning player
# would just continue to play forever against themselves.
if len(livingPlayers()) > 1:
setUpRound()
startTurn()
func victory(player):
#Tell the game log that player won.
gameLog.addText(player.get_name() + " wins!")
pass
func sendPeekToGameLog(player):
# Tell the game log that that player peeked.
# Called by player scripts.
gameLog.addText(player.get_name() + " peeked.")
pass
func showPlayerUI():
$UICanvas/PlayerUI.show()
updatePlayerUIButtonStates()
$UICanvas/PlayerUI/RaiseBidButton.grab_focus()
func updatePlayerUIButtonStates():
$UICanvas/PlayerUI/PeekButton.set_disabled(false)
if isFirstTurnOfRound or currentPlayer.eyesOpen <= 0 or currentPlayer.canSeeMiddleCard:
$UICanvas/PlayerUI/PeekButton.set_disabled(true)
$UICanvas/PlayerUI/ChallengeButton.set_disabled(false)
if isFirstTurnOfRound or currentPlayer.canChallengeThisRound == false:
$UICanvas/PlayerUI/ChallengeButton.set_disabled(true)
func hidePlayerUI():
$UICanvas/PlayerUI.hide()
$UICanvas/OpenMenuButton.grab_focus()
func _on_raise_bid_button_pressed():
hidePlayerUI()
if $UICanvas/PlayerUI/BidInput.value > currentBid:
raiseBid($UICanvas/PlayerUI/BidInput.value)
else:
raiseBid(currentBid + 1)
func _on_challenge_button_pressed():
if not isFirstTurnOfRound:
if currentPlayer.canChallengeThisRound:
hidePlayerUI()
startChallenge()
func _on_peek_button_pressed():
if not isFirstTurnOfRound:
if currentPlayer.eyesOpen > 0:
if currentPlayer.canChallengeThisRound:
currentPlayer.peek()
updatePlayerUIButtonStates()
func _on_return_to_main_button_pressed():
get_tree().change_scene_to_file("res://main_menu.tscn")
func _on_open_menu_button_pressed():
$Menu.show()
$Menu/CloseMenuButton.grab_focus()
func _on_close_menu_button_pressed():
$Menu.hide()
$UICanvas/PlayerUI/RaiseBidButton.grab_focus()
func _on_rules_button_pressed():
$RulesMenu.show()
$Menu.hide()
func _on_close_button_pressed():
$UICanvas/PlayerUI/RaiseBidButton.grab_focus()