update
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
extends ActionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
var source_slot = blackboard.get_value("source_slot")
|
||||
var target_slot = blackboard.get_value("target_slot")
|
||||
|
||||
if source_slot == -1 or target_slot == -1:
|
||||
return FAILURE
|
||||
|
||||
# Verify conditions are still valid
|
||||
if actor.action_points < 2 or actor.playerboard[source_slot] == -1:
|
||||
return FAILURE
|
||||
|
||||
if actor.playerboard[target_slot] != -1:
|
||||
return FAILURE
|
||||
|
||||
# Do the arrangement
|
||||
if actor.is_multiplayer_authority():
|
||||
var item = actor.playerboard[source_slot]
|
||||
actor.playerboard[target_slot] = item
|
||||
actor.playerboard[source_slot] = -1
|
||||
actor.rpc("sync_playerboard", actor.playerboard)
|
||||
actor.has_performed_action = true
|
||||
actor.action_points -= 2
|
||||
|
||||
return SUCCESS
|
||||
@@ -0,0 +1,27 @@
|
||||
extends ActionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
var grab_position = blackboard.get_value("grab_position")
|
||||
if not grab_position:
|
||||
return FAILURE
|
||||
|
||||
# Find empty slot in playerboard
|
||||
var empty_slot = actor.playerboard.find(-1)
|
||||
if empty_slot == -1:
|
||||
return FAILURE
|
||||
|
||||
# Get item at position
|
||||
var cell = Vector3i(grab_position.x, 1, grab_position.y)
|
||||
var item = actor.enhanced_gridmap.get_cell_item(cell)
|
||||
if item == -1 or actor.action_points <= 0:
|
||||
return FAILURE
|
||||
|
||||
# Grab the item
|
||||
if actor.is_multiplayer_authority():
|
||||
actor.playerboard[empty_slot] = item
|
||||
actor.rpc("sync_grid_item", cell.x, cell.y, cell.z, -1)
|
||||
actor.rpc("sync_playerboard", actor.playerboard)
|
||||
actor.has_performed_action = true
|
||||
actor.action_points -= 1
|
||||
|
||||
return SUCCESS
|
||||
@@ -0,0 +1,44 @@
|
||||
extends ActionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
var target_pos = blackboard.get_value("move_target")
|
||||
if not target_pos:
|
||||
return FAILURE
|
||||
|
||||
if actor.action_points <= 0:
|
||||
return FAILURE
|
||||
|
||||
# Verify target is still valid
|
||||
if not actor.is_within_movement_range(target_pos):
|
||||
return FAILURE
|
||||
|
||||
if actor.is_position_occupied(target_pos):
|
||||
return FAILURE
|
||||
|
||||
var cell_item = actor.enhanced_gridmap.get_cell_item(Vector3i(target_pos.x, 0, target_pos.y))
|
||||
if cell_item == -1 or cell_item in actor.enhanced_gridmap.non_walkable_items:
|
||||
return FAILURE
|
||||
|
||||
# Move to position
|
||||
actor.rotate_towards_target(target_pos)
|
||||
var path = actor.enhanced_gridmap.find_path(Vector2(actor.current_position), Vector2(target_pos))
|
||||
|
||||
if path.size() <= 1:
|
||||
return FAILURE
|
||||
|
||||
# Verify path is clear
|
||||
var valid_path = true
|
||||
for point in path.slice(1):
|
||||
if actor.is_position_occupied(Vector2i(point.x, point.y)):
|
||||
valid_path = false
|
||||
break
|
||||
|
||||
if valid_path:
|
||||
if actor.is_multiplayer_authority():
|
||||
path.pop_front()
|
||||
actor.rpc("start_movement_along_path", path)
|
||||
actor.action_points -= 1
|
||||
actor.clear_highlights()
|
||||
return SUCCESS
|
||||
|
||||
return FAILURE
|
||||
@@ -0,0 +1,28 @@
|
||||
extends ActionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
var put_position = blackboard.get_value("put_position")
|
||||
var put_slot = blackboard.get_value("put_slot")
|
||||
|
||||
if not put_position or put_slot == -1:
|
||||
return FAILURE
|
||||
|
||||
# Check if we still have the item and AP
|
||||
if actor.action_points <= 0 or actor.playerboard[put_slot] == -1:
|
||||
return FAILURE
|
||||
|
||||
# Check if target position is still empty
|
||||
var cell = Vector3i(put_position.x, 1, put_position.y)
|
||||
if actor.enhanced_gridmap.get_cell_item(cell) != -1:
|
||||
return FAILURE
|
||||
|
||||
# Put the item
|
||||
var item = actor.playerboard[put_slot]
|
||||
if actor.is_multiplayer_authority():
|
||||
actor.rpc("sync_grid_item", cell.x, cell.y, cell.z, item)
|
||||
actor.playerboard[put_slot] = -1
|
||||
actor.rpc("sync_playerboard", actor.playerboard)
|
||||
actor.has_performed_action = true
|
||||
actor.action_points -= 1
|
||||
|
||||
return SUCCESS
|
||||
@@ -0,0 +1,11 @@
|
||||
class_name GrabAction extends ActionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
var grab_position = blackboard.get_value("grab_position")
|
||||
if not grab_position:
|
||||
return FAILURE
|
||||
|
||||
if actor.grab_item(grab_position):
|
||||
return SUCCESS
|
||||
|
||||
return FAILURE
|
||||
@@ -0,0 +1,5 @@
|
||||
extends SequenceComposite
|
||||
|
||||
func _ready():
|
||||
add_child(ArrangeCondition.new())
|
||||
add_child(ArrangeAction.new())
|
||||
@@ -0,0 +1,22 @@
|
||||
class_name ArrangeAction extends ActionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
var source_slot = blackboard.get_value("source_slot", -1)
|
||||
var target_slot = blackboard.get_value("target_slot", -1)
|
||||
|
||||
if source_slot == -1 or target_slot == -1:
|
||||
return FAILURE
|
||||
|
||||
if actor.action_points < 2:
|
||||
return FAILURE
|
||||
|
||||
var selected_item = actor.playerboard[source_slot]
|
||||
actor.playerboard[target_slot] = selected_item
|
||||
actor.playerboard[source_slot] = -1
|
||||
|
||||
if actor.is_multiplayer_authority():
|
||||
actor.rpc("sync_playerboard", actor.playerboard)
|
||||
actor.action_points -= 2
|
||||
actor.has_performed_action = true
|
||||
|
||||
return SUCCESS
|
||||
@@ -0,0 +1,18 @@
|
||||
class_name ArrangeCondition extends ConditionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
# Check we have enough action points
|
||||
if actor.action_points < 2:
|
||||
return FAILURE
|
||||
|
||||
# Check for items that can be arranged
|
||||
for i in range(actor.playerboard.size()):
|
||||
if actor.playerboard[i] != -1:
|
||||
var neighbors = actor.get_adjacent_playerboard_slots(i)
|
||||
for adj_slot in neighbors:
|
||||
if actor.playerboard[adj_slot] == -1 and actor.playerboard[i] in actor.goals:
|
||||
blackboard.set_value("source_slot", i)
|
||||
blackboard.set_value("target_slot", adj_slot)
|
||||
return SUCCESS
|
||||
|
||||
return FAILURE
|
||||
@@ -0,0 +1,16 @@
|
||||
extends ConditionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
if actor.action_points < 2:
|
||||
return FAILURE
|
||||
|
||||
# Look for items that match goals
|
||||
for i in range(actor.playerboard.size()):
|
||||
if actor.playerboard[i] in actor.goals:
|
||||
var neighbors = actor.get_adjacent_playerboard_slots(i)
|
||||
for adj_slot in neighbors:
|
||||
if actor.playerboard[adj_slot] == -1:
|
||||
blackboard.set_value("source_slot", i)
|
||||
blackboard.set_value("target_slot", adj_slot)
|
||||
return SUCCESS
|
||||
return FAILURE
|
||||
@@ -0,0 +1,25 @@
|
||||
extends ConditionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
if actor.playerboard_is_full():
|
||||
return FAILURE
|
||||
|
||||
# Check current position
|
||||
var current_cell = Vector3i(actor.current_position.x, 1, actor.current_position.y)
|
||||
var item = actor.enhanced_gridmap.get_cell_item(current_cell)
|
||||
if item in actor.goals:
|
||||
blackboard.set_value("grab_position", actor.current_position)
|
||||
return SUCCESS
|
||||
|
||||
# Check adjacent cells
|
||||
var neighbors = actor.enhanced_gridmap.get_neighbors(actor.current_position, 0)
|
||||
for neighbor in neighbors:
|
||||
if not neighbor.is_walkable:
|
||||
continue
|
||||
var cell = Vector3i(neighbor.position.x, 1, neighbor.position.y)
|
||||
item = actor.enhanced_gridmap.get_cell_item(cell)
|
||||
if item in actor.goals:
|
||||
blackboard.set_value("grab_position", neighbor.position)
|
||||
return SUCCESS
|
||||
|
||||
return FAILURE
|
||||
@@ -0,0 +1,31 @@
|
||||
extends ConditionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
# Find an item in playerboard that matches goals
|
||||
var put_slot = -1
|
||||
for i in range(actor.playerboard.size()):
|
||||
if actor.playerboard[i] in actor.goals:
|
||||
put_slot = i
|
||||
break
|
||||
|
||||
if put_slot == -1:
|
||||
return FAILURE
|
||||
|
||||
# Find empty adjacent cell
|
||||
var current_cell = Vector3i(actor.current_position.x, 1, actor.current_position.y)
|
||||
if actor.enhanced_gridmap.get_cell_item(current_cell) == -1:
|
||||
blackboard.set_value("put_position", actor.current_position)
|
||||
blackboard.set_value("put_slot", put_slot)
|
||||
return SUCCESS
|
||||
|
||||
var neighbors = actor.enhanced_gridmap.get_neighbors(actor.current_position, 0)
|
||||
for neighbor in neighbors:
|
||||
if not neighbor.is_walkable:
|
||||
continue
|
||||
var cell = Vector3i(neighbor.position.x, 1, neighbor.position.y)
|
||||
if actor.enhanced_gridmap.get_cell_item(cell) == -1:
|
||||
blackboard.set_value("put_position", neighbor.position)
|
||||
blackboard.set_value("put_slot", put_slot)
|
||||
return SUCCESS
|
||||
|
||||
return FAILURE
|
||||
@@ -0,0 +1,21 @@
|
||||
class_name GrabCondition extends ConditionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
if actor.action_points < 1 or actor.playerboard_is_full():
|
||||
return FAILURE
|
||||
|
||||
# Check current position first
|
||||
var current_cell = Vector3i(actor.current_position.x, 1, actor.current_position.y)
|
||||
if actor.enhanced_gridmap.get_cell_item(current_cell) in actor.goals:
|
||||
blackboard.set_value("grab_position", actor.current_position)
|
||||
return SUCCESS
|
||||
|
||||
# Check adjacent cells
|
||||
var neighbors = actor.enhanced_gridmap.get_neighbors(actor.current_position, 1)
|
||||
for neighbor in neighbors:
|
||||
var cell = Vector3i(neighbor.position.x, 1, neighbor.position.y)
|
||||
if actor.enhanced_gridmap.get_cell_item(cell) in actor.goals:
|
||||
blackboard.set_value("grab_position", neighbor.position)
|
||||
return SUCCESS
|
||||
|
||||
return FAILURE
|
||||
@@ -0,0 +1,6 @@
|
||||
extends ConditionLeaf
|
||||
|
||||
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||
if actor.action_points >= 1:
|
||||
return SUCCESS
|
||||
return FAILURE
|
||||
@@ -0,0 +1,85 @@
|
||||
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
|
||||
@@ -0,0 +1,5 @@
|
||||
class_name GrabSequence extends SequenceComposite
|
||||
|
||||
func _ready():
|
||||
add_child(GrabCondition.new())
|
||||
add_child(GrabAction.new())
|
||||
@@ -0,0 +1,5 @@
|
||||
class_name MoveSequence extends SequenceComposite
|
||||
|
||||
func _ready():
|
||||
add_child(MoveCondition.new())
|
||||
add_child(MoveAction.new())
|
||||
@@ -0,0 +1,5 @@
|
||||
class_name PutSequence extends SequenceComposite
|
||||
|
||||
func _ready():
|
||||
add_child(PutCondition.new())
|
||||
add_child(PutAction.new())
|
||||
@@ -0,0 +1,120 @@
|
||||
@tool
|
||||
extends BeehaveTree
|
||||
|
||||
func _ready():
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
# Only setup for bots
|
||||
if not get_parent().is_in_group("Bots"):
|
||||
return
|
||||
|
||||
# Create root selector
|
||||
var selector = SelectorComposite.new()
|
||||
add_child(selector)
|
||||
|
||||
# Add sequences
|
||||
selector.add_child(create_arrange_sequence())
|
||||
selector.add_child(create_grab_sequence())
|
||||
selector.add_child(create_put_sequence())
|
||||
selector.add_child(create_move_sequence())
|
||||
|
||||
func create_arrange_sequence() -> SequenceComposite:
|
||||
var sequence = SequenceComposite.new()
|
||||
sequence.name = "ArrangeSequence"
|
||||
|
||||
# Has enough action points?
|
||||
var check_ap = ConditionLeaf.new()
|
||||
check_ap.name = "HasEnoughAP"
|
||||
check_ap.set_script(preload("res://scripts/behaviors/conditions/has_ap.gd"))
|
||||
|
||||
# Can arrange items?
|
||||
var can_arrange = ConditionLeaf.new()
|
||||
can_arrange.name = "CanArrange"
|
||||
can_arrange.set_script(preload("res://scripts/behaviors/conditions/can_arrange.gd"))
|
||||
|
||||
# Do arrange action
|
||||
var do_arrange = ActionLeaf.new()
|
||||
do_arrange.name = "DoArrange"
|
||||
do_arrange.set_script(preload("res://scripts/behaviors/actions/do_arrange.gd"))
|
||||
|
||||
sequence.add_child(check_ap)
|
||||
sequence.add_child(can_arrange)
|
||||
sequence.add_child(do_arrange)
|
||||
|
||||
return sequence
|
||||
|
||||
func create_grab_sequence() -> SequenceComposite:
|
||||
var sequence = SequenceComposite.new()
|
||||
sequence.name = "GrabSequence"
|
||||
|
||||
# Has enough action points?
|
||||
var check_ap = ConditionLeaf.new()
|
||||
check_ap.name = "HasAP"
|
||||
check_ap.set_script(preload("res://scripts/behaviors/conditions/has_ap.gd"))
|
||||
|
||||
# Can grab item?
|
||||
var can_grab = ConditionLeaf.new()
|
||||
can_grab.name = "CanGrab"
|
||||
can_grab.set_script(preload("res://scripts/behaviors/conditions/can_grab.gd"))
|
||||
|
||||
# Do grab action
|
||||
var do_grab = ActionLeaf.new()
|
||||
do_grab.name = "DoGrab"
|
||||
do_grab.set_script(preload("res://scripts/behaviors/actions/do_grab.gd"))
|
||||
|
||||
sequence.add_child(check_ap)
|
||||
sequence.add_child(can_grab)
|
||||
sequence.add_child(do_grab)
|
||||
|
||||
return sequence
|
||||
|
||||
func create_put_sequence() -> SequenceComposite:
|
||||
var sequence = SequenceComposite.new()
|
||||
sequence.name = "PutSequence"
|
||||
|
||||
# Has enough action points?
|
||||
var check_ap = ConditionLeaf.new()
|
||||
check_ap.name = "HasAP"
|
||||
check_ap.set_script(preload("res://scripts/behaviors/conditions/has_ap.gd"))
|
||||
|
||||
# Can put item?
|
||||
var can_put = ConditionLeaf.new()
|
||||
can_put.name = "CanPut"
|
||||
can_put.set_script(preload("res://scripts/behaviors/conditions/can_put.gd"))
|
||||
|
||||
# Do put action
|
||||
var do_put = ActionLeaf.new()
|
||||
do_put.name = "DoPut"
|
||||
do_put.set_script(preload("res://scripts/behaviors/actions/do_put.gd"))
|
||||
|
||||
sequence.add_child(check_ap)
|
||||
sequence.add_child(can_put)
|
||||
sequence.add_child(do_put)
|
||||
|
||||
return sequence
|
||||
|
||||
func create_move_sequence() -> SequenceComposite:
|
||||
var sequence = SequenceComposite.new()
|
||||
sequence.name = "MoveSequence"
|
||||
|
||||
# Has enough action points?
|
||||
var check_ap = ConditionLeaf.new()
|
||||
check_ap.name = "HasAP"
|
||||
check_ap.set_script(preload("res://scripts/behaviors/conditions/has_ap.gd"))
|
||||
|
||||
# Should move?
|
||||
var should_move = ConditionLeaf.new()
|
||||
should_move.name = "ShouldMove"
|
||||
should_move.set_script(preload("res://scripts/behaviors/conditions/should_move.gd"))
|
||||
|
||||
# Do move action
|
||||
var do_move = ActionLeaf.new()
|
||||
do_move.name = "DoMove"
|
||||
do_move.set_script(preload("res://scripts/behaviors/actions/do_move.gd"))
|
||||
|
||||
sequence.add_child(check_ap)
|
||||
sequence.add_child(should_move)
|
||||
sequence.add_child(do_move)
|
||||
|
||||
return sequence
|
||||
Reference in New Issue
Block a user