1
0
Fork 0

Initial version of boat construction

Yan Wittmann 2025-01-11 16:09:10 +01:00
parent ed665886d3
commit 731ff9ed12
23 changed files with 367 additions and 57 deletions

View File

@ -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")

View File

@ -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")

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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, "]")

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -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"

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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)})