diff --git a/scenes/main.gd b/scenes/main.gd index 70fad54..805a641 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -1640,8 +1640,8 @@ func sync_grid_item(x: int, y: int, z: int, item: int): var f1 = enhanced_gridmap.get_cell_item(Vector3i(x, 1, z)) # Block if Layer 0 is Wall (4) or Void (-1) - # OR Layer 1 is already a wall (4 or 13) - if f0 in [4, -1] or f1 == 4 or f1 == 13: + # OR Layer 1 is already a wall (4) + if f0 in [4, -1] or f1 == 4: return enhanced_gridmap.set_cell_item(Vector3i(x, y, z), item) @@ -1666,7 +1666,7 @@ func sync_grid_items_batch(data: Array): if y == 1 and item >= 7 and item <= 20: var f0 = enhanced_gridmap.get_cell_item(Vector3i(x, 0, z)) var f1 = enhanced_gridmap.get_cell_item(Vector3i(x, 1, z)) - if f0 in [4, -1] or f1 == 4 or f1 == 13: + if f0 in [4, -1] or f1 == 4: continue enhanced_gridmap.set_cell_item(Vector3i(x, y, z), item) diff --git a/scripts/managers/player_input_manager.gd b/scripts/managers/player_input_manager.gd index 2e414f1..760146f 100644 --- a/scripts/managers/player_input_manager.gd +++ b/scripts/managers/player_input_manager.gd @@ -114,22 +114,29 @@ func handle_unhandled_input(event): # Unified check for PowerUp keys if ek == key_p1: - player.activate_powerup(0) # FASTER_SPEED - elif ek == key_p2: - if is_sng: - player.activate_powerup(3) # Ghost for SNG P2 - else: - player.activate_powerup(2) # Wall for Normal P2 - elif ek == key_p3 and not is_sng: - player.activate_powerup(1) # AREA_FREEZE - elif ek == key_p4 and not is_sng: - player.activate_powerup(3) # INVISIBLE_MODE + # Single Slot Logic: Find whatever powerup is currently set to 'true' and activate it + var active_effect = -1 + if player.special_tiles_manager: + for effect_key in player.special_tiles_manager.inventory: + if player.special_tiles_manager.inventory[effect_key]: + active_effect = effect_key + break - # Non-Remappable variants (Numpad) - Optional fallback + if active_effect != -1: + player.activate_powerup(active_effect) + else: + print("No powerup in slot 1 to activate.") + + # KP Fallback elif ek == KEY_KP_1: - player.activate_powerup(0) - elif ek == KEY_KP_2: - player.activate_powerup(3 if is_sng else 2) + var active_effect = -1 + if player.special_tiles_manager: + for effect_key in player.special_tiles_manager.inventory: + if player.special_tiles_manager.inventory[effect_key]: + active_effect = effect_key + break + if active_effect != -1: + player.activate_powerup(active_effect) # Action Buttons (Remappable) elif ek == SettingsManager.get_control_keycode("attack_mode"): diff --git a/scripts/managers/player_movement_manager.gd b/scripts/managers/player_movement_manager.gd index f5be9d6..a65b101 100644 --- a/scripts/managers/player_movement_manager.gd +++ b/scripts/managers/player_movement_manager.gd @@ -96,7 +96,7 @@ func simple_move_to(grid_position: Vector2i) -> bool: return false # Check Floor 1 (Obstacles/Walls) - if (cell_item != -1 and cell_item in [4, 13, 16]) and not is_wall_passable: + if (cell_item != -1 and cell_item in [4, 16]) and not is_wall_passable: print("[Move] Failed: Blocked by Item %d on Floor 1" % cell_item) return false diff --git a/scripts/managers/special_tiles_manager.gd b/scripts/managers/special_tiles_manager.gd index 11dfd5c..420a28f 100644 --- a/scripts/managers/special_tiles_manager.gd +++ b/scripts/managers/special_tiles_manager.gd @@ -118,6 +118,12 @@ func initialize(p_player: Node3D, p_gridmap: Node): enhanced_gridmap = p_gridmap rng = RandomNumberGenerator.new() rng.randomize() + + # Ensure Powerup Tiles (11-14) are NOT in the non-walkable list + if enhanced_gridmap and "non_walkable_items" in enhanced_gridmap: + for id in HOLO_TILES: + if id in enhanced_gridmap.non_walkable_items: + enhanced_gridmap.non_walkable_items.erase(id) # ============================================================================= # Helper: Item ID to Effect Enum @@ -137,45 +143,58 @@ func add_powerup_from_item(item_id: int): var effect = get_effect_from_item(item_id) if effect == -1: return - # Unlock or Level Up - if not inventory.get(effect, false): - # New Unlock - inventory[effect] = true - powerup_levels[effect] = 1 - emit_signal("inventory_updated", inventory) - emit_signal("powerup_unlocked", effect, 1) - print("Player %s unlocked powerup %s (Lvl 1)" % [player.name, SpecialEffect.keys()[effect]]) - else: - # Level Up - var current_lvl = powerup_levels.get(effect, 1) - if current_lvl < 8: - powerup_levels[effect] = current_lvl + 1 - emit_signal("powerup_unlocked", effect, powerup_levels[effect]) - print("Player %s leveled up %s to Lvl %d" % [player.name, SpecialEffect.keys()[effect], powerup_levels[effect]]) + # 1-PowerUp Rule: If this is a DIFFERENT power-up, clear the old one + var is_different = not inventory.get(effect, false) + var already_has_any = false + for e in inventory: + if inventory[e]: + already_has_any = true + break + + if is_different and already_has_any: + print("Player %s replacing existing powerup with %s" % [player.name, SpecialEffect.keys()[effect]]) + for e in inventory: + inventory[e] = false + powerup_levels[e] = 1 # Reset levels of discarded powerups + + # Instant Level 8 on pickup (User Request) + inventory[effect] = true + powerup_levels[effect] = 8 + emit_signal("inventory_updated", inventory) + emit_signal("powerup_unlocked", effect, 8) + print("[SpecialTiles] SUCCESS: Player %s picked up %s. Force Level 8 applied." % [player.name, SpecialEffect.keys()[effect]]) if player.is_multiplayer_authority() and multiplayer.has_multiplayer_peer() and multiplayer.multiplayer_peer.get_connection_status() == MultiplayerPeer.CONNECTION_CONNECTED: - rpc("sync_inventory_add", effect, powerup_levels[effect]) + rpc("sync_inventory_add", effect, 8) @rpc("any_peer", "call_local", "reliable") func sync_inventory_add(effect: int, level: int): + # Clear others on sync too to maintain 1-powerup rule + for e in inventory: + inventory[e] = false + powerup_levels[e] = 1 # Reset levels of discarded powerups + inventory[effect] = true powerup_levels[effect] = level emit_signal("inventory_updated", inventory) emit_signal("powerup_unlocked", effect, level) func remove_powerup(effect: int): - # We DO NOT remove item from inventory on use anymore (for reusable leveling system)? - # Wait, user request: "cooldown is decarese and max is level 8" - # Does "activate it" consume the item? - # User says "it will cooldown agian for 15 seconds". - # Implies PERMANENT UNLOCK once picked up, reusable with cooldown. - # So we NEVER set inventory[effect] = false unless reset. - pass + # User Request: "If the power up already use it will remain empty" + if inventory.get(effect, false): + inventory[effect] = false + powerup_levels[effect] = 1 + emit_signal("inventory_updated", inventory) + print("[SpecialTiles] Player %s consumed powerup %s" % [player.name, SpecialEffect.keys()[effect]]) + + if player.is_multiplayer_authority() and multiplayer.has_multiplayer_peer() and multiplayer.multiplayer_peer.get_connection_status() == MultiplayerPeer.CONNECTION_CONNECTED: + rpc("sync_inventory_remove", effect) @rpc("any_peer", "call_local", "reliable") func sync_inventory_remove(effect: int): - # Deprecated for new system, but kept for compatibility if needed - pass + inventory[effect] = false + powerup_levels[effect] = 1 + emit_signal("inventory_updated", inventory) # ============================================================================= # Activate Effect (Explicit Target) @@ -228,8 +247,10 @@ func activate_effect(effect: int, target_player: Node3D = null): # Play generic cast animation or sound? if player.is_multiplayer_authority() and multiplayer.has_multiplayer_peer() and multiplayer.multiplayer_peer.get_connection_status() == MultiplayerPeer.CONNECTION_CONNECTED: player.rpc("trigger_screen_shake", "light") - # Sync cooldown to others not strictly needed unless UI shows it? - # Probably local UI only. + + # Consumable: Remove after use (User Request) + print("[SpecialTiles] Consuming %s after successful activation." % SpecialEffect.keys()[effect]) + remove_powerup(effect) # ============================================================================= @@ -256,10 +277,9 @@ func _execute_area_freeze(target_pos: Vector2i = Vector2i.ZERO): var current_lvl = powerup_levels.get(SpecialEffect.AREA_FREEZE, 1) if center_pos == Vector2i.ZERO: - # Calculate distance ahead based on Level - # Gap of 2 floors = 3 tiles ahead - # Gap of 4 floors = 5 tiles ahead - var distance = 3 if current_lvl < 5 else 5 + # Updated: Always 3 tiles ahead as per user request + var distance = 3 + print("[SpecialTiles] Area Freeze logic executing with distance: %d" % distance) var movement = player.movement_manager if movement and movement.current_move_direction != Vector2i.ZERO: @@ -441,7 +461,7 @@ func spawn_powerups_around(center: Vector2i, force_powerups: bool = true, only_c # PROTECTED FLOOR CHECK: Don't spawn on existing walls or void var f0 = enhanced_gridmap.get_cell_item(Vector3i(pos.x, 0, pos.y)) var f1 = enhanced_gridmap.get_cell_item(Vector3i(pos.x, 1, pos.y)) - if f0 in [4, -1] or f1 in [4, 13, 16]: + if f0 in [4, -1] or f1 in [4, 16]: continue var item_id: int diff --git a/scripts/managers/stop_n_go_manager.gd b/scripts/managers/stop_n_go_manager.gd index 49eefda..51a6754 100644 --- a/scripts/managers/stop_n_go_manager.gd +++ b/scripts/managers/stop_n_go_manager.gd @@ -20,7 +20,7 @@ var safe_zone_centers: Array[Vector2i] = [] var safe_zone_spawned: bool = false # Power-Up Tile Spawning -const POWERUP_TILES = [11, 14] # Speed (11) and Ghost (14) +const POWERUP_TILES = [11, 12, 13, 14] # Speed, Freeze, Wall, Ghost const POWERUP_SPAWN_COUNT: int = 5 # Number of power-up tiles to spawn var powerups_spawned: bool = false var stop_phase_occurred: bool = false @@ -362,7 +362,7 @@ func _spawn_mission_tiles(): var current_item = gridmap.get_cell_item(Vector3i(x, 1, z)) # PROTECTED FLOOR CHECK: Don't spawn on walls or void - if base_tile in [TILE_OBSTACLE, -1] or current_item == TILE_OBSTACLE or current_item == 13: + if base_tile in [TILE_OBSTACLE, -1] or current_item == TILE_OBSTACLE: continue # Spawn tiles with 60% density diff --git a/scripts/ui/powerup_inventory_ui.gd b/scripts/ui/powerup_inventory_ui.gd index e53c348..7d74d20 100644 --- a/scripts/ui/powerup_inventory_ui.gd +++ b/scripts/ui/powerup_inventory_ui.gd @@ -50,16 +50,13 @@ func _ready(): _setup_btn(2, wall_btn) _setup_btn(3, ghost_btn) - # All skills available with new logic, but restricted in Stop n Go - if is_restricted: - if wall_btn: wall_btn.visible = false - if freeze_btn: freeze_btn.visible = false - # Re-setup shortcut labels for restricted mode - _update_shortcuts_for_mode(true) - else: - if wall_btn: wall_btn.visible = true - if freeze_btn: freeze_btn.visible = true - _update_shortcuts_for_mode(false) + # Remove mode-based restrictions on visibility for now, as ownership controls visibility + if wall_btn: wall_btn.visible = false + if freeze_btn: freeze_btn.visible = false + if speed_btn: speed_btn.visible = false + if ghost_btn: ghost_btn.visible = false + + _update_shortcuts_for_mode(is_restricted) print("[PowerUpUI] UI Initialization Complete. Mapped %d buttons." % icon_containers.size()) @@ -140,33 +137,16 @@ func _update_shortcuts_for_mode(is_restricted: bool): var btn = icon_containers[effect_id] _update_btn_shortcut(effect_id, btn) -func _update_btn_shortcut(effect_id: int, btn: Button): +func _update_btn_shortcut(_effect_id: int, btn: Button): var sc_lbl = btn.get_node_or_null("ShortcutLabel") if not sc_lbl: return - var mode = LobbyManager.get_game_mode() - var is_sng = mode == GameMode.Mode.STOP_N_GO - - var key_text = "" - - # Safety check for SettingsManager (Autoload) if not SettingsManager: sc_lbl.text = "" return - if is_sng: - match effect_id: - 0: key_text = SettingsManager.get_control_text("powerup_1") - 3: key_text = SettingsManager.get_control_text("powerup_2") # Map P2 to Slot 3 (Ghost) in SNG - _: key_text = "" - else: - match effect_id: - 0: key_text = SettingsManager.get_control_text("powerup_1") - 2: key_text = SettingsManager.get_control_text("powerup_2") - 1: key_text = SettingsManager.get_control_text("powerup_3") - 3: key_text = SettingsManager.get_control_text("powerup_4") - - sc_lbl.text = key_text + # Show only Shortcut 1 as per single-slot request + sc_lbl.text = "[%s]" % SettingsManager.get_control_text("powerup_1") func _on_btn_pressed(effect_id: int): print("[PowerUpUI] Clicked Button %d" % effect_id) @@ -241,6 +221,10 @@ func _on_powerup_unlocked(effect: int, level: int): var lvl_lbl = btn.get_node_or_null("LevelLabel") if lvl_lbl: lvl_lbl.text = "Lvl %d" % level + + # Enforce 1-slot rule by hiding others + if special_manager_ref: + _on_inventory_updated(special_manager_ref.inventory) else: print("[PowerUpUI] ERROR: Unlocked Effect %d but no UI button found! Keys: %s" % [effect, icon_containers.keys()]) @@ -261,12 +245,15 @@ func _on_cooldown_updated(effect: int, time_left: float, max_time: float): btn.modulate = Color.WHITE func _on_inventory_updated(inventory: Dictionary): - # Update UI icons (Dimmed vs Lit) and Enablement - print("[PowerUpUI] Inventory Updated: ", inventory) + # Update UI icons (Only show ONE active slot as per user request) + print("[PowerUpUI] Inventory Updated Signal Received! Data: ", 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 + var has_item = inventory.get(effect, false) + var btn = icon_containers[effect] + + # Single slot logic: Only the owned one is visible + btn.visible = has_item + if has_item: + btn.disabled = false # Individual cooldown logic might disable it later + btn.modulate = Color.WHITE + _update_btn_shortcut(effect, btn)