diff --git a/addons/enhanced_gridmap/meshlibrary/default.tres b/addons/enhanced_gridmap/meshlibrary/default.tres index 1e0a22d..b97e6cf 100644 --- a/addons/enhanced_gridmap/meshlibrary/default.tres +++ b/addons/enhanced_gridmap/meshlibrary/default.tres @@ -14,7 +14,7 @@ [ext_resource type="Texture2D" uid="uid://dpkx1a780pvwv" path="res://assets/textures/tile_diamond.png" id="10_sx8rm"] [ext_resource type="BoxMesh" uid="uid://fy4bhoeii40c" path="res://addons/enhanced_gridmap/meshlibrary/tile_safe_zone.tres" id="10_uwjsj"] [ext_resource type="BoxMesh" uid="uid://b5cc3prem52r6" path="res://addons/enhanced_gridmap/meshlibrary/tile_freeze.tres" id="11_pgnbl"] -[ext_resource type="BoxMesh" uid="uid://dcjdwbffgtutt" path="res://addons/enhanced_gridmap/meshlibrary/tile_non_walkable.tres" id="11_uwjsj"] +[ext_resource type="BoxMesh" path="res://addons/enhanced_gridmap/meshlibrary/tile_non_walkable.tres" id="11_uwjsj"] [sub_resource type="CompressedTexture2D" id="CompressedTexture2D_5d0gc"] load_path = "res://.godot/imported/tile_heart.png-deeef50755ca225f028608dfd16900e6.s3tc.ctex" diff --git a/assets/graphics/gui/gauge/PowerLabel.png b/assets/graphics/gui/gauge/PowerLabel.png new file mode 100644 index 0000000..f2519fa Binary files /dev/null and b/assets/graphics/gui/gauge/PowerLabel.png differ diff --git a/assets/graphics/gui/gauge/PowerLabel.png.import b/assets/graphics/gui/gauge/PowerLabel.png.import new file mode 100644 index 0000000..4adf786 --- /dev/null +++ b/assets/graphics/gui/gauge/PowerLabel.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://73ayhl1lqdpt" +path="res://.godot/imported/PowerLabel.png-23ade6ab4576f0809ea35f302116f585.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/gui/gauge/PowerLabel.png" +dest_files=["res://.godot/imported/PowerLabel.png-23ade6ab4576f0809ea35f302116f585.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/graphics/gui/gauge/Segment0_empty.png b/assets/graphics/gui/gauge/Segment0_empty.png new file mode 100644 index 0000000..053fe01 Binary files /dev/null and b/assets/graphics/gui/gauge/Segment0_empty.png differ diff --git a/assets/graphics/gui/gauge/Segment0_empty.png.import b/assets/graphics/gui/gauge/Segment0_empty.png.import new file mode 100644 index 0000000..0b4f879 --- /dev/null +++ b/assets/graphics/gui/gauge/Segment0_empty.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dcoaeof23pt3c" +path="res://.godot/imported/Segment0_empty.png-b7c030026c468d14e0ee5f5a6e914f12.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/gui/gauge/Segment0_empty.png" +dest_files=["res://.godot/imported/Segment0_empty.png-b7c030026c468d14e0ee5f5a6e914f12.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/graphics/gui/gauge/Segment0_filled.png b/assets/graphics/gui/gauge/Segment0_filled.png new file mode 100644 index 0000000..7cf4055 Binary files /dev/null and b/assets/graphics/gui/gauge/Segment0_filled.png differ diff --git a/assets/graphics/gui/gauge/Segment0_filled.png.import b/assets/graphics/gui/gauge/Segment0_filled.png.import new file mode 100644 index 0000000..32ecc4e --- /dev/null +++ b/assets/graphics/gui/gauge/Segment0_filled.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cxe5hwhfel0kn" +path="res://.godot/imported/Segment0_filled.png-61b15ebc4e2e332c9338e13d48b3b894.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/gui/gauge/Segment0_filled.png" +dest_files=["res://.godot/imported/Segment0_filled.png-61b15ebc4e2e332c9338e13d48b3b894.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/graphics/gui/gauge/Segment1_empty.png b/assets/graphics/gui/gauge/Segment1_empty.png new file mode 100644 index 0000000..2e07131 Binary files /dev/null and b/assets/graphics/gui/gauge/Segment1_empty.png differ diff --git a/assets/graphics/gui/gauge/Segment1_empty.png.import b/assets/graphics/gui/gauge/Segment1_empty.png.import new file mode 100644 index 0000000..61babed --- /dev/null +++ b/assets/graphics/gui/gauge/Segment1_empty.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ctgxeo2i3vcfq" +path="res://.godot/imported/Segment1_empty.png-f2e3b66b72717376abc6fc2f9f21a148.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/gui/gauge/Segment1_empty.png" +dest_files=["res://.godot/imported/Segment1_empty.png-f2e3b66b72717376abc6fc2f9f21a148.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/graphics/gui/gauge/Segment1_filled.png b/assets/graphics/gui/gauge/Segment1_filled.png new file mode 100644 index 0000000..a8c8525 Binary files /dev/null and b/assets/graphics/gui/gauge/Segment1_filled.png differ diff --git a/assets/graphics/gui/gauge/Segment1_filled.png.import b/assets/graphics/gui/gauge/Segment1_filled.png.import new file mode 100644 index 0000000..1e6895b --- /dev/null +++ b/assets/graphics/gui/gauge/Segment1_filled.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d138cwvw3146l" +path="res://.godot/imported/Segment1_filled.png-3afd269de98a90c438d901eb3cfd6858.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/gui/gauge/Segment1_filled.png" +dest_files=["res://.godot/imported/Segment1_filled.png-3afd269de98a90c438d901eb3cfd6858.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/graphics/gui/gauge/Segment2_empty.png b/assets/graphics/gui/gauge/Segment2_empty.png new file mode 100644 index 0000000..0c020f2 Binary files /dev/null and b/assets/graphics/gui/gauge/Segment2_empty.png differ diff --git a/assets/graphics/gui/gauge/Segment2_empty.png.import b/assets/graphics/gui/gauge/Segment2_empty.png.import new file mode 100644 index 0000000..ef2aad9 --- /dev/null +++ b/assets/graphics/gui/gauge/Segment2_empty.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://djbin5556lwsx" +path="res://.godot/imported/Segment2_empty.png-7e05a0e0d674008e302588274eb2b991.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/gui/gauge/Segment2_empty.png" +dest_files=["res://.godot/imported/Segment2_empty.png-7e05a0e0d674008e302588274eb2b991.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/graphics/gui/gauge/Segment2_filled.png b/assets/graphics/gui/gauge/Segment2_filled.png new file mode 100644 index 0000000..09c0403 Binary files /dev/null and b/assets/graphics/gui/gauge/Segment2_filled.png differ diff --git a/assets/graphics/gui/gauge/Segment2_filled.png.import b/assets/graphics/gui/gauge/Segment2_filled.png.import new file mode 100644 index 0000000..d43079d --- /dev/null +++ b/assets/graphics/gui/gauge/Segment2_filled.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b3pfchqga6d1r" +path="res://.godot/imported/Segment2_filled.png-10768e2717abac9e3f9b7e6ff94067ee.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/gui/gauge/Segment2_filled.png" +dest_files=["res://.godot/imported/Segment2_filled.png-10768e2717abac9e3f9b7e6ff94067ee.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/scenes/main.gd b/scenes/main.gd index 5170aae..63ccc7d 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -467,6 +467,12 @@ func _setup_global_match_timer_ui(): func _process(delta): if not is_inside_tree(): return if not check_multiplayer(): return + + if ui_manager and get_tree(): + var all_players = get_tree().get_nodes_in_group("Players") + if all_players.size() > 0: + ui_manager.update_live_leaderboard(all_players) + if multiplayer.is_server() and GameStateManager.is_game_started(): if TurnManager.turn_based_mode: rpc("sync_turn_index", TurnManager.current_turn_index) @@ -2268,6 +2274,12 @@ func request_leaderboard_sync(): @rpc("authority", "call_local", "reliable") func sync_leaderboard_data(player_data: Array): """Receive leaderboard data from server and update UI.""" + # Update local player node scores first so live UI tick stays synced + for data in player_data: + var p_node = get_node_or_null(str(data.peer_id)) + if p_node: + p_node.score = data.score + var leaderboard_panel = get_node_or_null("LeaderboardPanel") if not leaderboard_panel: return @@ -2309,6 +2321,7 @@ func _update_leaderboard_display(): for p in all_players: var peer_id = p.name.to_int() var score = goals_cycle_manager.get_player_score(peer_id) if goals_cycle_manager else 0 + p.score = score # Assign locally so ui_manager.gd reads correct score player_data.append({"peer_id": peer_id, "name": p.display_name if not p.display_name.is_empty() else str(p.name), "score": score}) # Sort by score descending (with Stop n Go winner priority) diff --git a/scenes/main.tscn b/scenes/main.tscn index 8e38f60..4fbb636 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -14,6 +14,10 @@ [ext_resource type="Texture2D" uid="uid://68x88jj25yxg" path="res://assets/textures/Adjacent.png" id="9_6gcb6"] [ext_resource type="Texture2D" uid="uid://dasaeaytvhll0" path="res://assets/models/pboard/AdjacentRect.tres" id="9_aspsw"] [ext_resource type="FontFile" uid="uid://xnjx058n4tsw" path="res://assets/fonts/Nougat-ExtraBlack.ttf" id="13_j8jky"] +[ext_resource type="Texture2D" uid="uid://73ayhl1lqdpt" path="res://assets/graphics/gui/gauge/PowerLabel.png" id="14_vxglm"] +[ext_resource type="Texture2D" uid="uid://dcoaeof23pt3c" path="res://assets/graphics/gui/gauge/Segment0_empty.png" id="15_2f3dj"] +[ext_resource type="Texture2D" uid="uid://ctgxeo2i3vcfq" path="res://assets/graphics/gui/gauge/Segment1_empty.png" id="16_yq6so"] +[ext_resource type="Texture2D" uid="uid://djbin5556lwsx" path="res://assets/graphics/gui/gauge/Segment2_empty.png" id="17_fv21b"] [ext_resource type="Theme" uid="uid://0dhxl4ohyxh8" path="res://assets/graphics/game_setting/setting_theme.tres" id="18_pm3ni"] [ext_resource type="Texture2D" uid="uid://ba80xnybpixw2" path="res://assets/graphics/touch_control/take_tile.png" id="25_qkpxi"] [ext_resource type="Texture2D" uid="uid://bsgqrjx2ity4c" path="res://assets/graphics/touch_control/speed.png" id="26_2f3dj"] @@ -47,6 +51,20 @@ corner_radius_top_right = 8 corner_radius_bottom_right = 8 corner_radius_bottom_left = 8 +[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_tel4y"] + +[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_qkpxi"] +texture = ExtResource("14_vxglm") + +[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_5q0nq"] +texture = ExtResource("15_2f3dj") + +[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_dgi5k"] +texture = ExtResource("16_yq6so") + +[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_j8jky"] +texture = ExtResource("17_fv21b") + [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1cewu"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kmb1v"] @@ -1079,37 +1097,38 @@ layout_mode = 2 anchors_preset = 4 anchor_top = 0.5 anchor_bottom = 0.5 -offset_left = 40.0 -offset_top = -1.7106018 -offset_right = 224.0 -offset_bottom = 31.28952 +offset_left = 84.0 +offset_top = -7.0 +offset_right = 229.0 +offset_bottom = 29.0 grow_vertical = 2 rotation = -0.10297442 +theme_override_styles/panel = SubResource("StyleBoxTexture_tel4y") [node name="HBox" type="HBoxContainer" parent="PowerUpBar" unique_id=334600330] layout_mode = 2 -theme_override_constants/separation = 4 +theme_override_constants/separation = 0 +alignment = 1 -[node name="PowerLabel" type="Label" parent="PowerUpBar/HBox" unique_id=1945535407] +[node name="PowerLabel" type="Panel" parent="PowerUpBar/HBox" unique_id=1662719884] +custom_minimum_size = Vector2(39, 36) layout_mode = 2 -theme_override_font_sizes/font_size = 18 -text = "⚡" +theme_override_styles/panel = SubResource("StyleBoxTexture_qkpxi") [node name="Segment0" type="Panel" parent="PowerUpBar/HBox" unique_id=500774723] -custom_minimum_size = Vector2(36, 20) +custom_minimum_size = Vector2(33, 36) layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxTexture_5q0nq") [node name="Segment1" type="Panel" parent="PowerUpBar/HBox" unique_id=1042222722] -custom_minimum_size = Vector2(36, 20) +custom_minimum_size = Vector2(33, 36) layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxTexture_dgi5k") [node name="Segment2" type="Panel" parent="PowerUpBar/HBox" unique_id=272336972] -custom_minimum_size = Vector2(36, 20) -layout_mode = 2 - -[node name="Segment3" type="Panel" parent="PowerUpBar/HBox" unique_id=293120308] -custom_minimum_size = Vector2(36, 20) +custom_minimum_size = Vector2(40, 36) layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxTexture_j8jky") [node name="GoalsTimer" type="PanelContainer" parent="." unique_id=2106663301] offset_left = 235.8717 @@ -1229,17 +1248,26 @@ horizontal_alignment = 1 [node name="Separator" type="HSeparator" parent="LeaderboardPanel/MarginContainer/VBox" unique_id=1615297005] layout_mode = 2 -[node name="Entry1" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox" unique_id=1372346601] +[node name="Entry1" type="PanelContainer" parent="LeaderboardPanel/MarginContainer/VBox" unique_id=1372346601] layout_mode = 2 -[node name="RankLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry1" unique_id=828754165] +[node name="HBox" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox/Entry1" unique_id=617135879] +layout_mode = 2 + +[node name="RankLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry1/HBox" unique_id=828754165] custom_minimum_size = Vector2(50, 0) layout_mode = 2 theme_override_fonts/font = ExtResource("13_j8jky") theme_override_font_sizes/font_size = 22 text = "1st" -[node name="NameLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry1" unique_id=777741978] +[node name="PortraitRect" type="TextureRect" parent="LeaderboardPanel/MarginContainer/VBox/Entry1/HBox" unique_id=1512406425] +custom_minimum_size = Vector2(24, 24) +layout_mode = 2 +expand_mode = 1 +stretch_mode = 5 + +[node name="NameLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry1/HBox" unique_id=777741978] custom_minimum_size = Vector2(100, 0) layout_mode = 2 theme_override_fonts/font = ExtResource("13_j8jky") @@ -1247,7 +1275,14 @@ theme_override_font_sizes/font_size = 22 text = "Player 1" clip_text = true -[node name="ScoreLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry1" unique_id=163441394] +[node name="GhostIcon" type="TextureRect" parent="LeaderboardPanel/MarginContainer/VBox/Entry1/HBox" unique_id=143108099] +modulate = Color(1, 1, 1, 0) +custom_minimum_size = Vector2(16, 16) +layout_mode = 2 +expand_mode = 1 +stretch_mode = 5 + +[node name="ScoreLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry1/HBox" unique_id=163441394] layout_mode = 2 size_flags_horizontal = 3 theme_override_fonts/font = ExtResource("13_j8jky") @@ -1255,17 +1290,43 @@ theme_override_font_sizes/font_size = 22 text = "0" horizontal_alignment = 2 -[node name="Entry2" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox" unique_id=1213770719] +[node name="MiniPowerUpBar" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox/Entry1/HBox" unique_id=1277323584] +layout_mode = 2 +theme_override_constants/separation = 2 +alignment = 1 + +[node name="Segment0" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry1/HBox/MiniPowerUpBar" unique_id=797392101] +custom_minimum_size = Vector2(12, 12) layout_mode = 2 -[node name="RankLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry2" unique_id=276085006] +[node name="Segment1" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry1/HBox/MiniPowerUpBar" unique_id=789099266] +custom_minimum_size = Vector2(12, 12) +layout_mode = 2 + +[node name="Segment2" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry1/HBox/MiniPowerUpBar" unique_id=1018238656] +custom_minimum_size = Vector2(12, 12) +layout_mode = 2 + +[node name="Entry2" type="PanelContainer" parent="LeaderboardPanel/MarginContainer/VBox" unique_id=1213770719] +layout_mode = 2 + +[node name="HBox" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox/Entry2" unique_id=649896203] +layout_mode = 2 + +[node name="RankLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry2/HBox" unique_id=276085006] custom_minimum_size = Vector2(50, 0) layout_mode = 2 theme_override_fonts/font = ExtResource("13_j8jky") theme_override_font_sizes/font_size = 22 text = "2nd" -[node name="NameLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry2" unique_id=980063105] +[node name="PortraitRect" type="TextureRect" parent="LeaderboardPanel/MarginContainer/VBox/Entry2/HBox" unique_id=1005069505] +custom_minimum_size = Vector2(24, 24) +layout_mode = 2 +expand_mode = 1 +stretch_mode = 5 + +[node name="NameLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry2/HBox" unique_id=980063105] custom_minimum_size = Vector2(100, 0) layout_mode = 2 theme_override_fonts/font = ExtResource("13_j8jky") @@ -1273,7 +1334,14 @@ theme_override_font_sizes/font_size = 22 text = "Player 2" clip_text = true -[node name="ScoreLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry2" unique_id=630589738] +[node name="GhostIcon" type="TextureRect" parent="LeaderboardPanel/MarginContainer/VBox/Entry2/HBox" unique_id=1898054695] +modulate = Color(1, 1, 1, 0) +custom_minimum_size = Vector2(16, 16) +layout_mode = 2 +expand_mode = 1 +stretch_mode = 5 + +[node name="ScoreLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry2/HBox" unique_id=630589738] layout_mode = 2 size_flags_horizontal = 3 theme_override_fonts/font = ExtResource("13_j8jky") @@ -1281,17 +1349,43 @@ theme_override_font_sizes/font_size = 22 text = "0" horizontal_alignment = 2 -[node name="Entry3" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox" unique_id=988674004] +[node name="MiniPowerUpBar" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox/Entry2/HBox" unique_id=719453508] +layout_mode = 2 +theme_override_constants/separation = 2 +alignment = 1 + +[node name="Segment0" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry2/HBox/MiniPowerUpBar" unique_id=1487042283] +custom_minimum_size = Vector2(12, 12) layout_mode = 2 -[node name="RankLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry3" unique_id=940102589] +[node name="Segment1" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry2/HBox/MiniPowerUpBar" unique_id=1303981736] +custom_minimum_size = Vector2(12, 12) +layout_mode = 2 + +[node name="Segment2" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry2/HBox/MiniPowerUpBar" unique_id=564492200] +custom_minimum_size = Vector2(12, 12) +layout_mode = 2 + +[node name="Entry3" type="PanelContainer" parent="LeaderboardPanel/MarginContainer/VBox" unique_id=988674004] +layout_mode = 2 + +[node name="HBox" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox/Entry3" unique_id=2098193159] +layout_mode = 2 + +[node name="RankLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry3/HBox" unique_id=940102589] custom_minimum_size = Vector2(50, 0) layout_mode = 2 theme_override_fonts/font = ExtResource("13_j8jky") theme_override_font_sizes/font_size = 22 text = "3rd" -[node name="NameLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry3" unique_id=872999463] +[node name="PortraitRect" type="TextureRect" parent="LeaderboardPanel/MarginContainer/VBox/Entry3/HBox" unique_id=77999167] +custom_minimum_size = Vector2(24, 24) +layout_mode = 2 +expand_mode = 1 +stretch_mode = 5 + +[node name="NameLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry3/HBox" unique_id=872999463] custom_minimum_size = Vector2(100, 0) layout_mode = 2 theme_override_fonts/font = ExtResource("13_j8jky") @@ -1299,7 +1393,14 @@ theme_override_font_sizes/font_size = 22 text = "Player 3" clip_text = true -[node name="ScoreLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry3" unique_id=508325054] +[node name="GhostIcon" type="TextureRect" parent="LeaderboardPanel/MarginContainer/VBox/Entry3/HBox" unique_id=1209672815] +modulate = Color(1, 1, 1, 0) +custom_minimum_size = Vector2(16, 16) +layout_mode = 2 +expand_mode = 1 +stretch_mode = 5 + +[node name="ScoreLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry3/HBox" unique_id=508325054] layout_mode = 2 size_flags_horizontal = 3 theme_override_fonts/font = ExtResource("13_j8jky") @@ -1307,17 +1408,43 @@ theme_override_font_sizes/font_size = 22 text = "0" horizontal_alignment = 2 -[node name="Entry4" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox" unique_id=394023021] +[node name="MiniPowerUpBar" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox/Entry3/HBox" unique_id=1235595014] +layout_mode = 2 +theme_override_constants/separation = 2 +alignment = 1 + +[node name="Segment0" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry3/HBox/MiniPowerUpBar" unique_id=1321277357] +custom_minimum_size = Vector2(12, 12) layout_mode = 2 -[node name="RankLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry4" unique_id=539805932] +[node name="Segment1" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry3/HBox/MiniPowerUpBar" unique_id=847275899] +custom_minimum_size = Vector2(12, 12) +layout_mode = 2 + +[node name="Segment2" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry3/HBox/MiniPowerUpBar" unique_id=701782565] +custom_minimum_size = Vector2(12, 12) +layout_mode = 2 + +[node name="Entry4" type="PanelContainer" parent="LeaderboardPanel/MarginContainer/VBox" unique_id=394023021] +layout_mode = 2 + +[node name="HBox" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox/Entry4" unique_id=1481335373] +layout_mode = 2 + +[node name="RankLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry4/HBox" unique_id=539805932] custom_minimum_size = Vector2(50, 0) layout_mode = 2 theme_override_fonts/font = ExtResource("13_j8jky") theme_override_font_sizes/font_size = 22 text = "4th" -[node name="NameLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry4" unique_id=379355680] +[node name="PortraitRect" type="TextureRect" parent="LeaderboardPanel/MarginContainer/VBox/Entry4/HBox" unique_id=736863972] +custom_minimum_size = Vector2(24, 24) +layout_mode = 2 +expand_mode = 1 +stretch_mode = 5 + +[node name="NameLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry4/HBox" unique_id=379355680] custom_minimum_size = Vector2(100, 0) layout_mode = 2 theme_override_fonts/font = ExtResource("13_j8jky") @@ -1325,7 +1452,14 @@ theme_override_font_sizes/font_size = 22 text = "Player 4" clip_text = true -[node name="ScoreLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry4" unique_id=560418594] +[node name="GhostIcon" type="TextureRect" parent="LeaderboardPanel/MarginContainer/VBox/Entry4/HBox" unique_id=1812577580] +modulate = Color(1, 1, 1, 0) +custom_minimum_size = Vector2(16, 16) +layout_mode = 2 +expand_mode = 1 +stretch_mode = 5 + +[node name="ScoreLabel" type="Label" parent="LeaderboardPanel/MarginContainer/VBox/Entry4/HBox" unique_id=560418594] layout_mode = 2 size_flags_horizontal = 3 theme_override_fonts/font = ExtResource("13_j8jky") @@ -1333,6 +1467,23 @@ theme_override_font_sizes/font_size = 22 text = "0" horizontal_alignment = 2 +[node name="MiniPowerUpBar" type="HBoxContainer" parent="LeaderboardPanel/MarginContainer/VBox/Entry4/HBox" unique_id=2059921947] +layout_mode = 2 +theme_override_constants/separation = 2 +alignment = 1 + +[node name="Segment0" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry4/HBox/MiniPowerUpBar" unique_id=1695101926] +custom_minimum_size = Vector2(12, 12) +layout_mode = 2 + +[node name="Segment1" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry4/HBox/MiniPowerUpBar" unique_id=1697515395] +custom_minimum_size = Vector2(12, 12) +layout_mode = 2 + +[node name="Segment2" type="Panel" parent="LeaderboardPanel/MarginContainer/VBox/Entry4/HBox/MiniPowerUpBar" unique_id=500915161] +custom_minimum_size = Vector2(12, 12) +layout_mode = 2 + [node name="GlobalMatchTimer" type="PanelContainer" parent="." unique_id=1714357974] anchors_preset = 5 anchor_left = 0.5 @@ -1728,6 +1879,17 @@ custom_minimum_size = Vector2(0, 40) layout_mode = 2 text = "Back" +[node name="SettingsBtn" type="Button" parent="." unique_id=1964422444] +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -78.0 +offset_top = 8.0 +offset_right = -30.0 +offset_bottom = 56.0 +grow_horizontal = 0 +text = "⚙" + [connection signal="text_submitted" from="MessageInput" to="." method="_on_message_input_text_submitted"] [connection signal="pressed" from="PauseMenu/Panel/VBox/ResumeBtn" to="." method="_on_resume_pressed"] [connection signal="pressed" from="PauseMenu/Panel/VBox/HowToPlayBtn" to="." method="_on_how_to_play_pressed"] diff --git a/scripts/managers/ui_manager.gd b/scripts/managers/ui_manager.gd index 9ab8267..75b83dc 100644 --- a/scripts/managers/ui_manager.gd +++ b/scripts/managers/ui_manager.gd @@ -238,38 +238,37 @@ func setup_powerup_bar_ui(main_node): powerup_segments.clear() var hbox = powerup_bar.get_node_or_null("HBox") if hbox: - for i in range(4): + for i in range(3): var segment = hbox.get_node_or_null("Segment" + str(i)) if segment: # Apply initial empty style - var style = StyleBoxFlat.new() - style.bg_color = Color(0.15, 0.15, 0.15, 1.0) - style.border_color = Color(0.3, 0.7, 0.3, 1.0) - style.set_border_width_all(2) - style.corner_radius_top_left = 4 if i == 0 else 0 - style.corner_radius_bottom_left = 4 if i == 0 else 0 - style.corner_radius_top_right = 4 if i == 3 else 0 - style.corner_radius_bottom_right = 4 if i == 3 else 0 + var style = StyleBoxTexture.new() + var tex_path = "res://assets/graphics/gui/gauge/Segment%d_empty.png" % i + if ResourceLoader.exists(tex_path): + style.texture = load(tex_path) segment.add_theme_stylebox_override("panel", style) powerup_segments.append(segment) func update_powerup_bar(current_points: int, _max_points: int): """Update battery segments based on current power-up points.""" - # 4 Segments total. Max Boost is 100. So each segment represents 25 points. - # Was previously dividing by 4, causing it to fill at 16 points! - var points_per_segment = _max_points / 4.0 + # 3 Segments total. Max Boost is 100. So each segment represents 33.33 points. + var points_per_segment = _max_points / 3.0 var bars_filled = int(current_points / points_per_segment) for i in range(powerup_segments.size()): var segment = powerup_segments[i] - var style = segment.get_theme_stylebox("panel").duplicate() + var style = StyleBoxTexture.new() + var tex_path = "" if i < bars_filled: - # Filled segment - bright green - style.bg_color = Color(0.3, 0.9, 0.3, 1.0) + # Filled segment + tex_path = "res://assets/graphics/gui/gauge/Segment%d_filled.png" % i else: - # Empty segment - dark - style.bg_color = Color(0.2, 0.2, 0.2, 0.8) + # Empty segment + tex_path = "res://assets/graphics/gui/gauge/Segment%d_empty.png" % i + + if ResourceLoader.exists(tex_path): + style.texture = load(tex_path) segment.add_theme_stylebox_override("panel", style) @@ -277,8 +276,8 @@ var _previous_bars: int = 0 func _on_powerup_points_changed(current: int, max_points: int): if current % 10 == 0: print("[UIManager] Points changed: ", current) - # Calculate based on max points (100) / 4 segments = 25 points per segment - var new_bars = int(current / 25.0) + # Calculate based on max points (100) / 3 segments = 33.33 points per segment + var new_bars = int(current / (max_points / 3.0)) # Detect if a new bar was filled if new_bars > _previous_bars and powerup_bar: @@ -407,14 +406,21 @@ func initialize_leaderboard_with_players(players: Array): return for i in range(4): - var entry = vbox.get_node_or_null("Entry" + str(i + 1)) - if not entry: + var entry_root = vbox.get_node_or_null("Entry" + str(i + 1)) + if not entry_root: continue + + var entry = entry_root.get_node_or_null("HBox") + if not entry: + entry = entry_root if i < players.size(): var player = players[i] var name_label = entry.get_node_or_null("NameLabel") var score_label = entry.get_node_or_null("ScoreLabel") + var portrait_rect = entry.get_node_or_null("PortraitRect") + var ghost_icon = entry.get_node_or_null("GhostIcon") + var mini_powerup_bar = entry.get_node_or_null("MiniPowerUpBar") if name_label: # Use display_name if available, otherwise fallback to node name @@ -422,9 +428,194 @@ func initialize_leaderboard_with_players(players: Array): if player_display_name.is_empty(): player_display_name = str(player.name) if player else "Player " + str(i + 1) name_label.text = player_display_name + if score_label: score_label.text = str(player.score) if player and player.get("score") else "0" + if portrait_rect: + var character_name = "Pip" # Default fallback + var peer_id = player.name.to_int() if player else 0 + + var lobby_manager = get_node_or_null("/root/LobbyManager") + if lobby_manager: + var lobby_players = lobby_manager.get_players() + for p in lobby_players: + if p.get("id") == peer_id: + character_name = p.get("character", "Pip") + break + + var avatar_url = "res://assets/graphics/character_selection/sc_characters/sc_%s.png" % character_name.to_lower() + if ResourceLoader.exists(avatar_url): + portrait_rect.texture = load(avatar_url) + + if ghost_icon: + # Hidden by default. The live update loop will populate the correct texture. + ghost_icon.modulate = Color(1, 1, 1, 0) + + if mini_powerup_bar: + # Initialize to empty segments + for j in range(3): + var seg = mini_powerup_bar.get_node_or_null("Segment" + str(j)) + if seg: + var style = StyleBoxFlat.new() + style.bg_color = Color(0.2, 0.2, 0.2, 0.8) + style.border_color = Color(0.3, 0.7, 0.3, 1.0) + style.set_border_width_all(2) + seg.add_theme_stylebox_override("panel", style) + entry.visible = true else: entry.visible = false + +func update_live_leaderboard(players: Array): + """Update the leaderboard during gameplay (scores, ghosts, powerups).""" + if not leaderboard_panel: return + var vbox = leaderboard_panel.get_node_or_null("MarginContainer/VBox") + if not vbox: vbox = leaderboard_panel.get_node_or_null("VBox") + if not vbox: return + + var sorted_players = players.duplicate() + sorted_players.sort_custom(func(a, b): + var score_a = a.score if "score" in a else 0 + var score_b = b.score if "score" in b else 0 + return score_a > score_b + ) + + var my_id = -1 + if leaderboard_panel.is_inside_tree() and leaderboard_panel.get_tree().get_multiplayer(): + my_id = leaderboard_panel.get_tree().get_multiplayer().get_unique_id() + + var my_index = -1 + for i in range(sorted_players.size()): + if sorted_players[i] and sorted_players[i].name == str(my_id): + my_index = i + break + + var items_to_display = [] + for i in range(min(3, sorted_players.size())): + items_to_display.append({"player": sorted_players[i], "rank": i + 1}) + + if sorted_players.size() >= 4: + if my_index > 3: + items_to_display.append({"player": sorted_players[my_index], "rank": my_index + 1}) + else: + items_to_display.append({"player": sorted_players[3], "rank": 4}) + + for i in range(4): + var entry_root = vbox.get_node_or_null("Entry" + str(i + 1)) + if not entry_root or i >= items_to_display.size(): + if entry_root: entry_root.visible = false + continue + + entry_root.visible = true + var entry = entry_root.get_node_or_null("HBox") + if not entry: entry = entry_root + + var item = items_to_display[i] + var player = item.player + var rank = item.rank + + var rank_label = entry.get_node_or_null("RankLabel") + if rank_label: + match rank: + 1: rank_label.text = "1st" + 2: rank_label.text = "2nd" + 3: rank_label.text = "3rd" + _: rank_label.text = str(rank) + "th" + + if player and player.name == str(my_id): + entry_root.modulate = Color(1.0, 1.0, 0.0) # Yellow + else: + entry_root.modulate = Color.WHITE + + var score_label = entry.get_node_or_null("ScoreLabel") + var ghost_icon = entry.get_node_or_null("GhostIcon") + var mini_powerup_bar = entry.get_node_or_null("MiniPowerUpBar") + var portrait_rect = entry.get_node_or_null("PortraitRect") + var name_label = entry.get_node_or_null("NameLabel") + + if name_label: + var default_name = player.name if player else "Unknown" + name_label.text = player.get("display_name") if (player and player.get("display_name")) else default_name + + if portrait_rect: + var character_name = "Pip" # Default fallback + if player and player.get("selected_character"): + var sc = player.selected_character + match sc: + "Bob": character_name = "Pip" + "Masbro": character_name = "Dabro" + "Gatot": character_name = "Gatot" + "Oldpop": character_name = "Copper" + _: character_name = sc + + var avatar_url = "res://assets/graphics/character_selection/sc_characters/sc_%s.png" % character_name.to_lower() + if ResourceLoader.exists(avatar_url): + portrait_rect.texture = load(avatar_url) + + if score_label: + score_label.text = str(player.score) if player and player.get("score") else "0" + + if ghost_icon: + var active_skill_id = -1 + var is_blinking = false + + if player.get("special_tiles_manager"): + var stm = player.special_tiles_manager + # Check if any skill is CURRENTLY active (User requesting blinking state) + if stm.get("active_buffs") and stm.active_buffs.has(0): # FASTER_SPEED + active_skill_id = 0 + is_blinking = true + elif stm.get("active_freeze_zones") and stm.active_freeze_zones.size() > 0: + active_skill_id = 1 # AREA_FREEZE + is_blinking = true + elif stm.get("blocked_tiles") != null and stm.get("blocked_tiles").size() > 0: + active_skill_id = 2 # BLOCK_FLOOR + is_blinking = true + elif typeof(stm.get("invisible_timer")) in [TYPE_FLOAT, TYPE_INT] and float(stm.get("invisible_timer")) > 0.0: + active_skill_id = 3 # INVISIBLE_MODE + is_blinking = true + else: + var inv = stm.get("inventory") + if inv: + for effect_idx in inv: + if inv[effect_idx]: + active_skill_id = effect_idx + break + + if active_skill_id != -1: + var tex_path = "res://assets/textures/player_board_and_blue_print/tile_null.tres" + match int(active_skill_id): + 0: tex_path = "res://assets/graphics/touch_control/speed.png" + 1: tex_path = "res://assets/graphics/touch_control/freeze_area.png" + 2: tex_path = "res://assets/graphics/touch_control/wall.png" + 3: tex_path = "res://assets/graphics/touch_control/ghost.png" + + if ResourceLoader.exists(tex_path): + ghost_icon.texture = load(tex_path) + + if is_blinking: + var alpha = 1.0 if (Time.get_ticks_msec() % 500) > 250 else 0.3 + ghost_icon.modulate = Color(1, 1, 1, alpha) + else: + ghost_icon.modulate = Color(1, 1, 1, 1) + else: + ghost_icon.modulate = Color(1, 1, 1, 0) + + if mini_powerup_bar and player.get("powerup_manager"): + var p_mgr = player.powerup_manager + if p_mgr: + var max_pts = p_mgr.get_max_points() + var current_pts = p_mgr.get_points() + var points_per_segment = max_pts / 3.0 + var bars_filled = int(current_pts / points_per_segment) + + for j in range(3): + var seg = mini_powerup_bar.get_node_or_null("Segment" + str(j)) + if seg: + var style = seg.get_theme_stylebox("panel").duplicate() + if j < bars_filled: + style.bg_color = Color(0.3, 0.9, 0.3, 1.0) + else: + style.bg_color = Color(0.2, 0.2, 0.2, 0.8) + seg.add_theme_stylebox_override("panel", style)