main.gd (8545B)
1 extends Node 2 3 4 signal client_anted 5 const SERVER_IP := "10.0.0.76" # Development 6 #const SERVER_IP := "135.181.44.54" # Production 7 const SERVER_PORT := 1780 8 const MAX_PLAYERS := 5 9 const DREIDEL_FACES := ["nun", "gimmel", "hey", "pey/shin"] 10 const USERNAMES := ["Judah", "Yochanan", "Shimon", "Elazar", "Yonatan"] 11 const POT_STARTING_GELT := 5 12 const PLAYER_STARTING_GELT := 10 13 var ACCEL_THRESHOLD := 3 if OS.get_name() == "iOS" else 30 14 var players := {} 15 var pot := POT_STARTING_GELT 16 var spin_disabled := false 17 remotesync var game_started := false 18 remotesync var current_turn := { "id": -1, "index": -1 } 19 20 21 func _ready() -> void: 22 if "--server" in OS.get_cmdline_args() or OS.has_feature("Server"): 23 _initialize_server() 24 else: 25 _initialize_client() 26 27 28 func _process(delta: float) -> void: 29 if not ("--server" in OS.get_cmdline_args() or OS.has_feature("Server")): 30 _check_for_spin() 31 32 33 ## Server Logic 34 func _initialize_server() -> void: 35 var peer := NetworkedMultiplayerENet.new() 36 peer.create_server(SERVER_PORT, MAX_PLAYERS) 37 get_tree().network_peer = peer 38 get_tree().connect("network_peer_connected", self, "_client_joined_server") 39 get_tree().connect("network_peer_disconnected", self, "_client_left_server") 40 41 42 ### Network Peer Signals 43 func _client_joined_server(id: int) -> void: 44 players[id] = { 45 "name": USERNAMES[players.size()], 46 "gelt": PLAYER_STARTING_GELT, 47 "in": true, 48 "paid_ante": true, 49 } 50 51 var username: String = players[id]["name"] 52 var greeting: String = "Welcome to Sov! You're now known as %s." % username 53 print("%s (%s) joined successfully" % [username, id]) 54 rpc_id(id, "print_message_from_server", greeting) 55 56 var peers := _peers(id) 57 var message := "" 58 if peers.size() > 0: 59 var names := _join_array(_peers(id, true), "\n ") 60 message = "Some players are already here:\n %s" % names 61 else: 62 message = "You are the first player here – shake your phone to start the game once everybody's arrived!" 63 rpc_id(id, "print_message_from_server", message) 64 for player in peers: 65 message = "%s has joined the server!" % username 66 rpc_id(player, "print_message_from_server", message) 67 68 69 func _client_left_server(id: int) -> void: 70 var username: String = players[id]["name"] 71 print("%s (%s) disconnected from the server" % [username, id]) 72 players.erase(id) 73 if players.size() > 0: 74 _end_game("%s has left the server. Stopping the game." % username) 75 76 77 ### Game Phases 78 func _start_game() -> void: 79 get_tree().set_refuse_new_network_connections(true) 80 rset("game_started", true) 81 rpc("print_message_from_server", "The game has begun!") 82 yield(get_tree().create_timer(0.5), "timeout") 83 rset("current_turn", { "id": players.keys()[0], "index": 0 }) 84 var username: String = players[current_turn["id"]]["name"] 85 rpc("print_message_from_server", "It's %s's turn" % username) 86 rpc("print_message_from_server", _gelt_status()) 87 88 89 func _end_game(message: String) -> void: 90 get_tree().set_refuse_new_network_connections(false) 91 rset("game_started", false) 92 rset("current_turn", { "id": -1, "index": -1 }) 93 for id in players.keys(): 94 players[id]["gelt"] = PLAYER_STARTING_GELT 95 players[id]["in"] = true 96 pot = POT_STARTING_GELT 97 rpc("print_message_from_server", message) 98 rpc_id(players.keys()[0], "print_message_from_server", "To play again, shake your phone once everybody's ready!") 99 100 101 ### Player Actions 102 remote func shake_action() -> void: 103 var sender := get_tree().get_rpc_sender_id() 104 if game_started: 105 if sender == current_turn["id"] and players[sender]["in"] and _everyone_anted(): 106 _client_spun(sender) 107 rpc_id(sender, "vibrate_device") 108 elif not players[sender]["paid_ante"]: 109 _send_ante_signal(sender) 110 rpc_id(sender, "vibrate_device") 111 else: 112 if players.size() > 1 and sender == players.keys()[0]: 113 _start_game() 114 rpc_id(sender, "vibrate_device") 115 116 117 func _client_spun(sender: int) -> void: 118 rpc("print_message_from_server", "%s has spun the dreidel..." % players[sender]["name"]) 119 yield(get_tree().create_timer(1), "timeout") 120 _spin_dreidel(sender) 121 rpc("print_message_from_server", _gelt_status()) 122 rpc("print_message_from_server", "Time to ante up!") 123 yield(_everyone_puts_in_one(), "completed") 124 var has_won := _check_for_winner() 125 if has_won: 126 var winner := _find_winner() 127 _end_game("We have a winner! Congratulations, %s!" % players[winner]["name"]) 128 else: 129 rpc("print_message_from_server", _gelt_status()) 130 _iterate_turn() 131 132 133 func _spin_dreidel(id: int) -> void: 134 randomize() 135 var username: String = players[id]["name"] 136 var spin: int = floor(rand_range(0, 4)) 137 var result: String = DREIDEL_FACES[spin] 138 rpc("print_message_from_server", "%s landed on %s!" % [username, result]) 139 match(spin): 140 1: # gimmel 141 players[id]["gelt"] += pot 142 pot = 0 143 2: # hey 144 players[id]["gelt"] += ceil(pot / 2.0) 145 pot -= ceil(pot / 2.0) 146 3: # pey/shin 147 if players[id]["gelt"] > 0: 148 players[id]["gelt"] -= 1 149 pot += 1 150 else: 151 rpc("print_message_from_server", "%s can't pay – you lose!" % username) 152 players[id]["in"] = false 153 154 155 func _everyone_puts_in_one() -> void: 156 for id in players.keys(): 157 if players[id]["in"]: 158 players[id]["paid_ante"] = false 159 160 while not _everyone_anted(): 161 var id: int = yield(self, "client_anted") 162 var username: String = players[id]["name"] 163 if not players[id]["in"] or players[id]["paid_ante"]: 164 continue 165 if players[id]["gelt"] > 0: 166 players[id]["gelt"] -= 1 167 pot += 1 168 rpc("print_message_from_server", "%s has anted!" % username) 169 else: 170 rpc("print_message_from_server", "%s can't pay the ante – you lose!" % username) 171 players[id]["in"] = false 172 players[id]["paid_ante"] = true 173 174 175 func _iterate_turn() -> void: 176 var index: int 177 if current_turn["index"] == players.size() - 1: 178 index = 0 179 else: 180 index = current_turn["index"] + 1 181 var id: int = players.keys()[index] 182 if not players[id]["in"]: 183 current_turn = { "id": id, "index": index } 184 _iterate_turn() 185 else: 186 var username: String = players[id]["name"] 187 var new_turn := { "id": id, "index": index } 188 rset("current_turn", new_turn) 189 rpc("print_message_from_server", "It's now %s's turn" % username) 190 191 192 func _send_ante_signal(id: int) -> void: 193 emit_signal("client_anted", id) 194 195 196 ## Client Logic 197 func _initialize_client() -> void: 198 var peer := NetworkedMultiplayerENet.new() 199 peer.create_client(SERVER_IP, SERVER_PORT) 200 get_tree().network_peer = peer 201 get_tree().connect("connected_to_server", self, "_client_connected_successfully") 202 get_tree().connect("connection_failed", self, "_client_connection_failed") 203 var safe_area := OS.get_window_safe_area() 204 $Label.set_margin(MARGIN_TOP, safe_area.position.y) 205 206 207 func _client_connected_successfully() -> void: 208 $Label.text += "Connection to server established.\n" 209 210 211 func _client_connection_failed() -> void: 212 $Label.text += "Could not connect to server.\n" 213 214 215 func _check_for_spin() -> void: 216 var accel := Input.get_accelerometer() 217 if accel.length() > ACCEL_THRESHOLD and not spin_disabled: 218 rpc_id(1, "shake_action") 219 _toggle_spin() 220 221 222 func _toggle_spin() -> void: 223 spin_disabled = true 224 yield(get_tree().create_timer(0.5), "timeout") 225 spin_disabled = false 226 227 228 remote func print_message_from_server(message: String) -> void: 229 $Label.text += message + "\n" 230 231 232 remote func vibrate_device() -> void: 233 Input.vibrate_handheld() 234 235 236 ## Utility Functions 237 func _everyone_anted() -> bool: 238 return _compare_player_bool_properties("paid_ante", players.size()) 239 240 241 func _check_for_winner() -> bool: 242 return _compare_player_bool_properties("in", 1) 243 244 245 func _compare_player_bool_properties(prop: String, out: int) -> bool: 246 var sum := 0 247 for id in players.keys(): 248 sum += int(players[id][prop]) 249 return true if sum == out else false 250 251 252 func _find_winner() -> int: 253 for id in players.keys(): 254 if players[id]["in"]: 255 return id 256 return -1 257 258 259 func _gelt_status() -> String: 260 var message := "Current gelt status:\n Pot: %s\n" % pot 261 for id in players.keys(): 262 var username: String = players[id]["name"] 263 var gelt := "" 264 if players[id]["in"]: 265 gelt = players[id]["gelt"] 266 else: 267 gelt = "Out" 268 message += " %s: %s\n" % [username, gelt] 269 return message 270 271 272 func _peers(id: int, names := false) -> Array: 273 var peers_array := players.keys().duplicate() 274 peers_array.erase(id) 275 if names: 276 var names_array := [] 277 for peer in peers_array: 278 names_array.append(players[peer]["name"]) 279 return names_array 280 return peers_array 281 282 283 func _join_array(array: Array, delimiter := "") -> String: 284 var joined_string := "" 285 for item in array.slice(0, -2): 286 joined_string += "%s%s" % [item, delimiter] 287 joined_string += str(array[-1]) 288 return joined_string