Unicode glyph lookup instead of CP437 codes, rope and double-strand frames with clean title ends, progress bars in eighth blocks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
117 lines
12 KiB
Markdown
117 lines
12 KiB
Markdown
# 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: **Dinowyde** bitmap font (Unicode: Latin, Greek, Cyrillic, symbols; 6×8 px, CC BY 4.0, see CREDITS.md) for all texts, integer scaled; missing glyphs (arrows, suits, ...) from DINOBYTE; frames: rope (single) and double strand, bars in eighth blocks
|
||
- All UI windows use **box-drawing frames** of the font (single lines for panels, double lines for dialogs); **all bars are block characters** (█ ▌ ░)
|
||
- Text only in **fixed integer sizes**: 1×, 2× and 4× the 6×8 glyph size, times an integer **interface factor** (automatic from the device resolution, or 1×–4× in the settings)
|
||
- The interface is drawn in **device pixels** (high DPI) and laid out on the **character grid**, so every font pixel has exactly the same size
|
||
- **3D resolution** setting: the world can be rendered at 1/1 down to 1/16 resolution and scaled up by exactly that factor (pixel look); the setting refers to a window 1080 device pixels high and scales with the window size, so the 3D pixels keep their size relative to the window; the interface stays sharp
|
||
- 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
|
||
- **Server savegames** (savegame service in `server/`, shared list without accounts): save under a name / overwrite / load / delete in a list page; the game checks `api/health` at start and **falls back to savegame files** when the service cannot be reached (e.g. local HTML)
|
||
- **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, **35 pieces**, composed as `.xm` by `tools/compose_music.py` (editable in MilkyTracker): 2 title, 15 build, 7 wave battle, 4 gate assault, 2 boss (Paladin of Light, Gate Warden), 1 torture chamber mood, 1 temple mood, 2 victory, 1 defeat; **the title melody is a recognisable leitmotif in every piece**
|
||
- Most pieces come from a **variant generator**: the leitmotif is stored as scale degrees and realised in different keys and modes (minor, harmonic minor, dorian, phrygian, lydian), augmented, diminished, inverted or as fragment sequences, with varying accompaniment, drum styles, instruments and forms; title 2, both boss themes and the second victory jingle are hand-written
|
||
- 16 chip instruments (pulse, square, saw pad, triangle bass, pluck, kick, snare, hihat, organ, bell, choir, sub bass, tom, crash, harp, timpani); 8-bit samples, each file only contains the instruments it uses
|
||
- Music changes with **soft crossfades** (2.5 s): title → build (rotating through all build pieces) → battle when heroes invade → assault while attacking the gate → boss themes while a Paladin of Light or the Gate Warden is alive → jingles; near a torture chamber or temple the matching **room mood** plays
|
||
- 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)
|
||
- **Dwarf caves** in every mode: 1 to 4 slots depending on the map size, each filled with a 50% chance (at least one cave). A hoard (1500-4000 in gold and gems, more the further from the core) inside a cave ringed by rich veins, guarded by 4-6 neutral dwarves (bronze rings). Dwarves fight whoever comes within about 7 tiles of the cave, never chase further, heal at home and never count as opponents for victory. Their level grows with the distance to the core, and every 30 s they gain levels until they match about half the player's army strength.
|
||
- Knight treasure caves only exist where a campaign mission places them; everywhere else dwarf caves took their place.
|
||
- 30% of the dwarf caves hold a **rune chest**: claiming it gives one free build of the **rune forge tower** (1400 HP, range 10, the rune bolt jumps on to three more enemies). It can be upgraded for gold (800 / 1200). Selling it returns the base tower once: in the campaign as a chest for the next mission, in free play at once. Unbuilt rune towers carry over to the next mission.
|
||
- Imps repair damaged towers for free; repairs come before claiming more ground.
|
||
- 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 (+ torture chamber, temple)
|
||
- The Soul Core starts surrounded by a **one tile wide ring of treasury** (16 tiles)
|
||
- Claim the **portal** → creatures: kobold, cave spider, shadow mage, stone ogre (depending on rooms)
|
||
- **Needs**: sleep, food, wages (payday); unhappy creatures leave
|
||
- **Hand**: left click picks up own units (max. 8) and unconscious heroes on own ground; right click drops them on own ground (prisoners onto a free torture place are locked up); Shift + left click slaps: backhand for own units (15 s +50% speed, −5% HP, a little mood, wakes sleepers), fist for heroes on own ground (15 damage, 1 s stun, 0.5 s cooldown)
|
||
- **Toolbar by categories** (Dig, Hand, Rooms, Towers, Spells, Orders, Menu) for mouse and touch alike; categories with several tools open a row of tools
|
||
- **Touch interface** (Auto / On / Off; auto = touch device or first touch): larger interface factor (about 2/3 of the device pixel ratio), top bar wraps onto several lines, gestures: tap = tool, drag = rectangle or pan, two fingers = pan / pinch zoom / twist rotate, long press = info or drop, double tap with the hand = slap; savegame names via the browser's text dialog
|
||
- **Pixel-art mouse pointers**: pointing monster hand with the icon of the active tool; grabbing hand / fist for the hand tool; animated backhand and punch; the active tool is highlighted in the toolbar (pulsing frame and arrow)
|
||
- **Spells** (mana): lightning, heal, summon Pit Imp
|
||
- **Heroes**: knight, archer, priest, dwarf miner, paladin of light (they dig their way to the Soul Core)
|
||
|
||
## Walls, towers, torture, temple
|
||
- **Reinforced walls**: imps reinforce earth walls next to claimed ground automatically (free, lowest priority). Heroes avoid them (path cost ×10) and need ~10× as long to break through; the player's imps need twice as long to dig them out
|
||
- **Defence towers** on claimed floor (one tile, not walkable), three tools; clicking an own tower with the same tool upgrades it (3 levels). Gold for building/upgrading, the magic tower uses mana per shot
|
||
- Arrow tower: cheap, fast; arrows pierce up to two more heroes
|
||
- Cannon tower: slow, long range, splash damage with knockback, minimum range
|
||
- Magic tower: never misses, slows, jumps to a second hero
|
||
- Heroes attack towers; imps repair them; towers count with half their combat value to the army value
|
||
- **Torture chamber**: one prisoner per 2 tiles. Defeated heroes are knocked out (if there is room) and carried in by imps; torture drains their HP over ~100 s, ~40% defect (paladins ~25%) and become own creatures (needs, wage, lair). Attracts the **Jailer** (6+ tiles): tanky melee that pulls enemies in with a chain
|
||
- **Temple**: creatures pray for mana (more than studying) and mood. Attracts the **Flame Priestess** (6+ tiles): fireballs with splash damage, heals creatures, heals the Soul Core (~8 HP/s) when it is below 90% and no fight is nearby
|
||
|
||
## Chainbreaker (rare creature)
|
||
- Original design: massive obsidian demon with glowing cracks, broken chains and twin axes; very strong (600 HP, 36 attack), its axes also hit a second enemy nearby
|
||
- Comes through the portal only rarely, and only to great dungeons: 40+ room tiles, a creature of level 5+, 4000+ gold; only one at a time
|
||
- Restless: after two minutes without a fight its mood sinks
|
||
|
||
## Hero wave AI
|
||
- Each wave picks an **entry point** on the border of the realm facing the hero gate: few towers/creatures, no reinforced walls and a short way are attractive, entry points of recent waves are avoided, plus some randomness
|
||
- Waves of **6+ heroes split into two groups** with different entry points (the paladin goes with the bigger group)
|
||
- Heroes first tunnel to their entry point, then go for the core
|
||
- **Warning** 30 s before: scout message with the direction(s), blinking markers on the minimap and the **walls at the entry points glowing and pulsing red** (plus a pulsing red light) until the wave has broken in
|
||
|
||
## 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
|