extends Control # PowerUpInventoryUI - Displays stored powerups and handles selection # UI References var icon_containers: Dictionary = {} # { EffectEnum: TextureRect } var selection_indicators: Dictionary = {} # { EffectEnum: Control } # Local State var selected_effect: int = -1 var special_manager_ref: Node = null # Reference to SpecialTilesManager signal effect_selected(effect: int) func _ready(): # Wait for children to be ready await get_tree().process_frame # Map Effect Enum to UI Nodes (Assumes specific names in main.tscn) # Default structure: HBoxContainer > CoinIcon, HeartIcon, etc. var container = get_node_or_null("HBoxContainer") if not container: print("PowerUpUI: Container not found") return # ID 11 = Faster (Coin Icon?) User said: "Coin : random between two" originally, # but now "11 (Faster)". Let's use CoinIcon for Speed? Or Star? # User Request: "CoinIcon, HeartIcon, DiamondIcon and StarIcon" # Let's map: # 11 (Faster) -> CoinIcon # 12 (Freeze) -> DiamondIcon # 13 (Block) -> HeartIcon # 14 (Invisible) -> StarIcon _setup_icon(11, container.get_node_or_null("CoinIcon")) _setup_icon(12, container.get_node_or_null("DiamondIcon")) _setup_icon(13, container.get_node_or_null("HeartIcon")) _setup_icon(14, container.get_node_or_null("StarIcon")) # Note: SpecialEffect enum values from SpecialTilesManager: # BURN_TILES = 0 # SPAWN_TILES = 1 (we map Coin to 0, merged) # FREEZE_PLAYER = 2 # BLOCK_FLOOR = 3 # INVISIBLE_MODE = 4 func _setup_icon(effect_id: int, node: Control): if not node: return icon_containers[effect_id] = node # Assume node has specific children for selection state? # "SelectRect" child? var select_rect = node.get_node_or_null("SelectRect") if select_rect: selection_indicators[effect_id] = select_rect select_rect.visible = false # Add Cooldown Label if missing if not node.has_node("CooldownLabel"): var lbl = Label.new() lbl.name = "CooldownLabel" lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE # Ensure input passes to icon # Style the label lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER lbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER lbl.set_anchors_preset(Control.PRESET_FULL_RECT) # Cover icon lbl.add_theme_color_override("font_shadow_color", Color.BLACK) lbl.add_theme_constant_override("shadow_offset_x", 1) lbl.add_theme_constant_override("shadow_offset_y", 1) lbl.add_theme_font_size_override("font_size", 20) # Big text lbl.text = "" lbl.hide() node.add_child(lbl) # Connect click event if not node.gui_input.is_connected(_on_icon_input): node.gui_input.connect(_on_icon_input.bind(effect_id)) func _on_icon_input(event, effect_id: int): if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: print("[PowerUpUI] Clicked Icon %d. Manager: %s" % [effect_id, special_manager_ref]) # User Request: "Click the CoinIcon for activate" # Instead of just selecting, we ACTIVATE it immediately. if special_manager_ref: special_manager_ref.activate_effect(effect_id) else: print("[PowerUpUI] ERROR: SpecialManagerRef is null!") # Visual feedback (still useful) select_effect(effect_id) # Auto-deselect after short delay? # For now, keep selection highlight as feedback of "last used" or "active"? # Or just flash it? # If it's a "selection for target" ability (like Block Floor on Target?), # we might need selection state first, then clicking target. # But user said "CoinIcon ... activate faster speed". Speed is self-cast. # Freeze is 3x3 self-centered. # Invisible is self. # Block is "Wall Block"... maybe checks target? # SpecialTilesManager.activate_effect defaults target to self if null. # So direct activation is safe for IsInstant effects. func setup(player_node): var special_manager = player_node.get_node_or_null("SpecialTilesManager") if special_manager: special_manager_ref = special_manager # Store reference for activation logic if not special_manager.is_connected("inventory_updated", _on_inventory_updated): special_manager.connect("inventory_updated", _on_inventory_updated) if not special_manager.is_connected("cooldown_updated", _on_cooldown_updated): special_manager.connect("cooldown_updated", _on_cooldown_updated) _on_inventory_updated(special_manager.inventory) func _on_cooldown_updated(effect: int, time_left: float, max_time: float): if icon_containers.has(effect): var node = icon_containers[effect] var lbl = node.get_node_or_null("CooldownLabel") if lbl: if time_left > 0: lbl.text = "%.1fs" % time_left lbl.show() node.modulate = Color(0.5, 0.5, 0.5, 1.0) # Dimmed else: lbl.hide() # Check inventory to restore proper modulate var has_item = false # Need ref to inventory... or rely on next inventory update? # Inventory update might not fire when cooldown ends. # Let's restore bright if we have it? # We don't have inventory reference here easily without storing it. node.modulate = Color.WHITE # Assume we have it if we used it? # Or better, just restore to WHITE and let inventory logic handle "not owned" graying. # But wait, logic in _on_inventory_updated sets GRAY if not owned. # If we set WHITE here, we might un-gray an unowned item? # The only way cooldown runs is if we ACTIVATED it, so we HAD it. # And we treat it as infinite consumable now. So we still have it. pass # Better modulate handling: # If cooldown > 0, DIM. # If cooldown == 0, check owned state? # For now, simplistic: if cooldown ends, set white. if time_left <= 0: node.modulate = Color.WHITE func _on_inventory_updated(inventory: Dictionary): # Update UI icons (Dimmed vs Lit) for effect in icon_containers: if inventory.has(effect): var has_item = inventory[effect] icon_containers[effect].modulate = Color.WHITE if has_item else Color(0.3, 0.3, 0.3, 0.5) if not has_item and selected_effect == effect: deselect() func select_effect(effect: int): # Check if we own it first? The UI click handler should check. selected_effect = effect emit_signal("effect_selected", effect) _update_selection_visuals() func deselect(): selected_effect = -1 emit_signal("effect_selected", -1) _update_selection_visuals() func _update_selection_visuals(): for effect in selection_indicators: selection_indicators[effect].visible = (effect == selected_effect)