# MRPGI — Monster Robot Party Game Interpreter A **new-school, Apple-Silicon-native reimagining of Sierra's 1980s AGI engine** — the tech behind *King's Quest*, *Space Quest*, and *Police Quest* — rebuilt in Rust + [macroquad](https://macroquad.rs) so you can make cool, fun adventure games. It keeps the *soul* of AGI (vector rooms, the invisible priority/depth screen, loops-and-cels sprites, a verb-noun parser, flags & vars, the ego) and bridges it forward (Retina-crisp rendering, hand-editable text resources, a real embedded scripting language, and an optional AI parser). ## Run it ```sh cargo run -p mrpgi # the GUI (paint + play) — or ./run.sh cargo run -p mrpgi --release # smooth, optimized build ``` A window opens in the editor. Paint a room (or launch with `--sample` for the 3-room demo game), then press **Tab** to walk it — arrows or click to move, type verbs to play. `F1` toggles CRT scanlines, `F2` sound, `Esc` quits. ## Drive it from anywhere (headless) The engine is a headless core behind a typed command/event bus; the GUI is just one consumer. The same bus is exposed as JSONL stdio, HTTP, and MCP: ```sh cargo run -p mrpgi-core --bin mrpgi-headless -- --sample --game games/demo echo '{"cmd":"parse","text":"look"}' | cargo run -p mrpgi-core --bin mrpgi-headless -- --game games/demo mrpgi-headless --serve 127.0.0.1:7777 --game games/demo # HTTP + /frame.png claude mcp add mrpgi -- mrpgi-headless --mcp --game games/demo # Claude plays & authors ``` A game is a folder of JSON + PNGs — an LLM expansion is just JSON that deserializes. See **[docs/CONTROL.md](docs/CONTROL.md)** for the full guide (commands, events, HTTP routes, MCP tools, authoring JSON reference). **📖 The deep read:** [THE MRPGI BOOK](web/manual.html) — the combined user/dev manual with the authoring cookbook, AI prompt patterns with real outputs, and engine internals. Live at [monsterrobot.games/engine/manual.html](https://monsterrobot.games/engine/manual.html) and under **Game → Manual** in the engine itself. ## How it works (the AGI model, faithfully) Every room is drawn into **two buffers at once**: | Buffer | What it holds | Why | |--------|---------------|-----| | **visual** | palette indices (0–15, EGA) | what you see | | **priority** | depth bands (4–15) + control lines (0–3) | depth sorting & collision | Lower on screen ⇒ higher priority ⇒ drawn nearer the camera. The ego is drawn a pixel at a time, *only where its priority ≥ the scenery's* — that's the whole "walk behind the tree" trick, with zero per-object Z bookkeeping. Control lines (priority `0`) are walls the ego can't cross. ## Source map Two crates: **`mrpgi-core`** (the headless engine — zero windowing deps, a compile error is the guardrail) and **`mrpgi`** (the macroquad GUI). | File | Role | |------|------| | `mrpgi-core/src/state.rs` | **the spine**: `GameState`, `Command`/`Event` bus, fixed-step `tick` | | `mrpgi-core/src/world.rs` | rooms/objects/dialogue data model (all serde), `World`, game folders | | `mrpgi-core/src/parser.rs` | data-driven verb table, verb-noun parser, dialogue state | | `mrpgi-core/src/render.rs` | headless compositing → RGBA / PNG (the priority-buffer trick) | | `mrpgi-core/src/framebuffer.rs` | the visual + priority buffers and the `band(y)` depth table | | `mrpgi-core/src/picture.rs` | vector room painting (rects / lines / fills / stamps) | | `mrpgi-core/src/view.rs` | sprites as loops + cels, authored from tiny ASCII grids | | `mrpgi-core/src/sprite.rs` | the ego: movement, click-to-walk, collision, walk animation | | `mrpgi-core/src/assets.rs` | PNG → EGA quantize + dither; sprite folders; kit art | | `mrpgi-core/src/audio.rs` | chiptune synth + audio cues (played by front-ends, or files) | | `mrpgi-core/src/ai.rs` | AI parser lane (Ollama / OpenRouter / off) on a worker thread | | `mrpgi-core/src/kit.rs` | sample game + fantasy starter kit, built from the real types | | `mrpgi-core/src/bin/mrpgi-headless/` | JSONL stdio, `--script` replay, `--render-room`, HTTP, MCP | | `mrpgi/src/main.rs` | window, play loop over the bus, HUD | | `mrpgi/src/editor.rs` | the in-engine paint tool (edits go through the same bus) | | `mrpgi/src/sound.rs` | audio out: game-folder files override the built-in synth | ## Asset pipeline (the new-school bit) Images don't sit *on top* of the game — they're folded *into* it. Any PNG is quantized to the EGA palette (optional Bayer dithering for smooth retro gradients) and becomes indexed pixels, so from that moment it depth-sorts, gets occluded, and walks-behind exactly like hand-authored art. Three ways in: - **Tile** an image across a region (textures — e.g. the floor) - **Pour** an image into a shape via `stamp_cel_fit` with a fit mode (stretch / tile / center) — *the shape also stamps depth & collision.* This is the "draw a shape, load an image into it" idea, realized. - **Objects** — a PNG becomes a `Prop` that sorts with the ego Drop your own art into `assets/`, then press **R** in-game to hot-reload it. ## Roadmap - [x] **v0.1 — rendering core**: vector room, priority depth, walkable ego, click-to-walk, CRT toggle - [x] **v0.2 — asset pipeline**: PNG → EGA quantize + dither, tile / pour-into-shape / object insertion, hot-reload (`R`) - [x] **v0.3 — room editor**: in-engine paint tool with edit/play modes, dual-layer LOOK+MEANING painting, flood-fill, tools (brush/line/rect/fill/pick/erase), undo, and JSON room save/load — see [EDITOR_GUIDE.md](EDITOR_GUIDE.md) - [ ] **Priority-mask backgrounds**: a full-room art PNG + a companion mask PNG whose colors encode depth bands & control lines (the pro art workflow) - [ ] **True-color "HD" layer mode**: skip quantization for painted backdrops; the priority buffer stays indexed - [ ] **Polygon shapes** for `stamp_cel_fit` (not just rectangles) - [ ] **Directional views** (4 loops + horizontal mirroring) for the robot - [x] **Text parser**: data-driven verb table with synonyms, verb-noun matching, on-screen input line - [x] **Room transitions**, inventory, flags (with `requires_flag`/`sets_flag` puzzle gating) - [x] **AI parser adapter**: when the classic parse misses, an LLM maps free text onto an *already-allowed* command (deterministic core stays authoritative; works offline without it) - [x] **Loadable game folders** (`game.json` + JSON rooms + PNGs) so games ship without recompiling the engine - [x] **Headless core + control surfaces**: JSONL stdio, script replay, HTTP, MCP, headless PNG rendering — see [docs/CONTROL.md](docs/CONTROL.md) - [ ] **Rhai room logic**: rooms scripted in an AGI-flavored embedded language (`if said(...) { print(...) }`), hot-reloadable - [ ] **3-voice + noise chiptune synth** (per-game audio files already override the square-wave synth) - [ ] **Strudel sink**: browser sidecar over the HTTP surface, driven by the same audio events - [ ] **Vars & conditions on dialogue/objects** beyond boolean flags; cross-room NPC state - [ ] **Pathfinding** for click-to-walk (today: greedy steering)