online multiplayer chess game (note server currently down)
multiplayer
| -rw-r--r-- | Events.gd | 1 | ||||
| -rw-r--r-- | Globals.gd | 41 | ||||
| -rw-r--r-- | Grid.gd | 60 | ||||
| -rw-r--r-- | Square.gd | 2 | ||||
| -rw-r--r-- | Utils.gd | 26 | ||||
| -rw-r--r-- | networking/Network.gd | 105 | ||||
| -rw-r--r-- | pieces/Pawn.gd | 5 | ||||
| -rw-r--r-- | pieces/Piece.gd | 6 | ||||
| -rw-r--r-- | project.godot | 7 | ||||
| -rw-r--r-- | ui/Lobby.gd | 228 | ||||
| -rw-r--r-- | ui/Lobby.tscn | 117 | ||||
| -rw-r--r-- | ui/MovesList.gd | 2 | ||||
| -rw-r--r-- | ui/Settings.tscn | 20 | ||||
| -rw-r--r-- | ui/StartMenu.gd | 2 | ||||
| -rw-r--r-- | ui/StartMenu.tscn | 23 | ||||
| -rw-r--r-- | ui/Timer.gd | 2 | ||||
| -rw-r--r-- | ui/TimerLabels.gd | 4 |
17 files changed, 412 insertions, 239 deletions
@@ -5,3 +5,4 @@ signal turn_over signal just_before_turn_over # called just before turn over signal outoftime # called when the time is up signal game_over # called when the game is over +signal go_back # called when the game is over, and were ready to go back @@ -1,9 +1,12 @@ extends Node -var __nosethalfmove = false +const pieces = "NKQRBP" +var __nosethalfmove = false var pawns = [] # PoolPawnArray +var team = true var grid: Grid = null +var network: Network = null var piece_set := "california" var fullmove := 1 var halfmove := 0 @@ -15,7 +18,34 @@ var turn := true # true for white, false for black # true cuz white goes first -func turns(_winner) -> int: +func reset_vars() -> void: + __nosethalfmove = false + pawns = [] + team = true + grid = null + fullmove = 1 + halfmove = 0 + in_check = false + checking_piece = null + white_king = null + black_king = null + turn = true + Utils.reset_vars() + + +func pack_vars() -> Dictionary: + return { + "fullmove": fullmove, + "halfmove": halfmove, + "turn": turn, + } + + +func get_var(key): + return self.get(key) + + +func turns() -> int: return fullmove @@ -25,12 +55,15 @@ func reset_halfmove() -> void: func add_turn() -> void: + Events.emit_signal("just_before_turn_over") if !turn: fullmove += 1 if __nosethalfmove: __nosethalfmove = false - return - halfmove += 1 + else: + halfmove += 1 + turn = not turn + Events.emit_signal("turn_over") func _ready() -> void: @@ -36,7 +36,7 @@ var matrix := [] var promoting = null var background_matrix := [] var history_matrixes := {} -var last_clicked = null +var last_clicked: Piece = null onready var PIECE_SET: String = Globals.piece_set @@ -47,8 +47,11 @@ onready var pieces := $Pieces onready var status_label := $"../UI/Holder/Back/VBox/Status" +func _init(): + Globals.grid = self + + func _ready() -> void: - Globals.grid = self # tell the globals that this is the grid init_board() # create the tile squares init_matrix() # create the pieces init_labels() # add the labels @@ -101,9 +104,7 @@ func init_labels() -> void: letterslabel.rect_position.x = i * piece_size.x letterslabel.rect_position.y = piece_size.y * 7 size_label(letterslabel, i) - letterslabel.get_node("Label").text = Utils.calculate_algebraic_position( - letterslabel.rect_position / piece_size - )[0] + letterslabel.get_node("Label").text = Utils.to_algebraic(letterslabel.rect_position / piece_size)[0] foreground.add_child(letterslabel) var numberslabel := TopRightLabel.instance() numberslabel.rect_position.y = i * piece_size.x @@ -144,14 +145,16 @@ func drawed() -> void: Events.emit_signal("game_over") SoundFx.play("Draw") yield(get_tree().create_timer(5), "timeout") + Events.emit_signal("go_back") SoundFx.play("Victory") func win(winner) -> void: Events.emit_signal("game_over") - print(winner, " won the game in ", Globals.turns(winner), " turns!") + print(winner, " won the game in ", Globals.turns(), " turns!") SoundFx.play("Victory") yield(get_tree().create_timer(5), "timeout") + Events.emit_signal("go_back") SoundFx.play("Victory") @@ -159,8 +162,8 @@ func check_in_check(prin = false) -> bool: # check if in_check for i in range(0, 8): # for each row for j in range(0, 8): # for each column var spot = matrix[i][j] # get the square - if spot and spot.white != Globals.turn: # enemie - if spot.can_attack_piece(Globals.white_king if Globals.turn else Globals.black_king): # if it can take the king + if spot and spot.white != Globals.team: # enemie + if spot.can_attack_piece(Globals.white_king if Globals.team else Globals.black_king): # if it can take the king if prin: Globals.in_check = true # set in_check Globals.checking_piece = spot # set checking_piece @@ -173,7 +176,9 @@ func can_move() -> bool: for i in range(0, 8): # for each row for j in range(0, 8): # for each column var spot = matrix[i][j] # get the square - if spot and spot.white == Globals.turn: # fren + if Input.is_action_pressed("ui_down"): + breakpoint + if spot and spot.white != Globals.team: # enemie: checking for our enemys if spot.can_move(): return true return false @@ -265,7 +270,7 @@ func check_for_circle(position: Vector2) -> bool: # check for a circle, validat func check_for_frame(position: Vector2) -> bool: # check for a frame, validating taking - if !matrix[position.y][position.x]: # if there is no piece + if !is_instance_valid(matrix[position.y][position.x]): # if there is no piece return false # return false return matrix[position.y][position.x].frameon # return if the frame is on @@ -273,9 +278,11 @@ func check_for_frame(position: Vector2) -> bool: # check for a frame, validatin func square_clicked(position: Vector2) -> void: # square clicked if promoting != null: return + if Globals.turn != Globals.team: + return var spot = matrix[position.y][position.x] # get the spot - if !spot or spot.white != Globals.turn: # spot is not a tile or spot is not turn color - if !is_instance_valid(last_clicked): # last clicked is null, so this is pointless + if !spot or spot.white != Globals.team: + if !is_instance_valid(last_clicked): return if check_for_frame(position): # takeable handle_take(position) @@ -295,8 +302,8 @@ func handle_take(position) -> void: var pawn = last_clicked if check_promote(pawn, position, "take"): return - last_clicked.take(matrix[position.y][position.x]) # eat turn_over() + Globals.network.send_move_packet([last_clicked.real_position, position], Network.MOVEHEADERS.take) # piece taking piece func handle_move(position) -> void: @@ -304,10 +311,16 @@ func handle_move(position) -> void: for i in range(len(last_clicked.can_castle)): var castle_data = last_clicked.can_castle[i] if castle_data[0] == position: - Utils.add_move(last_clicked.castle(castle_data[0])) - castle_data[1].override_moveto = true - castle_data[1].moveto(castle_data[2]) - castle_data[1].override_moveto = false + # send some packet + Globals.network.send_move_packet( + { + "king": last_clicked.real_position, + "rook": castle_data[1].real_position, + "rookdestination": castle_data[2], + "kingdestination": castle_data[0] + }, + Network.MOVEHEADERS.castle + ) turn_over() return if last_clicked is Pawn: @@ -316,14 +329,17 @@ func handle_move(position) -> void: for i in range(len(pawn.enpassant)): var en_passant_data = pawn.enpassant[i] if en_passant_data[0] == position: - en_passant_data[1].took() # kill the unfortunate - pawn.passant(en_passant_data[0]) + # send some packet + Globals.network.send_move_packet( + [pawn.real_position, position, en_passant_data[1].real_position], + Network.MOVEHEADERS.passant + ) turn_over() return if check_promote(pawn, position): return - last_clicked.moveto(position) turn_over() + Globals.network.send_move_packet([last_clicked.real_position, position], Network.MOVEHEADERS.move) # piece moving func check_promote(pawn, position, calltype: String = "move") -> bool: @@ -336,10 +352,6 @@ func check_promote(pawn, position, calltype: String = "move") -> bool: func turn_over() -> void: promoting = null - Events.emit_signal("just_before_turn_over") - Globals.add_turn() - Globals.turn = not Globals.turn - Events.emit_signal("turn_over") func clear_fx() -> void: # clear the circles @@ -17,7 +17,7 @@ func _ready() -> void: circle.visible = false areacollisionshape.global_position += Globals.grid.piece_size / 2 areacollisionshape.shape.extents = Vector2(rect_size.x / 2, rect_size.y / 2) - algebraic_string = Utils.calculate_algebraic_position(real_position) + algebraic_string = Utils.to_algebraic(real_position) func _on_Squarea_input_event(_viewport: Node, _event: InputEvent, _shape_idx: int) -> void: @@ -25,10 +25,20 @@ func add_move(move) -> void: emit_signal("newmove", move) -func calculate_algebraic_position(real_position) -> String: +func reset_vars() -> void: + turn_moves.resize(0) + turns_moves.resize(0) + counter = 0 + + +func to_algebraic(real_position) -> String: return char(65 + (real_position.x)).to_lower() + str(8 - real_position.y) +func from_algebraic(algebraic_position: String) -> Vector2: + return Vector2(ord(algebraic_position[0]) - ord("a"), 8 - int(algebraic_position[1])) + + func get_node_name(node) -> Array: if is_pawn(node): return ["♙", "p"] if node.white else ["♟", "p"] @@ -65,12 +75,8 @@ func walk_dir(path = "res://assets/pieces") -> PoolStringArray: # walk the dire func format_seconds(time: float, use_milliseconds: bool = false) -> String: - var minutes := time / 60 - var seconds := fmod(time, 60) - - if not use_milliseconds: - return "%02d:%02d" % [minutes, seconds] - return "%02d:%04.1f" % [minutes, seconds] + var format_string = "%02d:%04.1f" if use_milliseconds else "%02d:%02d" + return format_string % [time / 60, fmod(time, 60)] func _on_turn_over() -> void: @@ -96,7 +102,7 @@ func fen() -> String: else: pieces += str(empty) else: - pieces += spot.shortname[0].to_upper() if spot.white else spot.shortname[0].to_lower() + pieces += (spot.shortname[0].to_upper() if spot.white else spot.shortname[0].to_lower()) empty = 0 if rank != 7: pieces += "/" @@ -115,12 +121,12 @@ func fen() -> String: var enpassants = "" for pawn in Globals.pawns: if pawn.twostepfirstmove and pawn.just_set: - enpassants += calculate_algebraic_position(pawn.real_position + (Vector2.DOWN * pawn.whiteint)) + enpassants += to_algebraic(pawn.real_position + (Vector2.DOWN * pawn.whiteint)) var fen = ( "%s %s %s %s %s %s" % [ pieces, - "w" if Globals.turn else "b", + "w" if Globals.team else "b", castlingrights, enpassants if enpassants else "-", Globals.halfmove, diff --git a/networking/Network.gd b/networking/Network.gd new file mode 100644 index 0000000..6c8758c --- /dev/null +++ b/networking/Network.gd @@ -0,0 +1,105 @@ +extends Node +class_name Network + +var ws := WebSocketClient.new() +var game_code := "" + +const HEADERS := { + "move": "M", + "joinrequest": "J", + "hostrequest": "H", + "stopgame": "K", + "ping": "P", + "startgame": "S", +} + +const MOVEHEADERS := { + "take": "K", + "move": "M", + "castle": "C", + "passant": "P", + "promote": "Q", +} + +var notation := "" + +signal start_game +signal move_data(data) +signal host_result(result) +signal join_result(result) +signal game_over(problem, isok) + +const url := "wss://gd-chess-server.herokuapp.com/" + + +func _ready() -> void: + ws.connect("connection_established", self, "_connection_established") + ws.connect("connection_closed", self, "_connection_closed") + ws.connect("connection_error", self, "_connection_error") + ws.connect("data_received", self, "_data_recieved") + print("Connecting to server...") # maybe i shouldnt broadcast the server url + ws.connect_to_url(url) + var t = Timer.new() + add_child(t) + t.wait_time = 1 + t.start(1) + t.connect("timeout", self, "ping") + + +func ping() -> void: + send_packet("ping", HEADERS.ping) + + +func _connection_established(_protocol) -> void: + print("Connection established") + + +func _connection_closed(_was_clean_closed) -> void: + printerr("Connection closed") + emit_signal("game_over", "Connection closed", false) + + +func _connection_error() -> void: + printerr("Connection error") + emit_signal("game_over", "Connection error", false) + + +func send_move_packet(positions, header: String) -> void: + var packet := {"movetype": header, "gamecode": game_code, "positions": positions} + Globals.add_turn() + var globals = Globals.pack_vars() + for variable in globals: + packet[variable] = globals[variable] + send_packet(packet, HEADERS.move) # your move will wait till the server relays back :> + + +func _data_recieved() -> void: + var recieve: Dictionary = ws.get_peer(1).get_var() + var header: String = recieve.header + var text = recieve.data + match header: + HEADERS.hostrequest: + emit_signal("host_result", text) + HEADERS.move: + emit_signal("move_data", text) + HEADERS.joinrequest: + emit_signal("join_result", text) + HEADERS.stopgame: + emit_signal("game_over", "your opponent requested stop", true) + HEADERS.startgame: + emit_signal("start_game") + HEADERS.ping: + pass + + +func _process(_delta) -> void: + if ( + ws.get_connection_status() == ws.CONNECTION_CONNECTING + or ws.get_connection_status() == ws.CONNECTION_CONNECTED + ): + ws.poll() + + +func send_packet(variant, header: String) -> void: + if ws.get_peer(1).is_connected_to_host(): + ws.get_peer(1).put_var({"header": header, "data": variant}) diff --git a/pieces/Pawn.gd b/pieces/Pawn.gd index 80a180b..298e00a 100644 --- a/pieces/Pawn.gd +++ b/pieces/Pawn.gd @@ -33,7 +33,9 @@ func _ready() -> void: func _exit_tree() -> void: - Globals.pawns.remove(Globals.pawns.find(self)) + var find = Globals.pawns.find(self) + if find != -1: + Globals.pawns.remove(find) func moveto(position, real = true, take = false, override_moveto = false) -> void: @@ -121,7 +123,6 @@ func en_passant(turncheck = true) -> Array: # in passing func promote(position, type) -> void: promote_prev_pos = real_position if type == "take": - print(real_position) take(at_pos(position), true) promotetake = true else: diff --git a/pieces/Piece.gd b/pieces/Piece.gd index 38a63f7..c0a5aa0 100644 --- a/pieces/Piece.gd +++ b/pieces/Piece.gd @@ -48,7 +48,6 @@ func clear_clicked() -> void: func algebraic_take_notation(position, startpos = real_position) -> String: var starter := shortname if shortname != "p" else to_algebraic(startpos)[0] - print(starter) return starter + "x" + to_algebraic(position) @@ -127,7 +126,9 @@ func traverse(arr := [Vector2.UP, Vector2.DOWN, Vector2.LEFT, Vector2.RIGHT]) -> static func at_pos(vector: Vector2): - return Globals.grid.matrix[vector.y][vector.x] + if is_instance_valid(Globals.grid): + return Globals.grid.matrix[vector.y][vector.x] + return null func can_move() -> bool: # checks if you can legally move @@ -182,6 +183,7 @@ static func set_circle(positions: Array, type := "move") -> void: func checkcheck(pos) -> bool: # moves to position, then checks if your king is in check + # TODO: figure out why this function isnt working with can_move() var mat: Array = Globals.grid.matrix.duplicate(true) # make a copy of the matrix moveto(pos, false) # move to the position if Globals.grid.check_in_check(): # if you are still in check diff --git a/project.godot b/project.godot index 18e9f39..72215d7 100644 --- a/project.godot +++ b/project.godot @@ -34,6 +34,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://pieces/Knight.gd" }, { +"base": "Node", +"class": "Network", +"language": "GDScript", +"path": "res://networking/Network.gd" +}, { "base": "Piece", "class": "Pawn", "language": "GDScript", @@ -60,6 +65,7 @@ _global_script_class_icons={ "Grid": "", "King": "res://assets/pieces/california/wK.png", "Knight": "res://assets/pieces/california/wN.png", +"Network": "", "Pawn": "res://assets/pieces/california/wP.png", "Piece": "res://assets/pieces/california/wP.png", "Queen": "res://assets/pieces/california/wQ.png", @@ -76,6 +82,7 @@ config/custom_user_dir_name="chess" boot_splash/image="res://icon.png" boot_splash/bg_color=Color( 0.309804, 0.309804, 0.309804, 0.313726 ) config/icon="res://icon.png" +config/quit_on_go_back=false [autoload] diff --git a/ui/Lobby.gd b/ui/Lobby.gd index b7332e8..15e609f 100644 --- a/ui/Lobby.gd +++ b/ui/Lobby.gd @@ -1,94 +1,29 @@ -# Default game server port. Can be any number between 1024 and 49151. -# Not on the list of registered or common ports as of November 2020: -# https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers extends Control -# Default game server port. Can be any number between 1024 and 49151. -# Not on the list of registered or common ports as of November 2020: -# https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers -const DEFAULT_PORT = 8910 - -var peer = null - onready var address: LineEdit = $Back/Center/HBox/VBox/Address -onready var host_button = $Back/Center/HBox/VBox/HBox/HostButton -onready var join_button = $Back/Center/HBox/VBox/HBox/JoinButton +onready var buttons = $Back/Center/HBox/VBox/buttons onready var status_ok = $Back/Center/HBox/VBox/StatusOK onready var status_fail = $Back/Center/HBox/VBox/StatusFail -onready var port_forward_label = $Back/Center/HBox/VBox2/Portforward -onready var find_public_ip_button = $Back/Center/HBox/VBox2/FindPublicIP func toggle(onoff) -> void: visible = onoff - - -func _ready() -> void: - address.context_menu_enabled = false - # Connect all the callbacks related to networking. - get_tree().connect("network_peer_connected", self, "_player_connected") - get_tree().connect("network_peer_disconnected", self, "_player_disconnected") - get_tree().connect("connected_to_server", self, "_connected_ok") - get_tree().connect("connection_failed", self, "_connected_fail") - get_tree().connect("server_disconnected", self, "_server_disconnected") - - -#### Network callbacks from SceneTree #### - - -# Callback from SceneTree. -func _player_connected(_id) -> void: - # Someone connected, start the game! - var chess = load("res://World.tscn").instance() - # Connect deferred so we can safely erase it from the callback. - Utils.connect("game_over", self, "_end_game", [], CONNECT_DEFERRED) - - get_tree().get_root().add_child(chess) - - -func _player_disconnected(_id) -> void: - if get_tree().is_network_server(): - _end_game("Client disconnected") + if onoff: + for i in get_tree().get_nodes_in_group("control"): + i.mouse_filter = MOUSE_FILTER_STOP else: - _end_game("Server disconnected") - - -# Callback from SceneTree, only for clients (not server). -func _connected_ok() -> void: - pass # This function is not needed for this project. - - -# Callback from SceneTree, only for clients (not server). -func _connected_fail() -> void: - _set_status("Couldn't connect", false) - - get_tree().set_network_peer(null) # Remove peer. - host_button.show() - address.editable = true - - -func _server_disconnected() -> void: - _end_game("Server disconnected") - + for i in get_tree().get_nodes_in_group("control"): + i.mouse_filter = MOUSE_FILTER_IGNORE -##### Game creation functions ###### +func _handle_game_over(error, isok) -> void: + reset_buttons() + Globals.reset_vars() + end_game() + _set_status(error, isok) -func _end_game(_with_error = "") -> void: - if has_node("/root/World"): - # Erase immediately, otherwise network might show - # errors (this is why we connected deferred above). - get_node("/root/World").free() - show() - get_tree().set_network_peer(null) # Remove peer. - host_button.show() - join_button.show() - address.editable = true - - -func _set_status(text, isok) -> void: - # Simple way to show status. +func _set_status(text, isok) -> void: # Simple way to show status. if isok: status_ok.set_text(text) status_fail.set_text("") @@ -101,35 +36,126 @@ func _set_status(text, isok) -> void: status_ok.visible = len(status_ok.text) > 0 -func _on_host_pressed() -> void: - peer = NetworkedMultiplayerENet.new() - peer.set_compression_mode(NetworkedMultiplayerENet.COMPRESS_RANGE_CODER) - var err = peer.create_server(DEFAULT_PORT, 1) # Maximum of 1 peer, since it's a 2-player game. - if err != OK: - # Is another server running? - _set_status("Can't host, address in use.", false) - return +func _on_join_pressed() -> void: + Globals.network.game_code = validate_text() + Globals.network.send_packet(Globals.network.game_code, Globals.network.HEADERS.joinrequest) + address.editable = false + buttons.hide() + - get_tree().set_network_peer(peer) - host_button.hide() +func _on_HostButton_pressed() -> void: + Globals.network.game_code = validate_text() + Globals.network.send_packet(Globals.network.game_code, Globals.network.HEADERS.hostrequest) address.editable = false - join_button.hide() - _set_status("Waiting for player...", true) + buttons.hide() - # Only show hosting instructions when relevant. +func validate_text(text = address.get_text()) -> String: + var pos = address.caret_position + text = text.strip_edges() + text = text.replace(" ", "_") + address.text = text + address.caret_position = pos + return text -func _on_join_pressed() -> void: - var ip = address.get_text() - if not ip.is_valid_ip_address(): - _set_status("IP address is invalid", false) - return - peer = NetworkedMultiplayerENet.new() - peer.set_compression_mode(NetworkedMultiplayerENet.COMPRESS_RANGE_CODER) - peer.create_client(ip, DEFAULT_PORT) - get_tree().set_network_peer(peer) +func _ready() -> void: + get_tree().set_auto_accept_quit(false) + Events.connect("go_back", self, "end_game") + if !is_instance_valid(Globals.network): + Globals.network = Network.new() + Globals.network.connect("move_data", self, "_on_data") + Globals.network.connect("join_result", self, "_on_join_result") + Globals.network.connect("host_result", self, "_on_host_result") + Globals.network.connect("game_over", self, "_handle_game_over") + Globals.network.connect("start_game", self, "_start_game") + add_child(Globals.network) + + +func end_game() -> void: + if get_tree().get_root().has_node("World"): + get_tree().get_root().get_node("World").queue_free() + toggle(true) + +func create_world() -> void: + var world = load("res://World.tscn").instance() + get_tree().get_root().add_child(world) + toggle(false) -func _on_find_public_ip_pressed() -> void: - OS.shell_open("https://icanhazip.com/") + +func _start_game() -> void: + create_world() + + +func _on_join_result(accepted: String) -> void: + Globals.team = false + if accepted == "Y": + _set_status("Joined!", true) + Globals.network.send_packet("", Globals.network.HEADERS.startgame) + else: + _set_status(accepted, false) + reset_buttons() + + +func reset_buttons() -> void: + buttons.show() + address.editable = true + + +func _on_host_result(accepted: String) -> void: + Globals.team = true + if accepted == "Y": + _set_status("Hosted!", true) + else: + _set_status(accepted, false) + reset_buttons() + + +func add_turn() -> void: + Events.emit_signal("just_before_turn_over") + Globals.add_turn() + Globals.turn = not Globals.turn + Events.emit_signal("turn_over") + + +func _on_data(data: Dictionary) -> void: + Globals.fullmove = data["fullmove"] + Globals.turn = data["turn"] + Globals.halfmove = data["halfmove"] + match data["movetype"]: + Network.MOVEHEADERS.passant: + # en passant + var end_pos = Vector2(dict2vec(data["positions"][1])) + var start_piece = Piece.at_pos(Vector2(dict2vec(data["positions"][0]))) + Piece.at_pos(Vector2(dict2vec(data["positions"][2]))).took() # kill the unfortunate + start_piece.passant(end_pos) + Network.MOVEHEADERS.take: + var start_piece = Piece.at_pos(Vector2(dict2vec(data["positions"][0]))) + var end_piece = Piece.at_pos(Vector2(dict2vec(data["positions"][1]))) + start_piece.take(end_piece) + Network.MOVEHEADERS.move: + var end_pos = Vector2(dict2vec(data["positions"][1])) + var start_piece = Piece.at_pos(Vector2(dict2vec(data["positions"][0]))) + start_piece.moveto(end_pos) + Network.MOVEHEADERS.castle: + var king = Piece.at_pos(dict2vec(data["positions"]["king"])) + var rook = Piece.at_pos(dict2vec(data["positions"]["rook"])) + rook.moveto(dict2vec(data["positions"]["rookdestination"]), true, false, true) + Utils.add_move(king.castle(dict2vec(data["positions"]["kingdestination"]))) + + +func dict2vec(dict: Dictionary) -> Vector2: + return Vector2(dict["x"], dict["y"]) + + +func _notification(what: int) -> void: + if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST or what == MainLoop.NOTIFICATION_WM_GO_BACK_REQUEST: + Globals.network.send_packet(Globals.network.game_code, Globals.network.HEADERS.stopgame) + yield(get_tree(), "idle_frame") # wait for the packet to send + get_tree().quit() + + +func _on_Address_text_entered(new_text: String): + validate_text(new_text) + Globals.network.game_code = new_text diff --git a/ui/Lobby.tscn b/ui/Lobby.tscn index 02e0148..123bf11 100644 --- a/ui/Lobby.tscn +++ b/ui/Lobby.tscn @@ -1,12 +1,7 @@ -[gd_scene load_steps=5 format=2] +[gd_scene load_steps=3 format=2] [ext_resource path="res://ui/main.tres" type="Theme" id=1] [ext_resource path="res://ui/Lobby.gd" type="Script" id=2] -[ext_resource path="res://assets/ui/verdana-bold.ttf" type="DynamicFontData" id=3] - -[sub_resource type="DynamicFont" id=1] -size = 30 -font_data = ExtResource( 3 ) [node name="Lobby" type="Control"] anchor_right = 1.0 @@ -14,94 +9,76 @@ anchor_bottom = 1.0 theme = ExtResource( 1 ) script = ExtResource( 2 ) -[node name="Back" type="ColorRect" parent="."] +[node name="Back" type="ColorRect" parent="." groups=["control"]] anchor_right = 1.0 anchor_bottom = 1.0 color = Color( 0, 0, 0, 0.784314 ) -[node name="Center" type="CenterContainer" parent="Back"] +[node name="Center" type="CenterContainer" parent="Back" groups=["control"]] anchor_right = 1.0 anchor_bottom = 1.0 -[node name="HBox" type="HBoxContainer" parent="Back/Center"] -margin_left = 437.0 -margin_top = 189.0 -margin_right = 763.0 -margin_bottom = 611.0 - -[node name="VBox" type="VBoxContainer" parent="Back/Center/HBox"] -margin_right = 311.0 -margin_bottom = 422.0 +[node name="HBox" type="HBoxContainer" parent="Back/Center" groups=["control"]] +margin_left = 425.0 +margin_top = 286.0 +margin_right = 775.0 +margin_bottom = 513.0 -[node name="AddressLabel" type="Label" parent="Back/Center/HBox/VBox"] -margin_right = 311.0 -margin_bottom = 50.0 -text = "address" +[node name="VBox" type="VBoxContainer" parent="Back/Center/HBox" groups=["control"]] +margin_right = 350.0 +margin_bottom = 227.0 -[node name="Address" type="LineEdit" parent="Back/Center/HBox/VBox"] -margin_top = 65.0 -margin_right = 311.0 -margin_bottom = 171.0 +[node name="Address" type="LineEdit" parent="Back/Center/HBox/VBox" groups=["control"]] +margin_right = 350.0 +margin_bottom = 106.0 +rect_min_size = Vector2( 350, 0 ) focus_mode = 1 -text = "127.0.0.1" -placeholder_text = "127.0.0.1" +text = "game_code" +align = 1 +max_length = 10 +placeholder_text = "game_code" caret_blink = true caret_blink_speed = 0.35 -[node name="HBox" type="HBoxContainer" parent="Back/Center/HBox/VBox"] -margin_top = 186.0 -margin_right = 311.0 -margin_bottom = 292.0 +[node name="buttons" type="HBoxContainer" parent="Back/Center/HBox/VBox" groups=["control"]] +margin_top = 121.0 +margin_right = 350.0 +margin_bottom = 227.0 -[node name="HostButton" type="Button" parent="Back/Center/HBox/VBox/HBox"] -margin_right = 154.0 +[node name="JoinButton" type="Button" parent="Back/Center/HBox/VBox/buttons" groups=["control"]] +margin_right = 150.0 margin_bottom = 106.0 +rect_min_size = Vector2( 150, 0 ) focus_mode = 0 +size_flags_horizontal = 4 enabled_focus_mode = 0 -text = "host" +text = "join" -[node name="JoinButton" type="Button" parent="Back/Center/HBox/VBox/HBox"] -margin_left = 169.0 -margin_right = 311.0 +[node name="HostButton" type="Button" parent="Back/Center/HBox/VBox/buttons" groups=["control"]] +margin_left = 165.0 +margin_right = 350.0 margin_bottom = 106.0 focus_mode = 0 +size_flags_horizontal = 3 enabled_focus_mode = 0 -text = "join" - -[node name="StatusOK" type="Label" parent="Back/Center/HBox/VBox"] -margin_top = 307.0 -margin_right = 311.0 -margin_bottom = 357.0 -custom_colors/font_color = Color( 1, 1, 1, 1 ) - -[node name="StatusFail" type="Label" parent="Back/Center/HBox/VBox"] -margin_top = 372.0 -margin_right = 311.0 -margin_bottom = 422.0 -custom_colors/font_color = Color( 0.698039, 0.415686, 0.415686, 1 ) - -[node name="VBox2" type="VBoxContainer" parent="Back/Center/HBox"] -margin_left = 326.0 -margin_right = 326.0 -margin_bottom = 422.0 +text = "host" -[node name="Portforward" type="Label" parent="Back/Center/HBox/VBox2"] +[node name="StatusOK" type="Label" parent="Back/Center/HBox/VBox" groups=["control"]] visible = false -margin_right = 600.0 -margin_bottom = 161.0 -rect_min_size = Vector2( 600, 0 ) -custom_fonts/font = SubResource( 1 ) -text = "If you want non-LAN clients to connect, -make sure the port 8910 in UDP -is forwarded on your router." +margin_top = 242.0 +margin_right = 500.0 +margin_bottom = 292.0 +custom_colors/font_color = Color( 1, 1, 1, 1 ) autowrap = true -[node name="FindPublicIP" type="LinkButton" parent="Back/Center/HBox/VBox2"] +[node name="StatusFail" type="Label" parent="Back/Center/HBox/VBox" groups=["control"]] visible = false -margin_right = 295.0 -margin_bottom = 50.0 -text = "find public ip" +margin_top = 307.0 +margin_right = 500.0 +margin_bottom = 357.0 +custom_colors/font_color = Color( 0.698039, 0.415686, 0.415686, 1 ) +autowrap = true -[connection signal="pressed" from="Back/Center/HBox/VBox/HBox/HostButton" to="." method="_on_host_pressed"] -[connection signal="pressed" from="Back/Center/HBox/VBox/HBox/JoinButton" to="." method="_on_join_pressed"] -[connection signal="pressed" from="Back/Center/HBox/VBox2/FindPublicIP" to="." method="_on_find_public_ip_pressed"] +[connection signal="text_entered" from="Back/Center/HBox/VBox/Address" to="." method="_on_Address_text_entered"] +[connection signal="pressed" from="Back/Center/HBox/VBox/buttons/JoinButton" to="." method="_on_join_pressed"] +[connection signal="pressed" from="Back/Center/HBox/VBox/buttons/HostButton" to="." method="_on_HostButton_pressed"] diff --git a/ui/MovesList.gd b/ui/MovesList.gd index 6da4285..d07be03 100644 --- a/ui/MovesList.gd +++ b/ui/MovesList.gd @@ -39,7 +39,7 @@ func create_san_label(text, alignment = Label.ALIGN_RIGHT) -> void: func on_new_move(move) -> void: var alignment = Label.ALIGN_RIGHT - if Globals.turn: # black just moved + if !Globals.turn: # black just moved alignment = Label.ALIGN_LEFT create_number_label(Globals.fullmove) number = 0 diff --git a/ui/Settings.tscn b/ui/Settings.tscn index 5622ce3..dd74845 100644 --- a/ui/Settings.tscn +++ b/ui/Settings.tscn @@ -4,35 +4,35 @@ [ext_resource path="res://ui/Settings.gd" type="Script" id=2] [ext_resource path="res://assets/pieces/california/wP.png" type="Texture" id=3] -[node name="Settings" type="Control"] +[node name="Settings" type="Control" groups=["control"]] anchor_right = 1.0 anchor_bottom = 1.0 theme = ExtResource( 1 ) script = ExtResource( 2 ) -[node name="ColorRect" type="ColorRect" parent="."] +[node name="ColorRect" type="ColorRect" parent="." groups=["control"]] anchor_right = 1.0 anchor_bottom = 1.0 color = Color( 0, 0, 0, 0.862745 ) -[node name="HBoxContainer" type="HBoxContainer" parent="ColorRect"] +[node name="HBoxContainer" type="HBoxContainer" parent="ColorRect" groups=["control"]] anchor_right = 1.0 anchor_bottom = 1.0 alignment = 1 -[node name="VBoxContainer" type="VBoxContainer" parent="ColorRect/HBoxContainer"] +[node name="VBoxContainer" type="VBoxContainer" parent="ColorRect/HBoxContainer" groups=["control"]] margin_left = 225.0 margin_right = 591.0 margin_bottom = 800.0 alignment = 1 -[node name="BackButton" type="Button" parent="ColorRect/HBoxContainer/VBoxContainer"] +[node name="BackButton" type="Button" parent="ColorRect/HBoxContainer/VBoxContainer" groups=["control"]] margin_top = 261.0 margin_right = 366.0 margin_bottom = 367.0 text = "back" -[node name="PieceSet" type="OptionButton" parent="ColorRect/HBoxContainer/VBoxContainer"] +[node name="PieceSet" type="OptionButton" parent="ColorRect/HBoxContainer/VBoxContainer" groups=["control"]] margin_top = 382.0 margin_right = 366.0 margin_bottom = 538.0 @@ -42,13 +42,13 @@ enabled_focus_mode = 0 text = "piece set" icon = ExtResource( 3 ) -[node name="VBoxContainer2" type="VBoxContainer" parent="ColorRect/HBoxContainer"] +[node name="VBoxContainer2" type="VBoxContainer" parent="ColorRect/HBoxContainer" groups=["control"]] margin_left = 606.0 margin_right = 975.0 margin_bottom = 800.0 alignment = 1 -[node name="VsyncButton" type="CheckBox" parent="ColorRect/HBoxContainer/VBoxContainer2"] +[node name="VsyncButton" type="CheckBox" parent="ColorRect/HBoxContainer/VBoxContainer2" groups=["control"]] margin_top = 175.0 margin_right = 369.0 margin_bottom = 315.0 @@ -57,7 +57,7 @@ pressed = true enabled_focus_mode = 0 text = "vsync" -[node name="FullscreenButton" type="CheckBox" parent="ColorRect/HBoxContainer/VBoxContainer2"] +[node name="FullscreenButton" type="CheckBox" parent="ColorRect/HBoxContainer/VBoxContainer2" groups=["control"]] margin_top = 330.0 margin_right = 369.0 margin_bottom = 470.0 @@ -65,7 +65,7 @@ focus_mode = 0 enabled_focus_mode = 0 text = "fullscreen" -[node name="Borderless" type="CheckBox" parent="ColorRect/HBoxContainer/VBoxContainer2"] +[node name="Borderless" type="CheckBox" parent="ColorRect/HBoxContainer/VBoxContainer2" groups=["control"]] margin_top = 485.0 margin_right = 369.0 margin_bottom = 625.0 diff --git a/ui/StartMenu.gd b/ui/StartMenu.gd index f39cde1..6a11fc1 100644 --- a/ui/StartMenu.gd +++ b/ui/StartMenu.gd @@ -29,7 +29,7 @@ func _on_local_pressed() -> void: func _on_quit_pressed() -> void: - get_tree().quit() + get_tree().notification(MainLoop.NOTIFICATION_WM_QUIT_REQUEST) func _on_settings_pressed() -> void: diff --git a/ui/StartMenu.tscn b/ui/StartMenu.tscn index 873b826..b05738c 100644 --- a/ui/StartMenu.tscn +++ b/ui/StartMenu.tscn @@ -5,20 +5,22 @@ [ext_resource path="res://ui/Settings.tscn" type="PackedScene" id=3] [ext_resource path="res://ui/Lobby.tscn" type="PackedScene" id=4] -[node name="StartMenu" type="Control"] +[node name="StartMenu" type="Control" groups=["control"]] anchor_right = 1.0 anchor_bottom = 1.0 +mouse_filter = 2 theme = ExtResource( 1 ) script = ExtResource( 2 ) timer_length = 2.8 nice_colors = [ Color( 0.784314, 0.427451, 0.427451, 1 ), Color( 0.913725, 0.847059, 0.403922, 1 ), Color( 0.380392, 0.741176, 0.647059, 1 ), Color( 0.321569, 0.368627, 0.858824, 1 ), Color( 0.843137, 0.133333, 0.133333, 1 ), Color( 0.109804, 0.160784, 0.564706, 1 ), Color( 0.376471, 0.796078, 0.317647, 1 ), Color( 0.8, 0.364706, 0.588235, 1 ), Color( 0.984314, 0.858824, 0.282353, 1 ), Color( 0.164706, 0.0862745, 0.247059, 1 ) ] -[node name="ColorRect" type="ColorRect" parent="."] +[node name="ColorRect" type="ColorRect" parent="." groups=["control"]] anchor_right = 1.0 anchor_bottom = 1.0 +mouse_filter = 2 color = Color( 0, 0, 0, 1 ) -[node name="MainButtons" type="VBoxContainer" parent="ColorRect"] +[node name="MainButtons" type="VBoxContainer" parent="ColorRect" groups=["control"]] anchor_left = 0.5 anchor_top = 0.5 anchor_right = 0.5 @@ -28,7 +30,7 @@ margin_top = -224.0 margin_right = 196.0 margin_bottom = 412.0 -[node name="multiplayer" type="Button" parent="ColorRect/MainButtons"] +[node name="multiplayer" type="Button" parent="ColorRect/MainButtons" groups=["control"]] margin_left = 36.0 margin_right = 351.0 margin_bottom = 106.0 @@ -37,7 +39,7 @@ size_flags_horizontal = 4 enabled_focus_mode = 0 text = "multiplayer" -[node name="settings" type="Button" parent="ColorRect/MainButtons"] +[node name="settings" type="Button" parent="ColorRect/MainButtons" groups=["control"]] margin_left = 75.0 margin_top = 121.0 margin_right = 313.0 @@ -47,7 +49,8 @@ size_flags_horizontal = 4 enabled_focus_mode = 0 text = "settings" -[node name="local" type="Button" parent="ColorRect/MainButtons"] +[node name="local" type="Button" parent="ColorRect/MainButtons" groups=["control"]] +visible = false margin_left = 113.0 margin_top = 242.0 margin_right = 275.0 @@ -58,11 +61,11 @@ size_flags_horizontal = 4 enabled_focus_mode = 0 text = "local" -[node name="quit" type="Button" parent="ColorRect/MainButtons"] +[node name="quit" type="Button" parent="ColorRect/MainButtons" groups=["control"]] margin_left = 123.0 -margin_top = 363.0 +margin_top = 242.0 margin_right = 265.0 -margin_bottom = 469.0 +margin_bottom = 348.0 focus_mode = 0 size_flags_horizontal = 4 enabled_focus_mode = 0 @@ -71,7 +74,7 @@ text = "exit" [node name="Settings" parent="ColorRect" instance=ExtResource( 3 )] visible = false -[node name="Lobby" parent="ColorRect" instance=ExtResource( 4 )] +[node name="Lobby" parent="ColorRect" groups=["control"] instance=ExtResource( 4 )] visible = false [node name="Tween" type="Tween" parent="."] diff --git a/ui/Timer.gd b/ui/Timer.gd index 6915862..4896962 100644 --- a/ui/Timer.gd +++ b/ui/Timer.gd @@ -15,7 +15,7 @@ func _ready() -> void: func _process(delta) -> void: if !enabled: return - if Globals.turn: + if Globals.team: if !whitelabel.set_time(whitelabel.time - delta): enabled = false else: diff --git a/ui/TimerLabels.gd b/ui/TimerLabels.gd index 03e8aee..6885881 100644 --- a/ui/TimerLabels.gd +++ b/ui/TimerLabels.gd @@ -38,6 +38,6 @@ func _on_game_over() -> void: func set_color() -> void: if time > 10: - colorrect.color = Globals.grid.clockrunning_color if Globals.turn == white else Color.transparent + colorrect.color = Globals.grid.clockrunning_color if Globals.team == white else Color.transparent else: - colorrect.color = Globals.grid.clockrunninglow if Globals.turn == white else Globals.grid.clocklow + colorrect.color = Globals.grid.clockrunninglow if Globals.team == white else Globals.grid.clocklow |