extends Node # PlayerActionManager - Handles action points, highlights, and visual feedback var player: Node3D var enhanced_gridmap: Node var highlighted_cells = [] func initialize(p_player: Node3D, p_gridmap: Node): player = p_player enhanced_gridmap = p_gridmap # ============================================================================= # Action Point Management # ============================================================================= func consume_action_points(points: int): if not is_instance_valid(player) or not player.is_multiplayer_authority(): return var main = player.get_tree().get_root().get_node_or_null("Main") if not main: return # Non-turn-based mode: unlimited action points for real-time fast-paced gameplay if not TurnManager.turn_based_mode: after_action_completed() return # Turn-based mode: consume action points normally player.action_points -= points if player.action_points <= 0: main.request_next_turn() 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 # Bots are owned by the host (authority match) but shouldn't trigger UI updates if multiplayer.get_unique_id() == player.get_multiplayer_authority(): if not player.is_bot and not player.is_in_group("Bots"): var main = player.get_tree().get_root().get_node_or_null("Main") if main: main.ui_manager.update_button_states() main.ui_manager.update_playerboard_ui() # Add this line to sync all boards main.update_all_players_boards() # Sync playerboard (Bots DO need to sync their board logic, just not update local UI) if player.is_multiplayer_authority(): var main = player.get_tree().get_root().get_node_or_null("Main") if main: main.rpc("sync_playerboard", player.get_multiplayer_authority(), player.playerboard) player._is_processing_action = false # ============================================================================= # Highlight Operations # ============================================================================= func highlight_cells_if_authorized(cells_to_highlight: Array): if not player.is_multiplayer_authority() or player.is_bot or player.is_in_group("Bots"): return clear_highlights() for cell in cells_to_highlight: highlighted_cells.append(cell) enhanced_gridmap.set_cell_item( Vector3i(cell.x, 0, cell.y), enhanced_gridmap.hover_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) enhanced_gridmap.set_cell_item(Vector3i(player.current_position.x, 0, 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) enhanced_gridmap.set_cell_item(Vector3i(cell_pos.x, 0, 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) enhanced_gridmap.set_cell_item(Vector3i(player.current_position.x, 0, 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) enhanced_gridmap.set_cell_item(Vector3i(cell_pos.x, 0, 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 highlight_valid_obstacle_cells(): if not player.is_multiplayer_authority() or player.is_bot or player.is_in_group("Bots"): return clear_highlights() var cells_to_highlight = [] # Highlight all empty cells on the grid except those occupied by players or obstacles for x in range(enhanced_gridmap.columns): for z in range(enhanced_gridmap.rows): var pos = Vector2i(x, z) var cell = Vector3i(x, 3, z) # Check floor 3 for occupancy var occupied_by_player = false var occupied_by_obstacle = false # Check if cell is occupied by any player for p in player.get_tree().get_nodes_in_group("Players"): if p.current_position == pos: occupied_by_player = true break # Check if cell is occupied by an obstacle if enhanced_gridmap.get_cell_item(cell) in enhanced_gridmap.obstacle_items: occupied_by_obstacle = true # Only add to highlights if not occupied by player or obstacle if not occupied_by_player and not occupied_by_obstacle: cells_to_highlight.append(pos) highlight_cells_if_authorized(cells_to_highlight) 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 # Store the current action state before clearing var main = player.get_tree().get_root().get_node_or_null("Main") var current_state = main.ui_manager.current_action_state if main else null for cell in highlighted_cells: if cell is Vector2i: enhanced_gridmap.set_cell_item(Vector3i(cell.x, 0, cell.y), enhanced_gridmap.normal_items[0]) 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() # Restore highlights based on current action state if main and current_state == main.ui_manager.ActionState.MOVING and player.is_my_turn and current_state != main.ui_manager.ActionState.PLACING_OBSTACLE: player.highlight_movement_range() 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()