# Character reuse & the seven-campaign arc — design **Date:** 2026-07-12 **Status:** approved (direction); implementation = guardrails inside existing milestones, no new milestone work Commits the **shape** of character reuse across campaigns, the seven-king meta-arc, and generation-time difficulty tiering — and names the cheap decisions that must land inside **M3/M4/M5/M9** and the content build tool so the shape stays reachable. It authors no content, adds no BOM line, and does not unpark v2 world generation. --- ## Problem A character is born at level 1, plays one authored campaign, and stops. There is no structure that lets a character grow *across* worlds, and nothing in the roadmap forbids one — but several unbuilt milestones are about to make choices that would quietly foreclose it. Specifically: **M5 owes a level curve** (the races/classes design says only "level curve → M5") and **M9 owes a save format**. Both are blank. If M5 picks an open-ended curve and M9 picks a single save blob, character reuse becomes a retrofit through the two most expensive systems in the game — the same class of mistake §10 warns about with the RNG seed. This is a **direction spec**. Its deliverable is a shape plus a short list of constraints, not a feature. ## Approach **One character, seven campaigns, one saga — then it ends.** Each campaign faces one of the Seven (`content/lore/the-seven.md`). The character, their companions, their deeds and their level carry from campaign to campaign; the *world* does not. Difficulty is chosen once, at world-construction time, from the campaign index — never during play. Replayability lives at the **character** level, not the campaign level: a new character is a new saga, a new sequence of worlds, potentially a different order of kings. Seven campaigns is a finite, satisfying arc that a level curve can actually be designed against. Rejected alternatives: - **Kings as milestones, not chapters** (campaigns not 1:1 with kings) — no natural level ceiling; "am I making progress" goes fuzzy. - **Kings unkillable, truly infinite** (canon-compatible: you only break a king's grip) — makes the level curve unsolvable, and the running joke turns bleak. - **Full carry of gear and gold** — the tier-N economy has nothing to sell a party hauling four campaigns of loot; §3's "counting coppers for an inn bed" grit dies. - **Event-sourced saga** (deeds are the log; the sheet is derived) — elegant, overkill. --- ## 1. The state model **The canon-log contract does not change.** No schema bump, no API change, the proxy never notices. Every field this design needs already exists in the log — `party[].disposition`, `humiliations[]`, `established_facts[]` — and `player` still admits only `name` / `class_id` / `luck_descriptor`, so the AI never sees a level. The §7 boundary holds for free. What changes is **who fills those fields**. ### Two objects **`Saga`** — durable, survives campaigns. Its own schema, its own save file. ``` schema_version, saga_id character: name, race_id, calling_id, level (1..20), stats {str, dex, con, fth, mag}, luck_base companions: [{id, approval}] # Cadwyn, Brannoc humiliations: [{id, text, weight, turn}] # STACKING across campaigns (§9) deeds: ["…"] # what the world knows you did kings_slain: ["ghaul_the_yoke", …] # subset of the Seven campaigns_completed: 0..7 # tier = this + 1 signature_item_id: string | null # the one thing that survives the Interlude ``` **`Campaign`** — per-campaign, discarded between them: `CanonLog` + `GameState` + the world content set + the RNG seed (§10). Exactly what M9's save/load was already going to hold. Rejected: **one save file with two sections** (the boundary becomes a naming convention rather than a structure). The `Saga` is *also* the future input to world generation — tier, deeds, kings already slain, party composition — so it wants to be a standalone serializable object on its own merits. ### Saga invariants - **One campaign, one king:** `len(kings_slain) == campaigns_completed`. The saga advances only by killing a king. - **The saga is complete at `campaigns_completed == 7`.** There is no campaign 8 and no tier 8. A complete saga is read-only: it can be viewed, not continued. That character is done, and the retirement finally takes. ### The thesis > **The `Saga` is the source. The canon log is a projection of the `Saga` into the > current campaign.** This is §11's own rule one level up — the canon log is never the source of truth for the `Saga`, exactly as AI prose is never the source of truth for state. It gives every carried thing one uniform mechanism instead of five special cases: | Carried | Projected into | Note | |---|---|---| | Companion approval | `party[].disposition` | The `Saga` overrides the origin's `disposition_overrides` | | Humiliations | `humiliations[]` | **Move:** they currently live in the log and would die with it | | Deeds | `established_facts[]` | Appended alongside the origin's `opening_facts` | | Level, stats, `luck_base` | `GameState` | Never the log — the AI sees no number (§7) | ### The seam `client/scripts/newgame/new_game.gd` already reads three immutable inputs and writes two products. It gains **one optional fourth input**: ```gdscript static func construct(origin, world, creation, rng, saga: Saga = null) -> Dictionary ``` - **`saga == null`** → campaign 1. Roll stats, roll Luck, read dispositions from the origin. **Today's behaviour, byte-for-byte unchanged.** - **`saga != null`** → campaign N. Stats / level / `luck_base` come from the `Saga` instead of the dice; companion approval overrides the origin; deeds and humiliations are injected; the signature item is the only grant that is not the origin's. One function, one new parameter, a null default that preserves every existing test. The character-creation UI is simply not shown on the saga path. *§2: state. The `Saga` is code-owned. The AI never reads or writes it.* --- ## 2. Tier `tier = campaigns_completed + 1`, an integer **1..7** (there is no tier 8 — see *Saga invariants*). It is an input to world construction, evaluated **exactly once**, at campaign start. > ### The hard rule > > **Difficulty is fixed at generation. Nothing scales during play.** > > This is the difference between the design and the Oblivion trap. Once the world > is built at tier 5 it is *fixed* — this dungeon is deadly, that road is safe, and > the gradient means something. A world that re-levels as the player levels is a > treadmill, and it makes leveling meaningless. **This is a prohibition, not a > preference.** What tier selects: - **Which enemies exist.** Deterministic damage (§7) forbids multiplying a stat block, and that is a gift: a tier-6 world has *different monsters*, not a rat with 40× HP. The cosmology already supplies the ladder — **proximity to a king is the power scale.** Ghaul's tax collector, then his yoked, then a possessed magistrate, then one of the Sent, then Ghaul. - **The level band.** Tier N ≈ levels 3N−2 … 3N, capped at 20. The exact numbers are M5's to tune; the *bands* are the guardrail. - **Loot, shop stock, and the price table** (§18: the loop is code, the numbers are content). - **The king** — one of the Seven, drawn from those not in `kings_slain`. - **The story-shape.** Tier 1 is a cult cell in a town. Tier 4 is a cult that owns a city. Tier 7 is the king himself. **Content-side cost: one field.** Content entries (`item`, `quest`, enemy units) carry `tier: 1..7`, validated by the build tool. This is schema, not content — it does not violate the content-track spec's rule ("never author anything that is not in the Bill of Materials"). *§2: state.* --- ## 3. The Interlude A state transition between campaigns: `Interlude(saga, completed_campaign) → saga'`. In fiction: **they retired, and it did not take.** They thought campaign 1 was the end. Here they are at campaign 5, still at it. Brannoc keeps expecting to die on a job like this one and keeps not dying, and being dragged back out is both the joke and the tragedy — §9 deepened, not undercut. Per §18 this is **two systems**: the transition is *state* (code owns it), the retirement-that-did-not-take is *text* (the DM narrates it, with an authored fallback per §13). What it does: - **Gold:** mostly gone. **Inventory:** gone — except the one **signature item** the player chooses to keep. - **Luck drift** resets to `luck_base`. They slept in real beds for a year. - **Deeds** harvested from the finished campaign's canon log; `kings_slain` appended. - **Humiliations merged, never overwritten** (§9 is explicit) — now stacking across *lives*, not just hours. - `campaigns_completed += 1`. - **Level, stats, companions, approval: untouched.** Two things make this more than bookkeeping. **It is an Improviser surface, already §7-compliant by construction.** *How* they lost the money is a Luck-selected outcome. Bad luck: Cadwyn lost the purse at dice and there was a fire. Good luck: you kept the good armour. The Interlude's validator whitelist is exactly the §7 line — **gear and coin are dignity; level, deeds, companions and the signature item are progress.** It is structurally incapable of taking progress, which is the same guarantee §7 demands of the Improviser, reused verbatim. **The signature-item choice is the cursed-blade decision, seven times.** §7 asks that "the decision to keep or discard a cursed item" be meaningful. *You may keep exactly one thing* turns the +4 STR / −5 LCK blade into a genuinely bad night's sleep. *§2: both — the transition is state, the interlude prose is text.* --- ## 4. Guardrails — what lands in existing milestones Nothing below adds a milestone or a BOM line. Each item constrains work already sequenced. ### M3 — Title screen *(unbuilt, next — cheapest possible moment)* A saga adds a third entry path alongside new-game / continue / load: **begin the next campaign of an existing saga.** Do not build it. Only avoid hardcoding the flow as `new game → creation → world` such that a fourth path cannot be added. ### M4 — Character creation `NewGame.construct` already takes `creation` as a plain `Dictionary`. Keep it that way: the creation *scene* produces that dict but must not become the only thing that can. On a saga path the dict is synthesized from the `Saga` and the UI is skipped. The guardrail is simply: **do not couple `construct` to the creation scene.** M4 must emit `race_id` and `calling_id` into the creation dict (it will anyway) — they are `Saga` fields. ### M5 — Tactical combat - **Design the level curve to a ceiling of 20 across 7 tiers.** The races/classes design currently says only "level curve → M5". It needs a number, and it needs to be this one, or campaign 7 discovers the math ran out. - **Enemy stat blocks carry `tier`. There is no scaling multiplier, and there never will be.** The M5 BOM line (1 enemy family + boss) is **tier 1** — all the slice needs. - Class abilities are planned to L20, not open-ended. - This design **depends on** the damage-determinism reconcile already flagged for M5 (§7/§10 vs the Combat HUD mock's ranges). Tiering by stat block is what makes "no scaling" possible. ### M9 — Save / load - **Two objects, not one:** `Saga` (durable) + `Campaign` (canon log + `GameState` + world + seed). This is the retrofit that genuinely hurts later — the §10 RNG-seed argument applied to persistence. - **Humiliations move to the `Saga`**, projected into the canon log. Today they live in the log and would die with the campaign. ### Content build tool When the `item` and `quest` namespaces land (already a sequenced M7/M8 prerequisite in the content-track design), add **`tier: 1..7`** to the entry envelope, validated. One field, at a moment the model is already being opened. ### Content roadmap Mark each BOM line **fixed substrate** (currency, price table, abilities, callings, cosmology, the Seven, disposition ladder) vs **per-campaign variable** (town, NPCs, gated knowledge, quest chain, king). The distinction now has a concrete consumer. --- ## 5. The vertical slice is already campaign 1 Greywater Docks, tier 1, patron **Ghaul the Yoke** — exactly what the content-track design authored, before this spec existed. **Zero change to that spec, zero change to the slice.** The saga is what happens *after* it. --- ## 6. Testing - **Regression gate:** `construct(saga = null)` → every existing test passes byte-for-byte. - `construct(saga = …)` → level / stats / approval / humiliations / deeds project correctly; the `Saga` overrides the origin's `disposition_overrides`; only the signature item is granted. - **The Interlude invariant, as a property test:** level, deeds, companions and the signature item can never be reduced. This is the §7 Improviser whitelist expressed as an assertion. - **The anti-Oblivion test:** no code path reads `tier` after construction. - **The saga invariants:** `len(kings_slain) == campaigns_completed`; a `Saga` at `campaigns_completed == 7` cannot begin a campaign. - `Saga` round-trips through save/load. --- ## Consequences - **M5 gains a hard level ceiling (20) and a tier model** — it can no longer pick a curve that forecloses the saga. - **M9 gains a two-object save format** before any save exists in the wild. - **Humiliations become durable** — Brannoc acquires an anthology across lives, not just a repertoire across hours (§9). - **The cosmology supplies the difficulty ladder for free** — proximity to a king is the power scale, so no scaling multiplier is ever needed. - **The `Saga` is the object v2 world generation will consume.** That is the whole point of writing this now. - Difficulty scaling is **structurally prohibited** from becoming a treadmill. ## Out of scope - **AI world generation stays v2.** This spec does not unpark it. It only guarantees the `Saga` is its input when it arrives. - **Tiers 2–7 of content**, the **other six kings**, and the **seven story-shapes** → Backlog. - Authoring any content at all. This spec builds a container and a set of prohibitions.