Files
wownerogue/docs/MULTI_LEVEL.md
T
jwinterm 643bec4721 docs: pass for the 2026-07 build — balance sim, multi-level, render packs
- README: rewrite Difficulty section (per-network LEVELS ∝ block time, WOW=5min,
  multi-level descent, corrected casino size); document game_event + depth in the
  Socket.IO table.
- NEW docs/BALANCE_SIM.md: the block-timed edge math (exponential deadline), the
  headless sim over the real engine, what it proved (size self-cancels, fast monster
  fails on slow chains), and the per-network NETWORK_TUNING model.
- NEW docs/MULTI_LEVEL.md: descent mechanic, vault-only treasure, per-level
  provably-fair seeding, config, file map, open polish.
- NEW docs/RENDER_PACKS.md: modes-vs-packs, the RK.fx layer, iso/tiled/zoom/cat.
- docs/ARCHITECTURE.md: mark the block-time-difficulty gotcha RESOLVED; add render
  kit + balance/pacing sections and cross-links.
- docs/TODO.md: 2026-07 done/pending section.
2026-07-11 22:29:57 -04:00

2.8 KiB
Raw Blame History

Multi-level dungeons

A run descends through maxDepth levels instead of a single map. This is the pacing lever that makes the block-timer provide the house edge on slow chains without a giant dungeon or a cheating monster (see BALANCE_SIM.md for why).

Mechanic

  • Each level is a normal preset-sized dungeon with its own entrance, exit, and a fair monster.
  • Reaching a non-final exit takes the stairs down → a fresh level is generated, the player is placed at its entrance, a new monster spawns, and fog-of-war resets. This is not a win.
  • Reaching the final level's exit escapes (win).
  • Treasure lives only in the vault (the final level). Intermediate levels are a race to the stairs; the 2×/3× treasure payout requires descending all the way and getting back out.
  • maxDepth = 1 (single level) is byte-identical to the pre-multi-level game.

Provably fair across the descent

The whole run regenerates from the one committed seed. Per-level seed (levelSeed(masterSeed, depth) in provablyFair.js): level 1 = the master seed verbatim (so single-level games are unchanged), deeper levels salt it (<seed>:L<depth>). Verify any level with DungeonGenerator.regenerateFromSeed(levelSeed(seed, depth), cryptoType).

Configuration

maxDepth comes from difficultyConfig.levels, set by NETWORK_TUNING per chain (GRIN 1 · XMR 2 · LTC 2 · WOW 4 · BTC 8, ∝ block time). Operator overrides: DUNGEON_LEVELS=<n>; NETWORK_TUNING_DISABLED=true forces a single level.

Where it lives

Concern Location
Level generation + descent src/game/game.js — _generateLevel(depth), _descend(), the exit branch in movePlayer (returns event: 'descend'), depth/maxDepth in getState
Per-level seed src/game/provablyFair.js — levelSeed()
Level count (pacing) src/game/difficultyConfig.js — NETWORK_TUNING, DUNGEON_LEVELS
Server wiring src/network/socketHandlers.js — afterPlayerMove 'descend' branch (no game-over, no monster move on arrival)
Client html/js/core/gameState.js — clears accumulated map/explored/visible tiles on a depth change so the old level doesn't ghost through the new one
Sim src/sim/simBots.js — explorer bot resets fog-of-war on descent
Tests test/multiLevel_ultra.test.js

Open polish

  • Client "Level N / M" indicator + a "descended" toast (the server sends depth/maxDepth and a game_event: descend; there is no client game_event handler yet).
  • Per-network level counts are sim starting points — pending a full multi-level calibration run.
  • Escalating hazards per level (level 1 tame → deep levels lava/poison) — the hazard-tile FX is already wired (RENDER_PACKS.md); it needs the generator to place hazards + gameplay stakes.