86 lines
2.7 KiB
GDScript
86 lines
2.7 KiB
GDScript
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
|