# DungeonCraft – Design Decisions An original dungeon management game (genre: dungeon building & defence) that runs as WASM in the browser. ## Technology - Rust + **macroquad** (WebGL), target `wasm32-unknown-unknown` - User interface drawn entirely **in the canvas** - Font: **DINOBYTE** bitmap font (CP437, 6×8 px, CC BY 4.0, see CREDITS.md) for all texts, integer scaled - All UI windows use **CP437 frames** (single lines for panels, double lines for dialogs); bars (HP/mana/gate) are pixel bars - Sound: event system + macroquad audio prepared (volume, mute key M); sounds will be generated later - Languages: all in-game texts live in **language files** (`lang/*.lang`, key = text); English is the reference/fallback, German included, more can be added. The language is chosen on first start and stored in the browser. - Repository language: **English** (code, comments, docs, commit messages) ## Graphics - **3D**, **true isometric** (orthographic camera) - Camera **freely rotatable 360° and tiltable** - Walls with an **irregular surface** (noise displacement of the wall faces, seamless between neighbours) - Textures: **procedural pixel art** (tile atlas) - Units: **pixel sprites as billboards** (always facing the camera), pulled towards the camera in depth so walls behind a unit never cut into its sprite - Lighting: **dark + torches** – dark base level; claimed areas and light sources (torches, core, portal, gate) are bright, flickering light - **Dig marking**: a marked block glows yellow along its **real irregular shape** (tinted top and open sides, outline following the displaced edges) - **Hover**: the wall block under the mouse gets a faint version of that highlight (in the colour of the active tool); while dragging a dig rectangle, every block inside is tinted faintly; floor tiles get an outline - **Tile outlines**: subtle dark lines around every tile (floors, wall tops, vertical wall edges), following the irregular surface; toggle with G (later in the graphics settings) - The UI is a 2D layer on top, including a minimap ## Controls - Left click: use the active tool (drag a rectangle for digging/rooms) - Right click: drop a unit from the hand - Camera: WASD/arrow keys, right mouse drag, mouse wheel zoom, screen edge - Rotate/tilt: middle mouse drag, Q/E rotate, R/F tilt - Spells: 0 lightning, X heal, V summon imp - Torches: placed automatically when ground is claimed; foreign areas are dimly visible ## Menus, savegames, settings - **Title screen** (Continue, New Game, Load, Settings, Help) and **pause menu** on Esc (Resume, Save, Load, Settings, Help, Main Menu) - Savegames as **JSON** (`*.dcsave`, format tag + version, ~300 KB): **save = download**, **load = file picker or drag & drop** onto the game window - **Autosave** in the browser (localStorage) every 2 minutes and when the tab is hidden/closed; "Continue" on the title screen - Settings: language + sound, camera (rotation/zoom speed, edge scrolling, invert mouse), graphics (tile outlines, wall detail, light sources, interface size), game (speed 1×/2×, hints), **key bindings** (conflicts swap keys; Esc and arrow keys are fixed) - Settings are stored in the browser **and** in every savegame; loading a savegame **always applies** its settings ## Music & sound - Own **XM/MOD replayer in Rust** (`src/xm.rs`): instruments, envelopes, fadeout, auto-vibrato, linear/Amiga frequencies, common FT2 effects; verified against libopenmpt - **Shared mixer** for music + sound effects (`src/audio.rs`), streamed to the browser by the JS plugin (replaces macroquad audio) - Soundtrack in classic **Amiga chiptune** style, composed as `.xm` by `tools/compose_music.py` (editable in MilkyTracker): title/menu, **3 build tracks** (rotating), **2 battle tracks** (wave defence, gate assault), victory/defeat jingles; **the title melody is a recognisable leitmotif in every piece** - Music changes with **soft crossfades** (2.5 s): title → build → battle when heroes invade → storm music while attacking the gate → jingles - Sound effects are **synthesised chip sounds** (`src/sfx.rs`), positioned by distance and stereo panning ## Map size - Chosen in the **New Game dialog**: width and height separately, **64–256 tiles** in steps of 32 (remembered in the settings) - Content scales with the area: rock, gold veins and caves; the Hero Gate lies on the far side, the **grace period grows with the distance** to the gate - **One portal per 64×64 tiles**; every claimed portal brings creatures (more portals = faster arrivals, still limited by the lair) - Bigger maps get **guarded treasure caves** (one less than the number of portals): very rich gold veins, defended by a hero squad that stays at its post - Savegames store the tiles packed (run-length encoded, base64), so even 256×256 maps stay small (~300 KB); version 1 savegames still load ## Game content - **Digging**: mark earth/gold → Pit Imps dig, bring gold home and claim ground - **Rooms**: treasury, lair, mushroom garden, training hall, library - Claim the **portal** → creatures: kobold, cave spider, shadow mage, stone ogre (depending on rooms) - **Needs**: sleep, food, wages (payday); unhappy creatures leave - **Hand**: pick up / drop own units (max. 8) - **Spells** (mana): lightning, heal, summon Pit Imp - **Heroes**: knight, archer, priest, dwarf miner, paladin of light (they dig their way to the Soul Core) ## Goal - **Victory**: destroy the Hero Gate - **Defeat**: the Soul Core is destroyed ## Attacking the gate - **Attack flag**: the player places a rally flag; free creatures march there and attack everything nearby (including the gate) - **Gate**: about 3000 HP, regenerates slowly when not under attack - **Defenders** appear at HP thresholds 75% / 50% / 25% (the last squad with a boss), challenging ## Hero waves - **Endless** while the gate stands - Strength follows the **army value** (sum of HP × damage of all creatures incl. levels) - Wave strength **grows from 60% to 100%** of the army value, with some randomness - **Grace period** of 5 minutes, then a **minimum wave** (e.g. 2 knights) even with a weak army - Goal: always beatable, but challenging ## Operations / testing - Build in Docker (multi-stage: Rust → nginx:alpine) - Test build on port **18093**, later additionally a subdomain via Nginx Proxy Manager