extends Node # PlayerActionManager - Handles action points, highlights, and visual feedback var player: Node3D var enhanced_gridmap: Node var highlighted_cells = [] # List of positions # highlight_restore_items no longer needed for Layer 2 func initialize(p_player: Node3D, p_gridmap: Node): player = p_player enhanced_gridmap = p_gridmap func consume_action_points(_points: int): # Action points are no longer used (real-time mode only). # Kept as a no-op stub so call sites don't need mass refactoring. after_action_completed() func after_action_completed(): # Guard against recursive calls if player._is_processing_action: return player._is_processing_action = true if player.is_multiplayer_authority(): player.update_finish_availability() # Clear the highlights after placing the tiles. (Quickfix for Clientside) clear_highlights() # Only update UI if this is the LOCAL HUMAN PLAYER # Guard against stale callbacks after peer teardown (host quitting solo match) if not multiplayer.has_multiplayer_peer(): player._is_processing_action = false return if multiplayer.get_unique_id() == player.get_multiplayer_authority(): # Sync playerboard (Bots DO need to sync their board logic, just not update local UI) if player.is_multiplayer_authority() and player.has_method("can_rpc") and player.can_rpc(): var main = player.get_tree().get_root().get_node_or_null("Main") if main: main.rpc("sync_playerboard", player.name.to_int(), player.playerboard) player._is_processing_action = false # ============================================================================= # Highlight Operations # ============================================================================= func highlight_cells_if_authorized(cells_to_highlight: Array, item_id: int = -1): if not player.is_multiplayer_authority() or player.is_bot or player.is_in_group("Bots"): return # Start with fresh highlights if logical state changes? # But dragging mouse calls this every frame. We need to clear previous calls. # The simplistic clear_highlights() clears ALL highlights. # Which is fine for targeting mode as we only highlight the target area. clear_highlights() var highlight_item = item_id if item_id != -1 else enhanced_gridmap.hover_item for cell in cells_to_highlight: highlighted_cells.append(cell) # Use Layer 2 for overlay highlights (prevents overwriting Execution on Layer 0) enhanced_gridmap.set_cell_item( Vector3i(cell.x, 2, cell.y), highlight_item ) func highlight_empty_adjacent_cells(): if player.is_bot == true or player.is_in_group("Bots"): return # Debug print print("Highlighting empty adjacent cells. Current position: ", player.current_position) # Clear previous highlights clear_highlights() # Highlight current position if empty var current_cell = Vector3i(player.current_position.x, 1, player.current_position.y) if enhanced_gridmap.get_cell_item(current_cell) == -1: highlighted_cells.append(player.current_position) # Set on Layer 2 (Overlay) enhanced_gridmap.set_cell_item(Vector3i(player.current_position.x, 2, player.current_position.y), enhanced_gridmap.hover_item) print("Highlighted current position: ", player.current_position) # Highlight empty adjacent cells var neighbors = enhanced_gridmap.get_neighbors(player.current_position, 0) for neighbor in neighbors: if neighbor.is_walkable: var cell_pos = neighbor.position var cell = Vector3i(cell_pos.x, 1, cell_pos.y) if enhanced_gridmap.get_cell_item(cell) == -1: # Check if cell is empty highlighted_cells.append(cell_pos) # Set on Layer 2 (Overlay) enhanced_gridmap.set_cell_item(Vector3i(cell_pos.x, 2, cell_pos.y), enhanced_gridmap.hover_item) print("Highlighted adjacent cell: ", cell_pos) func highlight_random_valid_cells(): if player.is_bot == true or player.is_in_group("Bots") or not player.is_multiplayer_authority(): return clear_highlights() # First check the current position var current_cell = Vector3i(player.current_position.x, 1, player.current_position.y) var current_item = enhanced_gridmap.get_cell_item(current_cell) if current_item != -1: highlighted_cells.append(player.current_position) # Set on Layer 2 (Overlay) enhanced_gridmap.set_cell_item(Vector3i(player.current_position.x, 2, player.current_position.y), enhanced_gridmap.hover_item) # Then check all adjacent cells for items var neighbors = enhanced_gridmap.get_neighbors(player.current_position, 0) for neighbor in neighbors: if neighbor.is_walkable: var cell_pos = neighbor.position var cell = Vector3i(cell_pos.x, 1, cell_pos.y) if enhanced_gridmap.get_cell_item(cell) != -1: # Only highlight cells with items highlighted_cells.append(cell_pos) # Set on Layer 2 (Overlay) enhanced_gridmap.set_cell_item(Vector3i(cell_pos.x, 2, cell_pos.y), enhanced_gridmap.hover_item) func highlight_occupied_playerboard_slots(): if player.is_bot == true or player.is_in_group("Bots") or not player.is_multiplayer_authority(): return var main = player.get_tree().get_root().get_node_or_null("Main") if not main or not main.ui_manager.playerboard_ui: return # First reset all slots to normal for i in range(player.playerboard.size()): var slot = main.ui_manager.playerboard_ui.get_child(i) for child in slot.get_children(): child.hide() # Highlight occupied slots that match goals for i in range(player.playerboard.size()): if player.playerboard[i] in player.goals: var slot = main.ui_manager.playerboard_ui.get_child(i) if slot.get_child_count() > 0: slot.get_child(0).show() # Show highlight for matching items highlighted_cells.append(i) # Add to highlighted cells for tracking # Update the UI to reflect changes main.ui_manager.update_playerboard_ui() func clear_highlights(): # Never allow bots to clear highlights for human players if player.is_bot or player.is_in_group("Bots"): return if not enhanced_gridmap or not player.is_multiplayer_authority(): return # Clear highlights normally var main = player.get_tree().get_root().get_node_or_null("Main") var hover_id = enhanced_gridmap.hover_item for cell in highlighted_cells: if cell is Vector2i: # Check Layer 2 (Overlay Highlight) var l2_pos = Vector3i(cell.x, 2, cell.y) var l2_item = enhanced_gridmap.get_cell_item(l2_pos) # Only clear if it is a highlight and NOT a Safe Zone (ID 2) or Freeze Area (ID 5) if l2_item != -1 and l2_item != 2 and l2_item != 5: enhanced_gridmap.set_cell_item(l2_pos, -1) highlighted_cells.clear() if main and main.ui_manager.playerboard_ui: for i in range(main.ui_manager.playerboard_ui.get_child_count()): var slot = main.ui_manager.playerboard_ui.get_child(i) for child in slot.get_children(): child.hide() func clear_playerboard_highlights(): # Never allow bots to clear highlights for human players if player.is_bot or player.is_in_group("Bots"): return if not player.is_multiplayer_authority(): return var main = player.get_tree().get_root().get_node_or_null("Main") if main and main.ui_manager.playerboard_ui: for i in range(main.ui_manager.playerboard_ui.get_child_count()): var slot = main.ui_manager.playerboard_ui.get_child(i) if slot.get_child_count() > 0: slot.get_child(0).hide() if slot.get_child_count() > 1: slot.get_child(1).hide() if slot.get_child_count() > 2: slot.get_child(2).hide() highlighted_cells.clear()