Crops, tree seedlings, and tile recovery no longer iterate all entries
every frame. Each event stores an absolute gameTime timestamp (growsAt).
A sorted priority queue is drained each tick — only due items are touched.
WorldState now tracks gameTime (ms); stateManager.advanceTime(delta)
increments it each frame. Save version bumped 5→6 with migration.
Action log ring buffer (15 entries) added to LocalAdapter; shown in
the F3 debug panel under "Last Actions".
Closes#36Closes#37
Fixes#31. All trees, rocks, seedlings and buildings now use
tileY+5 as depth instead of a fixed value, so objects further
down the screen always render in front of objects above them
regardless of spawn order. Build ghost moved to depth 1000/1001.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CHANGE_TILE only called worldSystem.setTile() (built-tile layer only),
never refreshTerrainTile() — so chopped trees stayed visually dark-green
(FOREST color) even though the tile type was already DARK_GRASS.
- adapter.onAction for CHANGE_TILE now also calls refreshTerrainTile()
→ all tile transitions (chop, mine, seedling maturation) update the
canvas pixel immediately and consistently in one place
- Remove now-redundant explicit refreshTerrainTile() call in
TreeSeedlingSystem (the adapter handler covers it)
- Tile-recovery path in GameScene (stateManager.tickTileRecovery) is
NOT routed through the adapter, so its manual refreshTerrainTile()
call is kept as-is
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously FOREST and ROCK tile types were always impassable, making 30 % of
forest floor and 50 % of rocky terrain permanently blocked even with no object
on them.
- Remove FOREST + ROCK from IMPASSABLE in types.ts
- Add RESOURCE_TERRAIN set (FOREST, ROCK) for tiles that need resource check
- WorldSystem: add resourceTiles Set<number> as O(1) spatial index
- initResourceTiles() builds index from state on create()
- addResourceTile() / removeResourceTile() keep it in sync at runtime
- isPassable() now: impassable tiles → false | RESOURCE_TERRAIN → check index | else → true
- GameScene: call addResourceTile() when SPAWN_RESOURCE fires (seedling matures)
- VillagerSystem: call removeResourceTile() after chop / mine completes
Side effect: trees fully enclosed by other trees are now reachable once an
adjacent tree is cleared; the hasAdjacentPassable() guard in pickJob still
correctly skips resources with zero passable neighbours.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clicking a Nisse opens a top-left panel showing name, AI status,
energy bar, active job, job priority buttons, and a live work log
(last 10 of 20 runtime-only entries). Closes via ESC, ✕, or clicking
another Nisse. Dynamic parts (status/energy/job/log) refresh each
frame without rebuilding the full group.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
F3 toggles a debug overlay with:
- FPS
- Mouse world/tile coordinates
- Tile type under cursor
- Resources, buildings, crops on hovered tile
- Nisse count broken down by AI state (idle/walking/working/sleeping)
- Active jobs by type (chop/mine/farm)
- Pathfinding visualization: cyan lines + destination highlight
drawn in world space via DebugSystem
Added DebugSystem to GameScene. VillagerSystem exposes
getActivePaths() for the path visualization. JSDoc added to all
previously undocumented methods in VillagerSystem, WorldSystem,
GameScene, and UIScene.