feat: add person history and trust reactions

This commit is contained in:
Rijad Zuzo
2026-07-12 11:42:10 +02:00
parent 99b8146f75
commit 9fcf6a0a58
19 changed files with 543 additions and 90 deletions
+56
View File
@@ -23,6 +23,8 @@ func _run() -> void:
visual.set_physics_process(false)
var profession_definition := SimulationDefinitions.get_profession(npc.profession)
var body: MeshInstance3D = visual.get_node("MeshInstance3D")
var trust_reaction_root: Node3D = visual.get_node("TrustReactionRoot")
_check(not trust_reaction_root.visible, "A newly spawned visual should not replay reactions")
_check(
body.material_override.albedo_color == profession_definition.visual_color,
"NPC body color should come from its profession definition"
@@ -56,12 +58,56 @@ func _run() -> void:
not visual.get_node("ProfessionLabel").visible and visual.get_node("TaskGlyphRoot").visible,
"Cinematic mode should hide debug labels while preserving task glyphs"
)
visual.play_trust_gain_reaction()
_check(trust_reaction_root.visible, "A direct trust reaction should reveal the blossom")
visual.play_trust_gain_reaction()
_check(
trust_reaction_root.visible and trust_reaction_root.get_child_count() == 4,
"Restarting a trust reaction should reuse one blossom without stacking visuals"
)
visual.set_debug_overlay_visible(false)
_check(
trust_reaction_root.visible,
"The trust reaction should remain visible in cinematic presentation mode"
)
var active_reaction_tween: Tween = visual.get("trust_reaction_tween")
await active_reaction_tween.finished
_check(
not trust_reaction_root.visible,
"The trust reaction should fade away instead of becoming permanent world clutter"
)
visual.set_debug_overlay_visible(true)
visual.set_task_presentation(SimulationIds.ACTION_WANDER, SimNPC.TASK_STATE_TRAVELING)
_check(
not visual.get_node("TaskGlyphRoot").visible,
"Ambient wander should not display a task glyph"
)
var routed_observer: SimNPC = manager.npcs[1]
var routed_subject: SimNPC = manager.npcs[2]
var observer_visual: Node3D = view.active_npc_visuals[routed_observer.id]
var subject_visual: Node3D = view.active_npc_visuals[routed_subject.id]
var routed_relationship := RelationshipStateRecord.create(
routed_observer.id, routed_subject.id, 0.5, 0.65, 9001
)
var routed_event := EconomicEventRecord.create(
9001,
SimulationIds.EVENT_STORAGE_DEPOSITED,
manager.tick_count,
routed_subject.id,
&"test_source",
SimulationIds.STORAGE_VILLAGE_PANTRY,
SimulationIds.RESOURCE_FOOD,
1.0
)
manager.emit_signal("relationship_changed", routed_relationship, routed_event)
_check(
observer_visual.get_node("TrustReactionRoot").visible,
"The authoritative relationship signal should route a reaction to its observer"
)
_check(
not subject_visual.get_node("TrustReactionRoot").visible,
"A routed trust reaction should not play on the relationship subject"
)
var test_decision := ActionSelectionResult.new(
SimulationIds.ACTION_GATHER_FOOD,
-1.0,
@@ -176,6 +222,16 @@ func _run() -> void:
visual_after_restore.global_position.is_equal_approx(npc.position),
"Rebuilt presentation should use the restored authoritative position"
)
_check(
not visual_after_restore.get_node("TrustReactionRoot").visible,
"Restoring state should rebuild the visual without replaying transient reactions"
)
visual_after_restore.play_trust_gain_reaction()
visual_after_restore.apply_dead_visual_state()
_check(
not visual_after_restore.get_node("TrustReactionRoot").visible,
"Death presentation should suppress an active trust reaction"
)
if failures.is_empty():
print("[TEST] NPC visual lifecycle passed")