diff --git a/cards/card_manager.gd b/cards/card_manager.gd index dd4a04d..dab94d4 100644 --- a/cards/card_manager.gd +++ b/cards/card_manager.gd @@ -33,7 +33,51 @@ func get_card_texture(card_id: int, style: CardStyle = CardStyle.STICKMAN) -> Te CardStyle.STICKMAN: style_name = "stickman" return load("res://cards/textures/" + style_name + "/" + _get_card_name(card_id) + ".webp") - + +func get_winning_card(card_ids: Array[int], trump: int) -> int: + if card_ids.has(56) or card_ids.has(57) or card_ids.has(58) or card_ids.has(59): + # cards contain magician + for card_id in card_ids: + if full_deck[card_id].card_type == Card.CardType.MAGICIAN: + return card_id + return -1 # should not happen + elif not trump == -1: + # trump exists, determine winner from this + var largest_trump_card_id: int = -1 + var trump_color: Card.CardColor = full_deck[trump].color + for card_id in card_ids: + if full_deck[card_id].color == trump_color and card_id > largest_trump_card_id: + largest_trump_card_id = card_id + if not largest_trump_card_id == -1: + return largest_trump_card_id + + # no trump played; determine from highest played card + # TODO check for white cards here! + return _get_largest_non_trump_card(card_ids) + else: + # no trump exists + return _get_largest_non_trump_card(card_ids) + +func _get_largest_non_trump_card(card_ids: Array[int]) -> int: + var largest_card_id: int = -1 + var first_color: Card.CardColor = _get_first_color_card(card_ids) + if first_color == Card.CardColor.WHITE: + return card_ids[0] # first one wins if all played cards are white + else: + for card_id in card_ids: + if full_deck[card_id].color == first_color and card_id > largest_card_id: + largest_card_id = card_id + + return largest_card_id + +## Returns the color of the first non-white card played. +## Returns WHITE if all cards played are white. +func _get_first_color_card(card_ids: Array[int]) -> Card.CardColor: + for card_id in card_ids: + if not full_deck[card_id].color == Card.CardColor.WHITE: + return full_deck[card_id].color + return Card.CardColor.WHITE + func _get_card_name(card_id: int) -> String: var color: String var suffix: String diff --git a/components/web_client_tcp.gd b/components/web_client_tcp.gd index cb052e4..65e7fb0 100644 --- a/components/web_client_tcp.gd +++ b/components/web_client_tcp.gd @@ -38,9 +38,11 @@ signal connection_status_changed(new_status: ConnectionStatus) signal client_order_received(client_ids: Array[String]) signal cards_received(cards: Dictionary) - +signal trump_received(trump_id: int) signal received_bet_request(disallowed_bet: int) - +signal received_win() +signal notify_play_card_request() +signal received_played_card(client_id: String, card_id: int) signal received_play_winner_request() signal request_next_round() @@ -135,20 +137,26 @@ func _handle_response(response: String) -> void: var received_cards = data["cards"] print(received_cards) cards_received.emit.call_deferred(received_cards) + trump_received.emit.call_deferred(data["trump"]) "client_submitted_bet": print(data) "request_bet": received_bet_request.emit.call_deferred(data["disallowed_bet"]) "begin_playing_cards": + # all players know it's time to play print(data) "request_card": - print(data) + # individual player asked to play card + notify_play_card_request.emit.call_deferred() "play_card": print(data) "determine_play_winner_request": # single card go-around received_play_winner_request.emit.call_deferred() + "client_played_card": + received_played_card.emit.call_deferred(data["client_id"], data["played_card"]) "client_won_play": - print(data) + if data["client_id"] == _client_id: + received_win.emit.call_deferred() func _handle_join(data) -> void: match data["status"]: @@ -217,6 +225,14 @@ func start_next_round(round_count: int) -> void: "cards": CardManager.get_shuffled_cards(_connected_client_ids, round_count), })) +func play_card(card_id: int) -> void: + _send_message(JSON.stringify({ + "response": "play_card", + "lobby_id": _lobby_id, + "client_id": _client_id, + "played_card": card_id, + })) + func submit_bet(bet: int, current_round: int) -> void: _send_message(JSON.stringify({ "response": "submit_bet", @@ -226,7 +242,7 @@ func submit_bet(bet: int, current_round: int) -> void: "bet": bet, })) -func submit_round_winner(winning_client_id: String) -> void: +func submit_play_winner(winning_client_id: String) -> void: _send_message(JSON.stringify({ "response": "submit_play_winner", "lobby_id": _lobby_id, diff --git a/elements/play.gd b/elements/play.gd new file mode 100644 index 0000000..03f0229 --- /dev/null +++ b/elements/play.gd @@ -0,0 +1,14 @@ +class_name Play +extends Resource + +## Card - player association + +@export var client_id: String +@export var card_id: int + +func _init( + client_id: String, + card_id: int, +) -> void: + self.client_id = client_id + self.card_id = card_id diff --git a/elements/play.gd.uid b/elements/play.gd.uid new file mode 100644 index 0000000..b7d89a6 --- /dev/null +++ b/elements/play.gd.uid @@ -0,0 +1 @@ +uid://cml22kioyddag diff --git a/elements/player_hand.gd b/elements/player_hand.gd index d48f57b..5210425 100644 --- a/elements/player_hand.gd +++ b/elements/player_hand.gd @@ -41,6 +41,7 @@ func add_cards(card_ids: Array[int], client_id: String) -> void: func remove_card(card: PlayingCard) -> void: self.remove_child(card) + card.queue_free() _arrange_cards() func _arrange_cards() -> void: @@ -78,6 +79,7 @@ func _on_play_card_button_pressed() -> void: return card_played.emit(_selected_card.card_details.card_id) - _selected_card.unselect() + remove_card(_selected_card) + #_selected_card.unselect() _selected_card = null card_selected.emit(-1) diff --git a/environment_manager.gd b/environment_manager.gd index 65ce24e..ed264dd 100644 --- a/environment_manager.gd +++ b/environment_manager.gd @@ -3,6 +3,10 @@ extends Node3D var hand_associations: Dictionary[String, PlayerHand] +@export var web_client: WebClientTCP + +@export var trump_container: Node3D + # In gameplay order #var hand_associations: Dictionary[int, PlayerHandAssociation] var _own_client_id: String @@ -21,6 +25,11 @@ var _own_client_id: String @export var hand_markers_6: Array[Marker3D] @export var player_hand_scene: PackedScene +@export var card_scene: PackedScene + +## Cards played in the current play. +var _plays: Array[Play] +var _trump_id: int = -1 func _on_web_client_tcp_client_order_received(client_ids: Array[String]) -> void: var marker_positions: Array[Marker3D] @@ -80,3 +89,28 @@ func _on_web_client_tcp_cards_received(cards: Dictionary) -> void: var card_ids: Array[int] card_ids.assign(cards[client_id]) hand_associations[client_id].add_cards(card_ids, client_id) + +func _on_web_client_tcp_received_played_card(client_id: String, card_id: int) -> void: + print(client_id + " played card " + str(card_id)) + _plays.append(Play.new(client_id, card_id)) + +func _on_web_client_tcp_received_play_winner_request() -> void: + if not $"../HBoxContainer/GameUI"._is_host: + return + + var card_ids: Array[int] = [] + card_ids.assign(_plays.map(func(p: Play): return p.card_id)) + var winning_card_id: int = CardManager.get_winning_card(card_ids, _trump_id) + + for play in _plays: + if play.card_id == winning_card_id: + web_client.submit_play_winner(play.client_id) + return + +func _on_web_client_tcp_trump_received(trump_id: int) -> void: + if trump_container.get_child_count() > 0: + trump_container.remove_child(trump_container.get_child(0)) + _trump_id = trump_id + var trump_card: PlayingCard = card_scene.instantiate() + trump_card.setup_card_details(_trump_id) + trump_container.add_child(trump_card) diff --git a/game.tscn b/game.tscn index b772db2..ac6a049 100644 --- a/game.tscn +++ b/game.tscn @@ -1,10 +1,11 @@ -[gd_scene load_steps=9 format=3 uid="uid://gqrdpjslr4np"] +[gd_scene load_steps=10 format=3 uid="uid://gqrdpjslr4np"] [ext_resource type="Script" uid="uid://p5gvnyhjqe6o" path="res://components/web_client_tcp.gd" id="1_feb5d"] [ext_resource type="Script" uid="uid://c0cqkatyo4uj1" path="res://components/client_interface.gd" id="2_e2o6t"] [ext_resource type="Script" uid="uid://utt8atbh7b2a" path="res://game_client.gd" id="3_feb5d"] [ext_resource type="Script" uid="uid://bipfa366flrfa" path="res://environment_manager.gd" id="4_7jktm"] [ext_resource type="PackedScene" uid="uid://jlovgr2iojrg" path="res://elements/player_hand.tscn" id="4_fc0e3"] +[ext_resource type="PackedScene" uid="uid://b55xpcxk7g5ph" path="res://cards/playing_card.tscn" id="6_eow3j"] [ext_resource type="PackedScene" uid="uid://dj1wye7o27vil" path="res://assets/table.glb" id="7_eow3j"] [sub_resource type="SystemFont" id="SystemFont_80nbo"] @@ -183,6 +184,7 @@ disabled = true text = "Play Card" [node name="BetContainer" type="VBoxContainer" parent="HBoxContainer/GameUI"] +visible = false layout_mode = 1 anchors_preset = 2 anchor_top = 1.0 @@ -200,14 +202,43 @@ layout_mode = 2 layout_mode = 2 text = "submit bet" -[node name="EnvironmentManager" type="Node3D" parent="." node_paths=PackedStringArray("own_player_hand", "hand_markers_3", "hand_markers_4", "hand_markers_5", "hand_markers_6")] +[node name="Label" type="Label" parent="HBoxContainer/GameUI"] +visible = false +layout_mode = 1 +anchors_preset = 5 +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -88.0 +offset_top = 300.0 +offset_right = 88.0 +offset_bottom = 323.0 +grow_horizontal = 2 +text = "it's your turn DUMMY!!" + +[node name="WinLabel" type="Label" parent="HBoxContainer/GameUI"] +visible = false +layout_mode = 1 +anchors_preset = 5 +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -20.0 +offset_top = 350.0 +offset_right = 20.0 +offset_bottom = 373.0 +grow_horizontal = 2 +text = "YOU WON!!!!!!" + +[node name="EnvironmentManager" type="Node3D" parent="." node_paths=PackedStringArray("web_client", "trump_container", "own_player_hand", "hand_markers_3", "hand_markers_4", "hand_markers_5", "hand_markers_6")] script = ExtResource("4_7jktm") +web_client = NodePath("../WebClientTCP") +trump_container = NodePath("TrumpPosition") own_player_hand = NodePath("PlayerHand0") hand_markers_3 = [NodePath("HandMarker1"), NodePath("HandMarker2")] hand_markers_4 = [NodePath("HandMarker1"), NodePath("HandMarker3"), NodePath("HandMarker2")] hand_markers_5 = [NodePath("HandMarker4"), NodePath("HandMarker1"), NodePath("HandMarker3"), NodePath("HandMarker2")] hand_markers_6 = [NodePath("HandMarker4"), NodePath("HandMarker1"), NodePath("HandMarker3"), NodePath("HandMarker2"), NodePath("HandMarker5")] player_hand_scene = ExtResource("4_fc0e3") +card_scene = ExtResource("6_eow3j") [node name="Camera3D" type="Camera3D" parent="EnvironmentManager"] transform = Transform3D(1, 0, 0, 0, 0.992546, 0.121869, 0, -0.121869, 0.992546, 0, 1.128, 3.933) @@ -239,6 +270,9 @@ transform = Transform3D(-0.5, 0, 0.866025, 0, 1, 0, -0.866025, 0, -0.5, 3.2, 0.4 [node name="Table" parent="EnvironmentManager" instance=ExtResource("7_eow3j")] +[node name="TrumpPosition" type="Marker3D" parent="EnvironmentManager"] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0.167186, 0) + [connection signal="cards_received" from="WebClientTCP" to="EnvironmentManager" method="_on_web_client_tcp_cards_received"] [connection signal="client_joined_lobby" from="WebClientTCP" to="HBoxContainer/ClientInterface" method="_on_web_client_tcp_client_joined_lobby"] [connection signal="client_joined_lobby" from="WebClientTCP" to="HBoxContainer/GameUI" method="_on_web_client_tcp_client_joined_lobby"] @@ -251,11 +285,16 @@ transform = Transform3D(-0.5, 0, 0.866025, 0, 1, 0, -0.866025, 0, -0.5, 3.2, 0.4 [connection signal="connection_status_changed" from="WebClientTCP" to="HBoxContainer/ClientInterface" method="_on_web_client_tcp_connection_status_changed"] [connection signal="disconnected_from_lobby" from="WebClientTCP" to="HBoxContainer/ClientInterface" method="_on_web_client_tcp_disconnected_from_lobby"] [connection signal="disconnected_from_server" from="WebClientTCP" to="HBoxContainer/ClientInterface" method="_on_web_client_tcp_disconnected_from_server"] +[connection signal="notify_play_card_request" from="WebClientTCP" to="HBoxContainer/GameUI" method="_on_web_client_tcp_notify_play_card_request"] [connection signal="received_bet_request" from="WebClientTCP" to="HBoxContainer/GameUI" method="_on_web_client_tcp_received_bet_request"] [connection signal="received_chat_message" from="WebClientTCP" to="HBoxContainer/ClientInterface" method="_on_web_client_tcp_received_chat_message"] [connection signal="received_client_id" from="WebClientTCP" to="EnvironmentManager" method="_on_web_client_tcp_received_client_id"] [connection signal="received_connection_message" from="WebClientTCP" to="HBoxContainer/ClientInterface" method="_on_web_client_tcp_received_connection_message"] +[connection signal="received_play_winner_request" from="WebClientTCP" to="EnvironmentManager" method="_on_web_client_tcp_received_play_winner_request"] +[connection signal="received_played_card" from="WebClientTCP" to="EnvironmentManager" method="_on_web_client_tcp_received_played_card"] +[connection signal="received_win" from="WebClientTCP" to="HBoxContainer/GameUI" method="_on_web_client_tcp_received_win"] [connection signal="request_next_round" from="WebClientTCP" to="HBoxContainer/GameUI" method="_on_web_client_tcp_request_next_round"] +[connection signal="trump_received" from="WebClientTCP" to="EnvironmentManager" method="_on_web_client_tcp_trump_received"] [connection signal="pressed" from="HBoxContainer/ClientInterface/MarginContainer/VBoxContainer/ServerInputs/ConnectButton" to="HBoxContainer/ClientInterface" method="_on_connect_button_pressed"] [connection signal="pressed" from="HBoxContainer/ClientInterface/MarginContainer/VBoxContainer/ServerInputs/CreateLobbyButton" to="HBoxContainer/ClientInterface" method="_on_create_lobby_button_pressed"] [connection signal="pressed" from="HBoxContainer/ClientInterface/MarginContainer/VBoxContainer/ServerInputs/CreateLobbyButton" to="HBoxContainer/GameUI" method="_on_create_lobby_button_pressed"] @@ -266,4 +305,5 @@ transform = Transform3D(-0.5, 0, 0.866025, 0, 1, 0, -0.866025, 0, -0.5, 3.2, 0.4 [connection signal="pressed" from="HBoxContainer/GameUI/StartGameButton" to="HBoxContainer/GameUI" method="_on_start_game_button_pressed"] [connection signal="pressed" from="HBoxContainer/GameUI/PlayCardButton" to="EnvironmentManager/PlayerHand0" method="_on_play_card_button_pressed"] [connection signal="pressed" from="HBoxContainer/GameUI/BetContainer/SubmitBetButton" to="HBoxContainer/GameUI" method="_on_submit_bet_button_pressed"] +[connection signal="card_played" from="EnvironmentManager/PlayerHand0" to="HBoxContainer/GameUI" method="_on_player_hand_0_card_played"] [connection signal="card_selected" from="EnvironmentManager/PlayerHand0" to="HBoxContainer/GameUI" method="_on_player_hand_card_selected"] diff --git a/game_client.gd b/game_client.gd index 536d99f..f596b23 100644 --- a/game_client.gd +++ b/game_client.gd @@ -67,3 +67,15 @@ func _on_web_client_tcp_received_bet_request(disallowed_bet: int) -> void: func _on_web_client_tcp_request_next_round() -> void: _start_next_round() + +func _on_player_hand_0_card_played(card_id: int) -> void: + web_client.play_card(card_id) + $Label.hide() + +func _on_web_client_tcp_notify_play_card_request() -> void: + $Label.show() + +func _on_web_client_tcp_received_win() -> void: + $WinLabel.show() + await get_tree().create_timer(1.0).timeout + $WinLabel.hide() diff --git a/server_tcp.py b/server_tcp.py index 7380c0a..590bbbe 100644 --- a/server_tcp.py +++ b/server_tcp.py @@ -220,7 +220,7 @@ class LobbyManager: json.dumps({ "response": "client_played_card", "client_id": client_id, - "card": played_card, + "played_card": played_card, }), ) @@ -466,6 +466,8 @@ async def process_input(message: str, websocket) -> None: }), ) + print("Sent game start") + playing_client_id = lobby_manager.get_lobby(lobby_id).client_playing_order[0] await lobby_manager.send_message( @@ -475,6 +477,8 @@ async def process_input(message: str, websocket) -> None: "response": "request_card", }), ) + + print(f"Playing client is {playing_client_id}") else: # bets are not finished; continue asking for bets disallowed_bet = -1 @@ -506,7 +510,7 @@ async def process_input(message: str, websocket) -> None: lobby_id, lobby_manager.get_lobby_host_client_id(lobby_id), json.dumps({ - "response": "determine_round_winner_request", + "response": "determine_play_winner_request", }) ) else: @@ -527,6 +531,8 @@ async def process_input(message: str, websocket) -> None: data_object["client_id"], ) + print(f"DING DING DING we have a winner!!! {data_object['client_id']}") + if __name__ == '__main__': run_local = False # Run locally without SSL certificate