# MRPCI — Monster Robot Party Creative Interpreter The **SCI generation** of the Monster Robot Party engine family. Where [MRPGI](../mrpgi) reimagines Sierra's 1980s AGI (16 colors, text parser, one merged priority buffer), MRPCI reimagines the tech behind *King's Quest V* and *Space Quest IV* — and then fixes everything Sierra never could: | Sierra SCI (1990) | MRPCI (now) | |---|---| | 256-color VGA, hand-cut palettes | 256-color palettes **quantized live from any PNG** (median cut), EGA/gray/ember ranges kept stable for sprites & cycles | | Palette cycling (waterfalls, neon) | Same trick, `cycles` are room data + script-toggleable | | Priority + control screens | **Four** screens: visual / priority / control / hotspot — hit-testing any pixel is one array read | | Polygon avoidance that wedged egos into corners | Real **A\*** with LOS-verified edges + string-pulling; actors walk the exact verified line, so a legal path can never clip | | Scale tables (SCI1.1) | Per-room perspective: actors shrink toward the horizon, walk speed scales to match | | CPU-speed timers → Error 52, instant Sequel Police | Fixed **30Hz deterministic cycles**; `after()` timers count ticks; the only RNG is seeded xorshift — replays are byte-identical | | `Error 47: Not an object` → crash to DOS | Missing resources = placeholders + an `error` event. A compile-error script = a log line, not a hang | | Die 3 hours after the dead-end | **Checkpoint at every room entry; death rewinds to it.** Save-anywhere slots on top | | OOP bytecode scripts, priest-tier tooling | **rhai** room scripts: `on_enter`, `on_verb(v,n)`, `on_trigger`, `after(ticks,"fn")` — hot-swappable over the bus | | Icon bar (SCI1) *or* parser (SCI0) | **Both.** Clicks and typed commands converge on one verb pipeline | The architecture is inherited from MRPGI and kept sacred: **`mrpci-core` is headless** (zero windowing deps — a compile error is the guardrail). The whole sim is a `GameState` behind a typed Command/Event bus, and every control surface — GUI, JSONL stdio, HTTP, MCP — is a thin adapter. ## Run it ```sh cargo run -p mrpci-core --bin mrpci-headless -- --sample # write the demo game cargo run -p mrpci # play Neon Precinct ``` **Neon Precinct**: you are Officer Morp-9. Rain, neon that actually cycles, a vend-bot with a tip, a keycard behind crates (watch the A\* go around), a lethal fusebox (watch death *not* ruin your evening), and a case to close. 25 points. Controls: left-click applies the verb, right-click cycles verbs, F1–F4 pick one, `I` inventory, **Enter types a command** (the parser is always alive), F5/F7 save/restore, F9 new game, M mute, N scanlines. ## Drive it headless (the point) ```sh cargo build -p mrpci-core target/debug/mrpci-headless --game games/neon-precinct # JSONL stdio target/debug/mrpci-headless --game games/neon-precinct --serve 8093 # HTTP target/debug/mrpci-headless --game games/neon-precinct --mcp # MCP for Claude target/debug/mrpci-headless --game games/neon-precinct --script play.jsonl # golden replay target/debug/mrpci-headless --game games/neon-precinct --room 2 --ticks 45 --render-room out.png target/debug/mrpci-headless --game games/neon-precinct --screens shots/ # all four screens ``` Register with Claude: ```sh claude mcp add mrpci -- $PWD/target/debug/mrpci-headless --mcp --game $PWD/games/neon-precinct ``` Claude can then *play* the game (verbs, walks, dialogue), *see* it (`mrpci_render_frame`, plus the invisible priority/control/hotspot screens), and *author* it (upsert rooms and rhai scripts live, validated before commit). See [docs/CONTROL.md](docs/CONTROL.md) for the full bus reference. ## A game is a folder ``` games/mygame/ game.json # manifest: name, start_room, intro, verbs, flags, max_score rooms/room0.json # RoomDoc: ops (paint), background, palette, cycles, scale, # spawn, exits, hotspots, props, npcs, music, script pics/street.png # optional backgrounds (+ street-pri.png / street-ctl.png masks) sprites/*.png # quantized per-room; filename = sprite name scripts/*.rhai # main.rhai + room scripts sfx/ music/ # optional audio overrides (else the built-in chip synth plays) saves/ # save-anywhere slots (gitignored) ``` Rooms paint with `PicOp`s — rects, polygons, floods, **dithered gradients**, plus procedural fills: **fBm noise** (clouds, asphalt, grime), **Voronoi cells** (cobbles, slabs) and **scatter** (stars, glints) — all seeded, all deterministic — through an `Ink` that writes any subset of the four screens at once. Or drop a PNG in `pics/` and let the quantizer fold it into the palette. Rooms can also set `weather` (rain / snow / embers): a particle layer on its own RNG stream, so visuals never perturb gameplay replays. ## Source map | Crate / file | Role | |---|---| | `mrpci-core/screens.rs` | the four aligned screens + depth bands | | `mrpci-core/palette.rs` | 256-color palettes, cycling LUTs | | `mrpci-core/pic.rs` | vector paint ops, Bayer-dithered gradients | | `mrpci-core/assets.rs` | median-cut quantizer, masks, sprite pipeline | | `mrpci-core/view.rs` | loops/cels, ASCII sprites, mirroring | | `mrpci-core/actor.rs` | ego + NPCs: scaling, line-exact path following | | `mrpci-core/path.rs` | A\*, LOS smoothing, `walk_line` | | `mrpci-core/room.rs` | RoomDoc / World / game folders / validation | | `mrpci-core/script.rs` | rhai host: hooks, Fx airlock, tick timers | | `mrpci-core/state.rs` | **the bus**: GameState, Command/Event, checkpoints | | `mrpci-core/render.rs` | headless compositing → RGBA/PNG | | `mrpci-core/audio.rs` | multi-voice chip synth (square/pulse/tri/noise) | | `mrpci-core/bin/mrpci-headless/` | stdio / HTTP / MCP / replay / sample | | `mrpci/` | the macroquad GUI (icon bar, dialogue windows, sound) | Headless frames are **annotated**: `--render-room`, HTTP `/frame.png` and MCP `mrpci_render_frame` stamp the room name, score, open dialogue window and transcript strip into the frame with the built-in 5x7 font — an LLM sees exactly what a player reads (add `--raw` / `/frame-raw.png` to skip). The GUI renders via a **GPU palette shader**: the frame ships to the card as indices + a 256x1 palette strip, and the fragment shader does the lookup plus the whole CRT (curvature, scanlines, vignette, room fades). ## The AI parser lane When the deterministic parser shrugs at a typed sentence, a small local LLM (Ollama by default; OpenRouter optional) translates it into ONE command from the *already-legal* verb/noun tables — then that command runs through the real game logic. The AI can suggest; only the sim decides. Configure with `MRPCI_AI` (`ollama`/`openrouter`/`off`), `MRPCI_AI_MODEL`, `MRPCI_AI_URL`. `--script` replays force the lane off, so golden tests stay byte-identical. ## Roadmap - [x] v0.1 — the engine above + Neon Precinct - [x] v0.2 — procedural fills (fBm/Voronoi/scatter), weather particles, in-core font + annotated frames, GPU palette/CRT shader - [x] v0.3 — world bundles carry art (`--export-bundle`/`--bundle`, the wasm path), AI parser lane, dialogue talker portraits - [ ] Priority-mask art workflow polish (paint depth in any image editor) - [ ] In-engine room editor (MRPGI's, upgraded to four screens) - [ ] wasm build → see the [MRP3GI](../mrp3gi) sibling (three.js + rigged GLBs over this core)