sevivon

[DORMANT] multiplayer dreidel game for mobile devices w/ godot
git clone git://git.figbert.com/sevivon.git
Log | Files | Refs | README | LICENSE

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