Commit graph

6 commits

Author SHA1 Message Date
00502153f3 feat(core): items & creatures — entity layer + EntityPlacer (9th pass)
The roadmap capstone: the dungeon is now populated.

- New entity layer: src/entity.rs (Entity { kind, at }, EntityKind {Entrance,
  Exit, Treasure, Monster}); Map gains an `entities: Vec<Entity>` overlay field
  (serde round-tripped). Entities aren't terrain, so no new Tile and the frozen
  viz is untouched.
- EntityPlacer/EntityConfig: places one Entrance (random room), one Exit (the
  room farthest from it — a traversal goal), per-room Treasure (treasure_chance)
  and Monsters (monster_chance, 1..=max, never in the entrance room). All on
  plain Floor only, never two per cell, fully deterministic.
- Handoff via the Blackboard (the designed side channel for non-tile/region/edge
  data) under entity::BLACKBOARD_KEY, harvested by Pipeline into Map.entities —
  so GenContext's 25 literals stay untouched.
- Renderer draws iconic markers on the final stage: green beacon (entrance),
  cyan portal (exit), gold diamond (treasure), crimson eyed-blob (monster), each
  with a soft glow. New entities toggle + treasure/monster sliders + readout.

Core: 135 tests green (6 new: one entrance/one exit on distinct floor, entrance
room monster-free, determinism, empty-map, recipe populated-check). clippy
clean. Pipeline is now 9 passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 01:11:13 -06:00
e7e8bb9187 feat(core): water & lava pools (PoolDecorator) + lava lighting
Seventh pass (before pillars): floods an organic blob of Water or Lava into
some larger rooms via randomized BFS growth.

- New Tile::Water / Tile::Lava (impassable hazards). Exhaustive matches updated
  (ascii '~'/'!', frozen viz colors, wasm codes 4/5).
- PoolDecorator/PoolConfig (water_chance, lava_chance, min_room): blob is
  interior-only (>= 2 from edge, never the center), and a connectivity guard
  verifies the room's remaining floor stays 4-connected with the center intact
  before committing — so a pool never orphans part of a room.
- DungeonConfig gains `pools`; recipe inserts PoolDecorator after DoorPlacer.
- Renderer: water as cool reflective pools; lava as molten rock that ALSO
  throws warm light onto nearby floor (BFS light field, wall-blocked) — lava
  chambers visibly glow. New water/lava sliders.

Core: 125 tests green (4 new: interior placement, floor stays connected,
zero/small-room skip, determinism); connectivity holds with pools in the
default recipe. clippy clean (core + viz).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 00:41:48 -06:00
128dce6310 tune(core): make pillars an occasional special-room feature
Per feedback ("not every room needs pillars"): default PillarConfig drops to
room_chance 0.30 / min_room 7 (was 0.55/7). A typical dungeon now has a couple
of distinctive pillared halls rather than pillars in most rooms — measured ~14
of 24 default seeds carry any pillars at all, usually just one room's worth.
The pillars slider still goes to 1.0 for full colonnades.

Also expose pillarTiles in the web state() hook (iteration/measurement aid).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 00:29:14 -06:00
b1449248f8 feat(core): pillars — PillarPlacer decorator + Tile::Pillar
A finishing decorator that scatters free-standing pillar columns into larger
rooms on a spaced interior grid. Sixth pass in the dungeon recipe.

- New Tile::Pillar (impassable like Wall, drawn distinctly). Exhaustive matches
  updated: ascii ('o'), frozen macroquad viz (still compiles), wasm code 3.
- PillarPlacer/PillarConfig (room_chance, min_room, spacing): places isolated
  single-cell pillars only on interior room floor (>= 2 from the edge, never the
  center), on a grid with spacing >= 2 — so the floor stays 4-connected by
  construction and a room is never orphaned. Respects non-rect room shapes
  (pillars land only on actual carved floor).
- DungeonConfig gains `pillars`; recipe appends PillarPlacer after DoorPlacer.
- Renderer draws pillars as lit stone columns with a contact shadow; new
  "pillars" density slider.

Core: 121 tests green (5 new: interior-only placement, floor stays connected,
zero-chance/small-room skip, determinism). clippy clean (core + viz).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 00:25:37 -06:00
a1d2a63937 feat(core): polygonal room shapes (rect/octagon/ellipse/plus)
RoomCarver now rolls a per-room shape within its chosen rectangle, weighted by
a new RoomConfig.shapes (ShapeWeights). The rect is still picked first and
unchanged, so room centers — and the corridors wired between them — are
identical to before; only the carved interior differs.

- Shapes built from per-row contiguous spans → guaranteed 4-connected and
  convex, so flood-fill never strands a cell.
- Hard invariant: every shape contains rect.center() (the corridor target),
  with a fallback to a full rect for tiny rooms or any non-covering shape —
  keeps MstConnect/CorridorCarver correct.
- ShapeWeights::default() is rect-only (preserves old behavior + existing
  tests); the dungeon recipe opts into ShapeWeights::varied().
- Configs lose Eq (now carry f64 weights); serde unaffected.

Core: 116 tests green (new forced-shape invariants test: in-bounds, center
carved, non-rectangular, 4-connected); connectivity + determinism + door tests
all pass with varied shapes active. Surfaced as 4 shape-weight sliders in the
web playground.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 00:16:45 -06:00
f849d82d31 feat(wasm+web): live browser dungeon playground (WASM core + atmospheric renderer)
Phase 0+1 of the browser viz effort:
- core: drop unused `rand` dep (removes getrandom/libc → clean wasm32 build);
  derive serde on DungeonConfig + 5 sub-configs so the bridge can (de)serialize
- reikhelm-wasm: thin wasm-bindgen cdylib exposing generate(seed, config_json)
  -> JSON envelope (tiles as int codes, regions, edges, per-pass snapshots) and
  default_config_json(); holds no generation logic
- workspace: add reikhelm-wasm member; default-members keeps host cargo
  test/clippy on core+viz only
- reikhelm-web: vanilla-JS + Canvas 2D renderer running the real core live in
  the browser. Atmospheric look — lit stone floor, raised stone walls with
  rim-lit carved edges + top bevel, room light-pooling, amber door thresholds,
  vignette. Controls: seed/reroll, 9 config sliders, stage scrubber, semantic
  overlays (region outlines / graph / grid). window.reikhelm hooks for
  Playwright-driven iteration.

Core stays 115 tests green. Driven + screenshotted via Playwright MCP.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 00:07:24 -06:00