diff --git a/project/assets/tilemap/tileset.tres b/project/assets/tilemap/tileset.tres index 4dfaa11..f399f2b 100644 --- a/project/assets/tilemap/tileset.tres +++ b/project/assets/tilemap/tileset.tres @@ -16,16 +16,22 @@ texture = ExtResource("1_ukrsa") 3:0/0/custom_data_0 = true 3:0/0/custom_data_2 = 1 3:0/8 = 8 +3:0/8/custom_data_0 = true 1:2/0 = 0 -3:2/next_alternative_id = 5 +3:2/next_alternative_id = 7 3:2/0 = 0 +3:2/0/custom_data_0 = true 3:2/4 = 4 0:0/0 = 0 0:0/0/custom_data_0 = true 0:0/0/custom_data_2 = 4 -3:1/next_alternative_id = 3 +3:1/next_alternative_id = 4 3:1/0 = 0 +3:1/0/custom_data_0 = true 3:1/2 = 2 +3:1/2/custom_data_0 = true +5:3/0 = 0 +5:3/0/custom_data_0 = true [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_x77e4"] texture = ExtResource("2_15xge") diff --git a/project/main-scenes/island.tscn b/project/main-scenes/island.tscn index 5f976ff..487d6a3 100644 --- a/project/main-scenes/island.tscn +++ b/project/main-scenes/island.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=26 format=4 uid="uid://b88asko1ugyd2"] +[gd_scene load_steps=35 format=4 uid="uid://b88asko1ugyd2"] [ext_resource type="Script" path="res://scripts/global/GameManager.gd" id="1_eeg2d"] [ext_resource type="Script" path="res://scripts/tilemap/World.gd" id="1_k0rw8"] @@ -25,6 +25,15 @@ [ext_resource type="Script" path="res://scripts/player/tree/impl/game/inventory/TaskPickupStick.gd" id="20_uw2ce"] [ext_resource type="Script" path="res://scripts/player/tree/impl/game/camp/TaskFindCamp.gd" id="21_cseat"] [ext_resource type="Script" path="res://scripts/player/tree/impl/game/critical_survival/TaskFindClosestWarmTile.gd" id="21_np756"] +[ext_resource type="Script" path="res://scripts/player/tree/impl/game/boat/TaskCheckBoatCompleted.gd" id="25_krdcp"] +[ext_resource type="Script" path="res://scripts/player/tree/impl/game/inventory/TaskInventoryContainsBoatPart.gd" id="25_pgpdv"] +[ext_resource type="Script" path="res://scripts/player/tree/impl/game/inventory/TaskInventoryContainsBoat.gd" id="25_vi38g"] +[ext_resource type="Script" path="res://scripts/player/tree/impl/game/boat/TaskGoToBoatLocation.gd" id="26_1saby"] +[ext_resource type="Script" path="res://scripts/player/tree/impl/game/boat/TaskDeliverBoatPart.gd" id="26_4pry2"] +[ext_resource type="Script" path="res://scripts/player/tree/impl/game/boat/TaskFindClosestBoatPart.gd" id="26_043la"] +[ext_resource type="Script" path="res://scripts/player/tree/impl/game/inventory/TaskPickupBoatPart.gd" id="26_hx2yd"] +[ext_resource type="Script" path="res://scripts/player/tree/impl/game/boat/TaskGoToBoatLeaveLocation.gd" id="26_vy1mu"] +[ext_resource type="Script" path="res://scripts/player/tree/impl/game/inventory/TaskPickupBoat.gd" id="27_tmoaj"] [node name="Island-scene" type="Node2D"] script = ExtResource("1_eeg2d") @@ -140,7 +149,7 @@ tile_map_data = PackedByteArray("AAAOAAkAAQACAAAAAAANAAkAAQACAAAAAAANAAoAAQACAAA tile_set = ExtResource("1_vlccq") [node name="InteractiveObjectsLayer" type="TileMapLayer" parent="Tileset"] -tile_map_data = PackedByteArray("AAAKABkAAQAAAAQAAAAUAAYAAQADAAEAAAAXAAYAAQADAAAAAAAJAAkAAQADAAEAAAAFAAgAAQADAAEAAAAFAAwAAQADAAEAAAAJAAwAAQADAAEAAAAYABAAAQACAAQAAAARABEAAQAGAAIAAAAQABEAAQAGAAEAAAAcABUAAQABAAEAAABCACMAAQACAAEAAABdAAkAAQACAAIAAABXADMAAQABAAIAAAA7ADUAAQADAAIAAAA8AAQAAQAEAAIAAAAPAAkAAQAEAAAAAAA=") +tile_map_data = PackedByteArray("AAAUAAYAAQADAAEAAAAXAAYAAQADAAAAAAAJAAkAAQADAAEAAAAFAAgAAQADAAEAAAAFAAwAAQADAAEAAAAJAAwAAQADAAEAAAARABEAAQAGAAIAAAAQABEAAQAGAAEAAAAcABUAAQABAAEAAABCACMAAQACAAEAAABdAAkAAQACAAIAAABXADMAAQABAAIAAAA7ADUAAQADAAIAAAA8AAQAAQAEAAIAAAAPAAkAAQAEAAAAAAAVABQAAQAEAAIAAAANABMAAQAAAAQAAAACACAAAQACAAQAABADAB8AAAAFAAMAAAACAB8AAAAFAAMAAAABAB8AAAAFAAMAAAADAB4AAAAFAAMAAAACAB4AAAAFAAMAAAABAB4AAAAFAAMAAAA=") tile_set = ExtResource("1_vlccq") [node name="PlayerLayer" type="TileMapLayer" parent="Tileset"] @@ -148,7 +157,7 @@ tile_map_data = PackedByteArray("AAAQAA4AAwAAAAAAAAA=") tile_set = ExtResource("1_vlccq") [node name="TemperatureLayer" type="TileMapLayer" parent="Tileset"] -tile_map_data = PackedByteArray("AAAAAAAAAgABAAAAAAAsAAYAAgABAAAAAAApAAYAAgABAAAAAAAqAAYAAgABAAAAAAArAAYAAgABAAAAAAAtAAYAAgABAAAAAAAuAAYAAgABAAAAAAAvAAYAAgABAAAAAAAwAAYAAgABAAAAAAAwAAcAAgABAAAAAAAvAAcAAgABAAAAAAAuAAcAAgABAAAAAAAtAAcAAgABAAAAAAAsAAcAAgABAAAAAAArAAcAAgABAAAAAAAqAAcAAgABAAAAAAAqAAgAAgABAAAAAAAqAAkAAgABAAAAAAArAAkAAgABAAAAAAAsAAkAAgABAAAAAAAtAAkAAgABAAAAAAAuAAkAAgABAAAAAAAuAAgAAgABAAAAAAAvAAgAAgABAAAAAAAwAAgAAgABAAAAAAAtAAgAAgABAAAAAAAsAAgAAgABAAAAAAArAAgAAgABAAAAAAAOAAwAAgAAAAAAAAAOAA0AAgABAAAAAAAOAA4AAgABAAAAAAAOAA8AAgABAAAAAAAPAAwAAgAAAAAAAAAPAA0AAgABAAAAAAAPAA4AAgABAAAAAAAPAA8AAgABAAAAAAAQAAwAAgAAAAAAAAAQAA0AAgABAAAAAAAQAA4AAgABAAAAAAAQAA8AAgABAAAAAAARAAsAAgAAAAAAAAARAAwAAgAAAAAAAAARAA0AAgABAAAAAAARAA4AAgABAAAAAAARAA8AAgABAAAAAAASAAsAAgAAAAAAAAASAAwAAgAAAAAAAAASAA0AAgABAAAAAAASAA4AAgABAAAAAAASAA8AAgABAAAAAAATAAsAAgAAAAAAAAATAAwAAgAAAAAAAAATAA0AAgAAAAAAAAATAA4AAgAAAAAAAAATAA8AAgAAAAAAAAAUAAsAAgAAAAAAAAAUAAwAAgAAAAAAAAAUAA0AAgAAAAAAAAAUAA4AAgAAAAAAAAAUAA8AAgAAAAAAAAAVAAsAAgAAAAAAAAAVAAwAAgAAAAAAAAAVAA0AAgAAAAAAAAA=") +tile_map_data = PackedByteArray("AAAAAAAAAgABAAAAAAAsAAYAAgABAAAAAAApAAYAAgABAAAAAAAqAAYAAgABAAAAAAArAAYAAgABAAAAAAAtAAYAAgABAAAAAAAuAAYAAgABAAAAAAAvAAYAAgABAAAAAAAwAAYAAgABAAAAAAAwAAcAAgABAAAAAAAvAAcAAgABAAAAAAAuAAcAAgABAAAAAAAtAAcAAgABAAAAAAAsAAcAAgABAAAAAAArAAcAAgABAAAAAAAqAAcAAgABAAAAAAAqAAgAAgABAAAAAAAqAAkAAgABAAAAAAArAAkAAgABAAAAAAAsAAkAAgABAAAAAAAtAAkAAgABAAAAAAAuAAkAAgABAAAAAAAuAAgAAgABAAAAAAAvAAgAAgABAAAAAAAwAAgAAgABAAAAAAAtAAgAAgABAAAAAAAsAAgAAgABAAAAAAArAAgAAgABAAAAAAATAAsAAgAAAAAAAAATAAwAAgABAAAAAAATAA0AAgABAAAAAAATAA4AAgAAAAAAAAATAA8AAgAAAAAAAAAUAAsAAgAAAAAAAAAUAAwAAgABAAAAAAAUAA0AAgABAAAAAAAUAA4AAgAAAAAAAAAUAA8AAgAAAAAAAAAVAAsAAgAAAAAAAAAVAAwAAgAAAAAAAAAVAA0AAgAAAAAAAAA=") tile_set = ExtResource("1_vlccq") [node name="NavigationVisualization" type="TileMapLayer" parent="Tileset"] @@ -244,6 +253,63 @@ script = ExtResource("21_cseat") [node name="GoToWhileRunningSuccessStop" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sq_Temperature/sl_PickMostRelevantTemperatureRemediation/sq_GoBackToCamp"] script = ExtResource("10_4v1m1") +[node name="sl_Boat" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival"] +script = ExtResource("7_1jajd") + +[node name="sq_BoatLeave" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat"] +script = ExtResource("9_i67mw") + +[node name="TaskInventoryContainsBoat" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_BoatLeave"] +script = ExtResource("25_vi38g") + +[node name="TaskGoToBoatLeaveLocation" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_BoatLeave"] +script = ExtResource("26_vy1mu") + +[node name="GoToWhileRunningSuccessStop" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_BoatLeave"] +script = ExtResource("10_4v1m1") + +[node name="sq_BuildBoat" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat"] +script = ExtResource("9_i67mw") + +[node name="TaskCheckBoatCompleted" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_BuildBoat"] +script = ExtResource("25_krdcp") + +[node name="TaskGoToBoatLocation" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_BuildBoat"] +script = ExtResource("26_1saby") + +[node name="GoToWhileRunningSuccessStop" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_BuildBoat"] +script = ExtResource("10_4v1m1") + +[node name="TaskPickupBoat" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_BuildBoat"] +script = ExtResource("27_tmoaj") + +[node name="sq_DeliverBoatPart" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat"] +script = ExtResource("9_i67mw") + +[node name="TaskInventoryContainsBoatPart" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_DeliverBoatPart"] +script = ExtResource("25_pgpdv") + +[node name="TaskGoToBoatLocation" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_DeliverBoatPart"] +script = ExtResource("26_1saby") + +[node name="GoToWhileRunningSuccessStop" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_DeliverBoatPart"] +script = ExtResource("10_4v1m1") + +[node name="TaskDeliverBoatPart" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_DeliverBoatPart"] +script = ExtResource("26_4pry2") + +[node name="sq_PickUpBoatPart" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat"] +script = ExtResource("9_i67mw") + +[node name="TaskFindClosestBoatPart" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_PickUpBoatPart"] +script = ExtResource("26_043la") + +[node name="GoToWhileRunningSuccessStop" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_PickUpBoatPart"] +script = ExtResource("10_4v1m1") + +[node name="TaskPickupBoatPart" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/sl_CriticalSurvival/sl_Boat/sq_PickUpBoatPart"] +script = ExtResource("26_hx2yd") + [node name="WalkUpToMouse" type="Node" parent="PlayerManager/BehaviorTree/sl_Root"] script = ExtResource("8_s6mqc") diff --git a/project/scripts/global/EventsTracker.gd b/project/scripts/global/EventsTracker.gd index 238fbca..965748d 100644 --- a/project/scripts/global/EventsTracker.gd +++ b/project/scripts/global/EventsTracker.gd @@ -8,6 +8,8 @@ enum Event { CAMP_ADDED_ITEM, CAMP_TAKEN_ITEM, CAMP_TAKE_ITEM_FAILED, + CAMP_BOAT_PART_DELIVERED, + CAMP_BOAT_COMPLETE, SLEEP, PLAYER_PICKED_UP_ITEM, PLAYER_DROPPED_ITEM, @@ -60,11 +62,17 @@ static func populate_visual_log_create_label(event: TrackedEvent, container: Con elif event_id == Event.SLEEP: text = "Player slept" elif event_id == Event.PLAYER_PICKED_UP_ITEM: - text = "took" + text = "Took" elif event_id == Event.PLAYER_DROPPED_ITEM: - text = "dropped" + text = "Dropped" elif event_id == Event.PLAYER_USED_ITEM: - text = "used" + text = "Used" + elif event_id == Event.CAMP_BOAT_PART_DELIVERED: + text = "Boat construction" + elif event_id == Event.CAMP_BOAT_COMPLETE: + text = "Boat complete" + else: + text = "Something happened..." var event_label: Label = Label.new() event_label.text = text diff --git a/project/scripts/global/GameManager.gd b/project/scripts/global/GameManager.gd index f5f2264..18890d8 100644 --- a/project/scripts/global/GameManager.gd +++ b/project/scripts/global/GameManager.gd @@ -39,7 +39,9 @@ func _process(delta: float) -> void: world.camp_manager.sleep_effect() world.camp_manager.campfire_extinguish() if Input.is_action_just_pressed("force_game_tick"): + Task.print_behavior_tree_evaluation = true _on_game_tick_timeout() + Task.print_behavior_tree_evaluation = false if Input.is_action_pressed("force_game_tick_fast"): _on_game_tick_timeout() if Input.is_action_just_pressed("key_6"): @@ -53,7 +55,7 @@ func player_health_depleted(): func _on_game_tick_timeout() -> void: var timer_on_game_tick_timeout: PerformanceTimer = PerformanceTimer.new() - timer_on_game_tick_timeout.display_name = "game tick duration" + timer_on_game_tick_timeout.display_name = "frame" tilemap_navigation.game_tick_start() world.game_tick_start() diff --git a/project/scripts/player/PlayerManager.gd b/project/scripts/player/PlayerManager.gd index 33928fa..96352f7 100644 --- a/project/scripts/player/PlayerManager.gd +++ b/project/scripts/player/PlayerManager.gd @@ -33,12 +33,12 @@ var temperature_buff_timer: int = 0 var temperature_timer: int = 0 var health: int = max_health -# var inventory_slot: Vector2i = tilemap_types.EMPTY: set(value): inventory_slot = value update_board() +var player_memory: Dictionary = {} func _ready() -> void: call_deferred("defer_ready") @@ -90,13 +90,15 @@ func pick_up_item(tilemap_pos: Vector2i) -> void: var pick_up_item_type: Vector2i = game_manager.world.tilemap_interactive.tilemap.get_cell_atlas_coords(tilemap_pos) - # check if tile will transform into another tile upon pickup + # check if inventory contains item that needs to be transformed on dropping + # this should never be the case, as the pick up item operation should already reflect this transformation var tile_drop_item: Vector2i = inventory_slot if tile_drop_item == tilemap_types.OBJECT_I_FILLED_BUSH: tile_drop_item = tilemap_types.OBJECT_I_BERRY elif tile_drop_item == tilemap_types.OBJECT_I_TREE_FULL: tile_drop_item = tilemap_types.OBJECT_I_STICK + # check if tile will transform into another tile upon pickup var tile_after_pickup_transform = null if pick_up_item_type == tilemap_types.OBJECT_I_FILLED_BUSH: tile_after_pickup_transform = tilemap_types.OBJECT_I_EMPTY_BUSH @@ -104,7 +106,6 @@ func pick_up_item(tilemap_pos: Vector2i) -> void: elif pick_up_item_type == tilemap_types.OBJECT_I_TREE_FULL: tile_after_pickup_transform = tilemap_types.OBJECT_I_TREE_CUT pick_up_item_type = tilemap_types.OBJECT_I_STICK - tile_drop_item = tilemap_types.OBJECT_I_STICK # check if the inventory slot is empty if inventory_slot == tilemap_types.EMPTY: @@ -233,6 +234,7 @@ func tick_handle_food(): func game_tick() -> void: behavior_tree.game_tick() + StepVisualization.add_circle_tileset(board_position, view_distance, StepVisualization.CircleType.PLAYER_VIEW) tick_handle_temperature(get_current_temperature()) tick_handle_food() diff --git a/project/scripts/player/tree/BehaviorTree.gd b/project/scripts/player/tree/BehaviorTree.gd index 56945af..2d2e1b1 100644 --- a/project/scripts/player/tree/BehaviorTree.gd +++ b/project/scripts/player/tree/BehaviorTree.gd @@ -8,25 +8,25 @@ var behavior_tree: Task = null func _ready() -> void: - if get_child_count() == 0 or get_child_count() > 1: - push_error("This controller needs exactly one Task child, got " + str(get_child_count())) + if get_child_count() == 0 or get_child_count() > 1: + push_error("This controller needs exactly one Task child, got " + str(get_child_count())) - var child: Node = get_child(0) - if not (child is Task): - push_error("Child is not a task: " + child.name) + var child: Node = get_child(0) + if not (child is Task): + push_error("Child is not a task: " + child.name) - behavior_tree = child as Task + behavior_tree = child as Task func populate_blackboard(): - blackboard["world"] = game_manager.world - blackboard["player"] = game_manager.player - blackboard["camera"] = game_manager.camera - blackboard["navigation"] = game_manager.tilemap_navigation + blackboard["world"] = game_manager.world + blackboard["player"] = game_manager.player + blackboard["camera"] = game_manager.camera + blackboard["navigation"] = game_manager.tilemap_navigation func game_tick() -> void: - print("game_tick:") - populate_blackboard() - behavior_tree.internal_run(blackboard) - print(" ==> [active state=", blackboard["current_task"], "] [status=", behavior_tree.status, "] [blackboard=", blackboard, "]") + populate_blackboard() + behavior_tree.internal_run(blackboard) + if Task.print_behavior_tree_evaluation: + print(" ==> [active state=", blackboard["current_task"], "] [status=", behavior_tree.status, "] [blackboard=", blackboard, "]") diff --git a/project/scripts/player/tree/Task.gd b/project/scripts/player/tree/Task.gd index 4b1add8..2907848 100644 --- a/project/scripts/player/tree/Task.gd +++ b/project/scripts/player/tree/Task.gd @@ -2,6 +2,8 @@ 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() @@ -22,9 +24,11 @@ func internal_run(blackboard: Dictionary) -> void: if running_child != null: extra_string = running_child.name - print(" -> ", human_readable(extra_string)) + if print_behavior_tree_evaluation: + print(" -> ", human_readable(extra_string)) run(blackboard) - print(" <- ", human_readable(extra_string)) + if print_behavior_tree_evaluation: + print(" <- ", human_readable(extra_string)) func find_running_child() -> Task: diff --git a/project/scripts/player/tree/impl/base/TaskSelector.gd b/project/scripts/player/tree/impl/base/TaskSelector.gd index 80a3b37..e6ae376 100644 --- a/project/scripts/player/tree/impl/base/TaskSelector.gd +++ b/project/scripts/player/tree/impl/base/TaskSelector.gd @@ -2,6 +2,11 @@ class_name TaskSelector extends Task func run(blackboard: Dictionary) -> void: + if get_children().size() == 0: + status = FAILURE + status_reason = "no children" + return + var running_child: Task = find_running_child() for c in slice_at_child(running_child): run_child(blackboard, c) diff --git a/project/scripts/player/tree/impl/base/TaskSequence.gd b/project/scripts/player/tree/impl/base/TaskSequence.gd index 2059336..f3db4bc 100644 --- a/project/scripts/player/tree/impl/base/TaskSequence.gd +++ b/project/scripts/player/tree/impl/base/TaskSequence.gd @@ -2,6 +2,11 @@ class_name TaskSequence extends Task func run(blackboard: Dictionary) -> void: + if get_children().size() == 0: + status = FAILURE + status_reason = "no children" + return + var running_child: Task = find_running_child() for c in slice_at_child(running_child): run_child(blackboard, c) diff --git a/project/scripts/player/tree/impl/game/boat/TaskCheckBoatCompleted.gd b/project/scripts/player/tree/impl/game/boat/TaskCheckBoatCompleted.gd new file mode 100644 index 0000000..e1d9560 --- /dev/null +++ b/project/scripts/player/tree/impl/game/boat/TaskCheckBoatCompleted.gd @@ -0,0 +1,13 @@ +class_name TaskCheckBoatCompleted +extends Task + +func run(blackboard: Dictionary) -> void: + var world: World = blackboard["world"] + + if world.camp_manager.boat_items.size() >= world.camp_manager.required_boat_parts: + status = SUCCESS + status_reason = "Boat is completed with " + str(world.camp_manager.boat_items.size()) + " parts" + return + + status = FAILURE + status_reason = "Boat is not completed, got only " + str(world.camp_manager.boat_items.size()) + " parts" diff --git a/project/scripts/player/tree/impl/game/boat/TaskDeliverBoatPart.gd b/project/scripts/player/tree/impl/game/boat/TaskDeliverBoatPart.gd new file mode 100644 index 0000000..92cbf28 --- /dev/null +++ b/project/scripts/player/tree/impl/game/boat/TaskDeliverBoatPart.gd @@ -0,0 +1,20 @@ +class_name TaskDeliverBoatPart +extends Task + +func run(blackboard: Dictionary) -> void: + var world: World = blackboard["world"] + var player: PlayerManager = blackboard["player"] + + if tilemap_types.is_part_of_collection(tilemap_types.OBJECT_COLLECTION_BOAT_PARTS, player.inventory_slot): + EventsTracker.track(EventsTracker.Event.CAMP_BOAT_PART_DELIVERED, {"item": player.inventory_slot}) + world.camp_manager.boat_items.append(player.inventory_slot) + player.inventory_slot = tilemap_types.EMPTY + if world.camp_manager.boat_items.size() >= world.camp_manager.required_boat_parts: + EventsTracker.track(EventsTracker.Event.CAMP_BOAT_COMPLETE, {"item": tilemap_types.OBJECT_I_BOAT_WITH_ENGINE}) + world.tilemap_interactive.set_cell(world.camp_manager.boat_build_location, tilemap_types.OBJECT_I_BOAT_WITH_ENGINE) + status = SUCCESS + status_reason = "Player delivered boat part" + return + + status = FAILURE + status_reason = "Player does not have boat part to deliver" diff --git a/project/scripts/player/tree/impl/game/boat/TaskFindClosestBoatPart.gd b/project/scripts/player/tree/impl/game/boat/TaskFindClosestBoatPart.gd new file mode 100644 index 0000000..9110fd3 --- /dev/null +++ b/project/scripts/player/tree/impl/game/boat/TaskFindClosestBoatPart.gd @@ -0,0 +1,35 @@ +class_name TaskFindClosestBoatPart +extends Task + +func run(blackboard: Dictionary) -> void: + var world: World = blackboard["world"] + var player: PlayerManager = blackboard["player"] + var navigation: TilemapNavigation = blackboard["navigation"] + + var parts: Array[Vector2i] = world.tilemap_interactive.get_cells_by_type_collection( + tilemap_types.OBJECT_COLLECTION_BOAT_PARTS, player.board_position, player.view_distance) + + if len(parts) == 0: + status = FAILURE + status_reason = "No boat parts found" + return + + var closest_part: Vector2i = navigation.manhattan_distance_closest(parts, player.board_position) + player.player_memory["boat_part"] = closest_part + StepVisualization.add_line_tileset(player.board_position, closest_part, StepVisualization.LineType.SEARCH_SELECTED) + if closest_part == tilemap_types.NO_TILE_FOUND: + status = FAILURE + status_reason = "No closest boat part found" + return + + blackboard["closest_part"] = closest_part + + var path: Array[Vector2i] = navigation.find_path_allow_neighbors(player.board_position, closest_part, player.view_distance) + if path.size() > 0: + blackboard["path"] = path + status_reason = "Found path to closest boat part" + status = SUCCESS + return + + status = FAILURE + status_reason = "No path found to closest boat part " + str(closest_part) diff --git a/project/scripts/player/tree/impl/game/boat/TaskGoToBoatLeaveLocation.gd b/project/scripts/player/tree/impl/game/boat/TaskGoToBoatLeaveLocation.gd new file mode 100644 index 0000000..30083e6 --- /dev/null +++ b/project/scripts/player/tree/impl/game/boat/TaskGoToBoatLeaveLocation.gd @@ -0,0 +1,20 @@ +class_name TaskGoToBoatLeaveLocation +extends Task + +func run(blackboard: Dictionary) -> void: + var world: World = blackboard["world"] + var player: PlayerManager = blackboard["player"] + var navigation: TilemapNavigation = blackboard["navigation"] + + var target: Vector2i = world.camp_manager.boat_leave_location + + StepVisualization.add_line_tileset(player.board_position, target, StepVisualization.LineType.SEARCH_SELECTED) + var path: Array[Vector2i] = navigation.find_path_allow_neighbors(player.board_position, target, player.view_distance) + if path.size() > 0: + blackboard["path"] = path + status_reason = "Found path to boat leave location" + status = SUCCESS + return + + status = FAILURE + status_reason = "No path found to boat leave location " + str(target) diff --git a/project/scripts/player/tree/impl/game/boat/TaskGoToBoatLocation.gd b/project/scripts/player/tree/impl/game/boat/TaskGoToBoatLocation.gd new file mode 100644 index 0000000..6018aaf --- /dev/null +++ b/project/scripts/player/tree/impl/game/boat/TaskGoToBoatLocation.gd @@ -0,0 +1,20 @@ +class_name TaskGoToBoatLocation +extends Task + +func run(blackboard: Dictionary) -> void: + var world: World = blackboard["world"] + var player: PlayerManager = blackboard["player"] + var navigation: TilemapNavigation = blackboard["navigation"] + + var target: Vector2i = world.camp_manager.boat_build_location + + StepVisualization.add_line_tileset(player.board_position, target, StepVisualization.LineType.SEARCH_SELECTED) + var path: Array[Vector2i] = navigation.find_path_allow_neighbors(player.board_position, target, player.view_distance) + if path.size() > 0: + blackboard["path"] = path + status_reason = "Found path to boat build location" + status = SUCCESS + return + + status = FAILURE + status_reason = "No path found to boat build location " + str(target) diff --git a/project/scripts/player/tree/impl/game/inventory/TaskInventoryContainsBoat.gd b/project/scripts/player/tree/impl/game/inventory/TaskInventoryContainsBoat.gd new file mode 100644 index 0000000..c1a118d --- /dev/null +++ b/project/scripts/player/tree/impl/game/inventory/TaskInventoryContainsBoat.gd @@ -0,0 +1,13 @@ +class_name TaskInventoryContainsBoat +extends Task + +func run(blackboard: Dictionary) -> void: + var player: PlayerManager = blackboard["player"] + + if tilemap_types.is_part_of_collection(tilemap_types.OBJECT_COLLECTION_BOAT, player.inventory_slot): + status = SUCCESS + status_reason = "Player has boat" + return + + status = FAILURE + status_reason = "Player does not have boat" diff --git a/project/scripts/player/tree/impl/game/inventory/TaskInventoryContainsBoatPart.gd b/project/scripts/player/tree/impl/game/inventory/TaskInventoryContainsBoatPart.gd new file mode 100644 index 0000000..9c9b323 --- /dev/null +++ b/project/scripts/player/tree/impl/game/inventory/TaskInventoryContainsBoatPart.gd @@ -0,0 +1,13 @@ +class_name TaskInventoryContainsBoatPart +extends Task + +func run(blackboard: Dictionary) -> void: + var player: PlayerManager = blackboard["player"] + + if tilemap_types.is_part_of_collection(tilemap_types.OBJECT_COLLECTION_BOAT_PARTS, player.inventory_slot): + status = SUCCESS + status_reason = "Player has boat part" + return + + status = FAILURE + status_reason = "Player does not have boat part" diff --git a/project/scripts/player/tree/impl/game/inventory/TaskPickupBoat.gd b/project/scripts/player/tree/impl/game/inventory/TaskPickupBoat.gd new file mode 100644 index 0000000..b031e85 --- /dev/null +++ b/project/scripts/player/tree/impl/game/inventory/TaskPickupBoat.gd @@ -0,0 +1,15 @@ +class_name TaskPickupBoat +extends Task + +func run(blackboard: Dictionary) -> void: + var player: PlayerManager = blackboard["player"] + var world: World = blackboard["world"] + + if world.camp_manager.boat_build_location == tilemap_types.EMPTY: + status = FAILURE + status_reason = "Boat is not on the map" + return + + player.pick_up_item(world.camp_manager.boat_build_location) + status = SUCCESS + status_reason = "Picked up boat" diff --git a/project/scripts/player/tree/impl/game/inventory/TaskPickupBoatPart.gd b/project/scripts/player/tree/impl/game/inventory/TaskPickupBoatPart.gd new file mode 100644 index 0000000..4a8cd4b --- /dev/null +++ b/project/scripts/player/tree/impl/game/inventory/TaskPickupBoatPart.gd @@ -0,0 +1,12 @@ +class_name TaskPickupBoatPart +extends Task + +func run(blackboard: Dictionary) -> void: + var player: PlayerManager = blackboard["player"] + var closest_part: Vector2i = blackboard["closest_part"] + + player.pick_up_item(closest_part) + player.player_memory.erase("boat_part") + + status = SUCCESS + status_reason = "Picked up boat part" diff --git a/project/scripts/tilemap/StepVisualization.gd b/project/scripts/tilemap/StepVisualization.gd index b3dae7e..1a2bdeb 100644 --- a/project/scripts/tilemap/StepVisualization.gd +++ b/project/scripts/tilemap/StepVisualization.gd @@ -4,10 +4,13 @@ extends Node2D static var game_manager: GameManager static var world: World # -enum LineType { SEARCH_BASE, SEARCH_SELECTED } +enum LineType { SEARCH_BASE, SEARCH_SELECTED, SEARCH_FAILED } +enum CircleType { PLAYER_VIEW } # # Dictionary[Array[Vector2i], LineType] ([from, to], line_type) static var draw_lines: Dictionary = {} +# Dictionary[Array[Vector2i], CircleType] ([center, radius], circle_type) +static var draw_circles: Dictionary = {} static func add_line(from: Vector2i, to: Vector2i, line_type: LineType) -> void: @@ -20,8 +23,19 @@ static func add_line_tileset(from: Vector2i, to: Vector2i, line_type: LineType) draw_lines[[from_tileset, to_tileset]] = line_type +static func add_circle(center: Vector2i, radius: int, circle_type: CircleType) -> void: + draw_circles[[center, radius]] = circle_type + + +static func add_circle_tileset(center: Vector2i, radius: int, circle_type: CircleType) -> void: + var center_tileset: Vector2i = world.tilemap_ground.cell_to_local(center) + radius *= world.tilemap_ground.tilemap.tile_set.tile_size.x + draw_circles[[center_tileset, radius]] = circle_type + + func game_tick_start(): draw_lines.clear() + draw_circles.clear() func game_tick_end(): @@ -29,7 +43,7 @@ func game_tick_end(): var label_font = Control.new().get_theme_default_font() -@export var default_line_color: Color = Color("red") +@export var default_color: Color = Color("red") func _ready() -> void: @@ -37,7 +51,6 @@ func _ready() -> void: func _draw() -> void: - # draw all draw_lines with their labels for key in draw_lines.keys(): var from: Vector2i = key[0] var to: Vector2i = key[1] @@ -47,6 +60,13 @@ func _draw() -> void: draw_line(from, to, Color("blue"), 1) elif line_type == LineType.SEARCH_SELECTED: draw_line(from, to, Color("green"), 2) + elif line_type == LineType.SEARCH_FAILED: + draw_line(from, to, Color(255, 0, 0, 0.2), 1) - # var center: Vector2 = (from + to) / 2 - # draw_string(label_font, center, label, 0, -1, 12, text_color) + for key in draw_circles.keys(): + var center: Vector2i = key[0] + var radius: int = key[1] + var circle_type: CircleType = draw_circles[key] + + if circle_type == CircleType.PLAYER_VIEW: + draw_circle(center, radius, Color("green"), false, 2, true) diff --git a/project/scripts/tilemap/TileMapLayerAccess.gd b/project/scripts/tilemap/TileMapLayerAccess.gd index 2aa9fac..565ff67 100644 --- a/project/scripts/tilemap/TileMapLayerAccess.gd +++ b/project/scripts/tilemap/TileMapLayerAccess.gd @@ -1,6 +1,8 @@ class_name TileMapLayerAccess extends Node +var tilemap_types: TileMapTileTypes = TileMapTileTypes.new() +# var tilemap: TileMapLayer = null var sid: int = 0 @@ -17,7 +19,7 @@ func get_cells_by_type( if max_distance < 99999999: var filtered_tiles: Array[Vector2i] = [] for tile in tiles_with_type: - if TilemapNavigation.manhattan_distance(center, tile, true) <= max_distance: + if TilemapNavigation.is_within_radius(center, tile, max_distance, true): filtered_tiles.append(tile) return filtered_tiles return tiles_with_type @@ -33,7 +35,7 @@ func get_cells_by_type_collection( if max_distance < 99999999: var filtered_tiles: Array[Vector2i] = [] for tile in tiles_with_type: - if TilemapNavigation.manhattan_distance(center, tile, true) <= max_distance: + if TilemapNavigation.is_within_radius(center, tile, max_distance, true): filtered_tiles.append(tile) return filtered_tiles return tiles_with_type @@ -67,6 +69,8 @@ func get_cell(position: Vector2i) -> TileData: func get_cell_atlas_coords(position: Vector2i) -> Vector2i: + if not get_cell(position): + return tilemap_types.NO_TILE_FOUND return tilemap.get_cell_atlas_coords(position) diff --git a/project/scripts/tilemap/TileMapTileTypes.gd b/project/scripts/tilemap/TileMapTileTypes.gd index b08ea8f..158d7f3 100644 --- a/project/scripts/tilemap/TileMapTileTypes.gd +++ b/project/scripts/tilemap/TileMapTileTypes.gd @@ -19,10 +19,10 @@ const OBJECT_NI_ROCK_1: Vector2i = Vector2i(2, 0) # # I = interactive # boat -const OBJECT_I_BOAT_NO_ENIGNE: Vector2i = Vector2i(4, 4) -const OBJECT_I_BOAT_WITH_ENGINE: Vector2i = Vector2i(6, 4) +const OBJECT_I_BOAT_NO_ENIGNE: Vector2i = Vector2i(0, 4) +const OBJECT_I_BOAT_WITH_ENGINE: Vector2i = Vector2i(2, 4) # boat parts -const OBJECT_I_BOAT_PART_GENERIC: Vector2i = Vector2i(4584, 5234) +const OBJECT_I_BOAT_PART_GENERIC: Vector2i = Vector2i(1, 1) const OBJECT_I_BOAT_PART_ENGINE: Vector2i = Vector2i(0, 1) const OBJECT_I_BOAT_PART_FUEL: Vector2i = Vector2i(1, 1) const OBJECT_I_BOAT_PART_ANCHOR: Vector2i = Vector2i(2, 1) @@ -52,6 +52,7 @@ const OBJECT_COLLECTION_BOAT_PARTS: Array[Vector2i] = [ # @formatter:off OBJECT_I_BOAT_PART_CHEST, OBJECT_I_BOAT_PART_GEARS, OBJECT_I_BOAT_PART_MEDIKIT, OBJECT_I_BOAT_PART_PADDLE, OBJECT_I_BOAT_PART_GAS_STOVE ] # @formatter:on +const OBJECT_COLLECTION_BOAT: Array[Vector2i] = [OBJECT_I_BOAT_NO_ENIGNE, OBJECT_I_BOAT_WITH_ENGINE] # # temperature, sid = 2 const TEMPERATURE_NORMAL: Vector2i = Vector2i(2, 0) @@ -82,3 +83,6 @@ func player_sprite_from_direction(direction: Vector2i) -> Vector2i: if direction == Vector2i(1, 0): return PLAYER_RIGHT return PLAYER_DOWN + +func is_part_of_collection(collection: Array[Vector2i], item: Vector2i) -> bool: + return collection.find(item) != -1 diff --git a/project/scripts/tilemap/TilemapNavigation.gd b/project/scripts/tilemap/TilemapNavigation.gd index 6c8c371..aec99a8 100644 --- a/project/scripts/tilemap/TilemapNavigation.gd +++ b/project/scripts/tilemap/TilemapNavigation.gd @@ -32,15 +32,18 @@ func game_tick_end() -> void: world.tilemap_nav_vis.set_cell(chosen_path[chosen_path.size() - 1], tilemap_types.NAVIGATION_TARGET) -func is_within_radius(position: Vector2i, center: Vector2i, radius: int, record: bool = false) -> bool: - return TilemapNavigation.manhattan_distance(position, center, record) <= radius - - -static func manhattan_distance(a: Vector2i, b: Vector2i, record: bool = false) -> int: - var dist: int = abs(a.x - b.x) + abs(a.y - b.y) +static func is_within_radius(position: Vector2i, center: Vector2i, radius: int, record: bool = false) -> bool: + var is_within: bool = TilemapNavigation.manhattan_distance(position, center) <= radius if record: - StepVisualization.add_line_tileset(a, b, StepVisualization.LineType.SEARCH_BASE) - return dist + if is_within: + StepVisualization.add_line_tileset(center, position, StepVisualization.LineType.SEARCH_BASE) + else: + StepVisualization.add_line_tileset(center, position, StepVisualization.LineType.SEARCH_FAILED) + return is_within + + +static func manhattan_distance(a: Vector2i, b: Vector2i) -> int: + return abs(a.x - b.x) + abs(a.y - b.y) func manhattan_distance_closest(options: Array[Vector2i], target: Vector2i) -> Vector2i: diff --git a/project/scripts/tilemap/objects/CampManager.gd b/project/scripts/tilemap/objects/CampManager.gd index 68e9ac5..921ab44 100644 --- a/project/scripts/tilemap/objects/CampManager.gd +++ b/project/scripts/tilemap/objects/CampManager.gd @@ -6,9 +6,14 @@ var tilemap_types: TileMapTileTypes = TileMapTileTypes.new() var game_manager: GameManager = null var tilemap_interactive: TileMapLayerAccess = null # -var items: Array[Vector2i] = [] -var camp: Vector2i = Vector2i(0, 0) -var campfire: Vector2i = Vector2i(0, 0) +var camp_items: Array[Vector2i] = [] +var boat_items: Array[Vector2i] = [] +var camp: Vector2i = tilemap_types.EMPTY +var campfire: Vector2i = tilemap_types.EMPTY +var boat_build_location: Vector2i = tilemap_types.EMPTY +var boat_leave_location: Vector2i = tilemap_types.EMPTY + +@export var required_boat_parts: int = 3 func setup() -> void: @@ -18,30 +23,45 @@ func setup() -> void: camp = camp_locations[0] else: push_error("No camp location found on tilemap") + var firepit_locations: Array[Vector2i] = tilemap_interactive.get_cells_by_type_collection(tilemap_types.OBJECT_COLLECTION_FIREPIT) if len(firepit_locations) > 0: campfire = firepit_locations[0] else: push_error("No firepit location found on tilemap") + + var boat_build_locations: Array[Vector2i] = tilemap_interactive.get_cells_by_type(tilemap_types.OBJECT_I_BOAT_NO_ENIGNE) + if len(boat_build_locations) > 0: + boat_build_location = boat_build_locations[0] + else: + push_error("No boat build location found on tilemap") + + var boat_leave_locations: Array[Vector2i] = tilemap_interactive.get_cells_by_type(tilemap_types.OBJECT_I_BOAT_WITH_ENGINE) + if len(boat_leave_locations) > 0: + boat_leave_location = boat_leave_locations[0] + tilemap_interactive.set_cell(boat_leave_location, tilemap_types.EMPTY) + else: + push_error("No boat leave location found on tilemap") + print("CampManager: camp=", camp, " campfire=", campfire) tilemap_interactive.set_cell(campfire, tilemap_types.OBJECT_I_FIREPIT_OFF) func camp_contains_item(item: Vector2i) -> bool: - return items.find(item) != -1 + return camp_items.find(item) != -1 func camp_contains_item_collection(item: Array[Vector2i]) -> bool: for i in item: - if items.find(i) == -1: + if camp_items.find(i) == -1: return false return true func camp_item_count(item: Vector2i) -> int: var count: int = 0 - for i in items: + for i in camp_items: if i == item: count += 1 return count @@ -49,7 +69,7 @@ func camp_item_count(item: Vector2i) -> int: func camp_item_collection_count(item: Array[Vector2i]) -> int: var count: int = 0 - for i in items: + for i in camp_items: if item.find(i) != -1: count += 1 return count @@ -62,9 +82,9 @@ func camp_take_item(item: Vector2i, count: int = 1) -> bool: return false var taken: int = 0 - for i in range(items.size()): - if items[i] == item: - items.remove_at(i) + for i in range(camp_items.size()): + if camp_items[i] == item: + camp_items.remove_at(i) taken += 1 if taken == count: break @@ -74,7 +94,7 @@ func camp_take_item(item: Vector2i, count: int = 1) -> bool: func camp_add_item(item: Vector2i) -> void: - items.append(item) + camp_items.append(item) EventsTracker.track(EventsTracker.Event.CAMP_ADDED_ITEM, {"item": item, "count": 1, "new_count": camp_item_count(item)})