feat: add knowledge-gated pantry opportunities

This commit is contained in:
Rijad Zuzo
2026-07-13 00:46:56 +02:00
parent 9fcf6a0a58
commit c722e32a88
26 changed files with 2027 additions and 77 deletions
+99
View File
@@ -119,6 +119,105 @@ func _run() -> void:
not listener_visual.get_node("TrustReactionRoot").visible,
"Learning a fact without a relationship consequence should not show a trust blossom"
)
var village_stats_label := (
main_scene.get_node("UI/VillagePanel/MarginContainer/VillageStatsLabel") as Label
)
var pantry_state: StorageStateRecord = simulation_manager.get_pantry()
contributor.hunger = 85.0
var withdrawn_for_need: float = simulation_manager.economy.withdraw_to_inventory(
contributor,
SimulationIds.RESOURCE_FOOD,
pantry_state.get_amount(SimulationIds.RESOURCE_FOOD)
)
_check(withdrawn_for_need > 0.0, "Runtime opportunity setup should empty the real pantry")
var opportunity: OpportunityStateRecord = simulation_manager.get_active_opportunity()
_check(opportunity != null, "Emptying the pantry should open one known shortage need")
_check(
(
"Village need" in village_stats_label.text
and "◆ Restock the empty pantry" in village_stats_label.text
and (
"%s is worried about the shortage" % contributor.npc_name
in village_stats_label.text
)
and "Food 0 / 1" in village_stats_label.text
),
"An open opportunity should add one compact state-derived village need"
)
village_ui.selected_npc_index = contributor.id
village_ui.call("_refresh_npc_inspector")
_check(
(
"Open village need" in inspector_label.text
and "◆ Restock the empty pantry" in inspector_label.text
and "Food 0 / 1" in inspector_label.text
),
"The interested villager should expose the open pantry need in their inspector"
)
village_ui.selected_npc_index = listener.id
village_ui.call("_refresh_npc_inspector")
_check(
"Open village need" not in inspector_label.text,
"An unrelated selected villager should not inherit someone else's open need"
)
_check(
(
simulation_manager.economy.deposit_inventory(contributor, SimulationIds.RESOURCE_FOOD)
> 0.0
),
"Opportunity presentation should resolve from a real pantry deposit"
)
_check(
"Village need" not in village_stats_label.text,
"Resolved opportunities should leave the compact village summary"
)
village_ui.selected_npc_index = contributor.id
village_ui.call("_refresh_npc_inspector")
_check(
(
"Resolved village need" in inspector_label.text
and "%s restocked the pantry" % contributor.npc_name in inspector_label.text
and "Food target 1" in inspector_label.text
),
"The interested villager should retain a resolved detail naming the real actor"
)
village_ui.selected_npc_index = listener.id
village_ui.call("_refresh_npc_inspector")
_check(
"Resolved village need" not in inspector_label.text,
"Resolved opportunity detail should remain scoped to its interested villager"
)
var player_need_withdrawal: float = simulation_manager.economy.withdraw_to_inventory(
contributor,
SimulationIds.RESOURCE_FOOD,
pantry_state.get_amount(SimulationIds.RESOURCE_FOOD)
)
_check(player_need_withdrawal > 0.0, "Player resolution setup should reopen a real need")
var player_opportunity: OpportunityStateRecord = simulation_manager.get_active_opportunity()
_check(player_opportunity != null, "A later shortage should open a new opportunity record")
var player := main_scene.get_node("Player") as Node3D
var opportunity_bush := (
main_scene.get_node("JajceWorld/WorldObjects/ResourceNodes/BerryBush_01") as ResourceNode
)
var opportunity_bush_state: ResourceStateRecord = simulation_manager.get_resource_state(
opportunity_bush.node_id
)
opportunity_bush_state.set_amount_remaining(1.0)
player.global_position = opportunity_bush.interaction_point.global_position
player.call("try_interact")
village_ui.selected_npc_index = contributor.id
village_ui.call("_refresh_npc_inspector")
_check(
(
player_opportunity.get_status() == OpportunityStateRecord.STATUS_RESOLVED
and "Resolved village need" in inspector_label.text
and "◆ Player restocked the pantry" in inspector_label.text
),
"Player gathering should resolve the same need and be named from its real event"
)
_check(
main_scene.has_node("JajceWorld/TerrainRoot/Terrain3D"),
"Playable runtime should instance the Jajce Terrain3D world"