feat: wood inventory, carrying, and woodpile storage

Wood now follows the same gather-carry-deposit pattern as food. NPCs put harvested wood into inventory, walk to the VillageWoodpile StorageNode, and deposit it. Village wood syncs from storage. Player harvesting also routes wood to the woodpile. ActiveWorldAdapter exposes woodpile routing for DEPOSIT_WOOD action targeting. WorldViewManager recognizes wood inventory changes. Tests verify woodpile node existence, storage ID, navigation reachability, and adapter routing.
This commit is contained in:
2026-07-08 18:55:51 +02:00
parent 5ea83b06ed
commit c61d286005
12 changed files with 124 additions and 17 deletions
+11
View File
@@ -106,6 +106,12 @@ func _run() -> void:
)
var pantry := main_scene.get_node("JajceWorld/WorldObjects/StorageSites/VillagePantry") as StorageNode
destinations.append(pantry.get_interaction_position())
_check(
main_scene.has_node("JajceWorld/WorldObjects/StorageSites/VillageWoodpile"),
"Runtime should expose a typed VillageWoodpile StorageNode"
)
var woodpile := main_scene.get_node("JajceWorld/WorldObjects/StorageSites/VillageWoodpile") as StorageNode
destinations.append(woodpile.get_interaction_position())
var activity_root := main_scene.get_node("JajceWorld/WorldObjects/ActivitySites")
_check(activity_root.get_child_count() == 3, "Runtime should expose three typed activity sites")
for site in activity_root.get_children():
@@ -149,6 +155,11 @@ func _run() -> void:
storage_target.get("target_id", "") == String(SimulationIds.STORAGE_VILLAGE_PANTRY),
"Runtime adapter should route storage actions to village_pantry"
)
var wood_target := adapter.get_activity_target(SimulationIds.ACTION_DEPOSIT_WOOD)
_check(
wood_target.get("target_id", "") == String(SimulationIds.STORAGE_VILLAGE_WOODPILE),
"Runtime adapter should route wood deposit to village_woodpile"
)
var study_target := adapter.get_activity_target(SimulationIds.ACTION_STUDY)
_check(
study_target.get("target_id", "") == "study_desk",
+13
View File
@@ -187,6 +187,12 @@ func _run() -> void:
pantry.storage_id == SimulationIds.STORAGE_VILLAGE_PANTRY,
"VillagePantry should preserve the stable storage ID"
)
var woodpile := world.get_node("WorldObjects/StorageSites/VillageWoodpile") as StorageNode
_check(woodpile != null, "JajceWorld should include a typed VillageWoodpile StorageNode")
_check(
woodpile.storage_id == SimulationIds.STORAGE_VILLAGE_WOODPILE,
"VillageWoodpile should preserve the stable storage ID"
)
_check(
not world.has_node("LegacyActivityMarkers/PantryMarker"),
"Pantry should no longer be a legacy activity marker"
@@ -224,6 +230,7 @@ func _run() -> void:
for resource in resources:
destinations.append((resource as ResourceNode).interaction_point.global_position)
destinations.append(pantry.get_interaction_position())
destinations.append(woodpile.get_interaction_position())
for site in activity_root.get_children():
destinations.append((site as ActivitySite).get_interaction_position())
@@ -243,6 +250,7 @@ func _run() -> void:
var adapter := ActiveWorldAdapter.new()
adapter.pantry_storage = pantry
adapter.woodpile_storage = woodpile
root.add_child(adapter)
var food_candidates := adapter.get_resource_candidates(SimulationIds.ACTION_GATHER_FOOD)
_check(food_candidates.size() >= 9, "Adapter should expose all authored food candidates")
@@ -296,6 +304,11 @@ func _run() -> void:
storage_target_position.distance_to(pantry.get_interaction_position()) < 0.01,
"Storage actions should use the pantry StorageNode interaction point"
)
var wood_target := adapter.get_activity_target(SimulationIds.ACTION_DEPOSIT_WOOD)
_check(
wood_target.get("target_id", "") == String(SimulationIds.STORAGE_VILLAGE_WOODPILE),
"Wood deposit should target the typed woodpile's stable ID"
)
var rest_target := adapter.get_activity_target(SimulationIds.ACTION_REST)
_check(
rest_target.get("target_id", "") == "rest_bench",
+1 -1
View File
@@ -34,7 +34,7 @@ func _test_registry_integrity() -> void:
SimulationDefinitions.get_action(definition.action_id) == definition,
"Action lookup should return '%s'" % definition.action_id
)
_check(action_ids.size() == 10, "Registry should contain all ten executable prototype actions")
_check(action_ids.size() == 11, "Registry should contain all eleven executable prototype actions")
var profession_ids := SimulationDefinitions.get_profession_ids()
_check(profession_ids.size() == 5, "Registry should contain all five prototype professions")