feat: deliver emergent Jajce commitments
This commit is contained in:
@@ -2,7 +2,7 @@ class_name SimulationStateRecord
|
||||
extends RefCounted
|
||||
|
||||
const SCHEMA_NAME := "the_steward.simulation"
|
||||
const SCHEMA_VERSION := 14
|
||||
const SCHEMA_VERSION := 15
|
||||
const LEGACY_SCHEMA_VERSION := 1
|
||||
const EVENT_LEGACY_SCHEMA_VERSION := 2
|
||||
const RELATIONSHIP_LEGACY_SCHEMA_VERSION := 3
|
||||
@@ -15,6 +15,7 @@ const ROUTINE_LEGACY_SCHEMA_VERSION := 10
|
||||
const PLAYER_RELATIONSHIP_SCHEMA_VERSION := 11
|
||||
const PLAYER_NEEDS_SCHEMA_VERSION := 12
|
||||
const CONFLICT_SCHEMA_VERSION := 13
|
||||
const PRE_EMERGENT_SCHEMA_VERSION := 14
|
||||
const PREVIOUS_SCHEMA_VERSION := 7
|
||||
|
||||
var simulation: Dictionary
|
||||
@@ -27,6 +28,10 @@ var economic_events: Array[EconomicEventRecord] = []
|
||||
var relationships: Array[RelationshipStateRecord] = []
|
||||
var event_knowledge: Array[KnownEventStateRecord] = []
|
||||
var opportunities: Array[OpportunityStateRecord] = []
|
||||
var situations: Array[SituationStateRecord] = []
|
||||
var quest_journal: Array[QuestJournalEntryStateRecord] = []
|
||||
var commitments: Array[CommitmentStateRecord] = []
|
||||
var conversation_history: Array[ConversationActStateRecord] = []
|
||||
var player: PlayerStateRecord
|
||||
var combatants: Array[CombatantStateRecord] = []
|
||||
var factions: Array[FactionStateRecord] = []
|
||||
@@ -58,6 +63,18 @@ func to_dictionary() -> Dictionary:
|
||||
var opportunity_data: Array[Dictionary] = []
|
||||
for opportunity_record in opportunities:
|
||||
opportunity_data.append(opportunity_record.to_dictionary())
|
||||
var situation_data: Array[Dictionary] = []
|
||||
for situation_record in situations:
|
||||
situation_data.append(situation_record.to_dictionary())
|
||||
var journal_data: Array[Dictionary] = []
|
||||
for journal_record in quest_journal:
|
||||
journal_data.append(journal_record.to_dictionary())
|
||||
var commitment_data: Array[Dictionary] = []
|
||||
for commitment_record in commitments:
|
||||
commitment_data.append(commitment_record.to_dictionary())
|
||||
var conversation_history_data: Array[Dictionary] = []
|
||||
for conversation_act in conversation_history:
|
||||
conversation_history_data.append(conversation_act.to_dictionary())
|
||||
var combatant_data: Array[Dictionary] = []
|
||||
for combatant_record in combatants:
|
||||
combatant_data.append(combatant_record.to_dictionary())
|
||||
@@ -78,6 +95,10 @@ func to_dictionary() -> Dictionary:
|
||||
"relationships": relationship_data,
|
||||
"event_knowledge": knowledge_data,
|
||||
"opportunities": opportunity_data,
|
||||
"situations": situation_data,
|
||||
"quest_journal": journal_data,
|
||||
"commitments": commitment_data,
|
||||
"conversation_history": conversation_history_data,
|
||||
"player": player.to_dictionary(),
|
||||
"combatants": combatant_data,
|
||||
"factions": faction_data
|
||||
@@ -115,6 +136,7 @@ static func from_dictionary(record_data: Dictionary) -> SimulationStateRecord:
|
||||
PLAYER_RELATIONSHIP_SCHEMA_VERSION,
|
||||
PLAYER_NEEDS_SCHEMA_VERSION,
|
||||
CONFLICT_SCHEMA_VERSION,
|
||||
PRE_EMERGENT_SCHEMA_VERSION,
|
||||
]
|
||||
):
|
||||
record_data = _migrate_legacy(record_data, version)
|
||||
@@ -134,6 +156,10 @@ static func from_dictionary(record_data: Dictionary) -> SimulationStateRecord:
|
||||
"relationships",
|
||||
"event_knowledge",
|
||||
"opportunities",
|
||||
"situations",
|
||||
"quest_journal",
|
||||
"commitments",
|
||||
"conversation_history",
|
||||
"player",
|
||||
"combatants",
|
||||
"factions",
|
||||
@@ -157,6 +183,10 @@ static func from_dictionary(record_data: Dictionary) -> SimulationStateRecord:
|
||||
"wander_random_streams",
|
||||
"next_event_id",
|
||||
"next_opportunity_id",
|
||||
"next_situation_id",
|
||||
"next_journal_entry_id",
|
||||
"next_commitment_id",
|
||||
"next_conversation_act_id",
|
||||
]
|
||||
)
|
||||
):
|
||||
@@ -166,6 +196,10 @@ static func from_dictionary(record_data: Dictionary) -> SimulationStateRecord:
|
||||
var saved_clock_accumulator := float(simulation_data["clock_accumulator"])
|
||||
var saved_clock_elapsed_ticks := int(simulation_data["clock_elapsed_ticks"])
|
||||
var saved_next_opportunity_id := int(simulation_data["next_opportunity_id"])
|
||||
var saved_next_situation_id := int(simulation_data["next_situation_id"])
|
||||
var saved_next_journal_entry_id := int(simulation_data["next_journal_entry_id"])
|
||||
var saved_next_commitment_id := int(simulation_data["next_commitment_id"])
|
||||
var saved_next_conversation_act_id := int(simulation_data["next_conversation_act_id"])
|
||||
if (
|
||||
not is_finite(saved_tick_interval)
|
||||
or saved_tick_interval <= 0.0
|
||||
@@ -174,6 +208,10 @@ static func from_dictionary(record_data: Dictionary) -> SimulationStateRecord:
|
||||
or saved_clock_accumulator < 0.0
|
||||
or saved_clock_elapsed_ticks < 0
|
||||
or saved_next_opportunity_id < 0
|
||||
or saved_next_situation_id < 0
|
||||
or saved_next_journal_entry_id < 0
|
||||
or saved_next_commitment_id < 0
|
||||
or saved_next_conversation_act_id < 0
|
||||
):
|
||||
return null
|
||||
if simulation_data.has("cycle_duration_seconds"):
|
||||
@@ -204,6 +242,10 @@ static func from_dictionary(record_data: Dictionary) -> SimulationStateRecord:
|
||||
var relationship_data = record_data["relationships"]
|
||||
var knowledge_data = record_data["event_knowledge"]
|
||||
var opportunity_data = record_data["opportunities"]
|
||||
var situation_data = record_data["situations"]
|
||||
var journal_data = record_data["quest_journal"]
|
||||
var commitment_data = record_data["commitments"]
|
||||
var conversation_history_data = record_data["conversation_history"]
|
||||
if (
|
||||
not npc_data is Array
|
||||
or not animal_data is Array
|
||||
@@ -213,6 +255,10 @@ static func from_dictionary(record_data: Dictionary) -> SimulationStateRecord:
|
||||
or not relationship_data is Array
|
||||
or not knowledge_data is Array
|
||||
or not opportunity_data is Array
|
||||
or not situation_data is Array
|
||||
or not journal_data is Array
|
||||
or not commitment_data is Array
|
||||
or not conversation_history_data is Array
|
||||
):
|
||||
return null
|
||||
|
||||
@@ -425,7 +471,10 @@ static func from_dictionary(record_data: Dictionary) -> SimulationStateRecord:
|
||||
return null
|
||||
var knower_id := known_event_record.get_knower_id()
|
||||
var known_event_id := known_event_record.get_event_id()
|
||||
if not npc_ids.has(knower_id) or not event_ids.has(known_event_id):
|
||||
if (
|
||||
(knower_id != SimulationIds.PLAYER_ACTOR_ID and not npc_ids.has(knower_id))
|
||||
or not event_ids.has(known_event_id)
|
||||
):
|
||||
return null
|
||||
var knowledge_key := "%d:%d" % [knower_id, known_event_id]
|
||||
if knowledge_keys.has(knowledge_key):
|
||||
@@ -448,29 +497,28 @@ static func from_dictionary(record_data: Dictionary) -> SimulationStateRecord:
|
||||
return null
|
||||
var observer_id := relationship_record.get_observer_id()
|
||||
var subject_id := relationship_record.get_subject_id()
|
||||
var is_player_observer := observer_id == SimulationIds.PLAYER_ACTOR_ID
|
||||
var is_player_subject := subject_id == SimulationIds.PLAYER_ACTOR_ID
|
||||
if not npc_ids.has(observer_id):
|
||||
if not is_player_observer and not npc_ids.has(observer_id):
|
||||
return null
|
||||
if not is_player_subject and not npc_ids.has(subject_id):
|
||||
return null
|
||||
var relationship_key := "%d:%d" % [observer_id, subject_id]
|
||||
if relationship_keys.has(relationship_key):
|
||||
return null
|
||||
var cause_event_id := relationship_record.get_last_trust_cause_event_id()
|
||||
if (
|
||||
cause_event_id != RelationshipStateRecord.NO_CAUSE_EVENT
|
||||
and not event_ids.has(cause_event_id)
|
||||
):
|
||||
return null
|
||||
if (
|
||||
cause_event_id != RelationshipStateRecord.NO_CAUSE_EVENT
|
||||
and not knowledge_keys.has("%d:%d" % [observer_id, cause_event_id])
|
||||
):
|
||||
return null
|
||||
if cause_event_id != RelationshipStateRecord.NO_CAUSE_EVENT:
|
||||
var cause_event := event_records_by_id[cause_event_id] as EconomicEventRecord
|
||||
if not _is_valid_relationship_cause(cause_event, subject_id, is_player_subject):
|
||||
for dimension in RelationshipStateRecord.DIMENSIONS:
|
||||
var cause_event_id := relationship_record.get_last_cause_event_id(dimension)
|
||||
if cause_event_id == RelationshipStateRecord.NO_CAUSE_EVENT:
|
||||
continue
|
||||
if (
|
||||
not event_ids.has(cause_event_id)
|
||||
or not knowledge_keys.has("%d:%d" % [observer_id, cause_event_id])
|
||||
):
|
||||
return null
|
||||
if dimension == RelationshipStateRecord.DIMENSION_TRUST:
|
||||
var cause_event := event_records_by_id[cause_event_id] as EconomicEventRecord
|
||||
if not _is_valid_relationship_cause(cause_event, subject_id, is_player_subject):
|
||||
return null
|
||||
relationship_keys[relationship_key] = true
|
||||
record.relationships.append(relationship_record)
|
||||
|
||||
@@ -515,6 +563,36 @@ static func from_dictionary(record_data: Dictionary) -> SimulationStateRecord:
|
||||
if int(record.simulation["next_opportunity_id"]) <= highest_opportunity_id:
|
||||
return null
|
||||
|
||||
var emergent_records: Variant = EmergentStateValidator.parse(
|
||||
situation_data, journal_data, commitment_data, simulation_data, npc_ids, event_ids
|
||||
)
|
||||
if emergent_records == null:
|
||||
return null
|
||||
record.situations.assign(emergent_records["situations"])
|
||||
record.quest_journal.assign(emergent_records["quest_journal"])
|
||||
record.commitments.assign(emergent_records["commitments"])
|
||||
var conversation_act_ids: Dictionary = {}
|
||||
var highest_conversation_act_id := -1
|
||||
for item in conversation_history_data:
|
||||
if not item is Dictionary:
|
||||
return null
|
||||
var conversation_act := ConversationActStateRecord.from_dictionary(item)
|
||||
if (
|
||||
conversation_act == null
|
||||
or conversation_act_ids.has(conversation_act.get_act_id())
|
||||
or conversation_act.get_tick() > saved_tick_count
|
||||
or not EmergentStateValidator.is_valid_actor(conversation_act.get_speaker(), npc_ids)
|
||||
or not EmergentStateValidator.is_valid_actor(conversation_act.get_listener(), npc_ids)
|
||||
):
|
||||
return null
|
||||
conversation_act_ids[conversation_act.get_act_id()] = true
|
||||
highest_conversation_act_id = maxi(
|
||||
highest_conversation_act_id, conversation_act.get_act_id()
|
||||
)
|
||||
record.conversation_history.append(conversation_act)
|
||||
if saved_next_conversation_act_id <= highest_conversation_act_id:
|
||||
return null
|
||||
|
||||
return record
|
||||
|
||||
|
||||
@@ -579,16 +657,21 @@ static func _is_valid_knowledge_provenance(
|
||||
SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED:
|
||||
if knower_id == actor_id:
|
||||
return false
|
||||
var source_npc_id := known_event.get_source_npc_id()
|
||||
if not npc_ids.has(source_npc_id):
|
||||
var source_actor_id := known_event.get_source_actor_id()
|
||||
if (
|
||||
source_actor_id != SimulationIds.PLAYER_ACTOR_ID
|
||||
and not npc_ids.has(source_actor_id)
|
||||
):
|
||||
return false
|
||||
var source_method := known_event.get_source_acquisition_method()
|
||||
if (
|
||||
(source_method == SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED)
|
||||
!= (source_npc_id == actor_id)
|
||||
!= (source_actor_id == actor_id)
|
||||
):
|
||||
return false
|
||||
return true
|
||||
if source_method not in KnownEventStateRecord.DIRECT_ACQUISITION_METHODS:
|
||||
return false
|
||||
return known_event.get_hop_count() == 1
|
||||
return false
|
||||
|
||||
|
||||
@@ -774,12 +857,13 @@ static func _is_valid_home_damaged_trigger(
|
||||
static func _is_valid_relationship_cause(
|
||||
cause_event: EconomicEventRecord, subject_id: int, is_player_subject: bool
|
||||
) -> bool:
|
||||
var event_type := StringName(cause_event.data["event_type"])
|
||||
if EmergentStateValidator.is_valid_commitment_relationship_cause(cause_event, subject_id):
|
||||
return true
|
||||
if not is_player_subject:
|
||||
return (
|
||||
int(cause_event.data["actor_id"]) == subject_id
|
||||
and (
|
||||
StringName(cause_event.data["event_type"]) == SimulationIds.EVENT_STORAGE_DEPOSITED
|
||||
)
|
||||
and (event_type == SimulationIds.EVENT_STORAGE_DEPOSITED)
|
||||
and StringName(cause_event.data["item_id"]) == SimulationIds.RESOURCE_FOOD
|
||||
and float(cause_event.data["amount"]) > 0.0
|
||||
)
|
||||
@@ -789,7 +873,7 @@ static func _is_valid_relationship_cause(
|
||||
return false
|
||||
if float(cause_event.data["amount"]) <= 0.0:
|
||||
return false
|
||||
if StringName(cause_event.data["event_type"]) == SimulationIds.EVENT_STORAGE_DEPOSITED:
|
||||
if event_type == SimulationIds.EVENT_STORAGE_DEPOSITED:
|
||||
return (
|
||||
StringName(cause_event.data["source_id"]) == SimulationIds.PLAYER_INVENTORY_ID
|
||||
and (
|
||||
@@ -798,7 +882,7 @@ static func _is_valid_relationship_cause(
|
||||
)
|
||||
)
|
||||
return (
|
||||
StringName(cause_event.data["event_type"]) == SimulationIds.EVENT_RESOURCE_EXTRACTED
|
||||
event_type == SimulationIds.EVENT_RESOURCE_EXTRACTED
|
||||
and StringName(cause_event.data["destination_id"]) == SimulationIds.STORAGE_VILLAGE_PANTRY
|
||||
)
|
||||
|
||||
@@ -848,6 +932,16 @@ static func _is_valid_supply_resolution(
|
||||
static func _migrate_legacy(legacy_data: Dictionary, version: int) -> Dictionary:
|
||||
var migrated := legacy_data.duplicate(true)
|
||||
migrated["schema_version"] = SCHEMA_VERSION
|
||||
migrated["situations"] = []
|
||||
migrated["quest_journal"] = []
|
||||
migrated["commitments"] = []
|
||||
migrated["conversation_history"] = []
|
||||
var emergent_simulation_data: Dictionary = migrated.get("simulation", {})
|
||||
emergent_simulation_data["next_situation_id"] = 0
|
||||
emergent_simulation_data["next_journal_entry_id"] = 0
|
||||
emergent_simulation_data["next_commitment_id"] = 0
|
||||
emergent_simulation_data["next_conversation_act_id"] = 0
|
||||
migrated["simulation"] = emergent_simulation_data
|
||||
if not migrated.has("player"):
|
||||
migrated["player"] = PlayerStateRecord.create_default().to_dictionary()
|
||||
if version < CONFLICT_SCHEMA_VERSION:
|
||||
@@ -927,6 +1021,7 @@ static func _migrate_legacy(legacy_data: Dictionary, version: int) -> Dictionary
|
||||
PLAYER_RELATIONSHIP_SCHEMA_VERSION,
|
||||
PLAYER_NEEDS_SCHEMA_VERSION,
|
||||
CONFLICT_SCHEMA_VERSION,
|
||||
PRE_EMERGENT_SCHEMA_VERSION,
|
||||
]
|
||||
):
|
||||
migrated["opportunities"] = []
|
||||
|
||||
Reference in New Issue
Block a user