# Status and roadmap **Read this first when picking up work.** It maps every feature in the design brief to its current state and the files that implement it, so you can find the relevant code without re-reading the whole project. Art and audio source packs, and their licence status, are recorded in [ASSETS.md](ASSETS.md) — the packs themselves are not in git. Design decisions that are already settled — and the reasoning behind them — live in [DECISIONS.md](DECISIONS.md). Check there before asking the user something that may already have an answer. Legend: **done** · **partial** (works, with a stated gap) · **todo** (not started) --- ## Stage 1 — World and exploration · *done* | Feature | State | Where | | --- | --- | --- | | Tile grid: movement / bullet / sight blocking | done | [src/sim/map_grid.gd](../src/sim/map_grid.gd) | | Dungeon generation from (seed, depth) | done | [src/sim/map_gen.gd](../src/sim/map_gen.gd) | | Hand-authored boss arenas and hub | done | [src/content/rooms.gd](../src/content/rooms.gd) | | Walls, pillars, pits, barricades | done | `MapGrid.Kind` + the three `BLOCKS_*` tables | | Enemies placed per room at creation | done | `Instance._populate()` | | Scrolling camera | done | [src/view/game_scene.gd](../src/view/game_scene.gd) | | Hard fog of war | done | `WorldView._draw_terrain` / `_visible` | | Per-peer map streaming (anti map-hack) | done | `ServerRuntime._stream_map` | | Aggro: range **and** line of sight | done | `SimWorld._aggro_target` | | Cursor-to-world aiming under a scrolling camera | done | `ClientRuntime.screen_to_world` | | Boss confined to its room | **partial** | `SimBoss.room` exists and bounds curtain patterns, but nothing clamps the boss — every boss is stationary today. Enforcement belongs with boss movement in Stage 5. | | **Actor interest management** | **todo** | The known gap. `ServerRuntime._physics_process` still encodes one snapshot and sends it to every peer in the instance, so clients are told about enemies the fog then hides. Terrain is properly withheld; actors are not. **Do this first.** | ### The invariant that matters most here Maps are streamed per peer, and the generation seed is **never** sent. See [NETCODE.md](NETCODE.md#maps-are-streamed-never-sent). `MAP_STREAM_RADIUS` must stay wider than `FOG_VIEW_RADIUS`, or the client predicts movement against terrain it does not have. --- ## Stage 2 — Characters, persistence, levels · *todo, next* Depends on nothing in Stage 1 except a place to stand. Blocked only on the identity layer, which is decided but unbuilt. | Feature | Notes | | --- | --- | | Identity abstraction | Shaped like Steamworks so it swaps out cleanly: opaque ticket from client → server validates → stable 64-bit account id (a SteamID64 stand-in). Local dev provider persists a generated id in `user://`. See [DECISIONS.md](DECISIONS.md#identity). | | Character store | Server-side, keyed by account id. Needs a schema and a file format; nothing persistent exists in the project today. | | Up to 5 characters, random colour each | Colour is a placeholder for a later cosmetic system. | | Last-played character auto-selected on join | | | Permadeath → mark inactive, never delete | Archival/troubleshooting. Confirm whether the 5-character cap counts only *active* characters. | | Death flow: pick another character or create one | Replaces today's "return to hub" button, which currently just revives you. | | Levels 1–15, +10 max HP per level | Confirm whether level 1 is 100 HP (→ 240 at cap) or 110. | | XP from kills, bosses worth much more | First full dungeon should give slightly more than one level. | Current behaviour to replace: `SimPlayer` has no identity beyond a peer id; `ServerRuntime.peer_names` is client-supplied and trusted for display only. --- ## Stage 3 — Upgrades · *todo* | Feature | Notes | | --- | --- | | Lobby NPC, 3 random choices per level gained | Confirm whether unclaimed level-ups queue. | | Every upgrade also grants +5% damage, additive | Displayed on the choice alongside its specific effects. | | Upgrade list | split shot, glass cannon, spread, sniper, doubleshot (rarer), poison (rare), eraser (legendary) | | Rarity weights | **Unspecified.** Needs numbers. | | Damage stacking formula | **Unspecified.** Sniper is explicitly multiplicative; the rest read as additive. Order needs pinning down before any of it is built. | | "Chosen upgrades" screen | | Damage is currently the constant `SimConfig.PLAYER_BULLET_DAMAGE`; upgrades turn it into a per-player computed stat, so `SimWorld._fire_player_shot` grows a stats block. Several upgrades (split, spread, doubleshot) change how many bullets spawn per shot, so they belong in the same place. --- ## Stage 4 — Inventory and loot · *todo* | Feature | Notes | | --- | --- | | Small always-on-screen inventory | Slot count unspecified. | | Health potions: rare from trash, guaranteed from bosses | | | World-shared loot | Player-instanced loot planned later. | | A unique, useless food item from bosses | Exists specifically to test player-instanced loot. Confirm whether it should be instanced *now* or just marked for it. | | Dropping items so others can pick them up | | --- ## Stage 5 — Boss features and new bosses · *todo* | Feature | State | | --- | --- | | Stationary phases | done — every current phase | | Roaming / chasing within the boss room | todo; needs `SimBoss.room` clamping (see Stage 1 partial) | | Phases that move to preset locations | todo | | Attacks spawned at a distance with a telegraph indicator | todo — new event type plus a renderer, and it must survive fog | | More bosses | partial — `Rooms.choir_vault()` is authored but has no `BossDef` yet | The boss format itself is proven: `tests/unit/test_boss.gd` builds a boss from scratch and asserts the simulation needs no changes to run it. Movement will be the first thing that format has not covered, so expect `BossPhase` to gain a movement field rather than `SimWorld` gaining a branch. --- ## Deliberate omissions Not oversights — each was considered and rejected for now, with the reasoning in [NETCODE.md](NETCODE.md) or [DECISIONS.md](DECISIONS.md): - **Lag compensation.** Rewinding to a shooter's view means a player who dodged still gets hit; wrong trade for this genre. - **Snapshot delta compression.** Fine at current actor counts. - **DTLS / encryption.** `ENetMultiplayerPeer` supports it. Required before any public server, not before then. - **Pattern-level bullet replication.** A real bandwidth win that couples the client to emitter behaviour. - **`MultiplayerSynchronizer` / `MultiplayerSpawner`.** Right tools, wrong shape for a bullet hell — see [ARCHITECTURE.md](ARCHITECTURE.md). --- ## Open questions for the user Genuinely unspecified; do not guess at these, they change the design: 1. Damage stacking order — additive pool then multiplicative, or something else? 2. Rarity weights for the four upgrade tiers. 3. Split shot geometry: ±22.5° from the original heading, or 45° to each side? 4. Poison: do applications stack, or refresh a single DoT? 5. Eraser: does it delete *enemy bullets* it passes through? 6. Inventory slot count. 7. Do unclaimed level-ups queue at the NPC? 8. Does the 5-character cap count only active characters? 9. Glass cannon's −50% health: of base HP, or of levelled max HP? 10. What advances dungeon depth? `--depth` is a dev flag; nothing raises it in play.