Files
Verbatim/WORLDGEN_PLAN.md
T
2026-06-21 22:27:20 +03:00

165 lines
6.3 KiB
Markdown

# World Generator Plan
## Goal
Procedural world generation with depth-based biomes, rooms, corridors, and randomized features.
## Current State
- Implemented in `src/world/worldgen.rs`
- Depth-based dispatch: surface (1-3), caves (4-6), BSP dungeon (7+)
- Randomized features, pools, trees, walls, rooms, corridors, traps
- World size: 2048x2048 for main game; 250x250 for tests/AI
- Seed-based generation with `Game::seed`
- Per-chunk world cache in `cache/worlds/<seed>/depth_<N>/`
- Tests in `tests/worldgen.rs` and `tests/large_world.rs` (ignored, slow)
## Algorithms Researched
### BSP (Binary Space Partitioning)
- Recursively divide space into rectangles
- Place room in each leaf node
- Connect siblings with corridors
- Guarantees no overlaps
- **Use for: dungeon rooms (depth 7+)**
### Cellular Automata (4-5 rule)
- Fill grid with ~45% random walls
- 5 iterations: wall if >=4 neighbors are walls, else empty
- Produces organic cave shapes
- Flood fill to verify connectivity
- **Use for: caves (depth 4-6, and underground at depth 1-3)**
### Drunkard's Walk
- Random walk digs tunnels through solid rock
- Creates winding cave-like paths
- **Use for: tunnels connecting rooms**
### Brogue Room Accretion
- Start with one room, attach new rooms to existing structure
- Inherently connected (tree structure)
- Room templates: rectangle, CA blob, circle
- **Use for: room placement strategy**
### Rooms and Mazes (Bob Nystrom)
- Place rooms → fill gaps with maze → connect → remove dead ends
- **Inspirational, not directly used**
### Noita — Herringbone Wang Tiles
- Pre-made chunks laid in herringbone pattern
- Randomized contents within chunks
- **Too complex for now, possible future enhancement**
## Architecture
### New module: `src/world/worldgen.rs`
```
WorldGenerator
├── rng: &mut CellularAutomaton
├── generate(grid, depth) — main entry point
├── generate_surface(grid, depth) — depth 1-3: terrain + caves + features
├── generate_caves(grid, depth) — depth 4-6: full underground caves
├── generate_dungeon(grid, depth) — depth 7+: BSP rooms + corridors
├── Surface sub-methods:
│ ├── terrain_noise(x, depth) — multi-octave surface height
│ ├── fill_terrain(grid, depth) — fill dirt/stone/grass by depth
│ ├── carve_underground_caves(grid) — CA caves below surface
│ ├── place_trees(grid, count) — random tree placement
│ ├── place_pools(grid, count, types)— random liquid pools
│ ├── place_sand_dunes(grid, count) — sand piles
│ └── place_walls(grid, count) — stone wall obstacles
├── Cave sub-methods:
│ ├── ca_caves(grid, fill_prob, iterations) — cellular automata
│ ├── flood_fill_largest(grid) — find largest connected region
│ ├── seal_small_regions(grid) — fill disconnected caves
│ └── place_underground_pools(grid) — lava/acid in caves
├── Dungeon sub-methods:
│ ├── bsp_split(rect, depth) — recursive space partitioning
│ ├── place_room(grid, rect) — carve room interior
│ ├── connect_rooms(grid, rooms) — L-shaped corridors
│ ├── place_doors(grid, rooms) — door at room entrances
│ └── place_traps(grid, rooms) — acid/fire traps in rooms
└── Shared:
├── place_stairs(grid, depth) — stairs in appropriate location
└── place_items(game, rooms) — items in rooms/on surface
```
## Depth-based Generation
| Depth | Type | Surface | Features | Algorithm |
|-------|------|---------|----------|-----------|
| 1-3 | Surface | Grass/dirt | Trees, water pools, sand dunes, stone walls, underground CA caves | Multi-octave noise + CA |
| 4-6 | Caves | Stone/dirt | Large CA caves, lava pools, acid pools, stalactites | Cellular automata (4-5 rule) |
| 7+ | Dungeon | Stone | BSP rooms (5x3 to 12x8), corridors, traps, stairs | BSP + corridor connection |
## Implementation Details
### Surface terrain (depth 1-3)
- Multi-octave sine noise: `base + detail + micro`
- Amplitude: 4-8 cells variation
- Surface material: grass at depth 1, dirt at 2-3
- Below surface: dirt for 8 cells, then stone
- Border: stone walls
### CA cave generation (depth 4-6)
1. Fill entire grid with stone
2. Random fill ~45% as empty (cave candidate)
3. Run 5 iterations of 4-5 rule:
- Cell becomes wall if >=4 of 8 neighbors are walls
- Cell becomes empty if <4 neighbors are walls
4. Flood fill from center, find largest connected region
5. Seal all cells not in largest region (fill with stone)
6. Place lava/acid pools in random empty areas
7. Place stalactites (stone pillars) in random positions
### BSP dungeon (depth 7+)
1. Start with full grid as stone
2. Recursively split into 2 halves (alternate H/V)
3. Stop when area < min_room_size (15x10)
4. In each leaf: place room (smaller than partition, centered)
5. Connect sibling rooms with L-shaped corridor (2 wide)
6. Place stairs in the deepest/farthest room
7. Place items in 2-3 random rooms
8. Place traps (acid pockets) in 1-2 rooms
### Feature placement (all depths)
- All positions via RNG, not hardcoded
- Pool count: 2 + depth/2
- Pool radius: 4-10 cells
- Pool types by depth:
- 1-3: water, sand
- 4-6: lava, acid, water
- 7+: acid (traps in rooms)
- Tree count: 3-7 (surface only)
- Wall count: 1-3 (surface only)
## Files
| File | Change |
|------|--------|
| `src/world/worldgen.rs` | New module — all generation logic |
| `src/world/mod.rs` | Add `pub mod worldgen` |
| `src/game.rs` | `init_world()` calls `WorldGenerator::generate()` |
| `tests/worldgen.rs` | New tests |
## Tests
- Stairs exist after generation at any depth
- At least 3 distinct materials present
- Player spawn position is not inside solid
- Different depths produce different structures
- Depth 7+ has rooms (empty regions > 5x3)
- CA caves are connected (flood fill test)
## Implementation Order
1. Create `worldgen.rs` with `WorldGenerator` struct and `generate()` dispatch
2. Implement surface generation (depth 1-3) — move existing code, add RNG
3. Implement CA cave generation (depth 4-6)
4. Implement BSP dungeon generation (depth 7+)
5. Integrate into `game.rs::init_world()`
6. Write tests
7. Run all tests + scenarios
8. Push