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
+60
View File
@@ -4,6 +4,9 @@ const SimulationEventLogScript := preload("res://simulation/events/SimulationEve
const VillageEconomyScript := preload("res://simulation/economy/VillageEconomy.gd")
const RelationshipSystemScript := preload("res://simulation/relationships/RelationshipSystem.gd")
const EventKnowledgeSystemScript := preload("res://simulation/knowledge/EventKnowledgeSystem.gd")
const FoodShortageOpportunitySystemScript := preload(
"res://simulation/opportunities/FoodShortageOpportunitySystem.gd"
)
signal npc_task_changed(npc: SimNPC, old_task: StringName, new_task: StringName)
signal village_changed(village: SimVillage)
@@ -18,6 +21,8 @@ signal relationship_changed(relationship: RelationshipStateRecord, cause_event:
signal event_knowledge_changed(knower_id: int, event: EconomicEventRecord)
signal event_knowledge_transferred(speaker_id: int, listener_id: int, event: EconomicEventRecord)
signal event_knowledge_forgotten(knower_id: int, event: EconomicEventRecord)
signal opportunity_opened(opportunity: OpportunityStateRecord)
signal opportunity_resolved(opportunity: OpportunityStateRecord, cause_event: EconomicEventRecord)
var village := SimVillage.new()
@@ -37,6 +42,7 @@ var event_log := SimulationEventLogScript.new()
var economy := VillageEconomyScript.new()
var relationship_system := RelationshipSystemScript.new()
var event_knowledge_system := EventKnowledgeSystemScript.new()
var opportunity_system := FoodShortageOpportunitySystemScript.new()
var storage_states: Dictionary:
get:
return economy.storage_states
@@ -595,6 +601,7 @@ func _on_economic_event_recorded(event: EconomicEventRecord) -> void:
)
for learned_record in learned_records:
_apply_new_event_knowledge(learned_record, event)
_update_opportunity_from_event(event)
economic_event_recorded.emit(event)
@@ -617,6 +624,7 @@ func try_communicate_at_shared_activity(speaker_id: int, listener_id: int) -> bo
continue
_apply_new_event_knowledge(learned_record, event)
event_knowledge_transferred.emit(speaker.id, listener.id, event)
_update_opportunity_from_event(event)
return true
return false
@@ -663,6 +671,19 @@ func _apply_new_event_knowledge(
_maintain_event_knowledge(false)
func _update_opportunity_from_event(event: EconomicEventRecord) -> void:
var changed: OpportunityStateRecord = opportunity_system.consider_event(
event, tick_count, get_pantry(), npcs, event_knowledge_system, resource_states
)
if changed == null:
return
if changed.get_status() == OpportunityStateRecord.STATUS_OPEN:
opportunity_opened.emit(changed)
return
opportunity_resolved.emit(changed, event)
_maintain_event_knowledge(false)
func _maintain_event_knowledge(expire_by_age: bool) -> void:
var forgotten := event_knowledge_system.maintain_retention(
tick_count, get_knowledge_review_interval(), _get_lasting_knowledge_records(), expire_by_age
@@ -688,6 +709,18 @@ func _get_lasting_knowledge_records() -> Array[KnownEventStateRecord]:
continue
seen[key] = true
lasting.append(record)
var open_opportunity: OpportunityStateRecord = opportunity_system.get_open_opportunity()
if open_opportunity != null:
var opportunity_record := event_knowledge_system.get_record(
open_opportunity.get_interested_npc_id(), open_opportunity.get_trigger_event_id()
)
if opportunity_record != null:
var opportunity_key := (
"%d:%d" % [opportunity_record.get_knower_id(), opportunity_record.get_event_id()]
)
if not seen.has(opportunity_key):
seen[opportunity_key] = true
lasting.append(opportunity_record)
return lasting
@@ -742,6 +775,29 @@ func get_retained_memory_events(npc_id: int, max_count: int = 4) -> Array[Econom
return retained
func get_active_opportunity() -> OpportunityStateRecord:
return opportunity_system.get_open_opportunity()
func get_latest_opportunity_for_npc(npc_id: int) -> OpportunityStateRecord:
return opportunity_system.get_latest_for_npc(npc_id)
func get_opportunity_trigger_event(opportunity: OpportunityStateRecord) -> EconomicEventRecord:
if opportunity == null:
return null
return event_log.get_by_id(opportunity.get_trigger_event_id())
func get_opportunity_resolution_event(opportunity: OpportunityStateRecord) -> EconomicEventRecord:
if (
opportunity == null
or opportunity.get_resolution_event_id() == OpportunityStateRecord.NO_EVENT_ID
):
return null
return event_log.get_by_id(opportunity.get_resolution_event_id())
func npc_knows_event(npc_id: int, event_id: int) -> bool:
return event_knowledge_system.knows_event(npc_id, event_id)
@@ -1032,6 +1088,7 @@ func create_state_record() -> SimulationStateRecord:
"clock_elapsed_ticks": clock.elapsed_ticks,
"wander_random_streams": wander_streams,
"next_event_id": next_event_id,
"next_opportunity_id": opportunity_system.next_opportunity_id,
"cycle_duration_seconds": clock.cycle_duration_seconds
}
record.village = VillageStateRecord.capture(village)
@@ -1054,6 +1111,8 @@ func create_state_record() -> SimulationStateRecord:
record.relationships.append(relationship)
for known_event in event_knowledge_system.get_all_sorted():
record.event_knowledge.append(known_event)
for opportunity in opportunity_system.get_all_sorted():
record.opportunities.append(opportunity)
return record
@@ -1091,6 +1150,7 @@ func restore_state(record: SimulationStateRecord) -> bool:
npcs.append(npc_record.restore(debug_logs))
relationship_system.restore(record.relationships)
event_knowledge_system.restore(record.event_knowledge)
opportunity_system.restore(record.opportunities, int(record.simulation["next_opportunity_id"]))
_maintain_event_knowledge(tick_count % get_knowledge_review_interval() == 0)
wander_random_sources.clear()