From e73f63b5d4ceda07319d7e53c73c9334a95495b4 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 8 Aug 2026 12:01:50 -0400 Subject: [PATCH] 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 --- docs/dialogue-consequences.md | 50 +++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 docs/dialogue-consequences.md diff --git a/docs/dialogue-consequences.md b/docs/dialogue-consequences.md new file mode 100644 index 0000000..ccb61ab --- /dev/null +++ b/docs/dialogue-consequences.md @@ -0,0 +1,50 @@ +# 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-`init`ed 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-`init`s 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` / `loadProgress` → `save/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.