summaryrefslogtreecommitdiffstats
path: root/docs/PLAN.md
blob: a071efe33fe3c81c4e591f38a7ffb75876300f02 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# Implementation Plan — Dungeon Crawler

## Overview

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.

See `CONTEXT.md` for the canonical glossary of domain terms.

---

## Phase 0 — Turn-Based Game Loop

Refactor the real-time loop into a turn-based model with smooth animations.

### 0.1 — Game state machine
Introduce a `GameState` enum:
- `WaitingForInput` — player can press keys
- `AnimatingPlayer` — player walk/turn animation playing
- `AnimatingEnemies` — enemy movement animations playing (simultaneous, 100ms)
- `ResolvingTurn` — apply damage, weakness, sanity, pickups
- `GameOver` — fade-out and exit

### 0.2 — Input gating
- Only accept input in `WaitingForInput`.
- On valid input → `AnimatingPlayer` (or `AnimatingEnemies` if skipping via C).
- After all animations → `ResolvingTurn` → back to `WaitingForInput`.
- C key skips turn (passes) — enemies still act.

### 0.3 — Key bindings
| Key | Action |
|-----|--------|
| W | Move forward |
| S | Move backward |
| A | Strafe left |
| D | Strafe right |
| Q | Turn 90° left |
| E | Turn 90° right |
| Space | Attack cell ahead |
| Z | Use selected inventory item |
| X | Discard selected inventory item |
| C | Skip turn |
| 1-4 | Select inventory slot |
| Esc | Quit |

---

## Phase 1 — Rooms-and-Corridors Maze Generation

Replace the recursive-backtracker (1-tile-wide corridors) with a rooms-and-corridors generator.

### 1.1 — Generation algorithm
1. Place random rectangular rooms (3×3 to 6×6) on the grid, non-overlapping.
2. Connect rooms with 1–2 tile wide corridors using a minimum spanning tree or BFS carving.
3. Ensure all rooms are reachable.
4. Place the player start in a room near top-left.
5. Place the exit staircase in a room far from start.
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+).

### 1.2 — Exit cell
- Exit is a passage cell with a special floor texture (tile with a hole).
- Walking onto it shows "Press Space to descend..."
- Pressing Space generates a new depth, places player in a different room facing east.

---

## Phase 2 — Entity System

Pre-place entities (enemies, hallucinations, pickups) in maze cells at generation time.

### 2.1 — Entity types
```rust
enum Entity {
    Enemy { hp: u32, max_hp: u32, damage: u32 },
    Hallucination { persistent: bool },
    Pickup(PickupType),
    HallucinatedPickup(PickupType),
}
```

### 2.2 — Generation
- **One entity per cell** — a cell is either empty or contains one entity.
- Real enemies: 3–5 at depth 1, +2 per depth.
- Hallucinations: 1–2 per level (regardless of depth). Their *behavior* scales with sanity, not their quantity.
- Real pickups: 2–3 at depth 1, +1 per 2 depths. Mixed types (food, pill, bandage, weapon).
- Hallucinated pickups: 0–1 at depth 1, +1 per 2 depths.
- Weapons: 0–1, guaranteed at depths 2, 4, 6, etc.

### 2.3 — Enemy stat scaling
| Depth tier | Enemy HP range | Enemy damage |
|------------|---------------|-------------|
| 1 | 1 | 1 |
| 2–3 | 2–3 | 1 |
| 4–6 | 3–5 | 1–2 |
| 7–9 | 5–8 | 2 |
| 10+ | 8+ | 2+ |

---

## Phase 3 — Combat System

### 3.1 — Attack action (Space)
- Checks the cell directly ahead (based on facing direction).
- If an enemy/hallucination is present in that cell → apply attack.
- If nothing → "You swing at the air." No effect.

