chroma_solstice/docs/dialogue-consequences.md
Your Name e73f63b5d4 add dialogue consequences design notes
next-steps plan for cross-conversation dialogue state: WorldState as the
serialized source of truth, Ink books as disposable views.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 12:01:50 -04:00

2.3 KiB

Dialogue consequences — next steps

Design for dialogue trees with consequences across conversations ("talk again does something else", NPC A affects NPC B, dialogue opens doors). Builds on the existing narrator (Ink) setup — see dialogue_manager.lua, dialogable.lua.

Core principle

Books are disposable views; a global WorldState table is the single source of truth. Each Ink book reads flags in and writes flags out; it holds no authority, so it can be re-inited and thrown away without losing anything. This resolves book-per-character's weakness (book A's visit counts are invisible to book B) — B branches on a WorldState flag, not on A's runtime state.

Mirrors the existing world-vs-room split (world.lua: "the world is only a layout; rooms own their puzzle state"). Narrative progress is a third, global category with its own save file.

Keep book-per-character (Dialogable.book), add a stable self.storyId.

The bug to fix first

Dialogue.open re-inits the story every bump (dialogue_manager.lua:31-33), discarding all state — so there's no "again" to hang consequences on.

Steps

  1. Add a global WorldState = {} (flags + counters).
  2. saveProgress / loadProgresssave/progress.sav via TSerial + readFromSource / writeToSource (helpers already exist, used in world.lua / world_seed.lua). Shape: { version = 1, flags = WorldState }. Flat table, no per-book blobs initially.
  3. Dialogue.bridge(story) on open:
    • story:bind("flag", fn) — read a WorldState flag from Ink.
    • story:bind("setflag", fn) — write one back.
    • gameplay binds, e.g. give_color / open_door calling into currentRoom.
  4. Cache the live story per storyId in the Dialogue module (stop re-init'ing).
  5. Hook saveProgress into the existing autosave points (near room.lua:814).

"Talk again does X" = increment an own WorldState counter (e.g. sage_talk_count) on open, branch on it in Ink. No reliance on Ink visit-count persistence.

Deferred

Persisting story:save_state() (plain table, keyed by storyId) only buys in-book niceties — consumed sticky choices, resume mid-conversation across a hard quit. Skipped initially: it couples the save file to book structure and forces narrator's migrate hook on every .ink edit. WorldState flags don't — a renamed flag just reads nil/false.