Zorg's Dungeon Maker — game spec & build plan
Translated and restructured from the French design manual (Zorg's Dungeon Maker — base edition + Deluxe Edition + level pack). This document is the build-ready reference: game rules, functional requirements (FR), non-functional requirements (NFR), open questions in the source material, and a phased build plan.
A visual, browsable version of this same content is published here: https://claude.ai/code/artifact/6cba5160-4467-42f4-a42a-ac8ae294c20a
1. Game rules
Every level runs in two phases. Construction: the player lays out every room supplied by the level on a grid, forming one connected dungeon. Extermination: heroes spawn one at a time and path toward Zorg's room using fixed, deterministic priorities; the player can cast one-time spells to stop them. A level is won once every hero is dead and every stated constraint holds — lost the instant any hero reaches Zorg.
Terminology
Rooms
| Room | Params | Effect |
|---|---|---|
A | — | Spawn room. Heroes appear here. Multiple A rooms: player names a "main" one; any A a hero passes through becomes the new main. All A rooms must share one orientation. |
Z | — | Zorg's room. A hero entering it ends the level in an instant loss. |
D(x) | x: int, can be negative | Deals x damage on every entry. Negative x heals. |
E(elem) | elem: fire / water / ice / poison | Green cells act per element: fire deals 1 dmg/entry; water is impassable and kills a non-immune hero who ends up on it; ice forces sliding until a wall stops the hero; poison gives +1 HP on a cell's first visit, −3 HP every visit after. Immune heroes ignore the cell entirely. |
P(n, f) | n: int, f: index→index | On a hero's i-th entry (i ≤ n), teleports them to the first cell of their f(i)-th-most-recent room visit. If f(i) overshoots their history, they return to the waiting room and respawn. |
O(x) | x: gold | First hero to enter takes all x gold. If that hero later dies, the gold attaches to the death room (which becomes an O room too). Pickup pre-empts any other effect of entering. |
T(x, elem) | x: gold cost | Dark cells behave like E(elem). Light cells charge the first x gold a hero has collected (FIFO, refunded to its source rooms) to cross; can't-pay heroes can't pass, and one shoved onto an unpayable cell dies instantly. |
C(…) | 1–2 numeric args seen | Referenced but never defined in the supplied manual — appears only inside the "Artillery" contract. See open questions. |
Heroes (path priorities, high → low)
| Hero | HP / params | Priorities |
|---|---|---|
Warrior(x) | x HP | Shortest path to Z, ignoring HP loss → ties: right, up, left, down. |
Elf(x, elems) | x HP, immune to elems | Shortest path to Z among those preserving the most HP → ties: right, up, left, down. |
Gunner(x, c[, dur]) | x HP, up to c shots | Path that lets it fire soonest → then HP-preserving shortest path (factoring its shots), up to c shots limited by shot duration → ties: right, up, left, down. Can fire a Shell cardinally onto an adjacent cell if the shot isn't of infinite duration. |
Shell (Gunner's projectile, not a hero) | — | Flies straight until a wall or the dungeon edge; resolves instantly (all other action pauses); clears elemental cells and D/Z monsters; hits every hero it crosses for 2 dmg. |
Mechanic(x, dict) | x HP, dict: room→steps | Shortest path to Z (ignoring HP, using its power) → fewest "unjustified" power uses, using power itself as a tie-break → ties: up, right, down, left. From a listed room it can shove that room (with contents) into an adjacent empty cell for dict[room] steps. |
Princess(x, dict, b) | x HP, dict: room→weight, b: pull | Heads for the reachable room with the highest perceived weight (own dict, default {Z:1}) → among equal targets, the HP-preserving shortest path → ties: right, up, left, down. A room's perceived weight = average of its default weight for her and every other princess's pull b standing in it; every hero, not just princesses, is pulled by weights this way. |
Shared rules: heroes activate one at a time in spawn order — a hero can't act while an earlier one is alive and not stuck, and a freed "stuck" hero blocks everyone spawned after it. Heroes never collide and ignore each other's presence. A hero at ≤0 HP dies instantly and stops planning as if it never could die. Heroes see the whole map at all times except: other heroes, remaining spells, and the consequences of death. With no better path available, a hero simply waits.
Spells (all single-use)
| Spell | Effect | Under Selection |
|---|---|---|
Attack(x) | x damage to every living hero. | x damage to the chosen heroes only. |
Teleport(n) | Active hero → first cell of their n-th-most-recent room visit (or the waiting room if history is too short). | Each selected hero teleports independently by the same rule. |
Move() | Instantly relocates the active hero's room (with contents) onto an empty grid cell. | Several distinct rooms move to distinct empty cells at once. |
Swap() | Swaps the active hero's room with one other room (contents travel with it). | Cyclic swap across the selected heroes' rooms plus one extra room. |
Selection(allow_corpses) | Meta-spell: pick heroes + one other unused spell, apply it to all of them at once. allow_corpses permits targeting the dead. | — |
Sleep() | Chosen awake hero can't act until woken or its HP changes. | — |
Wake() | Chosen sleeping hero wakes up. | — |
Banality | Chosen hero becomes a Warrior, keeping current HP. | — |
A spell can be cast the instant a hero finishes an action (a move, a spawn) but never mid-action — e.g. not while a portal teleport is still resolving. Casting a hero-targeted spell with no active hero is illegal.
Constraints, variables & mirror worlds
dist equations), ordering of deaths, HP floors, gold-at-death rules.choix) reused across a level's rooms, heroes, spells and constraints.2. Functional requirements
Level & content model
choix(n, E) variables chosen by the player at setup from a stated domain (ℕ, ℝ, a finite set, or a repeats-allowed list), substituted everywhere they're referenced in that level.Dungeon construction — "the Maker"
A rooms (matching wall-hatch direction); reject disagreeing layouts.dist(r, s) queries (Manhattan distance between placed rooms) for constraint evaluation.Room behaviors
A): heroes spawn from the current main A; a designated main at setup, auto-replaced by any A room a hero visits.Z): any hero entering ends the run in immediate loss.D(x)): apply x damage per entry, x possibly negative (healing).E): implement all four elements' distinct per-cell rules (fire/water/ice/poison) and full immunity bypass.P(n,f)): teleport on the i-th entry per f(i), with waiting-room fallback when history is too short.O(x)): first-entrant pickup, gold reattaching to a hero's death room, pickup taking priority over other move consequences.T(x,elem)): elemental dark cells plus a FIFO gold toll on light cells, with instant death for an unpayable forced crossing.C room type once its rules are specified — currently undefined in the source.Heroes & AI
Spells
Attack(x): damage to all living heroes, or a Selection subset.Teleport(n): active (or selected) hero to their n-th-most-recent room, waiting-room fallback.Move(): relocate the active hero's room onto an empty cell; Selection variant moves several at once.Swap(): exchange the active hero's room with another; Selection variant performs a cyclic swap.Selection(allow_corpses): apply one other unused spell to multiple chosen heroes at once, optionally including corpses.Sleep(): target hero can't act until woken or its HP changes.Wake(): wakes the target hero.Banality: converts the target hero to a Warrior, keeping its HP.Win/loss, constraints & mirror worlds
3. Non-functional requirements
4. Open questions in the source
C is used in the Artillery contract (C(1), C(2), C(∞,2)) but no chapter defines what it does.Gunner(x, c), but Artillery-contract levels use a third argument (e.g. Gunner(1, 3, 2), Gunner(2, ∞, ∞)) that reads as a shot-duration limit — never formally specified.choix(...) expression, and Deluxe 10.7 lists a literal placeholder hero, Gunner(_).5. Build plan
Two things get built on one shared model: a simulation engine that owns the rules above, and the Maker — the construction-phase editor — plus a thin runner that plays the extermination phase out. Keep the engine a pure library with no UI dependency so the same rules drive the editor's validation, the hero simulation, and the solvability search.
Core engine (library)
The Maker (editor) + runner
Phased roadmap
| Phase | Focus | Covers |
|---|---|---|
| 0 | Data model & level loader — parse every base-edition level without error. | FR-1–FR-3, NFR-2, NFR-9 |
| 1 | Maker MVP + Warrior — grid placement, adjacency/orientation validation, rooms A/Z/D. | FR-5–FR-8, FR-11–FR-13, FR-20, FR-26–FR-31 |
| 2 | Elements & the Elf. | FR-14, FR-21 |
| 3 | Portals, gold & tolls — the trickiest state-tracking rooms. | FR-15–FR-17 |
| 4 | Spellbook — all eight spells, including Selection's meta-dispatch. | FR-32–FR-42 |
| 5 | Remaining heroes — Mechanic, Gunner + Shell (resolve the duration question first), Princess's weight-pull system. | FR-22–FR-25 |
| 6 | Mirror worlds & solvability search. | FR-9, FR-45, FR-46, NFR-4 |
| 7 | Content & regression — import the ~130-level pack as fixtures; settle contract progression/gating. | FR-4, NFR-5 |
Stack-agnostic by design — nothing above assumes a language or renderer. The one hard constraint is NFR-1: whatever you pick, the simulation must stay deterministic and UI-free so the Maker and the solvability search can both drive it honestly.