From 3521732cd28099ce26858c2080dc0815d2c09d47 Mon Sep 17 00:00:00 2001 From: Kenshia <73539778+Kenshia@users.noreply.github.com> Date: Sat, 25 Jan 2025 11:45:55 +0700 Subject: [PATCH 1/5] feat: server discovery --- main.gd | 165 +++++++++++++++++++++++++++++++++++++------- main.tscn | 34 ++++++++- server_discovery.gd | 100 +++++++++++++++++++++++++++ 3 files changed, 273 insertions(+), 26 deletions(-) create mode 100644 server_discovery.gd diff --git a/main.gd b/main.gd index 621d8f4..b977d81 100644 --- a/main.gd +++ b/main.gd @@ -1,6 +1,7 @@ extends Node const PORT = 25565 +const PORT_RANGE := 10 const MAX_CONNECTIONS = 20 var counter = 0 @@ -8,31 +9,128 @@ var counter = 0 @onready var before_connect_container = get_node("BeforeConnect") as Container @onready var host_text_edit = get_node("%HostTextEdit") as TextEdit @onready var connect_button = get_node("%ConnectButton") as Button +@onready var host_button = get_node("%HostButton") as Button +@onready var server_discovery = get_node("%ServerDiscovery") as ServerDiscovery @onready var after_connect_container = get_node("%AfterConnect") as Container @onready var counter_label = get_node("%CounterLabel") as Label @onready var decrement_button = get_node("%DecrementButton") as Button @onready var increment_button = get_node("%IncrementButton") as Button +@onready var disconnect_button = get_node("%DisconnectButton") as Button +@onready var start_game_button = get_node("%StartGameButton") as Button + +var active_port: int +var server_buttons: Dictionary = Dictionary() + +func _clean_room(): + # this is if someone left the room and we will just clean the game room again + # should only called on host + _set_counter(0) + pass + +func _on_start_game_clicked(): + if !multiplayer.multiplayer_peer: + return + if !multiplayer.get_unique_id() != 1: + return + if (multiplayer.get_peers().size() == 0): + return + # do start game here, should only run on host + pass func _ready() -> void: - if OS.has_feature("dedicated_server"): - print("Starting dedicated server") - var peer = ENetMultiplayerPeer.new() - var err = peer.create_server(PORT, MAX_CONNECTIONS) + host_button.button_up.connect(_on_host_pressed) + host_button.text = "Host (%s)" % server_discovery.id + + start_game_button.button_up.connect(_on_start_game_clicked) + + print("Attach client") + multiplayer.peer_connected.connect(_on_player_connected) + multiplayer.peer_disconnected.connect(_on_player_disconnected) + multiplayer.connected_to_server.connect(_on_connected_ok) + #multiplayer.connection_failed.connect(_on_connected_fail) + multiplayer.server_disconnected.connect(_on_server_disconnected) + + increment_button.button_up.connect(func(): _increment.rpc()) + decrement_button.button_up.connect(func(): _decrement.rpc()) + disconnect_button.button_up.connect(_on_disconnect_clicked) + connect_button.get_parent().remove_child(connect_button) + + server_discovery.server_added.connect(_on_server_added) + server_discovery.server_removed.connect(_on_server_removed) + +func _on_disconnect_clicked(): + if (multiplayer.is_server()): + server_discovery.disable_server() + multiplayer.peer_connected.disconnect(_on_player_connected) + for peer_id in multiplayer.get_peers(): + multiplayer.disconnect_peer(peer_id) + + multiplayer.multiplayer_peer = null + + $BeforeConnect.visible = true + $AfterConnect.visible = false + +func _on_server_added(id, ip, port): + print("%s | Server added %s %s" % [server_discovery.id, id, ip]) + + var button = connect_button.duplicate() + before_connect_container.add_child(button) + + var key = "%s|%s" % [id,ip] + server_buttons[key] = button + + button.text = "%s\nConnect\n%s:%d" % [id, ip, port] + for conn in button.button_down.get_connections(): + button.button_down.disconnect(conn) + + var _on_button_downed = func(): + _do_connect(ip, port) + button.button_down.connect(_on_button_downed) + +func _on_server_removed(id, ip): + print("%s | Server removed %s %s" % [server_discovery.id, id, ip]) + + var key = "%s|%s" % [id,ip] + var button = server_buttons[key] + button.queue_free() + server_buttons.erase(key) + +func _do_connect(ip: String, port: int): + var peer = ENetMultiplayerPeer.new() + print("%s Connecting to %s:%d" % [server_discovery.id, ip, port]) + peer.create_client(ip, port) + multiplayer.multiplayer_peer = peer + +func _on_host_pressed(): + print("%s | Starting dedicated server" % server_discovery.id) + var peer = ENetMultiplayerPeer.new() + for offset in range(PORT_RANGE): + if not is_port_available(PORT + offset): + continue + + active_port = PORT + offset + var err = peer.create_server(active_port, MAX_CONNECTIONS) if err: print(err) - multiplayer.multiplayer_peer = peer - multiplayer.peer_connected.connect(_on_player_connected) + break + + multiplayer.multiplayer_peer = peer + + _on_connected_ok() + + server_discovery.enable_server(active_port) + +func is_port_available(port: int) -> bool: + var udp_peer = PacketPeerUDP.new() + + var error = udp_peer.bind(port) + + if error == OK: + udp_peer.close() + return true else: - print("Game starting") - #multiplayer.peer_disconnected.connect(_on_player_disconnected) - multiplayer.connected_to_server.connect(_on_connected_ok) - #multiplayer.connection_failed.connect(_on_connected_fail) - #multiplayer.server_disconnected.connect(_on_server_disconnected) - - increment_button.button_up.connect(func(): _increment.rpc()) - decrement_button.button_up.connect(func(): _decrement.rpc()) - connect_button.button_up.connect(_on_connect_pressed) + return false @rpc("any_peer", "call_local") func _increment(): @@ -49,28 +147,45 @@ func _set_counter(value: int): counter = value counter_label.text = str(counter) -func _on_connect_pressed(): - var peer = ENetMultiplayerPeer.new() - var parsed: PackedStringArray = host_text_edit.text.split(":") - print("Connecting to ", parsed[0]) - peer.create_client(parsed[0] if not parsed[0].is_empty() else "localhost", int(parsed[1]) if parsed.size() > 1 else PORT) - multiplayer.multiplayer_peer = peer - func _on_player_connected(id: int): if multiplayer.get_unique_id() == 1: _set_counter.rpc_id(id, counter) + + if (multiplayer.get_peers().size() > 0): + start_game_button.text = "Start Game" + server_discovery.disable_server() -func _on_player_disconnected(): - pass +func _on_player_disconnected(id): + print("%s | _on_player_disconnected %s" % [server_discovery.id, id]) + if multiplayer.get_unique_id() == id: + $BeforeConnect.visible = true + $AfterConnect.visible = false + + if (id != 1 and multiplayer.get_unique_id() == 1): + _clean_room() + start_game_button.text = "Start Game (Not enough player)" + server_discovery.enable_server(active_port) + func _on_connected_ok(): $AfterConnect.visible = true $BeforeConnect.visible = false counter_label.text = str(counter) + if (multiplayer.is_server()): + disconnect_button.text = "Disconnect (Host)" + if start_game_button.get_parent() != after_connect_container: + after_connect_container.add_child(start_game_button) + else: + disconnect_button.text = "Disconnect" + if start_game_button.get_parent() == after_connect_container: + after_connect_container.remove_child(start_game_button) + func _on_connected_fail(): pass func _on_server_disconnected(): - pass + print("%s | _on_server_disconnected" % [server_discovery.id]) + $AfterConnect.visible = false + $BeforeConnect.visible = true diff --git a/main.tscn b/main.tscn index d49cabf..d1043f9 100644 --- a/main.tscn +++ b/main.tscn @@ -1,6 +1,7 @@ -[gd_scene load_steps=2 format=3 uid="uid://c7gn46af6whf8"] +[gd_scene load_steps=3 format=3 uid="uid://c7gn46af6whf8"] [ext_resource type="Script" path="res://main.gd" id="1_e0ud3"] +[ext_resource type="Script" path="res://server_discovery.gd" id="2_hed18"] [node name="Main" type="Control"] layout_mode = 3 @@ -33,12 +34,31 @@ layout_mode = 2 size_flags_vertical = 3 placeholder_text = "192.168.*.*" +[node name="RefreshButton" type="Button" parent="BeforeConnect"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 64) +layout_mode = 2 +text = "Refresh" + +[node name="HostButton" type="Button" parent="BeforeConnect"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 64) +layout_mode = 2 +text = "Host" + [node name="ConnectButton" type="Button" parent="BeforeConnect"] unique_name_in_owner = true custom_minimum_size = Vector2(0, 64) layout_mode = 2 text = "Connect" +[node name="DiscoveryTimer" type="Timer" parent="BeforeConnect"] +unique_name_in_owner = true + +[node name="ServerDiscovery" type="Node" parent="BeforeConnect"] +unique_name_in_owner = true +script = ExtResource("2_hed18") + [node name="AfterConnect" type="VBoxContainer" parent="."] unique_name_in_owner = true visible = false @@ -64,6 +84,12 @@ text = "1" horizontal_alignment = 1 vertical_alignment = 1 +[node name="DisconnectButton" type="Button" parent="AfterConnect"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "Disconnect" + [node name="Actions" type="HBoxContainer" parent="AfterConnect"] layout_mode = 2 @@ -78,3 +104,9 @@ unique_name_in_owner = true layout_mode = 2 size_flags_horizontal = 3 text = "+" + +[node name="StartGameButton" type="Button" parent="AfterConnect"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "Start Game" diff --git a/server_discovery.gd b/server_discovery.gd new file mode 100644 index 0000000..e63154a --- /dev/null +++ b/server_discovery.gd @@ -0,0 +1,100 @@ +extends Node +class_name ServerDiscovery + +const PORT := 26566 +const PORT_RANGE := 10 # cannot listen to the same port on one device + +signal server_added(id: String, ip: String, port: int) +signal server_removed(id: String, ip: String) + +var server: UDPServer = null +var client: PacketPeerUDP = null +var port_offset: int +var id: String +var servers: Array[String] = [] +var enabled := false + +func enable_server(server_port: int): + enabled = true + var data = "%s|AVAILABLE|%d" %[id,server_port] + _broadcast_packet(data.to_utf8_buffer()) + +func disable_server(): + enabled = false + var data = "%s|NOT_AVAILABLE" %id + _broadcast_packet(data.to_utf8_buffer()) + +func _ready(): + id = _generate_id() + _init_server() + _init_client() + +func _process(_delta): + server.poll() + while(server.is_connection_available()): + var peer = server.take_connection() + while(peer.get_available_packet_count() > 0): + var packet = peer.get_packet() + var packet_str = packet.get_string_from_utf8() + if (packet_str.begins_with(id)): + continue + + var ip = peer.get_packet_ip() + var port = peer.get_packet_port() + print(id, " | Received data from ", ip, ":", port, " => ", packet_str) + + var data = packet_str.split("|") + var conn_id = data[0] + var conn_detail = data[1] + var key = "%s:%s" %[ip, port] + + if (conn_detail == "AVAILABLE" and key not in servers): + var conn_actual_server_port = int(data[2]) + servers.append(key) + server_added.emit(conn_id, ip, conn_actual_server_port) + elif (conn_detail == "NOT_AVAILABLE" and key in servers): + servers.erase(key) + server_removed.emit(conn_id, ip) + elif (conn_detail == "DISCOVERY" and enabled): + var available_data = "%s|AVAILABLE" %id + _broadcast_packet(available_data.to_utf8_buffer()) + +func _exit_tree(): + var data = "%s|NOT_AVAILABLE" %id + _broadcast_packet(data.to_utf8_buffer()) + +func _init_server(): + server = UDPServer.new() + + for offset in range(PORT_RANGE): + var err = server.listen(PORT + offset) + if !err: + port_offset = offset + break + + print("Server ", id, " initialized on port ", PORT + port_offset) + +func _init_client(): + client = PacketPeerUDP.new() + client.set_broadcast_enabled(true) + + var data = "%s|DISCOVERY" %id + _broadcast_packet(data.to_utf8_buffer()) + +func _broadcast_packet(buffer: PackedByteArray): + for offset in range(PORT_RANGE): + client.connect_to_host("255.255.255.255", PORT + offset) + client.put_packet(buffer) + +func _generate_id() -> String: + var id_len = 5 + var from = 'A'.unicode_at(0) + var to = 'Z'.unicode_at(0) + + var result:= "" + + for i in range(id_len): + var rand_char = char(randi_range(from, to)) + result += rand_char + + return result -- 2.49.1 From 0f5f1d466f814d21a10d7d44b03f62430375d187 Mon Sep 17 00:00:00 2001 From: Kenshia <73539778+Kenshia@users.noreply.github.com> Date: Sat, 25 Jan 2025 11:50:10 +0700 Subject: [PATCH 2/5] fix: start game text & disconnect signal --- main.gd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.gd b/main.gd index b977d81..3f1095d 100644 --- a/main.gd +++ b/main.gd @@ -62,7 +62,6 @@ func _ready() -> void: func _on_disconnect_clicked(): if (multiplayer.is_server()): server_discovery.disable_server() - multiplayer.peer_connected.disconnect(_on_player_connected) for peer_id in multiplayer.get_peers(): multiplayer.disconnect_peer(peer_id) @@ -119,6 +118,8 @@ func _on_host_pressed(): _on_connected_ok() + start_game_button.text = "Start Game (Not enough player)" + server_discovery.enable_server(active_port) func is_port_available(port: int) -> bool: -- 2.49.1 From 65dc02585e09dc008789fb3017f7287d36e24c5b Mon Sep 17 00:00:00 2001 From: istamarahsan Date: Sat, 25 Jan 2025 18:40:14 +0700 Subject: [PATCH 3/5] feat: red and green card templates --- assets/Bohemian Soul.otf | 3 + assets/Bohemian Soul.otf.import | 34 +++++ assets/Inter-Regular.otf | 3 + assets/Inter-Regular.otf.import | 34 +++++ assets/card_base/Frame.png | 3 + assets/card_base/Frame.png.import | 34 +++++ assets/card_base/G-OuterFill.png | 3 + assets/card_base/G-OuterFill.png.import | 34 +++++ assets/card_base/InnerFill.png | 3 + assets/card_base/InnerFill.png.import | 34 +++++ assets/card_base/Pill.png | 3 + assets/card_base/Pill.png.import | 34 +++++ assets/card_base/R-OuterFill.png | 3 + assets/card_base/R-OuterFill.png.import | 34 +++++ assets/card_base/Separator.png | 3 + assets/card_base/Separator.png.import | 34 +++++ assets/card_base/Stroke.png | 3 + assets/card_base/Stroke.png.import | 34 +++++ assets/energy.png | 3 + assets/energy.png.import | 34 +++++ cards.tres | 8 ++ data/cards/{ => monster}/baraga.tres | 0 data/cards/{ => monster}/taiman.tres | 0 data/cards/potion.tres | 16 --- data/cards/support/potion.tres | 20 +++ demo_game.tscn | 6 +- tcg/card/card.gd | 4 + test_card.gd | 7 + test_card.tscn | 28 ++++ ui/card/GreenCard.tscn | 165 +++++++++++++++++++++++ ui/card/RedCard.tscn | 167 ++++++++++++++++++++++++ ui/card/card_base.gd | 20 +++ 32 files changed, 792 insertions(+), 19 deletions(-) create mode 100644 assets/Bohemian Soul.otf create mode 100644 assets/Bohemian Soul.otf.import create mode 100644 assets/Inter-Regular.otf create mode 100644 assets/Inter-Regular.otf.import create mode 100644 assets/card_base/Frame.png create mode 100644 assets/card_base/Frame.png.import create mode 100644 assets/card_base/G-OuterFill.png create mode 100644 assets/card_base/G-OuterFill.png.import create mode 100644 assets/card_base/InnerFill.png create mode 100644 assets/card_base/InnerFill.png.import create mode 100644 assets/card_base/Pill.png create mode 100644 assets/card_base/Pill.png.import create mode 100644 assets/card_base/R-OuterFill.png create mode 100644 assets/card_base/R-OuterFill.png.import create mode 100644 assets/card_base/Separator.png create mode 100644 assets/card_base/Separator.png.import create mode 100644 assets/card_base/Stroke.png create mode 100644 assets/card_base/Stroke.png.import create mode 100644 assets/energy.png create mode 100644 assets/energy.png.import create mode 100644 cards.tres rename data/cards/{ => monster}/baraga.tres (100%) rename data/cards/{ => monster}/taiman.tres (100%) delete mode 100644 data/cards/potion.tres create mode 100644 data/cards/support/potion.tres create mode 100644 test_card.gd create mode 100644 test_card.tscn create mode 100644 ui/card/GreenCard.tscn create mode 100644 ui/card/RedCard.tscn create mode 100644 ui/card/card_base.gd diff --git a/assets/Bohemian Soul.otf b/assets/Bohemian Soul.otf new file mode 100644 index 0000000..6649ff1 --- /dev/null +++ b/assets/Bohemian Soul.otf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b387796a272c26c37ff918e48271cf139755a0ecb2398039103d79af2c91c850 +size 38880 diff --git a/assets/Bohemian Soul.otf.import b/assets/Bohemian Soul.otf.import new file mode 100644 index 0000000..7e974e0 --- /dev/null +++ b/assets/Bohemian Soul.otf.import @@ -0,0 +1,34 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://ncoq4i61plvt" +path="res://.godot/imported/Bohemian Soul.otf-321180efeec0e46d48937761716dc66f.fontdata" + +[deps] + +source_file="res://assets/Bohemian Soul.otf" +dest_files=["res://.godot/imported/Bohemian Soul.otf-321180efeec0e46d48937761716dc66f.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=1 +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/assets/Inter-Regular.otf b/assets/Inter-Regular.otf new file mode 100644 index 0000000..4ed3a79 --- /dev/null +++ b/assets/Inter-Regular.otf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7e791e8f5a0fb02b65663f7fca73e1d1ca9543f772ad480cbd76f4e3fe3f8cc +size 258992 diff --git a/assets/Inter-Regular.otf.import b/assets/Inter-Regular.otf.import new file mode 100644 index 0000000..6ec3561 --- /dev/null +++ b/assets/Inter-Regular.otf.import @@ -0,0 +1,34 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://08q3kkwmd4u6" +path="res://.godot/imported/Inter-Regular.otf-e79282422267193643bc1266eabc7aef.fontdata" + +[deps] + +source_file="res://assets/Inter-Regular.otf" +dest_files=["res://.godot/imported/Inter-Regular.otf-e79282422267193643bc1266eabc7aef.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=1 +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/assets/card_base/Frame.png b/assets/card_base/Frame.png new file mode 100644 index 0000000..5c7b0da --- /dev/null +++ b/assets/card_base/Frame.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b2315fae148c1d73e139ad51d9d90c0dc69314de870596e52fb2b4274a2e51b1 +size 165111 diff --git a/assets/card_base/Frame.png.import b/assets/card_base/Frame.png.import new file mode 100644 index 0000000..930f4d0 --- /dev/null +++ b/assets/card_base/Frame.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://l2nxxhh0pvh8" +path="res://.godot/imported/Frame.png-2cc9ebde58565bbc3036395eb0041ae9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/card_base/Frame.png" +dest_files=["res://.godot/imported/Frame.png-2cc9ebde58565bbc3036395eb0041ae9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/card_base/G-OuterFill.png b/assets/card_base/G-OuterFill.png new file mode 100644 index 0000000..114bbb7 --- /dev/null +++ b/assets/card_base/G-OuterFill.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e0e62d5e3d57866bfa09a4dbcd0a14a244bd704c94b8eeadb1eafb57f08562a +size 149729 diff --git a/assets/card_base/G-OuterFill.png.import b/assets/card_base/G-OuterFill.png.import new file mode 100644 index 0000000..0468b36 --- /dev/null +++ b/assets/card_base/G-OuterFill.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://liitr32ap646" +path="res://.godot/imported/G-OuterFill.png-08376930c432a32d81cb0c7a55fb089e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/card_base/G-OuterFill.png" +dest_files=["res://.godot/imported/G-OuterFill.png-08376930c432a32d81cb0c7a55fb089e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/card_base/InnerFill.png b/assets/card_base/InnerFill.png new file mode 100644 index 0000000..3beb15d --- /dev/null +++ b/assets/card_base/InnerFill.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aedb750f04941c2337bdad6c73b73399ed8fb625eaa436d6588017db9c0bee45 +size 126446 diff --git a/assets/card_base/InnerFill.png.import b/assets/card_base/InnerFill.png.import new file mode 100644 index 0000000..11ff539 --- /dev/null +++ b/assets/card_base/InnerFill.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://blejyda8mendg" +path="res://.godot/imported/InnerFill.png-75781e681a40959b716289bec2b32336.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/card_base/InnerFill.png" +dest_files=["res://.godot/imported/InnerFill.png-75781e681a40959b716289bec2b32336.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/card_base/Pill.png b/assets/card_base/Pill.png new file mode 100644 index 0000000..fb2a20d --- /dev/null +++ b/assets/card_base/Pill.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e21a3903c649abe91077ed55440eed2cd7f563f17b9c37f50430d68d322c4909 +size 846 diff --git a/assets/card_base/Pill.png.import b/assets/card_base/Pill.png.import new file mode 100644 index 0000000..51de1d3 --- /dev/null +++ b/assets/card_base/Pill.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://0gxplli5krq2" +path="res://.godot/imported/Pill.png-f7a0d13f20f1ea9ba344cea7c095427a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/card_base/Pill.png" +dest_files=["res://.godot/imported/Pill.png-f7a0d13f20f1ea9ba344cea7c095427a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/card_base/R-OuterFill.png b/assets/card_base/R-OuterFill.png new file mode 100644 index 0000000..d546cac --- /dev/null +++ b/assets/card_base/R-OuterFill.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2dcca3e0a0b82a518b6f0e23496a446f7d0e102b41763d35d9b3cc8c37d62afc +size 149723 diff --git a/assets/card_base/R-OuterFill.png.import b/assets/card_base/R-OuterFill.png.import new file mode 100644 index 0000000..cdfb01f --- /dev/null +++ b/assets/card_base/R-OuterFill.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ip7xjs20pd3d" +path="res://.godot/imported/R-OuterFill.png-f999c1a1aec742072b5689d6ee4573cf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/card_base/R-OuterFill.png" +dest_files=["res://.godot/imported/R-OuterFill.png-f999c1a1aec742072b5689d6ee4573cf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/card_base/Separator.png b/assets/card_base/Separator.png new file mode 100644 index 0000000..c722ba8 --- /dev/null +++ b/assets/card_base/Separator.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f41f216767597470e7f2b0b5bbb1a28718e591ee3283ee100ec8ae7965b08f3 +size 1537 diff --git a/assets/card_base/Separator.png.import b/assets/card_base/Separator.png.import new file mode 100644 index 0000000..af841a8 --- /dev/null +++ b/assets/card_base/Separator.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://by7ws88pn4tvb" +path="res://.godot/imported/Separator.png-3ef36f6d9a7c45cb144c99255cbf2668.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/card_base/Separator.png" +dest_files=["res://.godot/imported/Separator.png-3ef36f6d9a7c45cb144c99255cbf2668.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/card_base/Stroke.png b/assets/card_base/Stroke.png new file mode 100644 index 0000000..aad94f9 --- /dev/null +++ b/assets/card_base/Stroke.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:041b63c0964cdd231d08d220cfc236e6fe4ee5643e7373701491ff5f3dc98f40 +size 3940 diff --git a/assets/card_base/Stroke.png.import b/assets/card_base/Stroke.png.import new file mode 100644 index 0000000..668eddd --- /dev/null +++ b/assets/card_base/Stroke.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://crgrple0uik7x" +path="res://.godot/imported/Stroke.png-9acc55e7647197941083043ac51c45a4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/card_base/Stroke.png" +dest_files=["res://.godot/imported/Stroke.png-9acc55e7647197941083043ac51c45a4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/energy.png b/assets/energy.png new file mode 100644 index 0000000..29479d0 --- /dev/null +++ b/assets/energy.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9d835c0519e95c077b5b4f681673b4672a0728ad47b86595726f07775993f3eb +size 482598 diff --git a/assets/energy.png.import b/assets/energy.png.import new file mode 100644 index 0000000..d8aecba --- /dev/null +++ b/assets/energy.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://rh3aswb0p7ri" +path="res://.godot/imported/energy.png-d31ae10deb2f267a25814b3eac80d643.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/energy.png" +dest_files=["res://.godot/imported/energy.png-d31ae10deb2f267a25814b3eac80d643.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/cards.tres b/cards.tres new file mode 100644 index 0000000..e4debd9 --- /dev/null +++ b/cards.tres @@ -0,0 +1,8 @@ +[gd_resource type="Theme" load_steps=2 format=3 uid="uid://cj3vs5hq2mcbp"] + +[ext_resource type="FontFile" uid="uid://ncoq4i61plvt" path="res://assets/Bohemian Soul.otf" id="1_yowck"] + +[resource] +default_font = ExtResource("1_yowck") +Label/font_sizes/font_size = 12 +Label/fonts/font = ExtResource("1_yowck") diff --git a/data/cards/baraga.tres b/data/cards/monster/baraga.tres similarity index 100% rename from data/cards/baraga.tres rename to data/cards/monster/baraga.tres diff --git a/data/cards/taiman.tres b/data/cards/monster/taiman.tres similarity index 100% rename from data/cards/taiman.tres rename to data/cards/monster/taiman.tres diff --git a/data/cards/potion.tres b/data/cards/potion.tres deleted file mode 100644 index a68f262..0000000 --- a/data/cards/potion.tres +++ /dev/null @@ -1,16 +0,0 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=5 format=3 uid="uid://4eod3m0vc5a8"] - -[ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_alamh"] -[ext_resource type="Resource" uid="uid://cvu0rtt5nggf" path="res://data/support_effects/heal.tres" id="2_3x5mu"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="2_72hmi"] - -[sub_resource type="Resource" id="Resource_88lmk"] -script = ExtResource("1_alamh") -magnitude = 5 -effect = ExtResource("2_3x5mu") - -[resource] -script = ExtResource("2_72hmi") -type = "green" -priority = 0 -effects = Array[ExtResource("1_alamh")]([SubResource("Resource_88lmk")]) diff --git a/data/cards/support/potion.tres b/data/cards/support/potion.tres new file mode 100644 index 0000000..96ed2d7 --- /dev/null +++ b/data/cards/support/potion.tres @@ -0,0 +1,20 @@ +[gd_resource type="Resource" script_class="SupportCard" load_steps=6 format=3 uid="uid://4eod3m0vc5a8"] + +[ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_ujm0o"] +[ext_resource type="Resource" uid="uid://cvu0rtt5nggf" path="res://data/support_effects/heal.tres" id="2_k1cnl"] +[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="3_6r4k4"] +[ext_resource type="Texture2D" uid="uid://rh3aswb0p7ri" path="res://assets/energy.png" id="3_kyx3v"] + +[sub_resource type="Resource" id="Resource_88lmk"] +script = ExtResource("1_ujm0o") +magnitude = 30 +effect = ExtResource("2_k1cnl") + +[resource] +script = ExtResource("3_6r4k4") +type = "green" +priority = 0 +effects = Array[ExtResource("1_ujm0o")]([SubResource("Resource_88lmk")]) +name = "Potion" +description = "Heal 30 HP" +icon = ExtResource("3_kyx3v") diff --git a/demo_game.tscn b/demo_game.tscn index e5ae8d6..b6c0ea6 100644 --- a/demo_game.tscn +++ b/demo_game.tscn @@ -4,9 +4,9 @@ [ext_resource type="Script" path="res://player_side.gd" id="2_w4tnt"] [ext_resource type="Script" path="res://tcg/card/card.gd" id="2_xuft0"] [ext_resource type="PackedScene" uid="uid://cikstg43mudkn" path="res://tcg/match/match_manager.tscn" id="3_3yhrl"] -[ext_resource type="Resource" uid="uid://cs7q8i7bvohmj" path="res://data/cards/baraga.tres" id="3_we1tk"] -[ext_resource type="Resource" uid="uid://4eod3m0vc5a8" path="res://data/cards/potion.tres" id="4_kkhfk"] -[ext_resource type="Resource" uid="uid://di76avwc0gn8e" path="res://data/cards/taiman.tres" id="5_3cm5x"] +[ext_resource type="Resource" uid="uid://cs7q8i7bvohmj" path="res://data/cards/monster/baraga.tres" id="3_we1tk"] +[ext_resource type="Resource" uid="uid://4eod3m0vc5a8" path="res://data/cards/support/potion.tres" id="4_kkhfk"] +[ext_resource type="Resource" uid="uid://di76avwc0gn8e" path="res://data/cards/monster/taiman.tres" id="5_3cm5x"] [node name="DemoGame" type="Control"] layout_mode = 3 diff --git a/tcg/card/card.gd b/tcg/card/card.gd index 5c8826b..e14ff41 100644 --- a/tcg/card/card.gd +++ b/tcg/card/card.gd @@ -1,6 +1,10 @@ extends Resource class_name Card +@export var name: String +@export var description: String +@export var icon: Texture2D + var id: String: get: return resource_path.rsplit(".", true, 1)[0].rsplit("/", true, 1)[1] diff --git a/test_card.gd b/test_card.gd new file mode 100644 index 0000000..a0b8904 --- /dev/null +++ b/test_card.gd @@ -0,0 +1,7 @@ +extends Control + +@export var card: SupportCard + +func _ready() -> void: + $Green.card = card + $Red.card = card diff --git a/test_card.tscn b/test_card.tscn new file mode 100644 index 0000000..94b6965 --- /dev/null +++ b/test_card.tscn @@ -0,0 +1,28 @@ +[gd_scene load_steps=5 format=3 uid="uid://dhm4v4r7he0op"] + +[ext_resource type="Script" path="res://test_card.gd" id="1_tqmas"] +[ext_resource type="PackedScene" uid="uid://dg5amjm1gqi06" path="res://ui/card/GreenCard.tscn" id="2_22pto"] +[ext_resource type="Resource" uid="uid://4eod3m0vc5a8" path="res://data/cards/support/potion.tres" id="2_tbbjy"] +[ext_resource type="PackedScene" uid="uid://cds50kwwhlgam" path="res://ui/card/RedCard.tscn" id="3_7wd2e"] + +[node name="TestCard" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_tqmas") +card = ExtResource("2_tbbjy") + +[node name="Green" parent="." instance=ExtResource("2_22pto")] +offset_left = 225.0 +offset_top = 165.0 +offset_right = 445.0 +offset_bottom = 485.0 + +[node name="Red" parent="." instance=ExtResource("3_7wd2e")] +offset_left = 699.0 +offset_top = 168.0 +offset_right = 919.0 +offset_bottom = 488.0 diff --git a/ui/card/GreenCard.tscn b/ui/card/GreenCard.tscn new file mode 100644 index 0000000..019163e --- /dev/null +++ b/ui/card/GreenCard.tscn @@ -0,0 +1,165 @@ +[gd_scene load_steps=11 format=3 uid="uid://dg5amjm1gqi06"] + +[ext_resource type="Texture2D" uid="uid://l2nxxhh0pvh8" path="res://assets/card_base/Frame.png" id="1_4ivbl"] +[ext_resource type="Script" path="res://ui/card/card_base.gd" id="1_rpopv"] +[ext_resource type="Texture2D" uid="uid://liitr32ap646" path="res://assets/card_base/G-OuterFill.png" id="2_c6lcl"] +[ext_resource type="Texture2D" uid="uid://crgrple0uik7x" path="res://assets/card_base/Stroke.png" id="3_qajq3"] +[ext_resource type="Texture2D" uid="uid://blejyda8mendg" path="res://assets/card_base/InnerFill.png" id="4_pgomu"] +[ext_resource type="Texture2D" uid="uid://by7ws88pn4tvb" path="res://assets/card_base/Separator.png" id="5_501uu"] +[ext_resource type="Texture2D" uid="uid://0gxplli5krq2" path="res://assets/card_base/Pill.png" id="6_ce7hm"] +[ext_resource type="Theme" uid="uid://cj3vs5hq2mcbp" path="res://cards.tres" id="7_va1d7"] +[ext_resource type="Texture2D" uid="uid://rh3aswb0p7ri" path="res://assets/energy.png" id="8_4yq42"] +[ext_resource type="FontFile" uid="uid://08q3kkwmd4u6" path="res://assets/Inter-Regular.otf" id="10_c2ugn"] + +[node name="CardBase" type="Control" node_paths=PackedStringArray("card_name_label", "card_desc_label", "icon_rect")] +layout_mode = 3 +anchors_preset = 0 +offset_right = 220.0 +offset_bottom = 320.0 +script = ExtResource("1_rpopv") +card_name_label = NodePath("MarginContainer/Label") +card_desc_label = NodePath("MarginContainer/DescriptionLabel") +icon_rect = NodePath("MarginContainer/Icon") + +[node name="Frame" type="TextureRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("1_4ivbl") +expand_mode = 1 + +[node name="MarginContainer" type="Control" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 4.0 +offset_top = 3.0 +offset_right = -5.0 +offset_bottom = -4.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="TextureRect" type="TextureRect" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("2_c6lcl") +expand_mode = 1 + +[node name="OuterStroke" type="NinePatchRect" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("3_qajq3") + +[node name="TextureRect2" type="TextureRect" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = 62.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("4_pgomu") +expand_mode = 1 + +[node name="InnerStroke" type="NinePatchRect" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = 62.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("3_qajq3") + +[node name="TextureRect3" type="TextureRect" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = -1 +anchor_left = 0.01 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -0.0100002 +offset_top = -112.0 +offset_right = -1.0 +offset_bottom = -110.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("5_501uu") +expand_mode = 1 +metadata/_edit_use_anchors_ = true + +[node name="TextureRect4" type="NinePatchRect" parent="MarginContainer"] +modulate = Color(0.356863, 0.54902, 0.243137, 1) +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = 4.5 +offset_top = 30.5 +offset_right = 90.5 +offset_bottom = 60.5 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("6_ce7hm") + +[node name="Label" type="Label" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +offset_left = 2.0 +offset_top = 16.0 +offset_right = -3.0 +offset_bottom = 50.0 +grow_horizontal = 2 +theme = ExtResource("7_va1d7") +theme_override_colors/font_color = Color(0.576471, 0.788235, 0.819608, 1) +theme_override_font_sizes/font_size = 24 +text = "green card" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="Label2" type="Label" parent="MarginContainer"] +layout_mode = 0 +offset_left = 118.0 +offset_top = 190.0 +offset_right = 188.0 +offset_bottom = 213.0 +theme = ExtResource("7_va1d7") +text = "Green card" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="Icon" type="TextureRect" parent="MarginContainer"] +offset_left = 26.0 +offset_top = 74.0 +offset_right = 169.0 +offset_bottom = 179.0 +texture = ExtResource("8_4yq42") +expand_mode = 1 +stretch_mode = 6 + +[node name="DescriptionLabel" type="Label" parent="MarginContainer"] +offset_left = 11.0 +offset_top = 224.0 +offset_right = 200.0 +offset_bottom = 302.0 +theme = ExtResource("7_va1d7") +theme_override_fonts/font = ExtResource("10_c2ugn") +theme_override_font_sizes/font_size = 12 +text = "If your monster is supposed to be dead, keep it alive at 10 HP" +horizontal_alignment = 1 +autowrap_mode = 3 diff --git a/ui/card/RedCard.tscn b/ui/card/RedCard.tscn new file mode 100644 index 0000000..3744e13 --- /dev/null +++ b/ui/card/RedCard.tscn @@ -0,0 +1,167 @@ +[gd_scene load_steps=11 format=3 uid="uid://cds50kwwhlgam"] + +[ext_resource type="Script" path="res://ui/card/card_base.gd" id="1_d22a5"] +[ext_resource type="Texture2D" uid="uid://l2nxxhh0pvh8" path="res://assets/card_base/Frame.png" id="1_x5ex0"] +[ext_resource type="Texture2D" uid="uid://ip7xjs20pd3d" path="res://assets/card_base/R-OuterFill.png" id="2_xjg8y"] +[ext_resource type="Texture2D" uid="uid://crgrple0uik7x" path="res://assets/card_base/Stroke.png" id="3_q71h0"] +[ext_resource type="Texture2D" uid="uid://blejyda8mendg" path="res://assets/card_base/InnerFill.png" id="4_2fw8n"] +[ext_resource type="Texture2D" uid="uid://by7ws88pn4tvb" path="res://assets/card_base/Separator.png" id="5_n3v14"] +[ext_resource type="Texture2D" uid="uid://0gxplli5krq2" path="res://assets/card_base/Pill.png" id="6_wrd2a"] +[ext_resource type="Theme" uid="uid://cj3vs5hq2mcbp" path="res://cards.tres" id="7_fp6ys"] +[ext_resource type="FontFile" uid="uid://08q3kkwmd4u6" path="res://assets/Inter-Regular.otf" id="9_vilw6"] +[ext_resource type="Texture2D" uid="uid://rh3aswb0p7ri" path="res://assets/energy.png" id="10_2t0ey"] + +[node name="CardBase" type="Control" node_paths=PackedStringArray("card_name_label", "card_desc_label", "icon_rect")] +layout_mode = 3 +anchors_preset = 0 +offset_right = 220.0 +offset_bottom = 320.0 +script = ExtResource("1_d22a5") +card_name_label = NodePath("MarginContainer/Title") +card_desc_label = NodePath("MarginContainer/DescriptionLabel") +icon_rect = NodePath("MarginContainer/Icon") + +[node name="Frame" type="TextureRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("1_x5ex0") +expand_mode = 1 + +[node name="MarginContainer" type="Control" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 4.0 +offset_top = 3.0 +offset_right = -5.0 +offset_bottom = -4.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="TextureRect" type="TextureRect" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("2_xjg8y") +expand_mode = 1 + +[node name="OuterStroke" type="NinePatchRect" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("3_q71h0") + +[node name="TextureRect2" type="TextureRect" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = 62.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("4_2fw8n") +expand_mode = 1 + +[node name="InnerStroke" type="NinePatchRect" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = 62.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("3_q71h0") + +[node name="TextureRect3" type="TextureRect" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = -1 +anchor_left = 0.01 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -0.0100002 +offset_top = -112.0 +offset_right = -1.0 +offset_bottom = -110.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("5_n3v14") +expand_mode = 1 +metadata/_edit_use_anchors_ = true + +[node name="TextureRect4" type="NinePatchRect" parent="MarginContainer"] +modulate = Color(0.54902, 0.243137, 0.243137, 1) +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = 4.5 +offset_top = 30.5 +offset_right = 90.5 +offset_bottom = 60.5 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("6_wrd2a") + +[node name="Title" type="Label" parent="MarginContainer"] +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +offset_left = 2.0 +offset_top = 16.0 +offset_right = -3.0 +offset_bottom = 50.0 +grow_horizontal = 2 +theme = ExtResource("7_fp6ys") +theme_override_colors/font_color = Color(0.819608, 0.576471, 0.576471, 1) +theme_override_font_sizes/font_size = 24 +text = "red card" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="PillLabel" type="Label" parent="MarginContainer"] +layout_mode = 0 +offset_left = 118.0 +offset_top = 190.0 +offset_right = 188.0 +offset_bottom = 213.0 +theme = ExtResource("7_fp6ys") +text = "Red card" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="DescriptionLabel" type="Label" parent="MarginContainer"] +layout_mode = 0 +offset_left = 11.0 +offset_top = 224.0 +offset_right = 200.0 +offset_bottom = 302.0 +theme = ExtResource("7_fp6ys") +theme_override_fonts/font = ExtResource("9_vilw6") +theme_override_font_sizes/font_size = 12 +text = "If your monster is supposed to be dead, keep it alive at 10 HP" +horizontal_alignment = 1 +autowrap_mode = 3 + +[node name="Icon" type="TextureRect" parent="MarginContainer"] +layout_mode = 0 +offset_left = 30.0 +offset_top = 77.0 +offset_right = 173.0 +offset_bottom = 182.0 +texture = ExtResource("10_2t0ey") +expand_mode = 1 +stretch_mode = 6 diff --git a/ui/card/card_base.gd b/ui/card/card_base.gd new file mode 100644 index 0000000..12acc63 --- /dev/null +++ b/ui/card/card_base.gd @@ -0,0 +1,20 @@ +extends Control + +@export var card_name_label: Label +@export var card_desc_label: Label +@export var icon_rect: TextureRect + +var _card: SupportCard +var card: SupportCard: + get: + return _card + set(value): + _update(value) + _card = value + +func _update(card: SupportCard): + card_name_label.text = card.name + card_desc_label.text = card.description + icon_rect.texture = card.icon + + -- 2.49.1 From 5e3940b811ce0e586a69dba1cbd0b55abed203b1 Mon Sep 17 00:00:00 2001 From: istamarahsan Date: Sat, 25 Jan 2025 18:46:32 +0700 Subject: [PATCH 4/5] refactor: rename to card template --- test_card.tscn | 4 ++-- ui/{card => card_template}/card_base.gd | 0 ui/card_template/monster_card.tscn | 9 +++++++++ .../support_card_green.tscn} | 2 +- .../RedCard.tscn => card_template/support_card_red.tscn} | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) rename ui/{card => card_template}/card_base.gd (100%) create mode 100644 ui/card_template/monster_card.tscn rename ui/{card/GreenCard.tscn => card_template/support_card_green.tscn} (98%) rename ui/{card/RedCard.tscn => card_template/support_card_red.tscn} (98%) diff --git a/test_card.tscn b/test_card.tscn index 94b6965..ccbb6d6 100644 --- a/test_card.tscn +++ b/test_card.tscn @@ -1,9 +1,9 @@ [gd_scene load_steps=5 format=3 uid="uid://dhm4v4r7he0op"] [ext_resource type="Script" path="res://test_card.gd" id="1_tqmas"] -[ext_resource type="PackedScene" uid="uid://dg5amjm1gqi06" path="res://ui/card/GreenCard.tscn" id="2_22pto"] +[ext_resource type="PackedScene" uid="uid://dg5amjm1gqi06" path="res://ui/card_template/support_card_green.tscn" id="2_22pto"] [ext_resource type="Resource" uid="uid://4eod3m0vc5a8" path="res://data/cards/support/potion.tres" id="2_tbbjy"] -[ext_resource type="PackedScene" uid="uid://cds50kwwhlgam" path="res://ui/card/RedCard.tscn" id="3_7wd2e"] +[ext_resource type="PackedScene" uid="uid://cds50kwwhlgam" path="res://ui/card_template/support_card_red.tscn" id="3_7wd2e"] [node name="TestCard" type="Control"] layout_mode = 3 diff --git a/ui/card/card_base.gd b/ui/card_template/card_base.gd similarity index 100% rename from ui/card/card_base.gd rename to ui/card_template/card_base.gd diff --git a/ui/card_template/monster_card.tscn b/ui/card_template/monster_card.tscn new file mode 100644 index 0000000..3d9e3de --- /dev/null +++ b/ui/card_template/monster_card.tscn @@ -0,0 +1,9 @@ +[gd_scene format=3 uid="uid://bhrelvt51cbp2"] + +[node name="MonsterCard" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 diff --git a/ui/card/GreenCard.tscn b/ui/card_template/support_card_green.tscn similarity index 98% rename from ui/card/GreenCard.tscn rename to ui/card_template/support_card_green.tscn index 019163e..6bf7743 100644 --- a/ui/card/GreenCard.tscn +++ b/ui/card_template/support_card_green.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=11 format=3 uid="uid://dg5amjm1gqi06"] [ext_resource type="Texture2D" uid="uid://l2nxxhh0pvh8" path="res://assets/card_base/Frame.png" id="1_4ivbl"] -[ext_resource type="Script" path="res://ui/card/card_base.gd" id="1_rpopv"] +[ext_resource type="Script" path="res://ui/card_template/card_base.gd" id="1_rpopv"] [ext_resource type="Texture2D" uid="uid://liitr32ap646" path="res://assets/card_base/G-OuterFill.png" id="2_c6lcl"] [ext_resource type="Texture2D" uid="uid://crgrple0uik7x" path="res://assets/card_base/Stroke.png" id="3_qajq3"] [ext_resource type="Texture2D" uid="uid://blejyda8mendg" path="res://assets/card_base/InnerFill.png" id="4_pgomu"] diff --git a/ui/card/RedCard.tscn b/ui/card_template/support_card_red.tscn similarity index 98% rename from ui/card/RedCard.tscn rename to ui/card_template/support_card_red.tscn index 3744e13..d06b8dc 100644 --- a/ui/card/RedCard.tscn +++ b/ui/card_template/support_card_red.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=11 format=3 uid="uid://cds50kwwhlgam"] -[ext_resource type="Script" path="res://ui/card/card_base.gd" id="1_d22a5"] +[ext_resource type="Script" path="res://ui/card_template/card_base.gd" id="1_d22a5"] [ext_resource type="Texture2D" uid="uid://l2nxxhh0pvh8" path="res://assets/card_base/Frame.png" id="1_x5ex0"] [ext_resource type="Texture2D" uid="uid://ip7xjs20pd3d" path="res://assets/card_base/R-OuterFill.png" id="2_xjg8y"] [ext_resource type="Texture2D" uid="uid://crgrple0uik7x" path="res://assets/card_base/Stroke.png" id="3_q71h0"] -- 2.49.1 From 6c6e1b328989d9ca8162c2957ac5b9a926bceb91 Mon Sep 17 00:00:00 2001 From: Kenshia <73539778+Kenshia@users.noreply.github.com> Date: Sat, 25 Jan 2025 18:47:56 +0700 Subject: [PATCH 5/5] feat: more multiplayer --- demo_game.gd | 112 +++++++++++++-- demo_game.tscn | 6 +- export_presets.cfg | 208 +++++++++++++++++++++++++++ main.gd | 87 ++++++----- main.tscn | 65 ++------- player_side.gd | 40 +++++- project.godot | 1 + tcg/match/action/action_skip_card.gd | 2 + tcg/match/match_manager.gd | 12 ++ 9 files changed, 429 insertions(+), 104 deletions(-) create mode 100644 tcg/match/action/action_skip_card.gd diff --git a/demo_game.gd b/demo_game.gd index 359338d..36c0914 100644 --- a/demo_game.gd +++ b/demo_game.gd @@ -1,4 +1,10 @@ extends Control +class_name DemoGame + +signal own_played_card(card: Card) +signal opponent_played_card(card: Card) +signal own_played_rts(move: String) +signal opponent_played_rts(move: String) @export var player_1_deck: Array[Card] @export var player_2_deck: Array[Card] @@ -7,6 +13,8 @@ extends Control @onready var opponent_side = $Opponent @onready var start_game_btn = $StartGameButton +var id_to_card: Dictionary = {} + var player_action_queue: Dictionary var player_1_action: Action: get: @@ -19,14 +27,30 @@ var player_2_action: Action: set(value): player_action_queue[MatchManager.PLAYER_2_ID] = value -func _ready() -> void: +var id +var signal_connected := false + +func init(player_id: int) -> void: + id = player_id + + id_to_card.clear() + + var cards = player_1_deck.duplicate() + cards.append_array(player_2_deck) + for card in cards: + if card.id not in id_to_card: + id_to_card[card.id] = card + match_manager.init({ MatchManager.PLAYER_1_ID: player_1_deck, MatchManager.PLAYER_2_ID: player_2_deck }) - own_side.attach(match_manager) - opponent_side.attach(match_manager) - match_manager.state_transitioned.connect(_on_match_manager_state_transitioned) + own_side.attach(match_manager, player_id == MatchManager.PLAYER_1_ID) + opponent_side.attach(match_manager, player_id == MatchManager.PLAYER_2_ID) + + if !signal_connected: + match_manager.state_transitioned.connect(_on_match_manager_state_transitioned) + signal_connected = true var transition_history: Array[PhaseTransition] = [] func _on_match_manager_state_transitioned(transition: PhaseTransition): @@ -35,28 +59,100 @@ func _on_match_manager_state_transitioned(transition: PhaseTransition): print("Phase: ", Match.phase_to_str(transition.from), " -> ", Match.phase_to_str(transition.to)) func _on_start_game_button_button_up() -> void: + #match_manager.resolve({}) + pass + +func rpc_start_game() -> void: match_manager.resolve({}) -func _on_own_play_card(card: Card) -> void: - player_1_action = ActionPlayCard.new(card) +func rpc_own_play_card(id: String) -> void: + if !id.is_empty(): + var card = id_to_card[id] + player_1_action = ActionPlayCard.new(card) + else: + player_1_action = ActionSkipCard.new() + + print(self.id, " rpc_own_play_card", player_1_action, player_2_action) + if player_2_action: match_manager.resolve(player_action_queue) player_action_queue.clear() -func _on_opponent_play_card(card: Card) -> void: - player_2_action = ActionPlayCard.new(card) +func _on_own_play_card(card: Card) -> void: + if card: + player_1_action = ActionPlayCard.new(card) + own_played_card.emit(card) + else: + player_1_action = ActionSkipCard.new() + own_played_card.emit(null) + + print(id, " _on_own_play_card", player_1_action, player_2_action) + + if player_2_action: + match_manager.resolve(player_action_queue) + player_action_queue.clear() + +func rpc_opponent_play_card(id: String) -> void: + if !id.is_empty(): + var card = id_to_card[id] + player_2_action = ActionPlayCard.new(card) + else: + player_2_action = ActionSkipCard.new() + + print(self.id , " rpc_opponent_play_card", player_1_action, player_2_action) + if player_1_action: match_manager.resolve(player_action_queue) player_action_queue.clear() +func _on_opponent_play_card(card: Card) -> void: + if card: + player_2_action = ActionPlayCard.new(card) + opponent_played_card.emit(card) + else: + player_2_action = ActionSkipCard.new() + opponent_played_card.emit(null) + + print(id, " _on_opponent_play_card", player_1_action, player_2_action) + + if player_1_action: + match_manager.resolve(player_action_queue) + player_action_queue.clear() + +func rpc_own_rps_move(move: String) -> void: + player_1_action = ActionRPSMove.new(move) + + print(id, " rpc_own_rps_move", player_1_action, player_2_action, move) + + if player_2_action: + match_manager.resolve(player_action_queue) + player_action_queue.clear() + func _on_own_rps_move(move: String) -> void: player_1_action = ActionRPSMove.new(move) + own_played_rts.emit(move) + + print(id, " _on_own_rps_move", player_1_action, player_2_action, move) + if player_2_action: match_manager.resolve(player_action_queue) player_action_queue.clear() +func rpc_opponent_rps_move(move: String) -> void: + player_2_action = ActionRPSMove.new(move) + + print(id, " rpc_opponent_rps_move", player_1_action, player_2_action, move) + + if player_1_action: + match_manager.resolve(player_action_queue) + player_action_queue.clear() + func _on_opponent_rps_move(move: String) -> void: player_2_action = ActionRPSMove.new(move) + opponent_played_rts.emit(move) + + print(id, " rpc_opponent_rps_move", player_1_action, player_2_action, move) + if player_1_action: match_manager.resolve(player_action_queue) player_action_queue.clear() diff --git a/demo_game.tscn b/demo_game.tscn index e5ae8d6..697dd3b 100644 --- a/demo_game.tscn +++ b/demo_game.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=8 format=3 uid="uid://bgc0u117jqyr1"] +[gd_scene load_steps=8 format=3 uid="uid://l2ehohbd1xhk"] [ext_resource type="Script" path="res://demo_game.gd" id="1_jn16u"] [ext_resource type="Script" path="res://player_side.gd" id="2_w4tnt"] @@ -16,8 +16,8 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_jn16u") -player_1_deck = Array[ExtResource("2_xuft0")]([ExtResource("3_we1tk"), ExtResource("4_kkhfk"), ExtResource("4_kkhfk")]) -player_2_deck = Array[ExtResource("2_xuft0")]([ExtResource("5_3cm5x"), ExtResource("4_kkhfk"), ExtResource("4_kkhfk")]) +player_1_deck = Array[ExtResource("2_xuft0")]([ExtResource("3_we1tk"), ExtResource("4_kkhfk"), ExtResource("4_kkhfk"), ExtResource("4_kkhfk"), ExtResource("5_3cm5x")]) +player_2_deck = Array[ExtResource("2_xuft0")]([ExtResource("5_3cm5x"), ExtResource("4_kkhfk"), ExtResource("4_kkhfk"), ExtResource("4_kkhfk"), ExtResource("3_we1tk")]) [node name="Own" type="VBoxContainer" parent="." node_paths=PackedStringArray("deck", "monster_name_label", "monster_health_label", "incoming_damage_label", "energy_label")] layout_mode = 1 diff --git a/export_presets.cfg b/export_presets.cfg index 82e3d28..1c2b9dc 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -130,3 +130,211 @@ Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorActi ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue Remove-Item -Recurse -Force '{temp_dir}'" + +[preset.2] + +name="Android" +platform="Android" +runnable=true +advanced_options=false +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="" +encryption_include_filters="" +encryption_exclude_filters="" +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.2.options] + +custom_template/debug="" +custom_template/release="" +gradle_build/use_gradle_build=false +gradle_build/gradle_build_directory="" +gradle_build/android_source_template="" +gradle_build/compress_native_libraries=false +gradle_build/export_format=0 +gradle_build/min_sdk="" +gradle_build/target_sdk="" +architectures/armeabi-v7a=false +architectures/arm64-v8a=true +architectures/x86=false +architectures/x86_64=false +version/code=1 +version/name="" +package/unique_name="com.example.$genname" +package/name="" +package/signed=true +package/app_category=2 +package/retain_data_on_uninstall=false +package/exclude_from_recents=false +package/show_in_android_tv=false +package/show_in_app_library=true +package/show_as_launcher_app=false +launcher_icons/main_192x192="" +launcher_icons/adaptive_foreground_432x432="" +launcher_icons/adaptive_background_432x432="" +graphics/opengl_debug=false +xr_features/xr_mode=0 +screen/immersive_mode=true +screen/support_small=true +screen/support_normal=true +screen/support_large=true +screen/support_xlarge=true +user_data_backup/allow=false +command_line/extra_args="" +apk_expansion/enable=false +apk_expansion/SALT="" +apk_expansion/public_key="" +permissions/custom_permissions=PackedStringArray() +permissions/access_checkin_properties=false +permissions/access_coarse_location=false +permissions/access_fine_location=false +permissions/access_location_extra_commands=false +permissions/access_mock_location=false +permissions/access_network_state=false +permissions/access_surface_flinger=false +permissions/access_wifi_state=false +permissions/account_manager=false +permissions/add_voicemail=false +permissions/authenticate_accounts=false +permissions/battery_stats=false +permissions/bind_accessibility_service=false +permissions/bind_appwidget=false +permissions/bind_device_admin=false +permissions/bind_input_method=false +permissions/bind_nfc_service=false +permissions/bind_notification_listener_service=false +permissions/bind_print_service=false +permissions/bind_remoteviews=false +permissions/bind_text_service=false +permissions/bind_vpn_service=false +permissions/bind_wallpaper=false +permissions/bluetooth=false +permissions/bluetooth_admin=false +permissions/bluetooth_privileged=false +permissions/brick=false +permissions/broadcast_package_removed=false +permissions/broadcast_sms=false +permissions/broadcast_sticky=false +permissions/broadcast_wap_push=false +permissions/call_phone=false +permissions/call_privileged=false +permissions/camera=false +permissions/capture_audio_output=false +permissions/capture_secure_video_output=false +permissions/capture_video_output=false +permissions/change_component_enabled_state=false +permissions/change_configuration=false +permissions/change_network_state=false +permissions/change_wifi_multicast_state=false +permissions/change_wifi_state=false +permissions/clear_app_cache=false +permissions/clear_app_user_data=false +permissions/control_location_updates=false +permissions/delete_cache_files=false +permissions/delete_packages=false +permissions/device_power=false +permissions/diagnostic=false +permissions/disable_keyguard=false +permissions/dump=false +permissions/expand_status_bar=false +permissions/factory_test=false +permissions/flashlight=false +permissions/force_back=false +permissions/get_accounts=false +permissions/get_package_size=false +permissions/get_tasks=false +permissions/get_top_activity_info=false +permissions/global_search=false +permissions/hardware_test=false +permissions/inject_events=false +permissions/install_location_provider=false +permissions/install_packages=false +permissions/install_shortcut=false +permissions/internal_system_window=false +permissions/internet=false +permissions/kill_background_processes=false +permissions/location_hardware=false +permissions/manage_accounts=false +permissions/manage_app_tokens=false +permissions/manage_documents=false +permissions/manage_external_storage=false +permissions/master_clear=false +permissions/media_content_control=false +permissions/modify_audio_settings=false +permissions/modify_phone_state=false +permissions/mount_format_filesystems=false +permissions/mount_unmount_filesystems=false +permissions/nfc=false +permissions/persistent_activity=false +permissions/post_notifications=false +permissions/process_outgoing_calls=false +permissions/read_calendar=false +permissions/read_call_log=false +permissions/read_contacts=false +permissions/read_external_storage=false +permissions/read_frame_buffer=false +permissions/read_history_bookmarks=false +permissions/read_input_state=false +permissions/read_logs=false +permissions/read_phone_state=false +permissions/read_profile=false +permissions/read_sms=false +permissions/read_social_stream=false +permissions/read_sync_settings=false +permissions/read_sync_stats=false +permissions/read_user_dictionary=false +permissions/reboot=false +permissions/receive_boot_completed=false +permissions/receive_mms=false +permissions/receive_sms=false +permissions/receive_wap_push=false +permissions/record_audio=false +permissions/reorder_tasks=false +permissions/restart_packages=false +permissions/send_respond_via_message=false +permissions/send_sms=false +permissions/set_activity_watcher=false +permissions/set_alarm=false +permissions/set_always_finish=false +permissions/set_animation_scale=false +permissions/set_debug_app=false +permissions/set_orientation=false +permissions/set_pointer_speed=false +permissions/set_preferred_applications=false +permissions/set_process_limit=false +permissions/set_time=false +permissions/set_time_zone=false +permissions/set_wallpaper=false +permissions/set_wallpaper_hints=false +permissions/signal_persistent_processes=false +permissions/status_bar=false +permissions/subscribed_feeds_read=false +permissions/subscribed_feeds_write=false +permissions/system_alert_window=false +permissions/transmit_ir=false +permissions/uninstall_shortcut=false +permissions/update_device_stats=false +permissions/use_credentials=false +permissions/use_sip=false +permissions/vibrate=false +permissions/wake_lock=false +permissions/write_apn_settings=false +permissions/write_calendar=false +permissions/write_call_log=false +permissions/write_contacts=false +permissions/write_external_storage=false +permissions/write_gservices=false +permissions/write_history_bookmarks=false +permissions/write_profile=false +permissions/write_secure_settings=false +permissions/write_settings=false +permissions/write_sms=false +permissions/write_social_stream=false +permissions/write_sync_settings=false +permissions/write_user_dictionary=false diff --git a/main.gd b/main.gd index 3f1095d..5ba3478 100644 --- a/main.gd +++ b/main.gd @@ -1,41 +1,41 @@ extends Node +class_name MainNode const PORT = 25565 const PORT_RANGE := 10 const MAX_CONNECTIONS = 20 -var counter = 0 - @onready var before_connect_container = get_node("BeforeConnect") as Container -@onready var host_text_edit = get_node("%HostTextEdit") as TextEdit @onready var connect_button = get_node("%ConnectButton") as Button @onready var host_button = get_node("%HostButton") as Button @onready var server_discovery = get_node("%ServerDiscovery") as ServerDiscovery -@onready var after_connect_container = get_node("%AfterConnect") as Container -@onready var counter_label = get_node("%CounterLabel") as Label -@onready var decrement_button = get_node("%DecrementButton") as Button -@onready var increment_button = get_node("%IncrementButton") as Button +@onready var after_connect_container = get_node("%AfterConnect") as Node @onready var disconnect_button = get_node("%DisconnectButton") as Button -@onready var start_game_button = get_node("%StartGameButton") as Button + +@onready var demo_game = get_node("AfterConnect/DemoGame") as DemoGame +@onready var start_game_button = (get_node("AfterConnect/DemoGame") as DemoGame).start_game_btn + var active_port: int var server_buttons: Dictionary = Dictionary() +var base_seed: int func _clean_room(): # this is if someone left the room and we will just clean the game room again # should only called on host - _set_counter(0) + # need to clean for server pass func _on_start_game_clicked(): if !multiplayer.multiplayer_peer: return - if !multiplayer.get_unique_id() != 1: + if !multiplayer.is_server(): return if (multiplayer.get_peers().size() == 0): return # do start game here, should only run on host + _start_game.rpc() pass func _ready() -> void: @@ -51,13 +51,45 @@ func _ready() -> void: #multiplayer.connection_failed.connect(_on_connected_fail) multiplayer.server_disconnected.connect(_on_server_disconnected) - increment_button.button_up.connect(func(): _increment.rpc()) - decrement_button.button_up.connect(func(): _decrement.rpc()) disconnect_button.button_up.connect(_on_disconnect_clicked) connect_button.get_parent().remove_child(connect_button) server_discovery.server_added.connect(_on_server_added) server_discovery.server_removed.connect(_on_server_removed) + + demo_game.own_played_card.connect(func (card): _on_own_played_card.rpc(card.id if card else "")) + demo_game.opponent_played_card.connect(func (card): _on_opponent_played_card.rpc(card.id if card else "")) + demo_game.own_played_rts.connect(func (move): _on_own_played_rts.rpc(move)) + demo_game.opponent_played_rts.connect(func (move): _on_opponent_played_rts.rpc(move)) + +@rpc("any_peer", "call_remote", "reliable") +func _on_own_played_card(card_id: String): + demo_game.rpc_own_play_card(card_id) + +@rpc("any_peer", "call_remote", "reliable") +func _on_opponent_played_card(card_id: String): + demo_game.rpc_opponent_play_card(card_id) + +@rpc("any_peer", "call_remote", "reliable") +func _on_own_played_rts(move: String): + demo_game.rpc_own_rps_move(move) + +@rpc("any_peer", "call_remote", "reliable") +func _on_opponent_played_rts(move: String): + demo_game.rpc_opponent_rps_move(move) + +@rpc("authority", "call_local", "reliable") +func _sync_seed(seed: int): + seed(seed) + +@rpc("authority", "call_local", "reliable") +func _start_game(): + if multiplayer.is_server(): + demo_game.init(MatchManager.PLAYER_1_ID) + else: + demo_game.init(MatchManager.PLAYER_2_ID) + + demo_game.rpc_start_game() func _on_disconnect_clicked(): if (multiplayer.is_server()): @@ -118,8 +150,12 @@ func _on_host_pressed(): _on_connected_ok() + start_game_button.disabled = true start_game_button.text = "Start Game (Not enough player)" + base_seed = randi() + _sync_seed.rpc(base_seed) + server_discovery.enable_server(active_port) func is_port_available(port: int) -> bool: @@ -133,26 +169,13 @@ func is_port_available(port: int) -> bool: else: return false -@rpc("any_peer", "call_local") -func _increment(): - counter += 1 - counter_label.text = str(counter) - -@rpc("any_peer", "call_local") -func _decrement(): - counter -= 1 - counter_label.text = str(counter) - -@rpc("authority", "call_remote") -func _set_counter(value: int): - counter = value - counter_label.text = str(counter) - func _on_player_connected(id: int): if multiplayer.get_unique_id() == 1: - _set_counter.rpc_id(id, counter) + + _sync_seed.rpc(base_seed) if (multiplayer.get_peers().size() > 0): + start_game_button.disabled = false start_game_button.text = "Start Game" server_discovery.disable_server() @@ -165,22 +188,20 @@ func _on_player_disconnected(id): if (id != 1 and multiplayer.get_unique_id() == 1): _clean_room() + start_game_button.disabled = true start_game_button.text = "Start Game (Not enough player)" server_discovery.enable_server(active_port) func _on_connected_ok(): $AfterConnect.visible = true $BeforeConnect.visible = false - counter_label.text = str(counter) if (multiplayer.is_server()): disconnect_button.text = "Disconnect (Host)" - if start_game_button.get_parent() != after_connect_container: - after_connect_container.add_child(start_game_button) + start_game_button.visible = true else: disconnect_button.text = "Disconnect" - if start_game_button.get_parent() == after_connect_container: - after_connect_container.remove_child(start_game_button) + start_game_button.visible = false func _on_connected_fail(): pass diff --git a/main.tscn b/main.tscn index d1043f9..523431c 100644 --- a/main.tscn +++ b/main.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=3 format=3 uid="uid://c7gn46af6whf8"] +[gd_scene load_steps=4 format=3 uid="uid://c7gn46af6whf8"] [ext_resource type="Script" path="res://main.gd" id="1_e0ud3"] [ext_resource type="Script" path="res://server_discovery.gd" id="2_hed18"] +[ext_resource type="PackedScene" uid="uid://l2ehohbd1xhk" path="res://demo_game.tscn" id="3_2ln6b"] [node name="Main" type="Control"] layout_mode = 3 @@ -28,18 +29,6 @@ grow_horizontal = 2 grow_vertical = 2 alignment = 1 -[node name="HostTextEdit" type="TextEdit" parent="BeforeConnect"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_vertical = 3 -placeholder_text = "192.168.*.*" - -[node name="RefreshButton" type="Button" parent="BeforeConnect"] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 64) -layout_mode = 2 -text = "Refresh" - [node name="HostButton" type="Button" parent="BeforeConnect"] unique_name_in_owner = true custom_minimum_size = Vector2(0, 64) @@ -59,54 +48,24 @@ unique_name_in_owner = true unique_name_in_owner = true script = ExtResource("2_hed18") -[node name="AfterConnect" type="VBoxContainer" parent="."] +[node name="AfterConnect" type="Control" parent="."] unique_name_in_owner = true visible = false layout_mode = 1 -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = -187.5 -offset_top = -88.5 -offset_right = 187.5 -offset_bottom = 88.5 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -[node name="CounterLabel" type="Label" parent="AfterConnect"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_vertical = 3 -theme_override_font_sizes/font_size = 64 -text = "1" -horizontal_alignment = 1 -vertical_alignment = 1 +[node name="DemoGame" parent="AfterConnect" instance=ExtResource("3_2ln6b")] +layout_mode = 1 [node name="DisconnectButton" type="Button" parent="AfterConnect"] unique_name_in_owner = true layout_mode = 2 -size_flags_horizontal = 3 +offset_left = 966.0 +offset_right = 1152.0 +offset_bottom = 31.0 +size_flags_horizontal = 8 text = "Disconnect" - -[node name="Actions" type="HBoxContainer" parent="AfterConnect"] -layout_mode = 2 - -[node name="DecrementButton" type="Button" parent="AfterConnect/Actions"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -text = "-" - -[node name="IncrementButton" type="Button" parent="AfterConnect/Actions"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -text = "+" - -[node name="StartGameButton" type="Button" parent="AfterConnect"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -text = "Start Game" diff --git a/player_side.gd b/player_side.gd index 03eddf3..d834319 100644 --- a/player_side.gd +++ b/player_side.gd @@ -10,10 +10,15 @@ signal rps_move(move: String) @export var energy_label: Label var match_manager: MatchManager +var show_buttons: bool +var signal_connected: bool -func attach(match_manager: MatchManager): +func attach(match_manager: MatchManager, show_buttons: bool = true): + self.show_buttons = show_buttons self.match_manager = match_manager - match_manager.state_transitioned.connect(_on_update) + if !signal_connected: + match_manager.state_transitioned.connect(_on_update) + signal_connected = true func _on_update(transition): for child in deck.get_children(): @@ -28,13 +33,28 @@ func _on_update(transition): monster_health_label.text = "Health: " + str(monster.health) incoming_damage_label.text = "Incoming Damage: " + str(monster.health_delta) if match_manager.phase in [Match.Phase.SUMMON, Match.Phase.SUPPORT_1, Match.Phase.SUPPORT_2]: + + if ( + match_manager.phase != Match.Phase.SUMMON && show_buttons + ) or ( + match_manager.phase == Match.Phase.SUMMON and player.monster and player.monster.health > 0 && show_buttons + ): + var skip_btn = Button.new() + skip_btn.text = "Skip" + skip_btn.button_up.connect(func (): play_card.emit(null)) + deck.add_child(skip_btn) + for card: Card in player.hand: - if match_manager.phase == Match.Phase.SUMMON and card is not MonsterCard: - continue - if (match_manager.phase == Match.Phase.SUPPORT_1 or match_manager.phase == Match.Phase.SUPPORT_2) and card is not SupportCard: - continue - if match_manager.phase == Match.Phase.SUPPORT_1 and card.type == "red": + #if match_manager.phase == Match.Phase.SUMMON and card is not MonsterCard: + #continue + #if (match_manager.phase == Match.Phase.SUPPORT_1 or match_manager.phase == Match.Phase.SUPPORT_2) and card is not SupportCard: + #continue + #if match_manager.phase == Match.Phase.SUPPORT_1 and card.type == "red": + #continue + + if !show_buttons : continue + var btn = Button.new() btn.text = card.id btn.button_up.connect(func (): play_card.emit(card)) @@ -44,10 +64,16 @@ func _on_update(transition): card is SupportCard and match_manager.phase != Match.Phase.SUPPORT_1 and match_manager.phase != Match.Phase.SUPPORT_2 ) or ( card is SupportCard and card.type == "red" and match_manager.phase != Match.Phase.SUPPORT_2 + ) or ( + card is MonsterCard and match_manager.phase == Match.Phase.SUMMON and player.monster and player.monster.health > 0 ) deck.add_child(btn) if match_manager.phase == Match.Phase.RPS: for move in ["rock", "paper", "scissors"]: + + if !show_buttons: + continue + var btn = Button.new() btn.text = move btn.button_up.connect(func (): rps_move.emit(move)) diff --git a/project.godot b/project.godot index f8f23d6..3f421a3 100644 --- a/project.godot +++ b/project.godot @@ -22,3 +22,4 @@ Match="*res://tcg/match/match.gd" [rendering] renderer/rendering_method="mobile" +textures/vram_compression/import_etc2_astc=true diff --git a/tcg/match/action/action_skip_card.gd b/tcg/match/action/action_skip_card.gd new file mode 100644 index 0000000..a0fdf46 --- /dev/null +++ b/tcg/match/action/action_skip_card.gd @@ -0,0 +1,2 @@ +extends Action +class_name ActionSkipCard diff --git a/tcg/match/match_manager.gd b/tcg/match/match_manager.gd index 19cfe87..814b138 100644 --- a/tcg/match/match_manager.gd +++ b/tcg/match/match_manager.gd @@ -29,6 +29,14 @@ func init(decks: Dictionary): cleanup() for player_id in [PLAYER_1_ID, PLAYER_2_ID]: var deck_shuffled = decks[player_id].duplicate() as Array[Card] + + var first_monster = deck_shuffled.filter(func (card): return card is MonsterCard)[0] + var first_monster_idx = deck_shuffled.find(first_monster) + deck_shuffled.pop_at(first_monster_idx) + var zero_idx_card = deck_shuffled.pop_at(0) + deck_shuffled.insert(0, first_monster) + deck_shuffled.insert(first_monster_idx, zero_idx_card) + deck_shuffled.shuffle() players[player_id] = MatchPlayer.new(player_id, deck_shuffled) @@ -75,11 +83,13 @@ func resolve(action_by_player_id: Dictionary) -> PhaseTransition: "player": player_1, "card": player_1_action.card }) + player_1.hand.erase(player_1_action.card) if player_2_action is ActionPlayCard: support_cards.append({ "player": player_2, "card": player_2_action.card }) + player_2.hand.erase(player_2_action.card) support_cards.sort_custom(func(a, b): return a.card.priority < b.card.priority) for played_card in support_cards: var player: MatchPlayer = played_card.player @@ -102,11 +112,13 @@ func resolve(action_by_player_id: Dictionary) -> PhaseTransition: "player": player_1, "card": player_1_action.card }) + player_1.hand.erase(player_1_action.card) if player_2_action is ActionPlayCard: support_cards.append({ "player": player_2, "card": player_2_action.card }) + player_2.hand.erase(player_2_action.card) support_cards.sort_custom(func(a, b): return a.card.priority < b.card.priority) for played_card in support_cards: var player: MatchPlayer = played_card.player -- 2.49.1