Conversation
There was a problem hiding this comment.
Pull request overview
Introduces a new chunk-based BSP dungeon generator and supporting runtime systems (TileMap/FOV/exploration, floor transitions, loot, traps, AI), and updates UI + tests to reflect the new dungeon model.
Changes:
- Add BSP chunk/floor generation with a singleton TileMap, explored-map fog-of-war, and depth transitions.
- Add spatial indexing + updated vision/LOS/FOV plumbing to work with TileMap and entity blockers.
- Expand combat/items/loot (ammo slot, fire arrows, new affixes, loot tables/resolution) and update UI + tests accordingly.
Reviewed changes
Copilot reviewed 84 out of 85 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/transition.test.mjs | Adds coverage for depth transitions and DungeonState updates. |
| tests/tileMap.test.mjs | Adds TileMap unit tests (loading/unloading/chunk math, walkability/opacity). |
| tests/rangedAttack.test.mjs | Updates ranged LOS blocking test to use TileMap walls instead of Terrain entities. |
| tests/populate.test.mjs | Adds tests for spawn tables and materialization behavior. |
| tests/monsterPickupDrop.test.mjs | Ensures movement/pickup works with TileMap-backed walkability. |
| tests/materialize.test.mjs | Adds tests for chunk materialization (doors/entities) and TileMap properties. |
| tests/learnThenCast.test.mjs | Adds test for learning a spell then casting on a later tick. |
| tests/gridLOS.test.mjs | Updates LOS tests to use TileMap opacity + blockedCallback. |
| tests/fov.test.mjs | Adds tests for packed-key FOV helpers. |
| tests/floorPlan.test.mjs | Adds tests for deterministic floor plans and stair placement invariants. |
| tests/floor.test.mjs | Adds tests for initDungeon/generateFloor determinism and chunk loading. |
| tests/exploredMap.test.mjs | Adds fog-of-war/explored-map behavior tests. |
| tests/effects.test.mjs | Extends effect coverage (disease/bleed stacking & combat pipeline). |
| tests/dungeonSeed.test.mjs | Adds tests for deterministic seed derivation. |
| tests/chunkGen.test.mjs | Adds tests for chunk connectivity, gates, doors, and determinism. |
| tests/bsp.test.mjs | Adds tests for BSP splitting/room placement/corridor connectivity. |
| tests/blastwave.test.mjs | Updates spell tests to use TileMap walls/walkability. |
| tests/autopickup.test.mjs | Updates pickup test setup to ensure floor tiles exist in TileMap. |
| tests/aiChase.test.mjs | Updates AI chase tests to use Faction-based enemy detection. |
| src/shared/math/fov.js | Refactors FOV to support callback setters + adds packed-key variants. |
| src/rules/utils/vision.js | Switches vision blockers to TileMap opacity + chunked entity blocker mask. |
| src/rules/utils/spatialIndex.js | Adds a lightweight spatial index for Position queries in rect/radius. |
| src/rules/systems/useItemSystem.js | Updates World typedef import path. |
| src/rules/systems/trapSystem.js | Improves trap naming/identity derivation and typedef import path. |
| src/rules/systems/spatialIndexSystem.js | Adds system wrapper to keep spatial index synced per tick. |
| src/rules/systems/rangedAttackSystem.js | Adds equipped-ammo support, fire-arrow procs, and avoids work when no intents. |
| src/rules/systems/movementSystem.js | Replaces Terrain-walkability checks with TileMap.isWalkable() and adjusts bump logic. |
| src/rules/systems/monsterSpawnerSystem.js | Updates World typedef import path. |
| src/rules/systems/manaRegenerationSystem.js | Adds equipment-derived mana regen to per-tick mana regen. |
| src/rules/systems/interactionSystem.js | Adds chest loot drops and emits stair traversal events. |
| src/rules/systems/equipmentSystem.js | Adds manaRegenDerived support from item bonuses/affixes. |
| src/rules/systems/equipItemSystem.js | Allows equipping ammo and prevents non-ammo stack collapsing. |
| src/rules/systems/effectSystem.js | Adds bleed/disease/mindwipe effects and status derivations. |
| src/rules/systems/combatSystem.js | Adds disease penalties and supports natural monster scripts/damage dice. |
| src/rules/systems/cleanupSystem.js | Adds monster loot drops on death via loot tables. |
| src/rules/systems/castSpellSystem.js | Updates World typedef import path. |
| src/rules/systems/aiChaseSystem.js | Uses Faction + spatial index + Speed gating to bound AI work. |
| src/rules/systems/affixTriggerSystem.js | Makes trigger installation idempotent and adds naturalScript on-damaged hook. |
| src/rules/scripts/traps.js | Adds snake trap script that spawns snakes around trigger. |
| src/rules/scripts/spells.js | Migrates targeting/LOS and push blocking to TileMap + Faction checks. |
| src/rules/scripts/monsters.js | Adds innate monster combat scripts (procs, mindwipe, etc.). |
| src/rules/scripting.js | Updates World typedef import paths. |
| src/rules/environment/dungeonGenerator.js | Updates World typedef import path. |
| src/rules/environment/dungeon/transition.js | Adds depth transitions with tile/explored/spatial reset + explored snapshots. |
| src/rules/environment/dungeon/tileMap.js | Adds singleton chunk-tile storage with walkable/opaque queries. |
| src/rules/environment/dungeon/tables.js | Adds depth-scaled monster/item/trap picking helpers. |
| src/rules/environment/dungeon/seed.js | Adds deterministic seed derivation for chunks/floors/edges. |
| src/rules/environment/dungeon/populate.js | Adds per-room spawn generation and spawn materialization. |
| src/rules/environment/dungeon/materialize.js | Materializes doors/stairs/spawns as entities (tiles stay in TileMap). |
| src/rules/environment/dungeon/index.js | Adds public dungeon API (init, generateFloor, exports). |
| src/rules/environment/dungeon/floorPlan.js | Adds per-depth plan (stairs/theme/difficulty/extent). |
| src/rules/environment/dungeon/exploredMap.js | Adds singleton explored/visible storage and FOV update pipeline. |
| src/rules/environment/dungeon/dungeonConfig.js | Adds dungeon tuning config container. |
| src/rules/environment/dungeon/constants.js | Adds dungeon tile + BSP constants. |
| src/rules/environment/dungeon/chunk.js | Adds per-chunk BSP generation, doors, and edge gates. |
| src/rules/environment/dungeon/bsp.js | Adds BSP partitioning, room carving, corridor connection. |
| src/rules/data/lootTables.js | Adds declarative loot tables for monsters/chests/floors. |
| src/rules/data/lootResolver.js | Adds loot table resolution + materialization into entities. |
| src/rules/data/items.js | Updates spellbook slot metadata. |
| src/rules/data/equipment.js | Adds Ring of Arcana (mana regen bonus). |
| src/rules/data/affixes.js | Adds Attuned affix for mana regen. |
| src/rules/components/Speed.js | Adds Speed component for tick cadence control. |
| src/rules/components/Mana.js | Adjusts default mana regen rate. |
| src/rules/components/Equipment.js | Adds ammo slot + natural combat fields + mana regen derived. |
| src/rules/components/DungeonState.js | Adds DungeonState singleton component for floor ownership/depth tracking. |
| src/rules/components/Brain.js | Adds visionRange to Brain. |
| src/rules/archetypes/Stairs.js | Adds stair archetypes with Interactable actions. |
| src/rules/archetypes/Items.js | Adds fire arrows + mapping scroll and sets ammo slot on arrows. |
| src/rules/archetypes/Creatures.js | Adds Speed and natural combat fields to creatures. |
| src/main/ui/hudFeeds.js | Adds ammo count and dungeon depth feed events. |
| src/display/ui/statusLine.js | Adds a bottom status line that listens to HUD events. |
| src/display/ui/overlay.js | Adds stair tooltip + inventory UX updates (ammo equip, spell select). |
| src/display/ui/hud.js | Adds ammo line + status stack rendering improvements (stacks/aliases). |
| src/display/passes/lightmask/index.js | Allows lightmask to accept a predicate visibility function. |
| src/display/palette/packs/weapons.js | Adds bow_short palette entry. |
| src/display/palette/packs/rings.js | Adds ring_arcana palette entry. |
| src/display/palette/base.js | Adds many monster/tile/item palette identities (stairs, traps, ammo, spellbooks). |
| src/display/input/actions.js | Adds ShootRanged action. |
| src/display/input/InputManager.js | Binds r key to ShootRanged action. |
| src/bridge/schema/worldView.js | Integrates TileMap rendering hooks + explored/FOV visibility filtering + spatial index usage. |
| app/rules/scheduler.js | Registers mana regen + spatial index syncing and imports monster scripts. |
| app/input/rulesDispatch.js | Adds dispatch hooks for shoot-ranged and cast-without-spellId. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const downStairs = [{ | ||
| chunkX: 0, | ||
| chunkY: 0, | ||
| localX: 0, | ||
| localY: 0, |
There was a problem hiding this comment.
downStairs is created with localX/localY set to 0, which violates the invariant asserted by the new floorPlan tests (stairs should have chunk-local coords inside the safe interior range). Pick valid local coordinates (e.g., rng.int(4, CHUNK_SIZE-5)) for down stairs as well, and ensure the generation code uses those coordinates consistently.
| if (!isWalkable(nx, ny) || blocking.get(k)) { | ||
| // Cheap bump-attack: prefer a living target with Vitality in the destination cell. | ||
| let target = 0; | ||
| for (const [eid, p] of world.query(Position)) { | ||
| if (p.x !== nx || p.y !== ny) continue; |
There was a problem hiding this comment.
This blocked-move branch does a full world.query(Position) scan per MoveIntent to find a target at (nx,ny), which becomes O(entities × moves) per tick. You already build an occupants map at the top of the system; use that to look up the occupant for k and then check whether it has Vitality (and is not the actor).
| // ── DEBUG: force spellbooks into first room ──────────────── | ||
| if (chunk.rooms.length > 0) { | ||
| const r0 = chunk.rooms[0]; | ||
| const cx = r0.x + Math.floor(r0.w / 2); | ||
| const cy = r0.y + Math.floor(r0.h / 2); | ||
| for (const [i, bookId] of ['book_lightning', 'book_meteor', 'book_blastwave'].entries()) { | ||
| spawns.push({ x: cx - 1 + i, y: cy + 1, kind: 'book', params: { bookId } }); |
There was a problem hiding this comment.
The DEBUG block here unconditionally injects spellbooks, a bow, arrows, and a monster into the first room of every chunk. This will permanently skew gameplay balance and makes dungeon generation behavior diverge from the intended density logic below; please remove it or gate it behind an explicit debug/config flag that defaults off.
| function scheduler(world) { | ||
| try { useItemSystem(world); } catch (e) { console.error('use system error', e); } | ||
| try { castSpellSystem(world); } catch (e) { console.error('cast system error', e); } | ||
| } |
There was a problem hiding this comment.
This test swallows system exceptions via try/catch and only logs them, which can allow failing behavior to pass silently. Tests should fail fast on unexpected errors; remove the try/catch or rethrow after logging.
| console.log('Before learning - brain.learnedSpellIds:', JSON.stringify(brain.learnedSpellIds)); | ||
|
|
||
| // Tick 1: learn spell | ||
| world.add(player, UseIntent, { itemId: book }); | ||
| world.tick(1); | ||
|
|
||
| const brainAfterLearn = world.get(player, Brain); | ||
| console.log('After learning - brain.learnedSpellIds:', JSON.stringify(brainAfterLearn.learnedSpellIds)); | ||
| assert(brainAfterLearn.learnedSpellIds.includes('lightning'), 'should have learned lightning'); |
There was a problem hiding this comment.
There are multiple console.log calls in this test which will spam test output and make CI logs noisy. Please remove them (or gate behind a debug flag) and rely on assertions for verification.
No description provided.