601 lines
19 KiB
GDScript
601 lines
19 KiB
GDScript
extends CanvasLayer
|
||
|
||
@export var simulation_manager: Node
|
||
|
||
@onready var village_stats_label: Label = $VillagePanel/MarginContainer/VillageStatsLabel
|
||
@onready var npc_inspector_label: Label = $NpcInspectorPanel/MarginContainer/NpcInspectorLabel
|
||
|
||
var selected_npc_index := 0
|
||
var inspector_refresh_accumulator := 0.0
|
||
var debug_overlay_visible := true
|
||
|
||
|
||
func _ready() -> void:
|
||
if simulation_manager == null:
|
||
push_error("VillageUI: simulation_manager missing")
|
||
return
|
||
|
||
if simulation_manager.has_signal("village_changed"):
|
||
simulation_manager.village_changed.connect(_on_village_changed)
|
||
else:
|
||
push_error("VillageUI: SimulationManager has no village_changed signal")
|
||
if simulation_manager.has_signal("npc_decision_recorded"):
|
||
simulation_manager.npc_decision_recorded.connect(_on_npc_decision_recorded)
|
||
else:
|
||
push_error("VillageUI: SimulationManager has no npc_decision_recorded signal")
|
||
if simulation_manager.has_signal("state_restored"):
|
||
simulation_manager.state_restored.connect(_on_state_restored)
|
||
if simulation_manager.has_signal("speed_changed"):
|
||
simulation_manager.speed_changed.connect(_on_speed_changed)
|
||
if simulation_manager.has_signal("relationship_changed"):
|
||
simulation_manager.relationship_changed.connect(_on_relationship_changed)
|
||
if simulation_manager.has_signal("event_knowledge_changed"):
|
||
simulation_manager.event_knowledge_changed.connect(_on_event_knowledge_changed)
|
||
if simulation_manager.has_signal("event_knowledge_forgotten"):
|
||
simulation_manager.event_knowledge_forgotten.connect(_on_event_knowledge_forgotten)
|
||
if simulation_manager.has_signal("opportunity_opened"):
|
||
simulation_manager.opportunity_opened.connect(_on_opportunity_opened)
|
||
if simulation_manager.has_signal("opportunity_resolved"):
|
||
simulation_manager.opportunity_resolved.connect(_on_opportunity_resolved)
|
||
if simulation_manager.has_signal("opportunity_invalidated"):
|
||
simulation_manager.opportunity_invalidated.connect(_on_opportunity_invalidated)
|
||
|
||
if "village" in simulation_manager:
|
||
_on_village_changed(simulation_manager.village)
|
||
_refresh_npc_inspector()
|
||
|
||
|
||
func _process(delta: float) -> void:
|
||
inspector_refresh_accumulator += delta
|
||
if inspector_refresh_accumulator < 0.25:
|
||
return
|
||
inspector_refresh_accumulator = 0.0
|
||
_refresh_npc_inspector()
|
||
|
||
|
||
func _unhandled_key_input(event: InputEvent) -> void:
|
||
if not event is InputEventKey or not event.pressed or event.echo:
|
||
return
|
||
if event.keycode != KEY_TAB or simulation_manager.npcs.is_empty():
|
||
return
|
||
selected_npc_index = (selected_npc_index + 1) % simulation_manager.npcs.size()
|
||
_refresh_npc_inspector()
|
||
get_viewport().set_input_as_handled()
|
||
|
||
|
||
func _on_village_changed(village: SimVillage) -> void:
|
||
var name_map := {}
|
||
for npc in simulation_manager.npcs:
|
||
name_map[npc.id] = npc.npc_name
|
||
var event_lines: Array[String] = []
|
||
for event in simulation_manager.get_recent_events(3):
|
||
event_lines.append(event.description(name_map))
|
||
var event_text := "\n".join(event_lines)
|
||
if event_text.is_empty():
|
||
event_text = ""
|
||
else:
|
||
event_text = "\n" + event_text
|
||
var speed_text := ""
|
||
if simulation_manager.has_method("get_current_speed"):
|
||
speed_text = simulation_manager.get_current_speed()
|
||
var rates: Dictionary = simulation_manager.get_resource_rates()
|
||
var food_rate := ""
|
||
if rates["food_per_day"] > 0.01:
|
||
food_rate = " (−%.0f/d)" % rates["food_per_day"]
|
||
var wood_rate := ""
|
||
if rates["wood_per_day"] > 0.01:
|
||
wood_rate = " (−%.0f/d)" % rates["wood_per_day"]
|
||
var opportunity_text := _build_active_opportunity_display()
|
||
var season_text := "Cold" if simulation_manager.is_cold_season() else "Warm"
|
||
village_stats_label.text = (
|
||
"""
|
||
Village [%s]
|
||
|
||
Food: %s%s
|
||
Wood: %s%s
|
||
Safety: %s
|
||
Knowledge: %s
|
||
Starving: %s
|
||
Season: %s
|
||
|
||
Food Mod: %.2f
|
||
Safety Mod: %.2f
|
||
Knowledge Mod: %.2f
|
||
%s%s
|
||
"""
|
||
% [
|
||
speed_text,
|
||
round(village.food),
|
||
food_rate,
|
||
round(village.wood),
|
||
wood_rate,
|
||
round(village.safety),
|
||
round(village.knowledge),
|
||
simulation_manager.get_starving_count(),
|
||
season_text,
|
||
village.food_modifier,
|
||
village.safety_modifier,
|
||
village.knowledge_modifier,
|
||
opportunity_text,
|
||
event_text,
|
||
]
|
||
)
|
||
|
||
|
||
func _on_npc_decision_recorded(_npc: SimNPC, _decision: ActionSelectionResult) -> void:
|
||
_refresh_npc_inspector()
|
||
|
||
|
||
func _on_state_restored() -> void:
|
||
selected_npc_index = 0
|
||
_refresh_village_display()
|
||
_refresh_npc_inspector()
|
||
|
||
|
||
func _on_speed_changed(_multiplier: float) -> void:
|
||
if simulation_manager != null and "village" in simulation_manager:
|
||
_on_village_changed(simulation_manager.village)
|
||
|
||
|
||
func _on_relationship_changed(
|
||
_relationship: RelationshipStateRecord, _cause_event: EconomicEventRecord
|
||
) -> void:
|
||
_refresh_village_display()
|
||
_refresh_npc_inspector()
|
||
|
||
|
||
func _on_event_knowledge_changed(_knower_id: int, _event: EconomicEventRecord) -> void:
|
||
_refresh_village_display()
|
||
_refresh_npc_inspector()
|
||
|
||
|
||
func _on_event_knowledge_forgotten(_knower_id: int, _event: EconomicEventRecord) -> void:
|
||
_refresh_village_display()
|
||
_refresh_npc_inspector()
|
||
|
||
|
||
func _on_opportunity_opened(_opportunity: RefCounted) -> void:
|
||
_refresh_village_display()
|
||
_refresh_npc_inspector()
|
||
|
||
|
||
func _on_opportunity_resolved(
|
||
_opportunity: RefCounted, _resolution_event: EconomicEventRecord
|
||
) -> void:
|
||
_refresh_village_display()
|
||
_refresh_npc_inspector()
|
||
|
||
|
||
func _on_opportunity_invalidated(_opportunity: RefCounted) -> void:
|
||
_refresh_village_display()
|
||
_refresh_npc_inspector()
|
||
|
||
|
||
func _refresh_village_display() -> void:
|
||
if simulation_manager != null and "village" in simulation_manager:
|
||
_on_village_changed(simulation_manager.village)
|
||
|
||
|
||
func _refresh_npc_inspector() -> void:
|
||
if not debug_overlay_visible:
|
||
return
|
||
if simulation_manager == null or simulation_manager.npcs.is_empty():
|
||
npc_inspector_label.text = "No villagers available"
|
||
return
|
||
selected_npc_index = clampi(selected_npc_index, 0, simulation_manager.npcs.size() - 1)
|
||
var npc: SimNPC = simulation_manager.npcs[selected_npc_index]
|
||
var profession_definition := SimulationDefinitions.get_profession(npc.profession)
|
||
var profession_name := String(npc.profession)
|
||
if profession_definition != null:
|
||
profession_name = profession_definition.display_name
|
||
var action_name := _get_action_name(npc.current_task)
|
||
var destination_name := "Resolving"
|
||
if not npc.target_id.is_empty():
|
||
destination_name = String(npc.target_id)
|
||
var decision: ActionSelectionResult = simulation_manager.get_latest_decision(npc.id)
|
||
var reason_text := "Awaiting the next decision"
|
||
var score_text := ""
|
||
if decision != null:
|
||
reason_text = decision.reason
|
||
var score_keys: Array = decision.scores.keys()
|
||
score_keys.sort()
|
||
var score_rows: Array[String] = []
|
||
var rejection_rows: Array[String] = []
|
||
for action_id in score_keys:
|
||
if decision.rejections.has(action_id):
|
||
rejection_rows.append(
|
||
(
|
||
"%s — %s"
|
||
% [
|
||
_get_action_name(StringName(action_id)),
|
||
String(decision.rejections[action_id])
|
||
]
|
||
)
|
||
)
|
||
continue
|
||
score_rows.append(
|
||
(
|
||
"%s %.2f"
|
||
% [_get_action_name(StringName(action_id)), float(decision.scores[action_id])]
|
||
)
|
||
)
|
||
if not score_rows.is_empty():
|
||
score_text = "\n\nUtility\n" + "\n".join(score_rows)
|
||
if not rejection_rows.is_empty():
|
||
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_history_text := _build_memory_history_display(npc)
|
||
var opportunity_text := _build_npc_opportunity_display(npc)
|
||
npc_inspector_label.text = (
|
||
(
|
||
"%s · %s\n"
|
||
+ "Task: %s (%s)\n"
|
||
+ "Destination: %s\n"
|
||
+ "Hunger: %.0f Energy: %.0f\n"
|
||
+ "Carrying food: %.0f wood: %.0f\n"
|
||
+ "%s\n"
|
||
+ "%s\n"
|
||
+ "%s"
|
||
+ "Why\n%s%s\n\n"
|
||
+ "Own history\n%s\n\n"
|
||
+ "[Tab] Next villager [F10] Cinematic/debug [F11] Pantry story [F12] Reset"
|
||
)
|
||
% [
|
||
npc.npc_name,
|
||
profession_name,
|
||
action_name,
|
||
npc.task_state,
|
||
destination_name,
|
||
npc.hunger,
|
||
npc.energy,
|
||
npc.get_inventory_amount(SimulationIds.RESOURCE_FOOD),
|
||
npc.get_inventory_amount(SimulationIds.RESOURCE_WOOD),
|
||
relationship_text,
|
||
memory_history_text,
|
||
opportunity_text,
|
||
reason_text,
|
||
score_text,
|
||
event_text
|
||
]
|
||
)
|
||
|
||
|
||
func _build_active_opportunity_display() -> String:
|
||
if not simulation_manager.has_method("get_active_opportunity"):
|
||
return ""
|
||
var opportunity = simulation_manager.get_active_opportunity()
|
||
if opportunity == null:
|
||
return ""
|
||
var interested_name := _get_npc_name(opportunity.get_interested_npc_id())
|
||
var resource_name := String(opportunity.get_resource_id()).capitalize()
|
||
var current_amount := _get_opportunity_current_amount(opportunity)
|
||
var helper_text := _build_opportunity_helper_display()
|
||
match opportunity.get_opportunity_type():
|
||
SimulationIds.OPPORTUNITY_SUPPLY_MISSING_WOOD:
|
||
var action_name := _get_opportunity_action_name(opportunity)
|
||
return (
|
||
"\n\nVillage need\n"
|
||
+ "◆ Supply wood for blocked work\n"
|
||
+ "%s could not finish %s\n" % [interested_name, action_name]
|
||
+ (
|
||
"%s %.0f / %.0f"
|
||
% [resource_name, current_amount, opportunity.get_target_amount()]
|
||
)
|
||
+ helper_text
|
||
)
|
||
SimulationIds.OPPORTUNITY_FEED_WEAK_VILLAGER:
|
||
return (
|
||
"\n\nVillage need\n"
|
||
+ "◆ Bring food to %s\n" % interested_name
|
||
+ "%s is too weak to gather\n" % interested_name
|
||
+ (
|
||
"%s %.0f / %.0f"
|
||
% [resource_name, current_amount, opportunity.get_target_amount()]
|
||
)
|
||
+ helper_text
|
||
)
|
||
SimulationIds.OPPORTUNITY_REPAIR_HOME_ROOF:
|
||
return (
|
||
"\n\nVillage need\n"
|
||
+ "◆ Repair %s's roof\n" % interested_name
|
||
+ "%s is worried about their damaged home\n" % interested_name
|
||
+ (
|
||
"%s %.0f / %.0f"
|
||
% [resource_name, current_amount, opportunity.get_target_amount()]
|
||
)
|
||
+ helper_text
|
||
)
|
||
return (
|
||
"\n\nVillage need\n"
|
||
+ "◆ Restock the empty pantry\n"
|
||
+ "%s is worried about the shortage\n" % interested_name
|
||
+ "%s %.0f / %.0f" % [resource_name, current_amount, opportunity.get_target_amount()]
|
||
+ helper_text
|
||
)
|
||
|
||
|
||
func _build_opportunity_helper_display() -> String:
|
||
if not simulation_manager.has_method("get_active_opportunity_helper"):
|
||
return ""
|
||
var helper: OpportunityHelperResult = simulation_manager.get_active_opportunity_helper()
|
||
if helper == null:
|
||
var player_text := _build_opportunity_player_response_display()
|
||
return "\nPossible helper: none informed, trusted, and able to supply" + player_text
|
||
return (
|
||
"\nPossible helper: %s — %s\n%s"
|
||
% [_get_npc_name(helper.helper_npc_id), _get_action_name(helper.action_id), helper.reason]
|
||
)
|
||
|
||
|
||
func _build_opportunity_player_response_display() -> String:
|
||
if not simulation_manager.has_method("get_active_opportunity_player_response"):
|
||
return ""
|
||
var response: OpportunityPlayerResponseResult = (
|
||
simulation_manager.get_active_opportunity_player_response()
|
||
)
|
||
if response == null:
|
||
return ""
|
||
var source_suffix := "" if response.available_source_count == 1 else "s"
|
||
return (
|
||
"\nPlayer route: %s → %s · %d finite source%s"
|
||
% [
|
||
_get_action_name(response.action_id),
|
||
String(response.target_id).replace("_", " ").capitalize(),
|
||
response.available_source_count,
|
||
source_suffix,
|
||
]
|
||
)
|
||
|
||
|
||
func _build_npc_opportunity_display(npc: SimNPC) -> String:
|
||
if not simulation_manager.has_method("get_latest_opportunity_for_npc"):
|
||
return ""
|
||
var opportunity = simulation_manager.get_latest_opportunity_for_npc(npc.id)
|
||
if opportunity == null:
|
||
return ""
|
||
var resource_name := String(opportunity.get_resource_id()).capitalize()
|
||
if opportunity.get_status() == OpportunityStateRecord.STATUS_OPEN:
|
||
var current_amount := _get_opportunity_current_amount(opportunity)
|
||
match opportunity.get_opportunity_type():
|
||
SimulationIds.OPPORTUNITY_SUPPLY_MISSING_WOOD:
|
||
return (
|
||
"Open village need\n"
|
||
+ "◆ Find wood for %s\n" % _get_opportunity_action_name(opportunity)
|
||
+ (
|
||
"%s %.0f / %.0f\n\n"
|
||
% [resource_name, current_amount, opportunity.get_target_amount()]
|
||
)
|
||
)
|
||
SimulationIds.OPPORTUNITY_FEED_WEAK_VILLAGER:
|
||
return (
|
||
"Open village need\n"
|
||
+ "◆ %s is too weak to gather\n" % npc.npc_name
|
||
+ (
|
||
"%s %.0f / %.0f\n\n"
|
||
% [resource_name, current_amount, opportunity.get_target_amount()]
|
||
)
|
||
)
|
||
SimulationIds.OPPORTUNITY_REPAIR_HOME_ROOF:
|
||
return (
|
||
"Open village need\n"
|
||
+ "◆ %s's roof needs wood\n" % npc.npc_name
|
||
+ (
|
||
"%s %.0f / %.0f\n\n"
|
||
% [resource_name, current_amount, opportunity.get_target_amount()]
|
||
)
|
||
)
|
||
return (
|
||
"Open village need\n"
|
||
+ "◆ Restock the empty pantry\n"
|
||
+ (
|
||
"%s %.0f / %.0f\n\n"
|
||
% [resource_name, current_amount, opportunity.get_target_amount()]
|
||
)
|
||
)
|
||
if opportunity.get_status() == OpportunityStateRecord.STATUS_INVALIDATED:
|
||
var reason := (
|
||
"The interested villager died"
|
||
if (
|
||
opportunity.get_invalidation_reason()
|
||
== SimulationIds.OPPORTUNITY_INVALIDATED_INTERESTED_DIED
|
||
)
|
||
else "The evidence became stale"
|
||
)
|
||
return "Closed village need\n◆ %s\n\n" % reason
|
||
if opportunity.get_status() != OpportunityStateRecord.STATUS_RESOLVED:
|
||
return ""
|
||
var resolution_event: EconomicEventRecord = simulation_manager.get_opportunity_resolution_event(
|
||
opportunity
|
||
)
|
||
var actor_name := "Someone"
|
||
if resolution_event != null:
|
||
var actor_id := int(resolution_event.data["actor_id"])
|
||
actor_name = "Player" if actor_id < 0 else _get_npc_name(actor_id)
|
||
match opportunity.get_opportunity_type():
|
||
SimulationIds.OPPORTUNITY_SUPPLY_MISSING_WOOD:
|
||
return (
|
||
"Resolved village need\n"
|
||
+ "◆ %s supplied the woodpile\n" % actor_name
|
||
+ "%s target %.0f\n\n" % [resource_name, opportunity.get_target_amount()]
|
||
)
|
||
SimulationIds.OPPORTUNITY_FEED_WEAK_VILLAGER:
|
||
return (
|
||
"Resolved village need\n"
|
||
+ (
|
||
"◆ %s ate the supplied food\n"
|
||
% _get_npc_name(opportunity.get_interested_npc_id())
|
||
)
|
||
+ "%s target %.0f\n\n" % [resource_name, opportunity.get_target_amount()]
|
||
)
|
||
SimulationIds.OPPORTUNITY_REPAIR_HOME_ROOF:
|
||
return (
|
||
"Resolved village need\n"
|
||
+ "◆ %s repaired the roof\n" % actor_name
|
||
+ "%s target %.0f\n\n" % [resource_name, opportunity.get_target_amount()]
|
||
)
|
||
return (
|
||
"Resolved village need\n"
|
||
+ "◆ %s restocked the pantry\n" % actor_name
|
||
+ "%s target %.0f\n\n" % [resource_name, opportunity.get_target_amount()]
|
||
)
|
||
|
||
|
||
func _get_opportunity_current_amount(opportunity: OpportunityStateRecord) -> float:
|
||
var storage: StorageStateRecord
|
||
match opportunity.get_target_id():
|
||
SimulationIds.STORAGE_VILLAGE_PANTRY:
|
||
storage = simulation_manager.get_pantry()
|
||
SimulationIds.STORAGE_VILLAGE_WOODPILE:
|
||
storage = simulation_manager.get_woodpile()
|
||
return storage.get_amount(opportunity.get_resource_id()) if storage != null else 0.0
|
||
|
||
|
||
func _get_opportunity_action_name(opportunity: OpportunityStateRecord) -> String:
|
||
var trigger: EconomicEventRecord = simulation_manager.get_opportunity_trigger_event(opportunity)
|
||
if trigger == null:
|
||
return "work"
|
||
return _get_action_name(StringName(trigger.data.get("action_id", &"")))
|
||
|
||
|
||
func _get_npc_name(npc_id: int) -> String:
|
||
for npc in simulation_manager.npcs:
|
||
if npc.id == npc_id:
|
||
return npc.npc_name
|
||
return "Someone"
|
||
|
||
|
||
func _get_action_name(action_id: StringName) -> String:
|
||
if action_id == SimulationIds.ACTION_IDLE:
|
||
return "Idle"
|
||
if action_id == SimulationIds.ACTION_DEAD:
|
||
return "Dead"
|
||
var definition := SimulationDefinitions.get_action(action_id)
|
||
if definition != null:
|
||
return definition.display_name
|
||
return String(action_id).capitalize()
|
||
|
||
|
||
func set_debug_overlay_visible(is_visible: bool) -> void:
|
||
debug_overlay_visible = is_visible
|
||
visible = is_visible
|
||
if is_visible:
|
||
_refresh_npc_inspector()
|
||
|
||
|
||
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, 3)
|
||
if events.is_empty():
|
||
return "No recorded events yet"
|
||
var name_map := {}
|
||
for other_npc in simulation_manager.npcs:
|
||
name_map[other_npc.id] = other_npc.npc_name
|
||
var lines: Array[String] = []
|
||
for event in events:
|
||
lines.append(event.description(name_map))
|
||
return "\n".join(lines)
|
||
|
||
|
||
func _build_relationship_display(npc: SimNPC) -> String:
|
||
if not simulation_manager.has_method("get_primary_relationship"):
|
||
return ""
|
||
var relationship: RelationshipStateRecord = simulation_manager.get_primary_relationship(npc.id)
|
||
if relationship == null:
|
||
return ""
|
||
var other_name := "Someone"
|
||
for other_npc in simulation_manager.npcs:
|
||
if other_npc.id == relationship.get_subject_id():
|
||
other_name = other_npc.npc_name
|
||
break
|
||
var display := (
|
||
"Relationship: %s — familiar %.0f%%, trust %.0f%%"
|
||
% [
|
||
other_name,
|
||
relationship.get_familiarity() * 100.0,
|
||
relationship.get_trust() * 100.0,
|
||
]
|
||
)
|
||
if not simulation_manager.has_method("get_relationship_cause"):
|
||
return display
|
||
var cause: EconomicEventRecord = simulation_manager.get_relationship_cause(relationship)
|
||
if cause == null:
|
||
return display
|
||
var name_map := {}
|
||
for other_npc in simulation_manager.npcs:
|
||
name_map[other_npc.id] = other_npc.npc_name
|
||
return "%s\nBecause: %s" % [display, cause.description(name_map)]
|
||
|
||
|
||
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 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, event_id
|
||
)
|
||
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:
|
||
var event_type := StringName(event.data["event_type"])
|
||
var item_id := StringName(event.data["item_id"])
|
||
if (
|
||
event_type == SimulationIds.EVENT_STORAGE_DEPOSITED
|
||
and item_id == SimulationIds.RESOURCE_FOOD
|
||
):
|
||
var actor_name: String = name_map.get(int(event.data["actor_id"]), "Someone")
|
||
return "%s stocked %.0f food" % [actor_name, float(event.data["amount"])]
|
||
if (
|
||
event_type == SimulationIds.EVENT_STORAGE_WITHDRAWN
|
||
and item_id == SimulationIds.RESOURCE_FOOD
|
||
):
|
||
var actor_name: String = name_map.get(int(event.data["actor_id"]), "Someone")
|
||
return "%s took %.0f food from the pantry" % [actor_name, float(event.data["amount"])]
|
||
return event.description(name_map)
|
||
|
||
|
||
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"
|