diff options
| author | salmonik <raisersoft@proton.me> | 2026-07-11 01:41:50 +0200 |
|---|---|---|
| committer | salmonik <raisersoft@proton.me> | 2026-07-11 01:41:50 +0200 |
| commit | abec3946be10bfa79af3300b4876afefb34b0451 (patch) | |
| tree | d1d817930a64614ea3dca69f6d3d476c7b02ff4e | |
| parent | switch to rust 2024 (diff) | |
| download | dungeon-abec3946be10bfa79af3300b4876afefb34b0451.tar.gz dungeon-abec3946be10bfa79af3300b4876afefb34b0451.zip | |
we have plans
| -rw-r--r-- | CONTEXT.md | 30 | ||||
| -rw-r--r-- | docs/PLAN.md | 308 |
2 files changed, 338 insertions, 0 deletions
diff --git a/CONTEXT.md b/CONTEXT.md new file mode 100644 index 0000000..c942ce0 --- /dev/null +++ b/CONTEXT.md | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | # CONTEXT | ||
| 2 | |||
| 3 | ## Canonical terms | ||
| 4 | |||
| 5 | | Term | Definition | | ||
| 6 | |------|------------| | ||
| 7 | | **HP** | Physical health. Drops when a real Enemy attacks the Player. 0 = death. | | ||
| 8 | | **Sanity** | Mental clarity (0–100%). Drops when the Player attacks a Hallucination or discovers a Hallucinated Pickup. Low sanity causes visual/auditory distortions and makes Hallucinations indistinguishable from real Enemies. | | ||
| 9 | | **Weakness** | Hunger / exhaustion meter. Increases every Turn. At maximum, drains HP. Reduced by consuming Pickups (Food, Bandage, Pill). Drives hallucination frequency and screen darkness. | | ||
| 10 | | **Heartbeat** | Monotonically increasing counter of Turns elapsed. Displayed in the HUD. Drives the rate at which Weakness accumulates. | | ||
| 11 | | **Player** | The character controlled by the user. Moves tile-by-tile, attacks adjacent cells, manages an Inventory of Pickups. | | ||
| 12 | | **Turn** | One discrete game step triggered by a Player action (move, turn, attack, use item). All Enemies act, and Weakness advances, on every Turn. | | ||
| 13 | | **Enemy** | A real hostile entity pre-placed in the Maze. Moves toward the Player on its Turn and deals HP damage when adjacent. Blocked movement into an Enemy wastes the Player's turn and triggers an attack. | | ||
| 14 | | **Hallucination** | A fake entity that looks like an Enemy. Walking onto a non-persistent Hallucination makes it vanish harmlessly. Attacking one drains Sanity and vanishes it. At critically low Sanity, Hallucinations become Persistent and do not vanish on attack. At greater Depth / lower Sanity, Hallucinations behave identically to real Enemies (patrol, chase). | | ||
| 15 | | **Pickup** | An item placed in the Maze that the Player collects by walking onto its cell. Types: Food (`F`), Pill (`0`), Bandage (`+`), Weapon (`!`). | | ||
| 16 | | **Hallucinated Pickup** | A Pickup that is not real. Appears in the Inventory normally but has no effect when used. Discovering one drains Sanity. | | ||
| 17 | | **Weapon** | An equipped item that determines base damage when attacking. Has a continuous dice-roll for bonus damage (30% chance for +1, repeat on success). Auto-equips the best found Weapon. | | ||
| 18 | | **Inventory** | A limited set of carried Pickups (4 slots). Displayed in the bottom-bar HUD. Items are used explicitly via a "use" key. | | ||
| 19 | | **Maze** | The procedural grid of Walls, Passages, and an Exit staircase. A new Maze is generated for each Depth. | | ||
| 20 | | **Depth** | The current dungeon floor number (infinite, increases by 1 on descending the Exit). Higher Depth means tougher Enemies, more Hallucinations, and darker visuals. | | ||
| 21 | | **Exit** | The staircase cell that descends the Player to the next Depth. | | ||
| 22 | | **Phantom Wall** | A Wall rendered by the engine where a Passage actually exists. The Player can walk through it. Frequency increases with low Sanity. | | ||
| 23 | | **Phantom Passage** | A Passage rendered where a Wall actually exists. The Player cannot walk through it. Frequency increases with low Sanity. | | ||
| 24 | | **Shifting Maze** | Cells of the actual Maze data that rearrange when the Player is not looking. Triggered at low Sanity. | | ||
| 25 | | **Persistent Hallucination** | A Hallucination that does not vanish when walked onto or attacked. Occurs only at critically low Sanity (~<20%). The Player is blocked from moving onto its cell and must attack it repeatedly to dissipate it. | | ||
| 26 | | **Attack** | The Player action (Space key) that strikes the adjacent cell ahead. Deals Weapon damage to whatever occupies that cell. | | ||
| 27 | | **Room** | A rectangular open area (3×3 to 6×6 cells) in the Maze, generated by the rooms-and-corridors algorithm. Rooms provide space for combat maneuvering. | | ||
| 28 | | **Corridor** | A 1–2 tile wide passageway connecting Rooms. | | ||
| 29 | | **Message Log** | A single line in the HUD that displays the most recent game event (attack result, item use, blocked movement) for 2–3 Turns before fading. | | ||
| 30 | | **Score** | Calculated on death: (Kills × 100) + (Depth² × 50) + (Weapon base damage × 500). Output to terminal. | | ||
diff --git a/docs/PLAN.md b/docs/PLAN.md new file mode 100644 index 0000000..a071efe --- /dev/null +++ b/docs/PLAN.md | |||
| @@ -0,0 +1,308 @@ | |||
| 1 | # Implementation Plan — Dungeon Crawler | ||
| 2 | |||
| 3 | ## Overview | ||
| 4 | |||
| 5 | Transform the existing ray-casting maze game into a turn-based first-person dungeon crawler with infinite depth, resource management (HP / Sanity / Weakness), psychedelic horror effects, and an inventory system. | ||
| 6 | |||
| 7 | See `CONTEXT.md` for the canonical glossary of domain terms. | ||
| 8 | |||
| 9 | --- | ||
| 10 | |||
| 11 | ## Phase 0 — Turn-Based Game Loop | ||
| 12 | |||
| 13 | Refactor the real-time loop into a turn-based model with smooth animations. | ||
| 14 | |||
| 15 | ### 0.1 — Game state machine | ||
| 16 | Introduce a `GameState` enum: | ||
| 17 | - `WaitingForInput` — player can press keys | ||
| 18 | - `AnimatingPlayer` — player walk/turn animation playing | ||
| 19 | - `AnimatingEnemies` — enemy movement animations playing (simultaneous, 100ms) | ||
| 20 | - `ResolvingTurn` — apply damage, weakness, sanity, pickups | ||
| 21 | - `GameOver` — fade-out and exit | ||
| 22 | |||
| 23 | ### 0.2 — Input gating | ||
| 24 | - Only accept input in `WaitingForInput`. | ||
| 25 | - On valid input → `AnimatingPlayer` (or `AnimatingEnemies` if skipping via C). | ||
| 26 | - After all animations → `ResolvingTurn` → back to `WaitingForInput`. | ||
| 27 | - C key skips turn (passes) — enemies still act. | ||
| 28 | |||
| 29 | ### 0.3 — Key bindings | ||
| 30 | | Key | Action | | ||
| 31 | |-----|--------| | ||
| 32 | | W | Move forward | | ||
| 33 | | S | Move backward | | ||
| 34 | | A | Strafe left | | ||
| 35 | | D | Strafe right | | ||
| 36 | | Q | Turn 90° left | | ||
| 37 | | E | Turn 90° right | | ||
| 38 | | Space | Attack cell ahead | | ||
| 39 | | Z | Use selected inventory item | | ||
| 40 | | X | Discard selected inventory item | | ||
| 41 | | C | Skip turn | | ||
| 42 | | 1-4 | Select inventory slot | | ||
| 43 | | Esc | Quit | | ||
| 44 | |||
| 45 | --- | ||
| 46 | |||
| 47 | ## Phase 1 — Rooms-and-Corridors Maze Generation | ||
| 48 | |||
| 49 | Replace the recursive-backtracker (1-tile-wide corridors) with a rooms-and-corridors generator. | ||
| 50 | |||
| 51 | ### 1.1 — Generation algorithm | ||
| 52 | 1. Place random rectangular rooms (3×3 to 6×6) on the grid, non-overlapping. | ||
| 53 | 2. Connect rooms with 1–2 tile wide corridors using a minimum spanning tree or BFS carving. | ||
| 54 | 3. Ensure all rooms are reachable. | ||
| 55 | 4. Place the player start in a room near top-left. | ||
| 56 | 5. Place the exit staircase in a room far from start. | ||
| 57 | 6. Maze size scales with depth (16×16 rooms → 33×33 cells at depth 1, up to 28×28 rooms → 57×57 cells at depth 13+). | ||
| 58 | |||
| 59 | ### 1.2 — Exit cell | ||
| 60 | - Exit is a passage cell with a special floor texture (tile with a hole). | ||
| 61 | - Walking onto it shows "Press Space to descend..." | ||
| 62 | - Pressing Space generates a new depth, places player in a different room facing east. | ||
| 63 | |||
| 64 | --- | ||
| 65 | |||
| 66 | ## Phase 2 — Entity System | ||
| 67 | |||
| 68 | Pre-place entities (enemies, hallucinations, pickups) in maze cells at generation time. | ||
| 69 | |||
| 70 | ### 2.1 — Entity types | ||
| 71 | ```rust | ||
| 72 | enum Entity { | ||
| 73 | Enemy { hp: u32, max_hp: u32, damage: u32 }, | ||
| 74 | Hallucination { persistent: bool }, | ||
| 75 | Pickup(PickupType), | ||
| 76 | HallucinatedPickup(PickupType), | ||
| 77 | } | ||
| 78 | ``` | ||
| 79 | |||
| 80 | ### 2.2 — Generation | ||
| 81 | - **One entity per cell** — a cell is either empty or contains one entity. | ||
| 82 | - Real enemies: 3–5 at depth 1, +2 per depth. | ||
| 83 | - Hallucinations: 1–2 per level (regardless of depth). Their *behavior* scales with sanity, not their quantity. | ||
| 84 | - Real pickups: 2–3 at depth 1, +1 per 2 depths. Mixed types (food, pill, bandage, weapon). | ||
| 85 | - Hallucinated pickups: 0–1 at depth 1, +1 per 2 depths. | ||
| 86 | - Weapons: 0–1, guaranteed at depths 2, 4, 6, etc. | ||
| 87 | |||
| 88 | ### 2.3 — Enemy stat scaling | ||
| 89 | | Depth tier | Enemy HP range | Enemy damage | | ||
| 90 | |------------|---------------|-------------| | ||
| 91 | | 1 | 1 | 1 | | ||
| 92 | | 2–3 | 2–3 | 1 | | ||
| 93 | | 4–6 | 3–5 | 1–2 | | ||
| 94 | | 7–9 | 5–8 | 2 | | ||
| 95 | | 10+ | 8+ | 2+ | | ||
| 96 | |||
| 97 | --- | ||
| 98 | |||
| 99 | ## Phase 3 — Combat System | ||
| 100 | |||
| 101 | ### 3.1 — Attack action (Space) | ||
| 102 | - Checks the cell directly ahead (based on facing direction). | ||
| 103 | - If an enemy/hallucination is present in that cell → apply attack. | ||
| 104 | - If nothing → "You swing at the air." No effect. | ||
| 105 | |||
| 106 | ### 3.2 — Hitting an enemy | ||
| 107 | - Deal `base_damage + bonus_damage` to the enemy. | ||
| 108 | - Bonus damage: 30% chance for +1, repeat on success (infinite chain, geometric distribution). | ||
| 109 | - If enemy HP ≤ 0 → enemy dies (removed from cell). | ||
| 110 | - Enemy retaliates if still alive: deals its damage to player HP. | ||
| 111 | - Screen flash: red tint. | ||
| 112 | |||
| 113 | ### 3.3 — Hitting a hallucination | ||
| 114 | - Non-persistent hallucination: vanishes, player loses sanity. | ||
| 115 | - Persistent hallucination (sanity < ~20%): does NOT vanish; player loses sanity. May take multiple attacks to dissipate. | ||
| 116 | - Screen flash: purple tint. | ||
| 117 | |||
| 118 | ### 3.4 — Moving onto a cell with an entity | ||
| 119 | - **Real enemy:** blocked. "Something is blocking your way." Player loses their turn; enemy attacks. | ||
| 120 | - **Hallucination (non-persistent):** vanishes harmlessly — no sanity cost. | ||
| 121 | - **Persistent hallucination:** blocked. "You are frightened to death just by thinking about doing this." Turn wasted. | ||
| 122 | - **Pickup:** auto-collected into inventory. | ||
| 123 | - **Hallucinated pickup:** auto-collected into inventory (deception discovered on use). | ||
| 124 | |||
| 125 | ### 3.5 — Weapon system | ||
| 126 | - Player always has an equipped weapon (starts with fists: base damage 1). | ||
| 127 | - Picking up a weapon (`!`) auto-equips if its base damage is higher. | ||
| 128 | - If base damage ≤ current weapon, display message and discard it. | ||
| 129 | - Weapons cannot be manually discarded. | ||
| 130 | - Hallucinated weapon: nothing happens on pickup, sanity drops slightly. | ||
| 131 | - HUD displays `WPN:{base_damage}`. | ||
| 132 | |||
| 133 | --- | ||
| 134 | |||
| 135 | ## Phase 4 — Resource System | ||
| 136 | |||
| 137 | ### 4.1 — Resources | ||
| 138 | | Resource | Start | Max | At 0 | | ||
| 139 | |----------|-------|-----|------| | ||
| 140 | | HP | 5 | 5 | Death | | ||
| 141 | | Sanity | 100 | 100 | Severe distortion, persistent hallucinations | | ||
| 142 | | Weakness | 0 | 100 | HP starts draining | | ||
| 143 | |||
| 144 | ### 4.2 — Per-turn effects | ||
| 145 | - Weakness +1 every turn (passive hunger). | ||
| 146 | - If weakness hits 100, HP drains at 1/turn. | ||
| 147 | - Heartbeat counter increments by 1 each turn. | ||
| 148 | |||
| 149 | ### 4.3 — Pickup effects | ||
| 150 | | Type | Char | Real effect | Hallucinated effect | | ||
| 151 | |------|------|------------|-------------------| | ||
| 152 | | Food | `F` | -20 weakness | No effect. Sanity -5. "It was never there..." | | ||
| 153 | | Pill | `0` | -15 weakness, +20 sanity | No effect. Sanity -5. | | ||
| 154 | | Bandage | `+` | -15 weakness, +1 HP (if HP < max) | No effect. Sanity -5. | | ||
| 155 | |||
| 156 | ### 4.4 — Healing feedback | ||
| 157 | - Screen flash: green tint on successful heal. | ||
| 158 | |||
| 159 | --- | ||
| 160 | |||
| 161 | ## Phase 5 — Inventory System | ||
| 162 | |||
| 163 | ### 5.1 — Slots | ||
| 164 | - 4 inventory slots. | ||
| 165 | - Pickups auto-collect into the first empty slot. | ||
| 166 | - If full, message "Inventory full" — pickup stays on the ground. | ||
| 167 | |||
| 168 | ### 5.2 — Controls | ||
| 169 | - `1`–`4`: select slot. | ||
| 170 | - `Z`: use selected item (consumes a turn). | ||
| 171 | - `X`: discard selected item (does NOT consume a turn). Item disappears forever. | ||
| 172 | |||
| 173 | ### 5.3 — Hallucinated pickups in inventory | ||
| 174 | - Look identical to real pickups. | ||
| 175 | - Using one: no effect, sanity -5, message "It was never there..." | ||
| 176 | - The item is consumed (removed from inventory) on use. | ||
| 177 | |||
| 178 | --- | ||
| 179 | |||
| 180 | ## Phase 6 — Psychedelic Horror Effects | ||
| 181 | |||
| 182 | ### 6.1 — Sanity thresholds (smooth interpolation) | ||
| 183 | | Sanity | Visual effects | Semi-physical effects | | ||
| 184 | |--------|---------------|---------------------| | ||
| 185 | | 100–80% | Clean | None | | ||
| 186 | | 79–60% | Mild color drift, wall breathing | 5% phantom wall/passage | | ||
| 187 | | 59–40% | Stronger distortion, flickering textures | 10% phantom, maze shifts 5%/turn | | ||
| 188 | | 39–20% | Heavy warping, false `@` flickers | 15% phantom, shifting 10%/turn, hallucinations patrol | | ||
| 189 | | 19–0% | Severe distortion | 20% phantom, shifting 15%/turn, persistent hallucinations | | ||
| 190 | |||
| 191 | ### 6.2 — Phantom walls (A) | ||
| 192 | - Render a wall where a passage exists. | ||
| 193 | - Player can walk through it — discovers it was fake. | ||
| 194 | - Randomly placed each frame; frequency scales with sanity threshold. | ||
| 195 | |||
| 196 | ### 6.3 — Phantom passages (B) | ||
| 197 | - Render a passage where a wall exists. | ||
| 198 | - Player tries to move forward → blocked (invisible wall). | ||
| 199 | - Disorienting but doesn't trap the player. | ||
| 200 | |||
| 201 | ### 6.4 — Shifting maze (D) | ||
| 202 | - On turn resolution, sanity-based % chance that 1–3 wall cells outside player FOV flip (wall ↔ passage). | ||
| 203 | - Constraint: never block the exit, never fully enclose the player. | ||
| 204 | - Chance: 0% at depth 1–3, 5%/turn at 59–40% sanity, 10%/turn at 39–20%, 15%/turn at 19–0%. | ||
| 205 | |||
| 206 | ### 6.5 — Hallucination behavior scaling | ||
| 207 | - Depth 1–3: hallucinations static, easy to distinguish. | ||
| 208 | - Depth 4–6 + medium sanity: hallucinations start patrolling randomly (every 3 turns). | ||
| 209 | - Depth 7+ + low sanity: hallucinations move toward player, indistinguishable from real enemies. | ||
| 210 | |||
| 211 | ### 6.6 — Screen darkness | ||
| 212 | - Two factors multiplied: | ||
| 213 | 1. **Weakness dimming:** 0% (fresh) to ~80% (max weakness). | ||
| 214 | 2. **Depth dimming:** 0% (depth 1) to 80% (depth 15+). | ||
| 215 | - At depth 10 with high weakness, vision is severely restricted. | ||
| 216 | |||
| 217 | --- | ||
| 218 | |||
| 219 | ## Phase 7 — Enemy AI | ||
| 220 | |||
| 221 | ### 7.1 — Real enemy behavior (per turn) | ||
| 222 | 1. If adjacent to player → attack (deal damage). | ||
| 223 | 2. If line-of-sight to player → move one tile toward player (reduce Manhattan distance). | ||
| 224 | 3. If no LOS → patrol (every 3 turns): pick random adjacent passage and move there. | ||
| 225 | 4. Hallucinations at low sanity follow the same behavior. | ||
| 226 | |||
| 227 | ### 7.2 — Enemy animation | ||
| 228 | - All enemies animate simultaneously (100ms duration). | ||
| 229 | - Smooth tile-walk animation matching player's style. | ||
| 230 | |||
| 231 | --- | ||
| 232 | |||
| 233 | ## Phase 8 — HUD | ||
| 234 | |||
| 235 | ### 8.1 — Bottom bar (Doom-style) | ||
| 236 | ``` | ||
| 237 | [♥ 3/5] [♦ SAN: 72%] [⌂ Weak: 45%] ♥♥ 42 WPN:2 [F][0][ ][+] DEPTH:7 | ||
| 238 | ``` | ||
| 239 | - Hearts for HP, diamond for sanity, house for weakness. | ||
| 240 | - Heartbeat counter with heart symbol. | ||
| 241 | - Weapon display. | ||
| 242 | - 4 inventory slots showing item chars (empty = blank). | ||
| 243 | - Current depth number. | ||
| 244 | |||
| 245 | ### 8.2 — Message log | ||
| 246 | - Single line above or within the HUD bar. | ||
| 247 | - Displays the most recent message for 2–3 turns, then fades. | ||
| 248 | - Messages: attack results, item usage, blocked movement, hallucination encounters. | ||
| 249 | |||
| 250 | ### 8.3 — Entity sprites (ASCII) | ||
| 251 | | Entity | Char | Color | | ||
| 252 | |--------|------|-------| | ||
| 253 | | Enemy / Hallucination | `@` | Red | | ||
| 254 | | Food | `F` | Green | | ||
| 255 | | Pill | `0` | Cyan | | ||
| 256 | | Bandage | `+` | White | | ||
| 257 | | Weapon | `!` | Yellow | | ||
| 258 | | Exit | Floor texture (hole) | — | | ||
| 259 | |||
| 260 | Rendered as scaled pixel-font sprites in the 3D view, line-of-sight only. | ||
| 261 | |||
| 262 | --- | ||
| 263 | |||
| 264 | ## Phase 9 — Score & Death | ||
| 265 | |||
| 266 | ### 9.1 — Score formula | ||
| 267 | ``` | ||
| 268 | Score = (Kills × 100) + (Final Depth² × 50) + (Weapon Base Damage × 500) | ||
| 269 | ``` | ||
| 270 | - Calculated on death. Output to terminal. | ||
| 271 | - Values subject to tuning after playtesting. | ||
| 272 | |||
| 273 | ### 9.2 — Death sequence | ||
| 274 | 1. HP hits 0. | ||
| 275 | 2. Screen fades to black over ~2 seconds. | ||
| 276 | 3. Message: "You had become yet another legend of this dungeon." | ||
| 277 | 4. Score printed to terminal. | ||
| 278 | 5. Game exits. | ||
| 279 | |||
| 280 | --- | ||
| 281 | |||
| 282 | ## Phase 10 — Screen Flashes & Feedback | ||
| 283 | |||
| 284 | | Event | Feedback | | ||
| 285 | |-------|----------| | ||
| 286 | | Player hits enemy | Red flash | | ||
| 287 | | Player hits hallucination | Purple flash | | ||
| 288 | | Player takes damage | Red flash + camera jolt | | ||
| 289 | | Successful heal | Green flash | | ||
| 290 | | Hallucination vanishes (walk-through) | Brief warp/distortion effect | | ||
| 291 | | Enemy dies | White flash, entity removed | | ||
| 292 | |||
| 293 | --- | ||
| 294 | |||
| 295 | ## Implementation Strategy | ||
| 296 | |||
| 297 | Build incrementally — one feature at a time: | ||
| 298 | |||
| 299 | 1. **Phase 0** — Turn-based loop (foundation for everything) | ||
| 300 | 2. **Phase 1** — Rooms-and-corridors generation | ||
| 301 | 3. **Phase 2 + 3 + 4** — Entities, combat, and resources (tightly coupled) | ||
| 302 | 4. **Phase 5** — Inventory | ||
| 303 | 5. **Phase 8** — HUD | ||
| 304 | 6. **Phase 7** — Enemy AI + animations | ||
| 305 | 7. **Phase 6** — Psychedelic effects | ||
| 306 | 8. **Phase 9 + 10** — Score, death, polish | ||
| 307 | |||
| 308 | Each phase must be testable independently before moving to the next. | ||