### 3.2 — Hitting an enemy
- Deal `base_damage + bonus_damage` to the enemy.
- Bonus damage: 30% chance for +1, repeat on success (infinite chain, geometric distribution).
- If enemy HP ≤ 0 → enemy dies (removed from cell).
- Enemy retaliates if still alive: deals its damage to player HP.
- Screen flash: red tint.

### 3.3 — Hitting a hallucination
- Non-persistent hallucination: vanishes, player loses sanity.
- Persistent hallucination (sanity < ~20%): does NOT vanish; player loses sanity. May take multiple attacks to dissipate.
- Screen flash: purple tint.

### 3.4 — Moving onto a cell with an entity
- **Real enemy:** blocked. "Something is blocking your way." Player loses their turn; enemy attacks.
- **Hallucination (non-persistent):** vanishes harmlessly — no sanity cost.
- **Persistent hallucination:** blocked. "You are frightened to death just by thinking about doing this." Turn wasted.
- **Pickup:** auto-collected into inventory.
- **Hallucinated pickup:** auto-collected into inventory (deception discovered on use).

### 3.5 — Weapon system
- Player always has an equipped weapon (starts with fists: base damage 1).
- Picking up a weapon (`!`) auto-equips if its base damage is higher.
- If base damage ≤ current weapon, display message and discard it.
- Weapons cannot be manually discarded.
- Hallucinated weapon: nothing happens on pickup, sanity drops slightly.
- HUD displays `WPN:{base_damage}`.

---

## Phase 4 — Resource System

### 4.1 — Resources
| Resource | Start | Max | At 0 |
|----------|-------|-----|------|
| HP | 5 | 5 | Death |
| Sanity | 100 | 100 | Severe distortion, persistent hallucinations |
| Weakness | 0 | 100 | HP starts draining |

### 4.2 — Per-turn effects
- Weakness +1 every turn (passive hunger).
- If weakness hits 100, HP drains at 1/turn.
- Heartbeat counter increments by 1 each turn.

### 4.3 — Pickup effects
| Type | Char | Real effect | Hallucinated effect |
|------|------|------------|-------------------|
| Food | `F` | -20 weakness | No effect. Sanity -5. "It was never there..." |
| Pill | `0` | -15 weakness, +20 sanity | No effect. Sanity -5. |
| Bandage | `+` | -15 weakness, +1 HP (if HP < max) | No effect. Sanity -5. |

### 4.4 — Healing feedback
- Screen flash: green tint on successful heal.

---

## Phase 5 — Inventory System

### 5.1 — Slots
- 4 inventory slots.
- Pickups auto-collect into the first empty slot.
- If full, message "Inventory full" — pickup stays on the ground.

### 5.2 — Controls
- `1`–`4`: select slot.
- `Z`: use selected item (consumes a turn).
- `X`: discard selected item (does NOT consume a turn). Item disappears forever.

### 5.3 — Hallucinated pickups in inventory
- Look identical to real pickups.
- Using one: no effect, sanity -5, message "It was never there..."
- The item is consumed (removed from inventory) on use.

---

## Phase 6 — Psychedelic Horror Effects

### 6.1 — Sanity thresholds (smooth interpolation)
| Sanity | Visual effects | Semi-physical effects |
|--------|---------------|---------------------|
| 100–80% | Clean | None |
| 79–60% | Mild color drift, wall breathing | 5% phantom wall/passage |
| 59–40% | Stronger distortion, flickering textures | 10% phantom, maze shifts 5%/turn |
| 39–20% | Heavy warping, false `@` flickers | 15% phantom, shifting 10%/turn, hallucinations patrol |
| 19–0% | Severe distortion | 20% phantom, shifting 15%/turn, persistent hallucinations |

### 6.2 — Phantom walls (A)
- Render a wall where a passage exists.
- Player can walk through it — discovers it was fake.
- Randomly placed each frame; frequency scales with sanity threshold.

### 6.3 — Phantom passages (B)
- Render a passage where a wall exists.
- Player tries to move forward → blocked (invisible wall).
- Disorienting but doesn't trap the player.

