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
+57 -43
View File
@@ -188,8 +188,7 @@ func _refresh_npc_inspector() -> void:
score_text += "\n\nUnavailable\n" + "\n".join(rejection_rows)
var event_text := _build_event_history(npc)
var relationship_text := _build_relationship_display(npc)
var memory_text := _build_memory_display(npc)
var known_fact_text := _build_known_fact_display(npc)
var memory_history_text := _build_memory_history_display(npc)
npc_inspector_label.text = (
(
"%s · %s\n"
@@ -199,9 +198,8 @@ func _refresh_npc_inspector() -> void:
+ "Carrying food: %.0f wood: %.0f\n"
+ "%s\n"
+ "%s\n"
+ "%s\n"
+ "Why\n%s%s\n\n"
+ "Recent\n%s\n\n"
+ "Own history\n%s\n\n"
+ "[Tab] Next villager [F10] Cinematic/debug [F12] Demo reset"
)
% [
@@ -215,8 +213,7 @@ func _refresh_npc_inspector() -> void:
npc.get_inventory_amount(SimulationIds.RESOURCE_FOOD),
npc.get_inventory_amount(SimulationIds.RESOURCE_WOOD),
relationship_text,
memory_text,
known_fact_text,
memory_history_text,
reason_text,
score_text,
event_text
@@ -245,7 +242,7 @@ func set_debug_overlay_visible(is_visible: bool) -> void:
func _build_event_history(npc: SimNPC) -> String:
if not simulation_manager.has_method("get_npc_events"):
return ""
var events: Array = simulation_manager.get_npc_events(npc.id, 5)
var events: Array = simulation_manager.get_npc_events(npc.id, 3)
if events.is_empty():
return "No recorded events yet"
var name_map := {}
@@ -287,48 +284,65 @@ func _build_relationship_display(npc: SimNPC) -> String:
return "%s\nBecause: %s" % [display, cause.description(name_map)]
func _build_known_fact_display(npc: SimNPC) -> String:
if not simulation_manager.has_method("get_known_events"):
return ""
var known_events: Array = simulation_manager.get_known_events(npc.id, 1)
if known_events.is_empty():
return "Known fact: none yet"
func _build_memory_history_display(npc: SimNPC) -> String:
if not simulation_manager.has_method("get_retained_memory_events"):
return "Memories unavailable"
var summary: Dictionary = simulation_manager.get_memory_summary(npc.id)
var header := (
"Memories %d lasting · %d recent"
% [int(summary.get("lasting", 0)), int(summary.get("recent", 0))]
)
var retained_events: Array = simulation_manager.get_retained_memory_events(npc.id, 4)
if retained_events.is_empty():
return header + "\nNo retained memories"
var name_map := {}
for other_npc in simulation_manager.npcs:
name_map[other_npc.id] = other_npc.npc_name
var latest_event := known_events[known_events.size() - 1] as EconomicEventRecord
var provenance := "source not recorded"
var retention := "recent"
if simulation_manager.has_method("get_known_event_record"):
var lines: Array[String] = [header]
for event in retained_events:
var event_id := int(event.data["event_id"])
var known_record: KnownEventStateRecord = simulation_manager.get_known_event_record(
npc.id, int(latest_event.data["event_id"])
npc.id, event_id
)
if known_record != null:
match known_record.get_acquisition_method():
SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED:
provenance = "performed personally"
SimulationIds.KNOWLEDGE_ACQUISITION_WITNESSED:
provenance = "witnessed"
SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED:
var source_name: String = name_map.get(
known_record.get_source_npc_id(), "someone"
)
provenance = "heard from %s" % source_name
SimulationIds.KNOWLEDGE_ACQUISITION_LEGACY:
provenance = "source not recorded"
if known_record == null:
continue
var lasting: bool = simulation_manager.is_known_event_lasting(npc.id, event_id)
var marker := "" if lasting else ""
var retention := "lasting" if lasting else "recent"
(
lines
. append(
(
"%s %s · %s · %s"
% [
marker,
retention,
_build_compact_memory_summary(event, name_map),
_build_memory_provenance(known_record, name_map),
]
)
)
)
return "\n".join(lines)
func _build_compact_memory_summary(event: EconomicEventRecord, name_map: Dictionary) -> String:
if (
simulation_manager.has_method("is_known_event_lasting")
and (simulation_manager.is_known_event_lasting(npc.id, int(latest_event.data["event_id"])))
StringName(event.data["event_type"]) == SimulationIds.EVENT_STORAGE_DEPOSITED
and StringName(event.data["item_id"]) == SimulationIds.RESOURCE_FOOD
):
retention = "lasting"
return "Known fact: %s (%s · %s)" % [latest_event.description(name_map), provenance, retention]
var actor_name: String = name_map.get(int(event.data["actor_id"]), "Someone")
return "%s stocked %.0f food" % [actor_name, float(event.data["amount"])]
return event.description(name_map)
func _build_memory_display(npc: SimNPC) -> String:
if not simulation_manager.has_method("get_memory_summary"):
return ""
var summary: Dictionary = simulation_manager.get_memory_summary(npc.id)
return (
"Memory: %d lasting · %d recent"
% [int(summary.get("lasting", 0)), int(summary.get("recent", 0))]
)
func _build_memory_provenance(record: KnownEventStateRecord, name_map: Dictionary) -> String:
match record.get_acquisition_method():
SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED:
return "own action"
SimulationIds.KNOWLEDGE_ACQUISITION_WITNESSED:
return "witnessed"
SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED:
var source_name: String = name_map.get(record.get_source_npc_id(), "someone")
return "heard %s" % source_name
return "source unknown"
+18
View File
@@ -40,6 +40,10 @@ func initialize_world_view() -> void:
simulation_manager.npc_task_changed.connect(_on_npc_task_changed)
else:
push_error("WorldViewManager: SimulationManager has no npc_task_changed signal")
if simulation_manager.has_signal("relationship_changed"):
simulation_manager.relationship_changed.connect(_on_relationship_changed)
else:
push_error("WorldViewManager: SimulationManager has no relationship_changed signal")
if simulation_manager.has_signal("state_restored"):
simulation_manager.state_restored.connect(_on_simulation_state_restored)
else:
@@ -182,6 +186,20 @@ func _on_npc_task_changed(npc: SimNPC, _old_task: StringName, _new_task: StringN
push_error("WorldViewManager: NPCVisual has no set_task_presentation method")
func _on_relationship_changed(
relationship: RelationshipStateRecord, _cause_event: EconomicEventRecord
) -> void:
if relationship == null:
return
var visual = active_npc_visuals.get(relationship.get_observer_id())
if visual == null:
return
if visual.has_method("play_trust_gain_reaction"):
visual.play_trust_gain_reaction()
else:
push_error("WorldViewManager: NPCVisual has no play_trust_gain_reaction method")
func _on_simulation_state_restored() -> void:
for visual in active_npc_visuals.values():
visual.queue_free()