feat: add missing wood opportunities
This commit is contained in:
@@ -105,7 +105,7 @@ func _run() -> void:
|
||||
var active_restored := _create_manager(902)
|
||||
_check(
|
||||
active_restored.restore_state_from_json(active_json),
|
||||
"An active opportunity should survive schema-v8 save and restore"
|
||||
"An active opportunity should survive schema-v9 save and restore"
|
||||
)
|
||||
_check(
|
||||
(
|
||||
|
||||
@@ -235,9 +235,10 @@ func _run() -> void:
|
||||
var old_contributor_visual := contributor_visual
|
||||
_check(
|
||||
simulation_manager.restore_state_from_json(active_need_json),
|
||||
"The visible shortage should survive a valid schema-v8 restore"
|
||||
"The visible shortage should survive a valid schema-v9 restore"
|
||||
)
|
||||
await process_frame
|
||||
contributor = simulation_manager.npcs[contributor.id]
|
||||
contributor_visual = world_view.active_npc_visuals[contributor.id]
|
||||
player_opportunity = simulation_manager.get_active_opportunity()
|
||||
_check(
|
||||
@@ -270,6 +271,42 @@ func _run() -> void:
|
||||
),
|
||||
"Player gathering should resolve the same need and be named from its real event"
|
||||
)
|
||||
|
||||
var woodpile_state: StorageStateRecord = simulation_manager.get_woodpile()
|
||||
woodpile_state.withdraw(
|
||||
SimulationIds.RESOURCE_WOOD, woodpile_state.get_amount(SimulationIds.RESOURCE_WOOD)
|
||||
)
|
||||
simulation_manager.economy.sync_resource(SimulationIds.RESOURCE_WOOD)
|
||||
contributor.set_task(SimulationIds.ACTION_STUDY, 1.0)
|
||||
contributor.start_working()
|
||||
simulation_manager.simulate_tick()
|
||||
village_ui.selected_npc_index = contributor.id
|
||||
village_ui.call("_refresh_npc_inspector")
|
||||
_check(
|
||||
(
|
||||
"◆ Supply wood for blocked work" in village_stats_label.text
|
||||
and "could not finish Study" in village_stats_label.text
|
||||
and "◆ Find wood for Study" in inspector_label.text
|
||||
and not contributor_visual.get_node("OpportunityConcernRoot").visible
|
||||
),
|
||||
"A real missing-wood fact should surface through wood-specific UI without a food cue"
|
||||
)
|
||||
contributor.add_inventory(SimulationIds.RESOURCE_WOOD, 1.0)
|
||||
_check(
|
||||
is_equal_approx(
|
||||
simulation_manager.economy.deposit_inventory(contributor, SimulationIds.RESOURCE_WOOD),
|
||||
1.0
|
||||
),
|
||||
"Runtime opportunity presentation should resolve from a real wood deposit"
|
||||
)
|
||||
village_ui.call("_refresh_npc_inspector")
|
||||
_check(
|
||||
(
|
||||
"Village need" not in village_stats_label.text
|
||||
and "◆ %s supplied the woodpile" % contributor.npc_name in inspector_label.text
|
||||
),
|
||||
"The resolved wood need should name its exact supplier and leave the active summary"
|
||||
)
|
||||
_check(
|
||||
main_scene.has_node("JajceWorld/TerrainRoot/Terrain3D"),
|
||||
"Playable runtime should instance the Jajce Terrain3D world"
|
||||
|
||||
@@ -457,6 +457,27 @@ func _test_previous_world_opportunity_migration() -> void:
|
||||
),
|
||||
"World v7 migration should initialize deterministic opportunity identity"
|
||||
)
|
||||
var v8_data: Dictionary = _build_opportunity_world(manager, false)
|
||||
v8_data["schema_version"] = SimulationStateRecord.OPPORTUNITY_LEGACY_SCHEMA_VERSION
|
||||
var legacy_opportunity: Dictionary = v8_data["opportunities"][0]
|
||||
legacy_opportunity["schema_version"] = OpportunityStateRecord.LEGACY_SCHEMA_VERSION
|
||||
legacy_opportunity.erase("closed_tick")
|
||||
legacy_opportunity.erase("invalidation_reason")
|
||||
for event_data in v8_data["economic_events"]:
|
||||
event_data["schema_version"] = EconomicEventRecord.POSITION_LEGACY_SCHEMA_VERSION
|
||||
event_data.erase("action_id")
|
||||
event_data.erase("required_amount")
|
||||
var migrated_v8 := SimulationStateRecord.from_dictionary(v8_data)
|
||||
_check(migrated_v8 != null, "World schema v8 should preserve its pantry opportunity history")
|
||||
if migrated_v8 != null:
|
||||
_check(
|
||||
(
|
||||
migrated_v8.opportunities.size() == 1
|
||||
and migrated_v8.opportunities[0].get_status() == OpportunityStateRecord.STATUS_OPEN
|
||||
and migrated_v8.opportunities[0].get_closed_tick() == -1
|
||||
),
|
||||
"World v8 migration should normalize the nested opportunity lifecycle fields"
|
||||
)
|
||||
manager.free()
|
||||
|
||||
|
||||
|
||||
+24
-11
@@ -1,12 +1,12 @@
|
||||
extends GutTest
|
||||
|
||||
const FoodShortageOpportunitySystemScript := preload(
|
||||
"res://simulation/opportunities/FoodShortageOpportunitySystem.gd"
|
||||
const VillageOpportunitySystemScript := preload(
|
||||
"res://simulation/opportunities/VillageOpportunitySystem.gd"
|
||||
)
|
||||
|
||||
|
||||
func test_opening_requires_current_knowledge_and_care() -> void:
|
||||
var system := FoodShortageOpportunitySystemScript.new()
|
||||
var system := VillageOpportunitySystemScript.new()
|
||||
var pantry := _empty_pantry()
|
||||
var npc := _npc(0, 90.0)
|
||||
var npcs: Array[SimNPC] = [npc]
|
||||
@@ -15,14 +15,14 @@ func test_opening_requires_current_knowledge_and_care() -> void:
|
||||
|
||||
assert_null(system.consider_event(trigger, 8, pantry, npcs, knowledge, {}))
|
||||
_remember(knowledge, npc.id, 4, 8)
|
||||
npc.hunger = FoodShortageOpportunitySystem.CARE_HUNGER_THRESHOLD - 0.01
|
||||
npc.hunger = VillageOpportunitySystem.CARE_HUNGER_THRESHOLD - 0.01
|
||||
assert_null(system.consider_event(trigger, 8, pantry, npcs, knowledge, {}))
|
||||
assert_true(system.get_all_sorted().is_empty())
|
||||
assert_eq(system.next_opportunity_id, 0)
|
||||
|
||||
|
||||
func test_highest_hunger_then_lowest_id_deterministically_owns_the_opportunity() -> void:
|
||||
var system := FoodShortageOpportunitySystemScript.new()
|
||||
var system := VillageOpportunitySystemScript.new()
|
||||
var pantry := _empty_pantry()
|
||||
var lower_hunger := _npc(1, 85.0)
|
||||
var high_id := _npc(5, 92.0)
|
||||
@@ -58,7 +58,7 @@ func test_highest_hunger_then_lowest_id_deterministically_owns_the_opportunity()
|
||||
|
||||
|
||||
func test_near_equal_hunger_still_uses_the_exact_highest_value() -> void:
|
||||
var system := FoodShortageOpportunitySystemScript.new()
|
||||
var system := VillageOpportunitySystemScript.new()
|
||||
var pantry := _empty_pantry()
|
||||
var lower_id := _npc(1, 92.0)
|
||||
var slightly_hungrier := _npc(9, 92.000001)
|
||||
@@ -77,7 +77,7 @@ func test_near_equal_hunger_still_uses_the_exact_highest_value() -> void:
|
||||
|
||||
|
||||
func test_late_knowledge_can_open_old_event_and_open_opportunity_dedupes() -> void:
|
||||
var system := FoodShortageOpportunitySystemScript.new()
|
||||
var system := VillageOpportunitySystemScript.new()
|
||||
var pantry := _empty_pantry()
|
||||
var npc := _npc(3, 88.0)
|
||||
var npcs: Array[SimNPC] = [npc]
|
||||
@@ -101,7 +101,7 @@ func test_late_knowledge_can_open_old_event_and_open_opportunity_dedupes() -> vo
|
||||
|
||||
func test_only_strict_later_npc_deposit_resolves_without_mutating_supply() -> void:
|
||||
var fixture := _open_fixture()
|
||||
var system: FoodShortageOpportunitySystem = fixture["system"]
|
||||
var system: VillageOpportunitySystem = fixture["system"]
|
||||
var pantry: StorageStateRecord = fixture["pantry"]
|
||||
var npcs: Array[SimNPC] = fixture["npcs"]
|
||||
var knowledge: EventKnowledgeSystem = fixture["knowledge"]
|
||||
@@ -161,7 +161,7 @@ func test_only_strict_later_npc_deposit_resolves_without_mutating_supply() -> vo
|
||||
|
||||
func test_player_extraction_into_pantry_is_the_other_valid_resolution() -> void:
|
||||
var fixture := _open_fixture()
|
||||
var system: FoodShortageOpportunitySystem = fixture["system"]
|
||||
var system: VillageOpportunitySystem = fixture["system"]
|
||||
var pantry: StorageStateRecord = fixture["pantry"]
|
||||
var npcs: Array[SimNPC] = fixture["npcs"]
|
||||
var knowledge: EventKnowledgeSystem = fixture["knowledge"]
|
||||
@@ -179,11 +179,24 @@ func test_player_extraction_into_pantry_is_the_other_valid_resolution() -> void:
|
||||
assert_eq(resolved.get_status(), OpportunityStateRecord.STATUS_RESOLVED)
|
||||
|
||||
|
||||
func test_missing_wood_maintenance_does_not_change_the_existing_food_lifecycle() -> void:
|
||||
var fixture := _open_fixture()
|
||||
var system: VillageOpportunitySystem = fixture["system"]
|
||||
var pantry: StorageStateRecord = fixture["pantry"]
|
||||
var npcs: Array[SimNPC] = fixture["npcs"]
|
||||
var food_need: OpportunityStateRecord = system.get_open_opportunity()
|
||||
npcs[0].is_dead = true
|
||||
|
||||
assert_null(system.maintain_open_opportunity(1000, 10, npcs, pantry, null))
|
||||
assert_eq(food_need.get_status(), OpportunityStateRecord.STATUS_OPEN)
|
||||
assert_eq(food_need.get_closed_tick(), -1)
|
||||
|
||||
|
||||
func test_restore_preserves_ids_sorted_queries_and_resolves_only_oldest_open() -> void:
|
||||
var older := OpportunityStateRecord.create(2, 5, 4, 7)
|
||||
var newer := OpportunityStateRecord.create(5, 8, 7, 9)
|
||||
var restored_records: Array[OpportunityStateRecord] = [newer, older]
|
||||
var system := FoodShortageOpportunitySystemScript.new()
|
||||
var system := VillageOpportunitySystemScript.new()
|
||||
system.restore(restored_records, 6)
|
||||
|
||||
assert_eq(system.next_opportunity_id, 6)
|
||||
@@ -229,7 +242,7 @@ func test_record_parser_rejects_malformed_state_combinations() -> void:
|
||||
|
||||
|
||||
func _open_fixture() -> Dictionary:
|
||||
var system := FoodShortageOpportunitySystemScript.new()
|
||||
var system := VillageOpportunitySystemScript.new()
|
||||
var pantry := _empty_pantry()
|
||||
var npc := _npc(0, 90.0)
|
||||
var npcs: Array[SimNPC] = [npc]
|
||||
@@ -0,0 +1,318 @@
|
||||
extends SceneTree
|
||||
|
||||
var failures: Array[String] = []
|
||||
var invalidated_ids: Array[int] = []
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var manager := _create_manager(1201)
|
||||
manager.opportunity_invalidated.connect(_on_opportunity_invalidated)
|
||||
var actor: SimNPC = manager.npcs[0]
|
||||
var witness: SimNPC = manager.npcs[1]
|
||||
var supplier: SimNPC = manager.npcs[2]
|
||||
actor.position = Vector3.ZERO
|
||||
witness.position = Vector3(4.0, 0.0, 0.0)
|
||||
supplier.position = Vector3(30.0, 0.0, 0.0)
|
||||
_set_wood_amount(manager, 0.5)
|
||||
var safety_before: float = manager.village.safety
|
||||
var event_count_before: int = manager.economic_events.size()
|
||||
|
||||
actor.set_task(SimulationIds.ACTION_PATROL, 1.0)
|
||||
actor.start_working()
|
||||
manager.simulate_tick()
|
||||
var trigger := _latest_event_of_type(manager, SimulationIds.EVENT_TASK_BLOCKED, actor.id)
|
||||
var opportunity: OpportunityStateRecord = manager.get_active_opportunity()
|
||||
_check(trigger != null, "Missing wood should create one objective task_blocked fact")
|
||||
_check(opportunity != null, "The performer's known blocked-work fact should open one need")
|
||||
if trigger == null or opportunity == null:
|
||||
manager.free()
|
||||
_finish()
|
||||
return
|
||||
var trigger_id := int(trigger.data["event_id"])
|
||||
_check(
|
||||
(
|
||||
StringName(trigger.data.get("action_id", &"")) == SimulationIds.ACTION_PATROL
|
||||
and StringName(trigger.data["source_id"]) == SimulationIds.STORAGE_VILLAGE_WOODPILE
|
||||
and StringName(trigger.data["item_id"]) == SimulationIds.RESOURCE_WOOD
|
||||
and is_equal_approx(float(trigger.data.get("required_amount", 0.0)), 1.0)
|
||||
and is_equal_approx(float(trigger.data["amount"]), 0.0)
|
||||
),
|
||||
"The blocked fact should retain stable action, storage, resource, and requirement fields"
|
||||
)
|
||||
_check(
|
||||
(
|
||||
is_equal_approx(manager.village.safety, safety_before)
|
||||
and is_equal_approx(manager.get_woodpile().get_amount(SimulationIds.RESOURCE_WOOD), 0.5)
|
||||
and manager.economic_events.size() == event_count_before + 1
|
||||
),
|
||||
"Blocked work should apply no effect and opening should add no quest-only event"
|
||||
)
|
||||
_check(
|
||||
(
|
||||
manager.npc_knows_event(actor.id, trigger_id)
|
||||
and manager.npc_knows_event(witness.id, trigger_id)
|
||||
and opportunity.get_opportunity_type() == SimulationIds.OPPORTUNITY_SUPPLY_MISSING_WOOD
|
||||
and opportunity.get_interested_npc_id() == actor.id
|
||||
and opportunity.get_target_id() == SimulationIds.STORAGE_VILLAGE_WOODPILE
|
||||
and opportunity.get_resource_id() == SimulationIds.RESOURCE_WOOD
|
||||
and is_equal_approx(opportunity.get_target_amount(), 1.0)
|
||||
and manager.is_known_event_lasting(actor.id, trigger_id)
|
||||
),
|
||||
"The performer and nearby witness should know the exact fact while its owner retains it"
|
||||
)
|
||||
|
||||
var active_json: String = manager.serialize_state()
|
||||
var active_restored := _create_manager(1202)
|
||||
_check(
|
||||
active_restored.restore_state_from_json(active_json),
|
||||
"An active missing-wood need should survive schema-v9 restore"
|
||||
)
|
||||
_check(
|
||||
(
|
||||
active_restored.get_state_checksum() == manager.get_state_checksum()
|
||||
and active_restored.get_active_opportunity() != null
|
||||
and active_restored.is_known_event_lasting(actor.id, trigger_id)
|
||||
),
|
||||
"Active restore should preserve identity, checksum, and protected evidence"
|
||||
)
|
||||
active_restored.free()
|
||||
|
||||
supplier.add_inventory(SimulationIds.RESOURCE_WOOD, 1.0)
|
||||
_check(
|
||||
is_equal_approx(
|
||||
manager.economy.deposit_inventory(supplier, SimulationIds.RESOURCE_WOOD), 1.0
|
||||
),
|
||||
"A real NPC inventory deposit should supply the woodpile"
|
||||
)
|
||||
var resolved: OpportunityStateRecord = manager.get_latest_opportunity_for_npc(actor.id)
|
||||
var resolution_event: EconomicEventRecord = manager.get_opportunity_resolution_event(resolved)
|
||||
_check(
|
||||
(
|
||||
resolved != null
|
||||
and resolved.get_status() == OpportunityStateRecord.STATUS_RESOLVED
|
||||
and manager.get_active_opportunity() == null
|
||||
and resolution_event != null
|
||||
and (
|
||||
StringName(resolution_event.data["event_type"])
|
||||
== SimulationIds.EVENT_STORAGE_DEPOSITED
|
||||
)
|
||||
and StringName(resolution_event.data["item_id"]) == SimulationIds.RESOURCE_WOOD
|
||||
and resolved.get_resolution_event_id() == int(resolution_event.data["event_id"])
|
||||
and not manager.is_known_event_lasting(actor.id, trigger_id)
|
||||
),
|
||||
"The exact later wood deposit should resolve the need and release its trigger memory"
|
||||
)
|
||||
var resolved_json: String = manager.serialize_state()
|
||||
var resolved_restored := _create_manager(1203)
|
||||
_check(
|
||||
resolved_restored.restore_state_from_json(resolved_json),
|
||||
"Resolved missing-wood history should restore"
|
||||
)
|
||||
_check(
|
||||
resolved_restored.get_state_checksum() == manager.get_state_checksum(),
|
||||
"Resolved restore should preserve the deterministic checksum"
|
||||
)
|
||||
resolved_restored.free()
|
||||
manager.free()
|
||||
|
||||
var player_manager := _create_manager(1204)
|
||||
var player_actor := _open_missing_wood_need(player_manager)
|
||||
var tree := _create_player_tree()
|
||||
root.add_child(tree)
|
||||
await process_frame
|
||||
_check(player_manager.register_resource_node(tree), "Player branch should bind a real tree")
|
||||
_check(
|
||||
is_equal_approx(player_manager.harvest_resource_node(tree), 1.0),
|
||||
"Player tree extraction should supply the authoritative woodpile"
|
||||
)
|
||||
var player_resolved: OpportunityStateRecord = player_manager.get_latest_opportunity_for_npc(
|
||||
player_actor.id
|
||||
)
|
||||
var player_event: EconomicEventRecord = player_manager.get_opportunity_resolution_event(
|
||||
player_resolved
|
||||
)
|
||||
_check(
|
||||
(
|
||||
player_resolved.get_status() == OpportunityStateRecord.STATUS_RESOLVED
|
||||
and (
|
||||
StringName(player_event.data["event_type"])
|
||||
== SimulationIds.EVENT_RESOURCE_EXTRACTED
|
||||
)
|
||||
and int(player_event.data["actor_id"]) == -1
|
||||
and (
|
||||
StringName(player_event.data["destination_id"])
|
||||
== SimulationIds.STORAGE_VILLAGE_WOODPILE
|
||||
)
|
||||
),
|
||||
"Player extraction should resolve through its exact existing economy event"
|
||||
)
|
||||
tree.queue_free()
|
||||
player_manager.free()
|
||||
|
||||
invalidated_ids.clear()
|
||||
var death_manager := _create_manager(1205)
|
||||
death_manager.opportunity_invalidated.connect(_on_opportunity_invalidated)
|
||||
var doomed := _open_missing_wood_need(death_manager)
|
||||
var death_opportunity: OpportunityStateRecord = death_manager.get_active_opportunity()
|
||||
var death_trigger_id := death_opportunity.get_trigger_event_id()
|
||||
doomed.hunger = 100.0
|
||||
doomed.is_starving = true
|
||||
doomed.starvation_ticks = doomed.starvation_death_threshold - 1
|
||||
death_manager.simulate_tick()
|
||||
_check(
|
||||
(
|
||||
doomed.is_dead
|
||||
and death_opportunity.get_status() == OpportunityStateRecord.STATUS_INVALIDATED
|
||||
and (
|
||||
death_opportunity.get_invalidation_reason()
|
||||
== SimulationIds.OPPORTUNITY_INVALIDATED_INTERESTED_DIED
|
||||
)
|
||||
and death_opportunity.get_closed_tick() == death_manager.tick_count
|
||||
and invalidated_ids == [death_opportunity.get_opportunity_id()]
|
||||
and not death_manager.is_known_event_lasting(doomed.id, death_trigger_id)
|
||||
),
|
||||
"Interested-party death should deterministically invalidate once and release evidence"
|
||||
)
|
||||
var death_json: String = death_manager.serialize_state()
|
||||
var death_restored := _create_manager(1206)
|
||||
_check(
|
||||
death_restored.restore_state_from_json(death_json),
|
||||
"Death-invalidated opportunity history should restore"
|
||||
)
|
||||
death_restored.free()
|
||||
death_manager.free()
|
||||
|
||||
var stale_manager := _create_manager(1207)
|
||||
var stale_actor := _open_missing_wood_need(stale_manager)
|
||||
var stale_opportunity: OpportunityStateRecord = stale_manager.get_active_opportunity()
|
||||
var review_interval: int = stale_manager.get_knowledge_review_interval()
|
||||
_check(
|
||||
(
|
||||
stale_manager.opportunity_system.maintain_open_opportunity(
|
||||
stale_opportunity.get_created_tick() + review_interval - 1,
|
||||
review_interval,
|
||||
stale_manager.npcs,
|
||||
stale_manager.get_pantry(),
|
||||
stale_manager.get_woodpile()
|
||||
)
|
||||
== null
|
||||
),
|
||||
"The need should remain open until the exact daily staleness boundary"
|
||||
)
|
||||
var stale_closed: OpportunityStateRecord = (
|
||||
stale_manager
|
||||
. opportunity_system
|
||||
. maintain_open_opportunity(
|
||||
stale_opportunity.get_created_tick() + review_interval,
|
||||
review_interval,
|
||||
stale_manager.npcs,
|
||||
stale_manager.get_pantry(),
|
||||
stale_manager.get_woodpile()
|
||||
)
|
||||
)
|
||||
_check(
|
||||
(
|
||||
stale_closed == stale_opportunity
|
||||
and stale_closed.get_status() == OpportunityStateRecord.STATUS_INVALIDATED
|
||||
and (
|
||||
stale_closed.get_invalidation_reason()
|
||||
== SimulationIds.OPPORTUNITY_INVALIDATED_EVIDENCE_STALE
|
||||
)
|
||||
and not stale_manager.is_known_event_lasting(
|
||||
stale_actor.id, stale_closed.get_trigger_event_id()
|
||||
)
|
||||
),
|
||||
"Unresolved evidence should expire deterministically at one simulated day"
|
||||
)
|
||||
stale_manager.free()
|
||||
|
||||
_finish()
|
||||
|
||||
|
||||
func _open_missing_wood_need(manager: Node) -> SimNPC:
|
||||
var actor: SimNPC = manager.npcs[0]
|
||||
actor.position = Vector3.ZERO
|
||||
_set_wood_amount(manager, 0.0)
|
||||
actor.set_task(SimulationIds.ACTION_STUDY, 1.0)
|
||||
actor.start_working()
|
||||
manager.simulate_tick()
|
||||
_check(manager.get_active_opportunity() != null, "Setup should open a missing-wood need")
|
||||
return actor
|
||||
|
||||
|
||||
func _set_wood_amount(manager: Node, amount: float) -> void:
|
||||
var woodpile: StorageStateRecord = manager.get_woodpile()
|
||||
woodpile.withdraw(SimulationIds.RESOURCE_WOOD, woodpile.get_amount(SimulationIds.RESOURCE_WOOD))
|
||||
woodpile.deposit(SimulationIds.RESOURCE_WOOD, amount)
|
||||
manager.economy.sync_resource(SimulationIds.RESOURCE_WOOD)
|
||||
|
||||
|
||||
func _latest_event_of_type(
|
||||
manager: Node, event_type: StringName, actor_id: int
|
||||
) -> EconomicEventRecord:
|
||||
var events: Array = manager.get_npc_events(actor_id, 8)
|
||||
for index in range(events.size() - 1, -1, -1):
|
||||
var event := events[index] as EconomicEventRecord
|
||||
if StringName(event.data["event_type"]) == event_type:
|
||||
return event
|
||||
return null
|
||||
|
||||
|
||||
func _create_player_tree() -> ResourceNode:
|
||||
var tree := ResourceNode.new()
|
||||
tree.name = "OpportunityTree"
|
||||
tree.node_id = &"opportunity_tree"
|
||||
tree.action_id = SimulationIds.ACTION_GATHER_WOOD
|
||||
tree.resource_id = SimulationIds.RESOURCE_WOOD
|
||||
tree.initial_amount = 1.0
|
||||
tree.yield_per_action = 1.0
|
||||
tree.can_player_use = true
|
||||
tree.debug_label_enabled = false
|
||||
var interaction_point := Marker3D.new()
|
||||
interaction_point.name = "InteractionPoint"
|
||||
tree.add_child(interaction_point)
|
||||
return tree
|
||||
|
||||
|
||||
func _create_manager(seed_value: int) -> Node:
|
||||
var manager: Node = load("res://simulation/SimulationManager.gd").new()
|
||||
manager.simulation_seed = seed_value
|
||||
manager.debug_logs = false
|
||||
var home_positions: Array[Vector3] = [
|
||||
Vector3(0.0, 0.0, 0.0),
|
||||
Vector3(2.0, 0.0, 0.0),
|
||||
Vector3(20.0, 0.0, 0.0),
|
||||
Vector3(30.0, 0.0, 0.0),
|
||||
Vector3(40.0, 0.0, 0.0),
|
||||
Vector3(50.0, 0.0, 0.0),
|
||||
]
|
||||
manager.home_positions = home_positions
|
||||
root.add_child(manager)
|
||||
manager.set_process(false)
|
||||
for npc in manager.npcs:
|
||||
npc.set_task(SimulationIds.ACTION_WANDER, 1000.0)
|
||||
npc.start_working()
|
||||
return manager
|
||||
|
||||
|
||||
func _on_opportunity_invalidated(opportunity: OpportunityStateRecord) -> void:
|
||||
invalidated_ids.append(opportunity.get_opportunity_id())
|
||||
|
||||
|
||||
func _check(condition: bool, message: String) -> void:
|
||||
if not condition:
|
||||
failures.append(message)
|
||||
|
||||
|
||||
func _finish() -> void:
|
||||
if failures.is_empty():
|
||||
print("[TEST] Missing wood opportunity passed: blocked work -> supply or invalidation")
|
||||
quit(0)
|
||||
return
|
||||
for failure in failures:
|
||||
push_error("[TEST] " + failure)
|
||||
quit(1)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dfxcllud4ghy0
|
||||
Reference in New Issue
Block a user