extends Control # PowerUpInventoryUI - Displays stored powerups and handles selection # UI References var icon_containers: Dictionary = {} # { EffectEnum: Button } # Local State var selected_effect: int = -1 var special_manager_ref: Node = null # Reference to SpecialTilesManager signal effect_selected(effect: int) func _ready(): print("[PowerUpUI] _ready called") # Map Effect Enum to UI Nodes (Assumes specific names in main.tscn) # We try to get them immediately. If they are children, they should be accessible. var container = get_node_or_null("Container") if not container: print("[PowerUpUI] ERROR: HBoxContainer not found in ", get_path()) return # Mapping based on User Request # 11: FASTER_SPEED (0) -> SpeedBtn # 12: AREA_FREEZE (1) -> FreezeAreaBtn # 13: BLOCK_FLOOR (2) -> WallBtn # 14: INVISIBLE_MODE (3) -> GhostBtn # We use 0, 1, 2, 3 to match SpecialTilesManager.SpecialEffect enum _setup_btn(0, container.get_node_or_null("SpeedBtn")) _setup_btn(1, container.get_node_or_null("FreezeAreaBtn")) var wall_btn = container.get_node_or_null("WallBtn") _setup_btn(2, wall_btn) var mode = LobbyManager.get_game_mode() var is_restricted = GameMode.is_restricted(mode) if wall_btn and is_restricted: wall_btn.visible = false # Hide Wall Power-up in restricted modes _setup_btn(3, container.get_node_or_null("GhostBtn")) print("[PowerUpUI] UI Initialization Complete. Mapped %d buttons." % icon_containers.size()) func _setup_btn(effect_id: int, btn: Button): if not btn: print("[PowerUpUI] Warning: Button for effect %d is null" % effect_id) return icon_containers[effect_id] = btn # Start DISABLED btn.disabled = true btn.modulate = Color(0.5, 0.5, 0.5, 0.5) # Grayed out btn.focus_mode = Control.FOCUS_NONE # Add Level Label if not btn.has_node("LevelLabel"): var lvl_lbl = Label.new() lvl_lbl.name = "LevelLabel" lvl_lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE lvl_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT lvl_lbl.vertical_alignment = VERTICAL_ALIGNMENT_BOTTOM lvl_lbl.set_anchors_preset(Control.PRESET_FULL_RECT) lvl_lbl.add_theme_font_size_override("font_size", 16) lvl_lbl.add_theme_color_override("font_outline_color", Color.BLACK) lvl_lbl.add_theme_constant_override("outline_size", 4) lvl_lbl.text = "" # Hidden initially btn.add_child(lvl_lbl) # Add Cooldown Label if not btn.has_node("CooldownLabel"): var cd_lbl = Label.new() cd_lbl.name = "CooldownLabel" cd_lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE cd_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER cd_lbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER cd_lbl.set_anchors_preset(Control.PRESET_FULL_RECT) cd_lbl.add_theme_font_size_override("font_size", 20) cd_lbl.add_theme_color_override("font_outline_color", Color.BLACK) cd_lbl.add_theme_constant_override("outline_size", 4) cd_lbl.text = "" btn.add_child(cd_lbl) # Add Keyboard Shortcut Label if not btn.has_node("ShortcutLabel"): var sc_lbl = Label.new() sc_lbl.name = "ShortcutLabel" sc_lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE # Position: Top Left of the button sc_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT sc_lbl.vertical_alignment = VERTICAL_ALIGNMENT_TOP # Anchor to top left sc_lbl.set_anchors_preset(Control.PRESET_TOP_LEFT) # Offset to be close to the corner sc_lbl.offset_left = 0 sc_lbl.offset_top = -5 # Close to the button top sc_lbl.add_theme_font_size_override("font_size", 16) sc_lbl.add_theme_color_override("font_outline_color", Color.BLACK) sc_lbl.add_theme_constant_override("outline_size", 4) # Add color override to make it distinct (optional, but good for visibility) sc_lbl.add_theme_color_override("font_color", Color(0.9, 0.9, 0.9)) # Determine Label Text based on Effect ID var key_text = "" var mode = LobbyManager.get_game_mode() var is_restricted = GameMode.is_restricted(mode) if is_restricted: # Restricted Mapping: 1, 2, 3 (No Wall) match effect_id: 0: key_text = "1" 1: key_text = "2" # Freeze is now 2 3: key_text = "3" # Ghost is now 3 else: # Free Mode Mapping: 1, 2, 3, 4 (Original) match effect_id: 0: key_text = "1" 2: key_text = "2" 1: key_text = "3" 3: key_text = "4" sc_lbl.text = key_text btn.add_child(sc_lbl) # Connect click if not btn.pressed.is_connected(_on_btn_pressed): btn.pressed.connect(_on_btn_pressed.bind(effect_id)) func _on_btn_pressed(effect_id: int): print("[PowerUpUI] Clicked Button %d" % effect_id) if special_manager_ref: special_manager_ref.activate_effect(effect_id) else: print("[PowerUpUI] ERROR: special_manager_ref is null during click") func setup(player_node): print("[PowerUpUI] Setup called for player: ", player_node.name) var special_manager = player_node.get_node_or_null("SpecialTilesManager") if special_manager: _connect_special_manager(special_manager) else: print("[PowerUpUI] SpecialTilesManager not found on %s. Waiting for it..." % player_node.name) if not player_node.child_entered_tree.is_connected(_on_player_child_entered): player_node.child_entered_tree.connect(_on_player_child_entered.bind(player_node)) func _on_player_child_entered(node: Node, player_node: Node): if node.name == "SpecialTilesManager": print("[PowerUpUI] SpecialTilesManager appeared on %s!" % player_node.name) _connect_special_manager(node) # Disconnect to avoid checking every child forever if player_node.child_entered_tree.is_connected(_on_player_child_entered): player_node.child_entered_tree.disconnect(_on_player_child_entered) func _connect_special_manager(special_manager): special_manager_ref = special_manager print("[PowerUpUI] Connected to SpecialTilesManager") # Connect signals if not already connected if not special_manager.is_connected("powerup_unlocked", _on_powerup_unlocked): special_manager.connect("powerup_unlocked", _on_powerup_unlocked) if not special_manager.is_connected("cooldown_updated", _on_cooldown_updated): special_manager.connect("cooldown_updated", _on_cooldown_updated) if not special_manager.is_connected("inventory_updated", _on_inventory_updated): special_manager.connect("inventory_updated", _on_inventory_updated) # Initial State Sync if icon_containers.is_empty(): print("[PowerUpUI] Warning: Icon containers empty during setup. Attempting _ready logic now...") var container = get_node_or_null("HBoxContainer") if container: # Fix: Use correct IDs 0-3 here too _setup_btn(0, container.get_node_or_null("SpeedBtn")) _setup_btn(1, container.get_node_or_null("FreezeAreaBtn")) _setup_btn(2, container.get_node_or_null("WallBtn")) _setup_btn(3, container.get_node_or_null("GhostBtn")) # Sync Inventory _on_inventory_updated(special_manager.inventory) # Sync Levels for owned items for effect in special_manager.inventory: if special_manager.inventory[effect]: var lvl = special_manager.powerup_levels.get(effect, 1) _on_powerup_unlocked(effect, lvl) func _on_powerup_unlocked(effect: int, level: int): # Enable button and set level if icon_containers.has(effect): var btn = icon_containers[effect] print("[PowerUpUI] Enabling button for Effect %d (Node: %s)" % [effect, btn.name]) btn.disabled = false btn.modulate = Color.WHITE # Restore color btn.visible = true # Ensure visible # Update Level var lvl_lbl = btn.get_node_or_null("LevelLabel") if lvl_lbl: lvl_lbl.text = "Lvl %d" % level else: print("[PowerUpUI] ERROR: Unlocked Effect %d but no UI button found! Keys: %s" % [effect, icon_containers.keys()]) func _on_cooldown_updated(effect: int, time_left: float, max_time: float): if icon_containers.has(effect): var btn = icon_containers[effect] var cd_lbl = btn.get_node_or_null("CooldownLabel") if cd_lbl: if time_left > 0: cd_lbl.text = "%d" % int(time_left) btn.disabled = true btn.modulate = Color(0.7, 0.7, 0.7, 0.8) else: cd_lbl.text = "" # Re-enable if we own it if special_manager_ref and special_manager_ref.inventory.get(effect, false): btn.disabled = false btn.modulate = Color.WHITE func _on_inventory_updated(inventory: Dictionary): # Update UI icons (Dimmed vs Lit) and Enablement print("[PowerUpUI] Inventory Updated: ", inventory) for effect in icon_containers: if inventory.has(effect): var has_item = inventory[effect] var btn = icon_containers[effect] btn.modulate = Color.WHITE if has_item else Color(0.5, 0.5, 0.5, 0.5) btn.disabled = !has_item