### 6.4 — Shifting maze (D)
- On turn resolution, sanity-based % chance that 1–3 wall cells outside player FOV flip (wall ↔ passage).
- Constraint: never block the exit, never fully enclose the player.
- Chance: 0% at depth 1–3, 5%/turn at 59–40% sanity, 10%/turn at 39–20%, 15%/turn at 19–0%.

### 6.5 — Hallucination behavior scaling
- Depth 1–3: hallucinations static, easy to distinguish.
- Depth 4–6 + medium sanity: hallucinations start patrolling randomly (every 3 turns).
- Depth 7+ + low sanity: hallucinations move toward player, indistinguishable from real enemies.

### 6.6 — Screen darkness
- Two factors multiplied:
  1. **Weakness dimming:** 0% (fresh) to ~80% (max weakness).
  2. **Depth dimming:** 0% (depth 1) to 80% (depth 15+).
- At depth 10 with high weakness, vision is severely restricted.

---

## Phase 7 — Enemy AI

### 7.1 — Real enemy behavior (per turn)
1. If adjacent to player → attack (deal damage).
2. If line-of-sight to player → move one tile toward player (reduce Manhattan distance).
3. If no LOS → patrol (every 3 turns): pick random adjacent passage and move there.
4. Hallucinations at low sanity follow the same behavior.

### 7.2 — Enemy animation
- All enemies animate simultaneously (100ms duration).
- Smooth tile-walk animation matching player's style.

---

## Phase 8 — HUD

### 8.1 — Bottom bar (Doom-style)
```
[♥ 3/5] [♦ SAN: 72%] [⌂ Weak: 45%]  ♥♥ 42  WPN:2  [F][0][ ][+]  DEPTH:7
```
- Hearts for HP, diamond for sanity, house for weakness.
- Heartbeat counter with heart symbol.
- Weapon display.
- 4 inventory slots showing item chars (empty = blank).
- Current depth number.

### 8.2 — Message log
- Single line above or within the HUD bar.
- Displays the most recent message for 2–3 turns, then fades.
- Messages: attack results, item usage, blocked movement, hallucination encounters.

### 8.3 — Entity sprites (ASCII)
| Entity | Char | Color |
|--------|------|-------|
| Enemy / Hallucination | `@` | Red |
| Food | `F` | Green |
| Pill | `0` | Cyan |
| Bandage | `+` | White |
| Weapon | `!` | Yellow |
| Exit | Floor texture (hole) | — |

Rendered as scaled pixel-font sprites in the 3D view, line-of-sight only.

---

## Phase 9 — Score & Death

### 9.1 — Score formula
```
Score = (Kills × 100) + (Final Depth² × 50) + (Weapon Base Damage × 500)
```
- Calculated on death. Output to terminal.
- Values subject to tuning after playtesting.

### 9.2 — Death sequence
1. HP hits 0.
2. Screen fades to black over ~2 seconds.
3. Message: "You had become yet another legend of this dungeon."
4. Score printed to terminal.
5. Game exits.

---

## Phase 10 — Screen Flashes & Feedback

| Event | Feedback |
|-------|----------|
| Player hits enemy | Red flash |
| Player hits hallucination | Purple flash |
| Player takes damage | Red flash + camera jolt |
| Successful heal | Green flash |
| Hallucination vanishes (walk-through) | Brief warp/distortion effect |
| Enemy dies | White flash, entity removed |

---

## Implementation Strategy

Build incrementally — one feature at a time:

1. **Phase 0** — Turn-based loop (foundation for everything)
2. **Phase 1** — Rooms-and-corridors generation
3. **Phase 2 + 3 + 4** — Entities, combat, and resources (tightly coupled)
4. **Phase 5** — Inventory
5. **Phase 8** — HUD
6. **Phase 7** — Enemy AI + animations
7. **Phase 6** — Psychedelic effects
8. **Phase 9 + 10** — Score, death, polish

Each phase must be testable independently before moving to the next.