632 lines
22 KiB
GDScript
632 lines
22 KiB
GDScript
extends Node
|
|
|
|
# UIManager - Handles all UI setup and updates
|
|
|
|
const item_tex = [
|
|
preload("res://assets/textures/player_board_and_blue_print/tiles_slot.png"),
|
|
preload("res://assets/textures/player_board_and_blue_print/tile_heart.tres"),
|
|
preload("res://assets/textures/player_board_and_blue_print/tile_diamond.tres"),
|
|
preload("res://assets/textures/player_board_and_blue_print/tile_star.tres"),
|
|
preload("res://assets/textures/player_board_and_blue_print/tile_coin.tres")
|
|
]
|
|
|
|
# Node references - will be set by Main
|
|
# var victory_ui_scene = preload("res://scenes/ui/victory_ui.tscn")
|
|
var victory_ui_scene = null
|
|
var powerup_inventory_ui_script = preload("res://scripts/ui/powerup_inventory_ui.gd")
|
|
|
|
var main_menu_instance
|
|
var victory_ui_instance
|
|
var playerboard_ui
|
|
var action_menu_instance
|
|
var powerup_inventory_ui
|
|
var timer_label: Label
|
|
var playerboard_label: Label # Shows (xN) goal completions
|
|
var player_name_label: Label # Shows player name on main UI
|
|
|
|
var local_player_character
|
|
var _previous_playerboard_state: Array = []
|
|
|
|
|
|
func initialize(player_node):
|
|
# Get PowerUp Inventory UI from scene
|
|
powerup_inventory_ui = player_node.get_node_or_null("PowerUpInventoryUI")
|
|
|
|
# Get node references from main scene
|
|
playerboard_ui = player_node.get_node_or_null("PlayerBoardUI/PlayerboardUI")
|
|
if not playerboard_ui:
|
|
playerboard_ui = player_node.get_node_or_null("PlayerboardUI")
|
|
|
|
# Connect PlayerName label — now lives under PlayerBoardUI
|
|
player_name_label = player_node.get_node_or_null("PlayerBoardUI/PlayerName")
|
|
if not player_name_label:
|
|
player_name_label = player_node.get_node_or_null("PlayerName")
|
|
|
|
|
|
func set_local_player(player):
|
|
local_player_character = player
|
|
|
|
if powerup_inventory_ui:
|
|
powerup_inventory_ui.setup(player)
|
|
|
|
# Connect to powerup signals with deferred call (manager needs time to initialize)
|
|
_connect_powerup_manager_deferred(player)
|
|
|
|
# Update Player Name Label
|
|
if player_name_label:
|
|
player_name_label.text = player.display_name
|
|
print("[UIManager] Updated PlayerName label to: ", player.display_name)
|
|
|
|
|
|
func setup_playerboard_ui():
|
|
if not playerboard_ui:
|
|
push_warning("playerboard_ui node is missing!")
|
|
return
|
|
for child in playerboard_ui.get_children():
|
|
child.queue_free()
|
|
|
|
playerboard_ui.columns = 5
|
|
|
|
for i in range(25):
|
|
var slot = TextureRect.new()
|
|
|
|
var highlight_rect = TextureRect.new()
|
|
var hr_tex = load("res://assets/models/pboard/HighlightRect.tres")
|
|
|
|
var select_rect = TextureRect.new()
|
|
var sr_tex = load("res://assets/models/pboard/SelectRect.tres")
|
|
|
|
var adjacent_rect = TextureRect.new()
|
|
var ar_tex = load("res://assets/models/pboard/AdjacentRect.tres")
|
|
|
|
|
|
slot.custom_minimum_size = Vector2(36, 36)
|
|
slot.texture = item_tex[0]
|
|
|
|
# 0-based indices corresponding to User's 1-based request: 1,5,6,10,11,15,16,20,21,22,23,24,25
|
|
var hidden_slots = [0, 4, 5, 9, 10, 14, 15, 19, 20, 21, 22, 23, 24]
|
|
|
|
if i in hidden_slots:
|
|
slot.modulate = Color(1, 1, 1, 0)
|
|
slot.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
else:
|
|
slot.modulate = Color.WHITE
|
|
slot.mouse_filter = Control.MOUSE_FILTER_PASS
|
|
|
|
playerboard_ui.add_child(slot, true)
|
|
|
|
highlight_rect.texture = hr_tex
|
|
highlight_rect.size = Vector2(36, 36)
|
|
select_rect.texture = sr_tex
|
|
select_rect.size = Vector2(36, 36)
|
|
adjacent_rect.texture = ar_tex
|
|
adjacent_rect.size = Vector2(36, 36)
|
|
|
|
slot.add_child(highlight_rect)
|
|
slot.add_child(select_rect)
|
|
slot.add_child(adjacent_rect)
|
|
|
|
slot.get_child(0).hide()
|
|
slot.get_child(1).hide()
|
|
slot.get_child(2).hide()
|
|
|
|
func update_playerboard_ui():
|
|
if not local_player_character or not playerboard_ui:
|
|
return
|
|
|
|
# Center 3x3 slot indices in a 5x5 grid (0-indexed)
|
|
# Row 1: 6, 7, 8
|
|
# Row 2: 11, 12, 13
|
|
# Center 3x3 slot indices in a 5x5 grid (0-indexed)
|
|
# Row 1: 6, 7, 8 (Now Storage - but kept in index map for goals[0-2])
|
|
# Row 2: 11, 12, 13 (Goals[3-5])
|
|
# Row 3: 16, 17, 18 (Goals[6-8])
|
|
var center_slots = [6, 7, 8, 11, 12, 13, 16, 17, 18]
|
|
var goals = local_player_character.goals if local_player_character.goals else []
|
|
|
|
for i in range(25):
|
|
var slot = playerboard_ui.get_child(i)
|
|
|
|
# Safety check: Ensure playerboard has enough items
|
|
if i >= local_player_character.playerboard.size():
|
|
continue
|
|
|
|
var item = local_player_character.playerboard[i]
|
|
|
|
# 0-based indices corresponding to User's 1-based request: 1,5,6,10,11,15,16,20,21,22,23,24,25
|
|
var hidden_slots = [0, 4, 5, 9, 10, 14, 15, 19, 20, 21, 22, 23, 24]
|
|
|
|
# Default texture (empty)
|
|
slot.texture = item_tex[0]
|
|
|
|
if i in hidden_slots:
|
|
slot.modulate = Color(1, 1, 1, 0)
|
|
slot.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
else:
|
|
slot.modulate = Color.WHITE
|
|
slot.mouse_filter = Control.MOUSE_FILTER_PASS
|
|
|
|
# Check if this is a center slot that should show a goal
|
|
# BUT only show ghost goals for rows 2 & 3 (indices 11+)
|
|
var center_index = center_slots.find(i)
|
|
if center_index != -1 and center_index < goals.size() and i > 8:
|
|
var goal_value = goals[center_index]
|
|
|
|
if item != -1:
|
|
# Player has a tile in this slot - show it at full brightness
|
|
match item:
|
|
7: slot.texture = item_tex[1]
|
|
8: slot.texture = item_tex[2]
|
|
9: slot.texture = item_tex[3]
|
|
10: slot.texture = item_tex[4]
|
|
slot.modulate = Color.WHITE
|
|
else:
|
|
# Show goal tile dimmed (not collected yet)
|
|
match goal_value:
|
|
7: slot.texture = item_tex[1]
|
|
8: slot.texture = item_tex[2]
|
|
9: slot.texture = item_tex[3]
|
|
10: slot.texture = item_tex[4]
|
|
_: slot.texture = item_tex[0]
|
|
# Dim uncollected goals with black overlay
|
|
slot.modulate = Color(0.3, 0.3, 0.3, 1.0)
|
|
else:
|
|
# Non-center slot - just show playerboard item normally
|
|
match item:
|
|
7: slot.texture = item_tex[1]
|
|
8: slot.texture = item_tex[2]
|
|
9: slot.texture = item_tex[3]
|
|
10: slot.texture = item_tex[4]
|
|
# Non-center slots always full brightness (UNLESS HIDDEN)
|
|
if not (i in hidden_slots):
|
|
slot.modulate = Color.WHITE
|
|
|
|
# Check for new special tile placement to trigger effect
|
|
if i < _previous_playerboard_state.size():
|
|
var prev_item = _previous_playerboard_state[i]
|
|
# If slot was empty or different, and now has a special tile (7-10)
|
|
if item != prev_item and item >= 7 and item <= 10:
|
|
_pulse_slot_effect(slot)
|
|
|
|
# Update cache
|
|
_previous_playerboard_state = local_player_character.playerboard.duplicate()
|
|
|
|
func _pulse_slot_effect(slot: Control):
|
|
"""Visual feedback when a special tile is placed."""
|
|
var tween = create_tween()
|
|
|
|
# Reset scale first to be safe
|
|
slot.scale = Vector2.ONE
|
|
slot.pivot_offset = slot.size / 2 # Center pivot
|
|
|
|
# Pop effect
|
|
tween.tween_property(slot, "scale", Vector2(1.4, 1.4), 0.15).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
|
|
tween.tween_property(slot, "scale", Vector2(1.0, 1.0), 0.2).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
|
|
|
|
# Flash effect
|
|
var original_modulate = slot.modulate
|
|
slot.modulate = Color(1.5, 1.5, 1.5) # Overbright
|
|
tween.parallel().tween_property(slot, "modulate", original_modulate, 0.3)
|
|
|
|
|
|
|
|
|
|
func _connect_powerup_manager_deferred(player):
|
|
"""Wait for PowerUpManager to be initialized before connecting."""
|
|
# player._ready waits 0.5s before creating managers, so wait longer
|
|
await player.get_tree().create_timer(0.8).timeout
|
|
|
|
var powerup_manager = player.get_node_or_null("PowerUpManager")
|
|
if powerup_manager:
|
|
if not powerup_manager.points_changed.is_connected(_on_powerup_points_changed):
|
|
powerup_manager.points_changed.connect(_on_powerup_points_changed)
|
|
# Initialize bar with current values
|
|
update_powerup_bar(powerup_manager.get_points(), powerup_manager.get_max_points())
|
|
# Force initial label update
|
|
_on_powerup_points_changed(powerup_manager.get_points(), powerup_manager.get_max_points())
|
|
else:
|
|
push_warning("[UIManager] PowerUpManager not found on player after 0.8s wait")
|
|
|
|
# =============================================================================
|
|
# Power-Up Bar UI (Battery Style)
|
|
# =============================================================================
|
|
|
|
var powerup_bar: PanelContainer
|
|
var powerup_ready_rect: TextureRect
|
|
var powerup_segments: Array = []
|
|
|
|
func setup_powerup_bar_ui(main_node):
|
|
"""Get reference to existing PowerUpBar in scene and cache segment references."""
|
|
powerup_bar = main_node.get_node_or_null("PowerBar/PowerUpBar")
|
|
if not powerup_bar:
|
|
powerup_bar = main_node.get_node_or_null("PowerUpBar")
|
|
if not powerup_bar:
|
|
push_warning("PowerUpBar node not found in scene")
|
|
return
|
|
|
|
powerup_ready_rect = main_node.get_node_or_null("PowerBar/PowerUpReady")
|
|
|
|
# Get segment references from scene
|
|
powerup_segments.clear()
|
|
var hbox = powerup_bar.get_node_or_null("HBox")
|
|
if hbox:
|
|
for i in range(3):
|
|
var segment = hbox.get_node_or_null("Segment" + str(i))
|
|
if segment:
|
|
# Apply initial empty style
|
|
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."""
|
|
# 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 = StyleBoxTexture.new()
|
|
var tex_path = ""
|
|
|
|
if i < bars_filled:
|
|
# Filled segment
|
|
tex_path = "res://assets/graphics/gui/gauge/Segment%d_filled.png" % i
|
|
else:
|
|
# 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)
|
|
|
|
if powerup_ready_rect:
|
|
if current_points >= _max_points and _max_points > 0:
|
|
powerup_ready_rect.visible = true
|
|
else:
|
|
powerup_ready_rect.visible = false
|
|
|
|
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) / 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:
|
|
# Pulse effect on newly filled segment
|
|
var segment_index = new_bars - 1
|
|
if segment_index >= 0 and segment_index < powerup_segments.size():
|
|
var segment = powerup_segments[segment_index]
|
|
_pulse_segment(segment)
|
|
|
|
_previous_bars = new_bars
|
|
update_powerup_bar(current, max_points)
|
|
|
|
# Update Safety: Check if timer_label is valid
|
|
if timer_label and local_player_character and local_player_character.powerup_manager:
|
|
var time_left = local_player_character.powerup_manager.get_time_until_full()
|
|
if time_left <= 0:
|
|
timer_label.text = " READY "
|
|
timer_label.add_theme_color_override("font_color", Color(0.3, 0.9, 0.3)) # Green
|
|
else:
|
|
# User request: "Do it on int not float"
|
|
timer_label.text = str(int(ceil(time_left))) + "s"
|
|
timer_label.add_theme_color_override("font_color", Color(1.0, 0.85, 0.2)) # Gold
|
|
|
|
func _pulse_segment(segment: Panel):
|
|
"""Create a visual pulse effect on a powerup segment."""
|
|
var original_scale = segment.scale
|
|
var tween = segment.create_tween()
|
|
tween.set_loops(2)
|
|
tween.tween_property(segment, "scale", Vector2(1.3, 1.3), 0.1).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
|
|
tween.tween_property(segment, "scale", original_scale, 0.15).set_trans(Tween.TRANS_SINE)
|
|
|
|
# =============================================================================
|
|
# Leaderboard UI
|
|
# =============================================================================
|
|
|
|
var leaderboard_panel: PanelContainer
|
|
|
|
func setup_leaderboard_ui(main_node):
|
|
"""Get reference to existing LeaderboardPanel in scene."""
|
|
leaderboard_panel = main_node.get_node_or_null("LeaderboardPanel")
|
|
if not leaderboard_panel:
|
|
push_warning("LeaderboardPanel node not found in scene")
|
|
return
|
|
|
|
func _get_rank_text(rank: int) -> String:
|
|
match rank:
|
|
1: return "1st"
|
|
2: return "2nd"
|
|
3: return "3rd"
|
|
4: return "4th"
|
|
_: return str(rank) + "th"
|
|
|
|
# =============================================================================
|
|
# Timer Labels for Goal Panels
|
|
# =============================================================================
|
|
|
|
func setup_timer_labels(main_node):
|
|
"""Apply styling to standalone GoalsTimer in scene."""
|
|
var goals_timer = main_node.get_node_or_null("GoalsTimer")
|
|
if not goals_timer:
|
|
push_warning("GoalsTimer node not found in scene")
|
|
return
|
|
|
|
# Apply dark background style
|
|
var style = StyleBoxFlat.new()
|
|
style.bg_color = Color(0.1, 0.1, 0.15, 0.9)
|
|
style.border_color = Color(1.0, 0.85, 0.2, 1.0) # Gold border
|
|
style.set_border_width_all(2)
|
|
style.corner_radius_top_left = 8
|
|
style.corner_radius_top_right = 8
|
|
style.corner_radius_bottom_left = 8
|
|
style.corner_radius_bottom_right = 8
|
|
goals_timer.add_theme_stylebox_override("panel", style)
|
|
|
|
# Style the timer label
|
|
var t_label = goals_timer.get_node_or_null("TimerLabel")
|
|
if t_label:
|
|
timer_label = t_label # Store reference
|
|
t_label.add_theme_color_override("font_color", Color(1.0, 0.85, 0.2))
|
|
else:
|
|
print("[UIManager] ERROR: GoalsTimer found but TimerLabel NOT found at node/TimerLabel")
|
|
var suffix_label = goals_timer.get_node_or_null("SuffixLabel")
|
|
if suffix_label:
|
|
suffix_label.add_theme_color_override("font_color", Color(0.7, 0.7, 0.7))
|
|
|
|
func setup_playerboard_label(main_node):
|
|
# PlayerBoardLabel now lives under PlayerBoardUI
|
|
var lbl = main_node.get_node_or_null("PlayerBoardUI/PlayerBoardLabel")
|
|
if not lbl:
|
|
lbl = main_node.get_node_or_null("PlayerBoardLabel")
|
|
if lbl:
|
|
playerboard_label = lbl
|
|
playerboard_label.text = "x0"
|
|
print("[UIManager] Found PlayerBoardLabel")
|
|
else:
|
|
print("[UIManager] PlayerBoardLabel not found")
|
|
|
|
func update_goal_count_label(count: int):
|
|
if playerboard_label:
|
|
playerboard_label.text = "x%d" % count
|
|
|
|
# Pop effect only for progress
|
|
if count > 0:
|
|
var tween = playerboard_label.create_tween()
|
|
playerboard_label.scale = Vector2(1.5, 1.5)
|
|
tween.tween_property(playerboard_label, "scale", Vector2(1.0, 1.0), 0.3).set_trans(Tween.TRANS_BOUNCE)
|
|
|
|
# Method to update leaderboard with all players in match
|
|
func initialize_leaderboard_with_players(players: Array):
|
|
"""Initialize leaderboard showing all players with score 0."""
|
|
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
|
|
|
|
for i in range(4):
|
|
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("SplitterContainer/SectionA/NameLabel")
|
|
var score_label = entry.get_node_or_null("SplitterContainer/SectionB/ScoreLabel")
|
|
var portrait_rect = entry.get_node_or_null("PortraitRect")
|
|
var ghost_icon = entry.get_node_or_null("SplitterContainer/SectionA/GhostIcon")
|
|
var mini_powerup_bar = entry.get_node_or_null("SplitterContainer/SectionB/MiniPowerUpBar")
|
|
|
|
if name_label:
|
|
# Use display_name if available, otherwise fallback to node name
|
|
var player_display_name = player.display_name if player and player.get("display_name") else ""
|
|
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(0.3, 0.7, 1.0) # Blue highlight for local player
|
|
else:
|
|
entry_root.modulate = Color.WHITE
|
|
|
|
var score_label = entry.get_node_or_null("SplitterContainer/SectionB/ScoreLabel")
|
|
var ghost_icon = entry.get_node_or_null("SplitterContainer/SectionA/GhostIcon")
|
|
var mini_powerup_bar = entry.get_node_or_null("SplitterContainer/SectionB/MiniPowerUpBar")
|
|
var portrait_rect = entry.get_node_or_null("PortraitRect")
|
|
var name_label = entry.get_node_or_null("SplitterContainer/SectionA/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)
|