# 2026-07-05 — The SPACE bar is dead: continuous simulation lands ``` Type: log ``` Commits: `7f6cf5b` (sim pivot), `05048e4` (fmt), plus the design doc. ## The design session Sat down to answer "what is this game, actually?" The repo was a competent wave-defense roguelike, but the stated vision was always Evil Genius x Dwarf Fortress: persistent lair-empire, simulation-driven pressure, a villain you grow, no campaign ceiling. Wrote DESIGN.md and locked the big calls: - **Stylized Bevy 2D/2.5D**, not 3D. 3D roughly triples asset/readability cost for a game whose soul is simulation density. - **Hybrid loop pivot**: keep the raid machinery, replace its trigger. Raids become consequences (DF sieges), not scheduled waves. - **Real-time with pause, fixed tick.** One clock for everything. - **Schemes = abstract world-map dispatch** (Evil Genius style), designed so big ones can become playable set pieces later. - **Minions get needs/morale** (middle depth) — not full DF inner lives yet. - **Multiplayer = async shared world, later** — but determinism + full serializability are day-one requirements so the door stays open. - **The villain is all four layers**: chargen, avatar power tree, org infamy, cosmetic style. Phased in that order-ish. ## What shipped The wave loop is gone. `src/sim.rs` now owns all game state behind a renderer-agnostic `Sim` with a fixed-tick `advance()`: - Economy accrues every 20 ticks, schemes progress and heat decays every 40, raid combat runs every tick. Everything keeps running during raids — that's the point. - **Threat model v1:** heat >= 10 starts a raid countdown; hotter burns the countdown faster (1 + heat/50 per tick); notoriety + heat set raid strength; an intel warning fires ~12s before arrival; repelling a raid vents 10 heat and pays salvage. A cold lair is simply never raided. - Terminal frontend rewrote down to a thin view (~430 lines): SPACE/p pauses, +/- scales time, powers work anytime, world map is a modal not a phase. - Deleted the 1,900-line legacy binary (`src/main.rs` + friends) that predated the lib split. Net diff: **-1,434 lines** while adding a whole system. Great feeling. - Save format grew a `SIM` line (tick, raid countdown), backward compatible. - 130 tests (19 new on the sim), clippy clean. ## Notes & gotchas - The old code only accrued income inside `update_resources()`, which was called on *build actions* — passive income basically didn't exist unless you kept clicking. The economy tick fixes that structurally. - Smoke-testing the TUI through a pty caught a real crash: `script` reports a 0x0 terminal, layout math went negative, `as usize` produced a capacity overflow panic. Added a 60x20 minimum-size guard. Lesson: pty smoke tests are cheap and find real bugs — keep doing them. - `Instant::now()` still lives in the frontend only. The sim itself never reads the wall clock — protect this; it's the multiplayer/replay seam. ## Known debts (deliberate) - Scheme minions are **consumed**, not deployed-and-returned. Wrong tradeoff long-term; fix when schemes get risk/failure rolls. - One global "agency" pool. The escalation ladder (investigator → infiltrator → strike team → siege) and per-agency heat are the next threat iteration. - RNG is unseeded (`rand::rng()`) — fine for now, but determinism guardrail says this becomes a seeded, serialized RNG before any multiplayer work. - Raids in progress aren't persisted; on load the raiders politely withdraw.