174 lines
8.6 KiB
Markdown
174 lines
8.6 KiB
Markdown
# Feature slice: events, memory, situations, quests, and dialogue
|
||
|
||
This is the emergent narrative pipeline. It turns real world mutations into
|
||
evidence, social meaning, unresolved situations, commitments, and semantic
|
||
conversation options without creating a parallel scripted world.
|
||
|
||
## One causal chain
|
||
|
||
```text
|
||
authoritative mutation
|
||
-> WorldEventRecord / EconomicEventRecord
|
||
-> indexed WorldEventStore + compatibility SimulationEventLog
|
||
-> performed/witnessed knowledge with provenance
|
||
-> relationship dimensions with exact causal event IDs
|
||
-> SituationSystem evaluates unresolved predicates
|
||
-> QuestJournalSystem exposes discovery/tracking metadata
|
||
-> SocialCommitmentSystem records promises and outcomes
|
||
-> ConversationService plans semantic intents/topics/options
|
||
-> Dialogue Manager presenter renders one derived turn
|
||
```
|
||
|
||
The event is the shared join key. A quest, journal entry, relationship, or
|
||
dialogue line may reference it, but none of those layers may invent an item,
|
||
resource, damage result, enemy, or reward.
|
||
|
||
## World facts
|
||
|
||
`WorldEntityRef` identifies an actor/participant by typed stable ID.
|
||
`SpatialAddress` identifies `(world_id, location_id, local_position)` and keeps
|
||
coincident local coordinates from crossing contexts. `WorldEventRecord` stores
|
||
event ID/type/tick, participants, optional location, and JSON-safe payload.
|
||
`WorldEventStore` provides O(1) ID lookup plus deterministic indexes by type,
|
||
participant, location, exact tick, and tick range.
|
||
|
||
`SimulationEventLog` remains the local Jajce compatibility façade. It records
|
||
economic and activity facts, enforces the configured world/location scope, and
|
||
refuses to reinterpret retained events under a different active context.
|
||
`ActivityEventValidator` validates definition-backed success and blocked
|
||
facts, including legacy markers. Older unstructured blocked facts remain
|
||
loadable only with explicit migration provenance and cannot become new
|
||
knowable evidence.
|
||
|
||
## Knowledge and relationships
|
||
|
||
`EventKnowledgeSystem` stores a bounded `(knower, event)` record, not copied
|
||
prose. Each memory carries acquisition method, source actor, hop count,
|
||
confidence, salience, pinning, and acquisition tick. Direct actor/witness
|
||
observation happens when the event is recorded; restore never recomputes old
|
||
witnesses from current positions. Communication is one hop from a performed or
|
||
witnessed fact, and the player is a valid knower/source sentinel.
|
||
|
||
Ordinary recent memories are bounded to three per knower; pinned causal facts
|
||
and facts referenced by situations/commitments are protected. The retention
|
||
system changes memory references only; it never deletes objective event facts.
|
||
|
||
`RelationshipSystem` stores sparse directed edges. The seven dimensions are
|
||
familiarity, trust, affection, respect, fear, obligation, and hostility. Each
|
||
non-neutral dimension can retain its exact causal event ID. Consequences are
|
||
bounded and replay-safe: for example, food aid can increase a hungry familiar
|
||
villager's trust toward the actor, while commitment lifecycle consequences
|
||
adjust obligation/trust/hostility by commitment and outcome identity.
|
||
|
||
## Situations and journal entries
|
||
|
||
`SituationDefinition` declares triggering predicates, interested-party and
|
||
participant context, dedupe fields, severity/priority, alternatives, valid
|
||
resolution patterns, expiry/invalidation rules, topics, and commitment terms.
|
||
`SituationSystem` evaluates definitions in deterministic order, caps the
|
||
initial Jajce slice at three active situations, deduplicates by configured
|
||
context, and stores only a `SituationStateRecord` with exact trigger and
|
||
resolution event IDs. Progress is derived live from current state and ordinary
|
||
events.
|
||
|
||
`QuestJournalSystem` stores `QuestJournalEntryStateRecord`: situation ID,
|
||
discovery tick, selected alternative, tracking preference, and close/archive
|
||
state. It never copies objectives or progress. The journal remains empty until
|
||
the player acquires knowledge of the situation through an ordinary path.
|
||
|
||
The current authored pantry shortage is in
|
||
`simulation/situations/resources/pantry_shortage.tres`. Four legacy local
|
||
opportunity types are retained as a compatibility family in
|
||
`VillageOpportunitySystem`; the generic situation system is the direction for
|
||
new content. Roof repair remains disabled until authoritative home-condition
|
||
state exists.
|
||
|
||
## Commitments
|
||
|
||
`SocialCommitmentSystem` creates a `CommitmentStateRecord` when a social promise
|
||
is accepted. It stores debtor/creditor refs, situation, terms, deadline, status,
|
||
and exact acceptance/outcome event IDs. Acceptance does not reserve stock or
|
||
prevent another actor from resolving the situation.
|
||
|
||
`CommitmentLifecycleService` records accepted, fulfilled, broken, released, and
|
||
superseded facts and applies relationship consequences idempotently. A matching
|
||
outcome performed by the debtor fulfills; an outcome performed by another actor
|
||
supersedes without penalty. A still-achievable deadline reached at or after its
|
||
due tick breaks the promise. Release and external impossibility are explicit
|
||
outcomes. Untracking a journal entry is not cancellation.
|
||
|
||
## Deterministic conversations
|
||
|
||
`ConversationService` owns transient conversation records and semantic turns:
|
||
|
||
- `begin(speaker, listener, context)` validates typed participants and context;
|
||
- `get_turn(conversation_id)` returns a copied current turn;
|
||
- `select_option(conversation_id, option_id, expected_revision)` revalidates
|
||
the revision and recomputes the next turn/action;
|
||
- `end()` or `invalidate()` closes the transient session.
|
||
|
||
The planner reads current relationship dimensions/causes, knowledge, performed
|
||
and witnessed history, task/need/profession/role, known situations,
|
||
commitments, and retained conversation acts. Intent definitions provide
|
||
preconditions, deterministic scoring, response intents, cooldowns, and optional
|
||
authoritative actions. Current Jajce intents include greeting, work/wellbeing,
|
||
what happened, sharing a fact, describing a need, offering help, commitment
|
||
accept/decline/renegotiation, progress, thanks/reproach, supersession, and
|
||
goodbye.
|
||
|
||
Only `ConversationActStateRecord` is persisted: typed speaker/listener refs,
|
||
intent ID, topic IDs, tick, and a bounded history. Conversation IDs, revision,
|
||
options, rendered text, and balloon state are transient.
|
||
|
||
## Dialogue Manager boundary
|
||
|
||
The project vendors Dialogue Manager v3.10.4 under `addons/dialogue_manager`
|
||
with provenance/checksum and MIT license in `addons/dialogue_manager/UPSTREAM.md`.
|
||
`DialogueManagerConversationPresenter` receives one planned `ConversationTurn`,
|
||
selects a stable template variant, escapes dynamic names/topics, and creates an
|
||
ephemeral resource. It does not execute game mutations, conditions, or
|
||
authority shortcuts. Controlled option tags map back to stable option IDs and
|
||
the presented revision.
|
||
|
||
`DialogueModeController` owns the loaded player mode: nearest-NPC Talk has
|
||
priority, movement/combat/ordinary interaction lock while open, simulation
|
||
speed is normalized to 1×, stale option selections refresh safely, and the
|
||
mode closes if the speaker dies, unloads, or leaves range. The fake presenter
|
||
tests keep domain tests renderer-independent; parser and mapping tests cover
|
||
the vendored plugin.
|
||
|
||
## Vertical slice and extension recipe
|
||
|
||
The complete Jajce proof is in `tests/emergent_jajce_slice_test.gd` and
|
||
`tests/conversation_domain_test.gd`:
|
||
|
||
1. exact pantry shortage evidence opens a situation;
|
||
2. an NPC knows it while the player does not;
|
||
3. speaking transfers knowledge and discovers the journal entry;
|
||
4. generated options reflect hunger, relationship, evidence, and need;
|
||
5. accepting creates a commitment without reserving stock;
|
||
6. ordinary food gather/deposit resolves the real shortage;
|
||
7. the commitment fulfills or, in variants, breaks/supersedes;
|
||
8. later conversation references the actual outcome;
|
||
9. save/reload preserves semantic history and deterministic options.
|
||
|
||
To add a new emergent story, author an event type and situation definition,
|
||
ensure the authoritative action emits the event, add any social consequence or
|
||
dialogue intent/template, and test the complete causal chain. Do not begin with
|
||
a quest-only enemy/item or a dialogue graph that mutates state behind the
|
||
simulation.
|
||
|
||
## Reference tests and deeper contracts
|
||
|
||
- `tests/unit/test_world_event_store.gd`
|
||
- `tests/unit/test_social_foundations.gd`
|
||
- `tests/unit/test_situation_system.gd`
|
||
- `tests/unit/test_commitment_lifecycle_service.gd`
|
||
- `tests/conversation_domain_test.gd`
|
||
- `tests/dialogue_manager_conversation_presenter_test.gd`
|
||
- `tests/dialogue_mode_controller_test.gd`
|
||
- `tests/emergent_jajce_slice_test.gd`
|
||
- [Economic event stream](ECONOMIC_EVENTS.md)
|
||
- [Simulation state schema](SIMULATION_STATE_SCHEMA.md)
|
||
- [ADR 0002](decisions/0002-emergent-world-content-and-narrative.md)
|