class_name Task extends Node enum {FAILURE = -1, SUCCESS = 1, RUNNING = 0, SUCCESS_STOP = 2} static var print_behavior_tree_evaluation: bool = false # var status: int = FAILURE var status_reason: String = "" var tilemap_types: TileMapTileTypes = TileMapTileTypes.new() func _ready() -> void: for c in get_children(): if not c is Task: push_error("Child is not a task: " + c.name + " in " + name) return func internal_run(blackboard: Dictionary) -> void: blackboard["current_task"] = self var running_child: Task = find_running_child() var extra_string: String = "" if running_child != null: extra_string = running_child.name if print_behavior_tree_evaluation: print(" -> ", human_readable(extra_string)) run(blackboard) if print_behavior_tree_evaluation: print(" <- ", human_readable(extra_string)) func find_running_child() -> Task: for c in get_children(): if c.status == RUNNING: return c return null func run_child(blackboard: Dictionary, p_child: Task) -> void: p_child.internal_run(blackboard) if p_child.status != RUNNING: status = RUNNING func slice_at_child(start_child: Task) -> Array: var children: Array[Node] = get_children() if start_child == null: return children var start_index: int = children.find(start_child) if start_index == -1: return children return children.slice(start_index, children.size()) func run(blackboard: Dictionary) -> void: pass func cancel(blackboard: Dictionary): pass func get_first_child() -> Task: if get_child_count() == 0: push_error("Task does not have any children: " + name) return null return get_children()[0] as Task func human_readable(addon: String = "") -> String: var clear_status: String = "UNKNOWN" if status == FAILURE: clear_status = "FAILURE" elif status == SUCCESS: clear_status = "SUCCESS" elif status == RUNNING: clear_status = "RUNNING" elif status == SUCCESS_STOP: clear_status = "SUCCESS_STOP" var ret: String = name; if addon != "": ret += " " + addon if status_reason != "": ret += " [" + clear_status + ", " + status_reason + "]" else: ret += " [" + clear_status + "]" return ret # SECTION: utility func find_closest_item(blackboard: Dictionary, item_types: Array[Vector2i], memory_key: String, max_distance: int = -1) -> Dictionary: var world: World = blackboard["world"] var player: PlayerManager = blackboard["player"] var navigation: TilemapNavigation = blackboard["navigation"] var result: Dictionary = {"status": FAILURE, "status_reason": "", "closest_item": null} var items: Array[Vector2i] = world.tilemap_interactive.get_cells_by_type_collection( item_types, player.board_position, max_distance if max_distance > -1 else player.view_distance) if len(items) == 0: result.status_reason = "No items of type " + str(item_types) + " found" return result var closest_item: Vector2i = navigation.manhattan_distance_closest(items, player.board_position) player.player_memory[memory_key] = closest_item StepVisualization.add_line_tileset(player.board_position, closest_item, StepVisualization.LineType.SEARCH_SELECTED) if closest_item == tilemap_types.NO_TILE_FOUND: result.status_reason = "No closest item of type " + str(item_types) + " found" return result result.status = SUCCESS result.closest_item = closest_item return result