extends ConditionLeaf func tick(actor: Node, blackboard: Blackboard) -> int: if actor.action_points <= 0: return FAILURE var target_pos = find_best_move_position(actor) if target_pos == Vector2i(-1, -1): return FAILURE blackboard.set_value("move_target", target_pos) return SUCCESS func find_best_move_position(actor: Node) -> Vector2i: # First priority: Move towards items that match our goals var closest_goal_item = find_closest_goal_item(actor) if closest_goal_item != Vector2i(-1, -1): return get_position_towards(actor, closest_goal_item) # Second priority: Move towards empty cells if we have items if actor.has_items_in_playerboard(): var empty_pos = find_closest_empty_cell(actor) if empty_pos != Vector2i(-1, -1): return get_position_towards(actor, empty_pos) # Last resort: Random valid move return actor.find_random_valid_position_in_range() func find_closest_goal_item(actor: Node) -> Vector2i: var min_distance = 999999 var closest_pos = Vector2i(-1, -1) for x in range(actor.enhanced_gridmap.columns): for z in range(actor.enhanced_gridmap.rows): var cell = Vector3i(x, 1, z) var item = actor.enhanced_gridmap.get_cell_item(cell) if item in actor.goals: var dist = actor.current_position.distance_squared_to(Vector2i(x, z)) if dist < min_distance: min_distance = dist closest_pos = Vector2i(x, z) return closest_pos func find_closest_empty_cell(actor: Node) -> Vector2i: var min_distance = 999999 var closest_pos = Vector2i(-1, -1) for x in range(actor.enhanced_gridmap.columns): for z in range(actor.enhanced_gridmap.rows): var cell = Vector3i(x, 1, z) if actor.enhanced_gridmap.get_cell_item(cell) == -1: var dist = actor.current_position.distance_squared_to(Vector2i(x, z)) if dist < min_distance: min_distance = dist closest_pos = Vector2i(x, z) return closest_pos func get_position_towards(actor: Node, target: Vector2i) -> Vector2i: # Find a valid position within movement range that's closest to target var best_pos = Vector2i(-1, -1) var min_distance = 999999 for x in range(actor.current_position.x - actor.movement_range, actor.current_position.x + actor.movement_range + 1): for z in range(actor.current_position.y - actor.movement_range, actor.current_position.y + actor.movement_range + 1): var pos = Vector2i(x, z) if not actor.is_within_movement_range(pos): continue if actor.is_position_occupied(pos): continue var cell_item = actor.enhanced_gridmap.get_cell_item(Vector3i(x, 0, z)) if cell_item == -1 or cell_item in actor.enhanced_gridmap.non_walkable_items: continue var dist = pos.distance_squared_to(target) if dist < min_distance: min_distance = dist best_pos = pos return best_pos