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>
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
- Add a global
WorldState = {}(flags + counters). saveProgress/loadProgress→save/progress.savvia TSerial +readFromSource/writeToSource(helpers already exist, used inworld.lua/world_seed.lua). Shape:{ version = 1, flags = WorldState }. Flat table, no per-book blobs initially.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_doorcalling intocurrentRoom.
- Cache the live story per
storyIdin the Dialogue module (stop re-init'ing). - Hook
saveProgressinto the existing autosave points (nearroom.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.