extends Node3D @export var is_bot: bool = false @export var enhanced_gridmap_path: NodePath = "/root/Main/EnhancedGridMap" var enhanced_gridmap: EnhancedGridMap @export var current_position: Vector2i var is_player_moving: bool = false @export var cell_size: Vector3 = Vector3(2, 2, 2) @export var cell_offset: Vector3 = Vector3(0, 0, 0) @export var goals: Array[int] = [0,0,0,0,0,0,0,0,0] @export var playerboard: Array[int] = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] var has_performed_action: bool = false var selected_gridmap_position = Vector2i(-1, -1) var selected_playerboard_slot = -1 var targeted_playerboard_slot = -1 var action_points: int = 2 var target_rotation: float = 0.0 var rotation_speed: float = 10.0 @export var movement_range: int = 1 @export var use_diagonal_movement: bool = false: set(value): use_diagonal_movement = value if enhanced_gridmap: enhanced_gridmap.set_diagonal_movement(value) @export var is_my_turn: bool = false: set(value): is_my_turn = value if is_my_turn and is_multiplayer_authority(): rpc("display_message", "It's your turn!") @export var has_moved_this_turn = false var highlighted_cells = [] func _ready(): name = str(get_multiplayer_authority()) $Name.text = str(name) # More robust way to get the main scene var main_scene = get_tree().get_root().get_node_or_null("Main") if not main_scene: push_error("Main scene not found") return # Ensure proper initialization order enhanced_gridmap = get_node(enhanced_gridmap_path) if main_scene: enhanced_gridmap = main_scene.get_node("EnhancedGridMap") # Initialize behavior tree for bots var behavior_tree = $BehaviorTree # Early setup for bots if is_bot or is_in_group("Bots"): # Set Input process to false for bots immediately set_process_input(false) set_process_unhandled_input(false) # Disable visual highlights for bots highlighted_cells.clear() if behavior_tree: behavior_tree.enabled = is_multiplayer_authority() behavior_tree.actor = self rpc("sync_bot_status", true) # Initialize bot-specific components if enhanced_gridmap: current_position = find_valid_starting_position() update_player_position(current_position) append_random_goals() playerboard.resize(25) playerboard.fill(-1) return # Rest of initialization (only for human players) if enhanced_gridmap: enhanced_gridmap.initialize_astar() enhanced_gridmap.set_diagonal_movement(use_diagonal_movement) current_position = find_valid_starting_position() update_player_position(current_position) append_random_goals() playerboard.resize(25) playerboard.fill(-1) @rpc("any_peer", "call_local") func sync_bot_status(is_bot_status: bool): is_bot = is_bot_status if is_bot: add_to_group("Bots", true) set_process_input(false) set_process_unhandled_input(false) # Clear any existing highlights highlighted_cells.clear() #clear_highlights() #clear_playerboard_highlights() var behavior_tree = get_node_or_null("BehaviorTree") if behavior_tree: behavior_tree.enabled = is_multiplayer_authority() behavior_tree.actor = self if not is_multiplayer_authority(): behavior_tree.set_physics_process(false) behavior_tree.set_process(false) func _physics_process(_delta): if is_multiplayer_authority(): rpc("remote_set_position", global_position) func _unhandled_input(event): if is_bot or is_in_group("Bots"): set_process_unhandled_input(false) set_process_input(false) return # Use get_node_or_null for safer node access var main = get_tree().get_root().get_node_or_null("Main") if not main: return if not is_multiplayer_authority() or (main.turn_based_mode and (not is_my_turn or is_player_moving)): return if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: if is_bot or is_in_group("Bots"): set_process_unhandled_input(false) set_process_input(false) return var camera = get_viewport().get_camera_3d() var from = camera.project_ray_origin(event.position) var to = from + camera.project_ray_normal(event.position) * 1000 var click_position = raycast_to_grid(from, to) if click_position != Vector2i(-1, -1): handle_grid_click(click_position) func _on_slot_gui_input(event, slot_index, slot_ui) -> int: if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: var main = get_tree().get_root().get_node_or_null("Main") if main.current_action_state == main.ActionState.ARRANGING: if selected_playerboard_slot == -1: select_playerboard_slot(slot_index) return slot_index else: if selected_playerboard_slot == slot_index: deselect_playerboard_slot() return slot_index elif can_move_to_target_playerboard_slot(): target_playerboard_slot(slot_index) main.emit_signal("can_move_item", true) return slot_index else: return -1 return -1 func handle_grid_click(grid_position: Vector2i): if is_bot or is_in_group("Bots"): return var main = get_tree().get_root().get_node_or_null("Main") if not main: push_error("Main node not found") return match main.current_action_state: main.ActionState.MOVING: if grid_position in highlighted_cells: move_player_to_clicked_position(grid_position) main.ActionState.GRABBING: if grid_position in highlighted_cells or grid_position == current_position: grab_item(grid_position) main.ActionState.PUTTING: if grid_position in highlighted_cells and selected_playerboard_slot != -1: put_item(grid_position) main.ActionState.RANDOMIZING: if grid_position in highlighted_cells: main.randomize_item_at_position(grid_position) func is_position_occupied(pos: Vector2i) -> bool: for player in get_tree().get_nodes_in_group("Players"): if player != self and player.current_position == pos: return true return false func find_valid_starting_position() -> Vector2i: var rng = RandomNumberGenerator.new() rng.randomize() var max_attempts = 100 var attempts = 0 while attempts < max_attempts: var x = rng.randi_range(0, enhanced_gridmap.columns - 1) var y = rng.randi_range(0, enhanced_gridmap.rows - 1) var pos = Vector2i(x, y) if not is_position_occupied(pos): return pos attempts += 1 return Vector2i.ZERO func find_random_valid_position_in_range() -> Vector2i: var rng = RandomNumberGenerator.new() rng.randomize() var valid_positions = [] for x in range(max(0, current_position.x - movement_range), min(enhanced_gridmap.columns, current_position.x + movement_range + 1)): for z in range(max(0, current_position.y - movement_range), min(enhanced_gridmap.rows, current_position.y + movement_range + 1)): var pos = Vector2i(x, z) if pos != current_position and is_within_movement_range(pos): var cell_item = enhanced_gridmap.get_cell_item(Vector3i(x, 0, z)) if cell_item != -1 and not (cell_item in enhanced_gridmap.non_walkable_items) and not is_position_occupied(pos): valid_positions.append(pos) if valid_positions.size() > 0: return valid_positions[rng.randi() % valid_positions.size()] return current_position func raycast_to_grid(from: Vector3, to: Vector3) -> Vector2i: var plane = Plane(Vector3.UP, cell_offset.y) var intersection = plane.intersects_ray(from, to - from) if intersection: var adjusted_intersection = intersection - cell_offset var grid_position = Vector2i( floor(adjusted_intersection.x / cell_size.x), floor(adjusted_intersection.z / cell_size.z) ) if grid_position.x >= 0 and grid_position.x < enhanced_gridmap.columns and \ grid_position.y >= 0 and grid_position.y < enhanced_gridmap.rows: return grid_position return Vector2i(-1, -1) func is_within_movement_range(target_position: Vector2i) -> bool: var distance: int if use_diagonal_movement: distance = max(abs(target_position.x - current_position.x), abs(target_position.y - current_position.y)) else: distance = abs(target_position.x - current_position.x) + abs(target_position.y - current_position.y) return distance <= movement_range func move_player_to_clicked_position(grid_position: Vector2i): if not is_multiplayer_authority() or is_player_moving or action_points <= 0: return var main = get_tree().get_root().get_node_or_null("Main") if not main or main.current_action_state != main.ActionState.MOVING or not grid_position in highlighted_cells: return if not is_within_movement_range(grid_position): return var cell_item = enhanced_gridmap.get_cell_item(Vector3i(grid_position.x, 0, grid_position.y)) if cell_item in enhanced_gridmap.non_walkable_items or is_position_occupied(grid_position): return rotate_towards_target(grid_position) var path = enhanced_gridmap.find_path(Vector2(current_position), Vector2(grid_position)) if path.size() <= 1: return var valid_path = true for point in path.slice(1): if is_position_occupied(Vector2i(point.x, point.y)): valid_path = false break if valid_path: path.pop_front() rpc("start_movement_along_path", path) action_points -= 1 if not is_bot: clear_highlights() else: print("Path is blocked by other players") @rpc("any_peer", "call_local") func start_movement_along_path(path: Array, clear_visual: bool = true): is_player_moving = true var tween = create_tween() tween.set_trans(Tween.TRANS_CUBIC) tween.set_ease(Tween.EASE_IN_OUT) for point in path: tween.tween_property(self, "position", grid_to_world(Vector2i(point.x, point.y)), 0.5) tween.tween_callback(func(): current_position = Vector2i(path[-1].x, path[-1].y) is_player_moving = false if clear_visual: enhanced_gridmap.clear_path_visualization() has_moved_this_turn = path.size() <= movement_range var main = get_tree().get_root().get_node_or_null("Main") main.set_action_state(main.ActionState.NONE) if main.turn_based_mode: end_turn() _after_action_completed() ) func update_player_position(grid_position: Vector2i): position = grid_to_world(grid_position) func grid_to_world(grid_position: Vector2i) -> Vector3: var world_position = Vector3( grid_position.x * cell_size.x + cell_size.x * 0.5, cell_size.y, grid_position.y * cell_size.z + cell_size.z * 0.5 ) + cell_offset return world_position func start_turn(): action_points = 2 has_moved_this_turn = false has_performed_action = false is_my_turn = true if is_multiplayer_authority(): rpc("display_message", "It's your turn!") _after_action_completed() func end_turn(): is_my_turn = false has_moved_this_turn = false if is_multiplayer_authority(): get_tree().get_root().get_node_or_null("Main").request_next_turn() @rpc("any_peer", "call_local", "unreliable") func remote_set_position(authority_position): global_position = authority_position @rpc("any_peer", "call_local") func display_message(message): $Bubble.show() $Bubble/Message.show() $Bubble/Message.text = str(message) await get_tree().create_timer(3).timeout $Bubble.hide() $Bubble/Message.hide() func initialize_random_goals(_size:int, min_value:int, max_value:int, null_count:float) -> Array[int]: goals.clear() var rng = RandomNumberGenerator.new() rng.randomize() var result : Array[int] = [] var null_val = 0 var max_nulls = 3 const SPECIAL_VALUES = {1: 7, 2: 8, 3: 9, 4: 10} for i in range(_size): if null_val < max_nulls and rng.randf() < null_count: result.append(-1) null_val += 1 else: var val = rng.randi_range(min_value, max_value) result.append(val if not val in SPECIAL_VALUES else SPECIAL_VALUES[val]) return result func append_random_goals(): goals.append_array(initialize_random_goals(9, 7, 10, 1.0)) if is_multiplayer_authority(): rpc("sync_goals", goals) func grab_item(grid_position: Vector2i = current_position) -> bool: if not enhanced_gridmap or action_points <= 0: return false var cell = Vector3i(grid_position.x, 1, grid_position.y) var item = enhanced_gridmap.get_cell_item(cell) if grid_position != current_position: var neighbors = enhanced_gridmap.get_neighbors(current_position, 0) var is_adjacent = false for neighbor in neighbors: if neighbor.position == grid_position: is_adjacent = true break if not is_adjacent: return false if item == -1: return false if is_in_group("Bots") or is_bot: var empty_slot = playerboard.find(-1) if empty_slot == -1: return false if is_multiplayer_authority(): playerboard[empty_slot] = item rpc("sync_grid_item", cell.x, cell.y, cell.z, -1) rpc("sync_playerboard", playerboard) has_performed_action = true consume_action_points(1) clear_playerboard_highlights() _after_action_completed() return true else: var main = get_tree().get_root().get_node_or_null("Main") if main: selected_gridmap_position = grid_position clear_highlights() clear_playerboard_highlights() for i in range(playerboard.size()): if playerboard[i] == -1: var slot = main.playerboard_ui.get_child(i) if slot.get_child_count() > 0: slot.get_child(0).show() highlighted_cells.append(i) return true return false func put_item(grid_position: Vector2i = current_position) -> bool: if not enhanced_gridmap or action_points <= 0 or selected_playerboard_slot == -1: return false var cell = Vector3i(grid_position.x, 1, grid_position.y) if enhanced_gridmap.get_cell_item(cell) != -1: return false # Check if position is adjacent or current position if grid_position != current_position: var is_adjacent = false var neighbors = enhanced_gridmap.get_neighbors(current_position, 0) for neighbor in neighbors: if neighbor.position == grid_position: is_adjacent = true break if not is_adjacent: return false var item = playerboard[selected_playerboard_slot] if is_multiplayer_authority(): rpc("sync_grid_item", cell.x, cell.y, cell.z, item) playerboard[selected_playerboard_slot] = -1 rpc("sync_playerboard", playerboard) has_performed_action = true consume_action_points(1) if not is_bot: clear_highlights() clear_playerboard_highlights() selected_playerboard_slot = -1 var main = get_tree().get_root().get_node_or_null("Main") if main: main.set_action_state(main.ActionState.NONE) _after_action_completed() return true func handle_put_action(): var main = get_tree().get_root().get_node_or_null("Main") if not main or action_points < 1: return if not is_bot: clear_highlights() clear_playerboard_highlights() # Highlight non-empty slots in playerboard for i in range(playerboard.size()): if playerboard[i] != -1: # Highlight occupied slots var slot = main.playerboard_ui.get_child(i) if slot.get_child_count() > 0: slot.get_child(0).show() # Show highlight for occupied slots highlighted_cells.append(i) func handle_playerboard_slot_selected(slot_index: int): var main = get_tree().get_root().get_node_or_null("Main") if not main: return if main.current_action_state == main.ActionState.PUTTING: if playerboard[slot_index] != -1: # If slot has an item selected_playerboard_slot = slot_index clear_highlights() highlight_empty_adjacent_cells() # Highlight valid put locations elif main.current_action_state == main.ActionState.GRABBING: if slot_index in highlighted_cells and playerboard[slot_index] == -1: var cell = Vector3i(selected_gridmap_position.x, 1, selected_gridmap_position.y) var item = enhanced_gridmap.get_cell_item(cell) if item != -1: if is_multiplayer_authority(): playerboard[slot_index] = item rpc("sync_grid_item", cell.x, cell.y, cell.z, -1) rpc("sync_playerboard", playerboard) has_performed_action = true consume_action_points(1) if not is_bot: clear_highlights() clear_playerboard_highlights() selected_gridmap_position = Vector2i(-1, -1) main.set_action_state(main.ActionState.NONE) _after_action_completed() # We also need to add handle_put_slot_selected: func handle_put_slot_selected(slot_index: int): var main = get_tree().get_root().get_node_or_null("Main") if not main or main.current_action_state != main.ActionState.PUTTING: return if slot_index in highlighted_cells and playerboard[slot_index] in goals: selected_playerboard_slot = slot_index clear_highlights() if not is_bot: highlight_empty_adjacent_cells() func arrange_playerboard_item(slot_index: int): if action_points < 2 or playerboard[slot_index] == -1: return var selected_item = playerboard[slot_index] var adjacent_slots = get_adjacent_playerboard_slots(slot_index) var main = get_tree().get_root().get_node_or_null("Main") if not main or not main.playerboard_ui: return # Store the selected slot selected_playerboard_slot = slot_index # Highlight selected slot var selected_slot_ui = main.playerboard_ui.get_child(slot_index) if selected_slot_ui.get_child_count() > 1: selected_slot_ui.get_child(1).show() # Highlight valid adjacent slots for adj_slot in adjacent_slots: if playerboard[adj_slot] == -1: # Only highlight empty adjacent slots var adj_slot_ui = main.playerboard_ui.get_child(adj_slot) if adj_slot_ui.get_child_count() > 2: adj_slot_ui.get_child(2).show() highlighted_cells.append(adj_slot) # Connect to slot click signals for i in range(playerboard.size()): var slot = main.playerboard_ui.get_child(i) if not slot.gui_input.is_connected(_on_slot_clicked): slot.gui_input.connect(_on_slot_clicked.bind(i)) func _on_slot_clicked(event: InputEvent, slot_index: int): if not event is InputEventMouseButton or is_bot or not event.pressed or event.button_index != MOUSE_BUTTON_LEFT: return var main = get_tree().get_root().get_node_or_null("Main") if not main or main.current_action_state != main.ActionState.ARRANGING: return if selected_playerboard_slot == -1 or slot_index == selected_playerboard_slot: return var adjacent_slots = get_adjacent_playerboard_slots(selected_playerboard_slot) if slot_index in adjacent_slots and playerboard[slot_index] == -1: # Move item to empty target slot var selected_item = playerboard[selected_playerboard_slot] playerboard[slot_index] = selected_item playerboard[selected_playerboard_slot] = -1 if is_multiplayer_authority(): rpc("sync_playerboard", playerboard) consume_action_points(2) has_performed_action = true # Clear highlights clear_highlights() clear_playerboard_highlights() # Reset selection selected_playerboard_slot = -1 # Update the visual representation main.update_playerboard_ui() main.set_action_state(main.ActionState.NONE) func is_valid_arrangement_slot(from_slot: int, to_slot: int) -> bool: var from_row = from_slot / 5 var from_col = from_slot % 5 var to_row = to_slot / 5 var to_col = to_slot % 5 var row_diff = abs(from_row - to_row) var col_diff = abs(from_col - to_col) return (row_diff == 1 and col_diff == 0) or (row_diff == 0 and col_diff == 1) func get_adjacent_playerboard_slots(slot_index) -> Array: var adjacent = [] var row = slot_index / 5 var col = slot_index % 5 if row > 0: adjacent.append(slot_index - 5) if row < 4: adjacent.append(slot_index + 5) if col > 0: adjacent.append(slot_index - 1) if col < 4: adjacent.append(slot_index + 1) return adjacent func has_item_at_current_position() -> bool: var current_cell = Vector3i(current_position.x, 1, current_position.y) return enhanced_gridmap.get_cell_item(current_cell) != -1 func has_items_in_playerboard() -> bool: return playerboard.any(func(item): return item != -1) func playerboard_is_full() -> bool: return playerboard.find(-1) == -1 func highlight_movement_range(): if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): return for x in range(enhanced_gridmap.columns): for z in range(enhanced_gridmap.rows): var test_pos = Vector2i(x, z) if is_within_movement_range(test_pos): var cell_item = enhanced_gridmap.get_cell_item(Vector3i(x, 0, z)) if cell_item != -1 and not (cell_item in enhanced_gridmap.non_walkable_items) and not is_position_occupied(test_pos): highlighted_cells.append(test_pos) enhanced_gridmap.set_cell_item(Vector3i(x, 0, z), enhanced_gridmap.hover_item) func highlight_adjacent_cells(): if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): return var current_cell = Vector3i(current_position.x, 1, current_position.y) if enhanced_gridmap.get_cell_item(current_cell) != -1: highlighted_cells.append(current_position) enhanced_gridmap.set_cell_item(Vector3i(current_position.x, 0, current_position.y), enhanced_gridmap.hover_item) var neighbors = enhanced_gridmap.get_neighbors(current_position, 0) for neighbor in neighbors: if neighbor.is_walkable: var cell_pos = neighbor.position if enhanced_gridmap.get_cell_item(Vector3i(cell_pos.x, 1, cell_pos.y)) != -1: highlighted_cells.append(cell_pos) enhanced_gridmap.set_cell_item(Vector3i(cell_pos.x, 0, cell_pos.y), enhanced_gridmap.hover_item) func highlight_empty_adjacent_cells(): if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): return # Clear previous highlights clear_highlights() # Highlight current position if empty var current_cell = Vector3i(current_position.x, 1, current_position.y) if enhanced_gridmap.get_cell_item(current_cell) == -1: highlighted_cells.append(current_position) enhanced_gridmap.set_cell_item(Vector3i(current_position.x, 0, current_position.y), enhanced_gridmap.hover_item) # Highlight empty adjacent cells var neighbors = enhanced_gridmap.get_neighbors(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) func highlight_random_valid_cells(): if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): return var valid_cells = [] for x in range(enhanced_gridmap.columns): for z in range(enhanced_gridmap.rows): var cell_pos = Vector2i(x, z) var cell_item = enhanced_gridmap.get_cell_item(Vector3i(x, 0, z)) if cell_item != -1 and not (cell_item in enhanced_gridmap.non_walkable_items): valid_cells.append(cell_pos) var rng = RandomNumberGenerator.new() rng.randomize() for _i in range(min(5, valid_cells.size())): var index = rng.randi() % valid_cells.size() var cell = valid_cells[index] highlighted_cells.append(cell) enhanced_gridmap.set_cell_item(Vector3i(cell.x, 0, cell.y), enhanced_gridmap.hover_item) valid_cells.remove_at(index) func highlight_occupied_playerboard_slots(): if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): return var main = get_tree().get_root().get_node_or_null("Main") if not main or not main.playerboard_ui: return # First reset all slots to normal for i in range(playerboard.size()): var slot = main.playerboard_ui.get_child(i) for child in slot.get_children(): child.hide() # Highlight occupied slots that match goals for i in range(playerboard.size()): if playerboard[i] in goals: var slot = main.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.update_playerboard_ui() func clear_highlights(): if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): return if not enhanced_gridmap: return 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() var main = get_tree().get_root().get_node_or_null("Main") if main and main.playerboard_ui: for i in range(main.playerboard_ui.get_child_count()): var slot = main.playerboard_ui.get_child(i) for child in slot.get_children(): child.hide() func clear_playerboard_highlights(): if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): return var main = get_tree().get_root().get_node_or_null("Main") if main and main.playerboard_ui: for i in range(main.playerboard_ui.get_child_count()): var slot = main.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() func rotate_towards_target(target_pos: Vector2i): var direction = Vector2(target_pos.x - current_position.x, target_pos.y - current_position.y).normalized() target_rotation = atan2(direction.x, direction.y) if is_multiplayer_authority(): rpc("sync_rotation", target_rotation) var tween = create_tween() tween.tween_property(self, "rotation:y", target_rotation, 0.2) # We also need to add these supporting functions: func select_playerboard_slot(slot_index: int): selected_playerboard_slot = slot_index _update_playerboard_slot_visual(slot_index) _highlight_adjacent_playerboard_slots() func deselect_playerboard_slot(): var old_selected = selected_playerboard_slot selected_playerboard_slot = -1 if old_selected != -1: _update_playerboard_slot_visual(old_selected) untarget_playerboard_slot() _highlight_adjacent_playerboard_slots() func target_playerboard_slot(slot_index: int): if targeted_playerboard_slot != -1: untarget_playerboard_slot() targeted_playerboard_slot = slot_index _update_playerboard_slot_visual(slot_index) func untarget_playerboard_slot(): if targeted_playerboard_slot != -1: var old_targeted = targeted_playerboard_slot targeted_playerboard_slot = -1 _update_playerboard_slot_visual(old_targeted) func can_move_to_target_playerboard_slot() -> bool: if selected_playerboard_slot == -1 or targeted_playerboard_slot == -1 or selected_playerboard_slot == targeted_playerboard_slot: return false var adjacent_slots = get_adjacent_playerboard_slots(selected_playerboard_slot) return adjacent_slots.has(targeted_playerboard_slot) func _update_playerboard_slot_visual(slot_index: int): var main = get_tree().get_root().get_node_or_null("Main") if not main or not main.playerboard_ui: return var slot = main.playerboard_ui.get_child(slot_index) if slot: if slot.get_child_count() > 0: slot.get_child(0).visible = slot_index == selected_playerboard_slot if slot.get_child_count() > 1: slot.get_child(1).visible = slot_index == targeted_playerboard_slot if slot.get_child_count() > 2: slot.get_child(2).visible = selected_playerboard_slot != -1 and get_adjacent_playerboard_slots(selected_playerboard_slot).has(slot_index) func _highlight_adjacent_playerboard_slots(): var main = get_tree().get_root().get_node_or_null("Main") if not main or not main.playerboard_ui: return for i in range(25): var slot = main.playerboard_ui.get_child(i) if slot.get_child_count() > 2: slot.get_child(2).hide() if selected_playerboard_slot != -1: var adjacent_slots = get_adjacent_playerboard_slots(selected_playerboard_slot) for adj_slot in adjacent_slots: var slot = main.playerboard_ui.get_child(adj_slot) if slot.get_child_count() > 2: slot.get_child(2).show() @rpc("any_peer", "call_local", "reliable") func sync_rotation(new_rotation: float): if not is_multiplayer_authority(): rotation.y = new_rotation @rpc("any_peer", "call_local", "reliable") func sync_grid_item(x: int, y: int, z: int, item: int): if enhanced_gridmap: enhanced_gridmap.set_cell_item(Vector3i(x, y, z), item) @rpc("any_peer", "call_local") func sync_goals(new_goals: Array): goals = new_goals @rpc("any_peer", "call_local") func sync_playerboard(new_playerboard: Array): playerboard = new_playerboard _after_action_completed() @rpc("any_peer", "call_local") func sync_behavior_tree(enabled: bool): var behavior_tree = $BehaviorTree if behavior_tree: behavior_tree.enabled = enabled behavior_tree.actor = self #behavior_tree.blackboard = blackboard ## Ensure blackboard has required values #blackboard.set_value("action_points", action_points) #blackboard.set_value("goals", goals) #blackboard.set_value("playerboard", playerboard) func _after_action_completed(): if multiplayer.get_unique_id() == get_multiplayer_authority(): var main = get_tree().get_root().get_node_or_null("Main") if main: # Add this condition for bots if not main.turn_based_mode and (action_points <= 0 or is_bot): action_points = 20 # For bots in non-turn-based mode, this will keep refreshing has_performed_action = false has_moved_this_turn = false # Update blackboard after action points change #var blackboard = $Blackboard #if blackboard: #blackboard.set_value("action_points", action_points) main.update_button_states() main.update_playerboard_ui() func consume_action_points(points: int): if not is_instance_valid(self) or not is_multiplayer_authority(): return var main = get_tree().get_root().get_node_or_null("Main") if not main: return # Don't consume points for bots in non-turn-based mode if is_bot and not main.turn_based_mode: _after_action_completed() return action_points -= points if action_points <= 0: if main.turn_based_mode: main.request_end_turn() else: action_points = 2 has_performed_action = false has_moved_this_turn = false rpc("display_message", "Action Points Reset!") _after_action_completed()