- MANUAL.md brought up to the workspace era: game folders + manifest, flags & gated puzzles, hidden dialogue choices, audio file overrides, a Programmatic control section (CLI/HTTP/MCP/Python), and the new two-crate architecture map. - games/lost-fuse: three rooms that demonstrate every mechanic in one chain — item, needs-lock, object sets_flag, a dialogue choice hidden behind requires_flag, dialogue sets_flag, and a flag-locked wins finale. Verified winnable headlessly, gate included. - games/lost-fuse/expansion/roof.jsonl: a live lore drop that upserts a fourth room into a running game and rewires an exit — the "drop JSON lore in" workflow, runnable as a one-liner. - games/README.md: the guided tour — mechanic-to-JSON map, the live expansion demo, and how to prompt an LLM (or point Claude's MCP at the engine) to write valid lore. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
88 lines
3.9 KiB
Markdown
88 lines
3.9 KiB
Markdown
# Games are folders. Lore is JSON.
|
||
|
||
Every MRPGI game is a folder you can zip, share, hand-write, or have an LLM
|
||
generate. This directory holds examples; **`lost-fuse/`** is the guided one —
|
||
three rooms that demonstrate every mechanic the engine has, in one small
|
||
puzzle chain.
|
||
|
||
## Play it
|
||
|
||
```sh
|
||
cargo run -p mrpgi -- --game games/lost-fuse # in the GUI
|
||
cargo run -p mrpgi-core --bin mrpgi-headless -- --game games/lost-fuse # in a terminal, JSON in/out
|
||
```
|
||
|
||
*(Spoilers below — play it first! It's five minutes.)*
|
||
|
||
## The anatomy of a quest
|
||
|
||
The whole game is ~200 lines of JSON. The chain:
|
||
|
||
```
|
||
take fuse an item → inventory (room 0)
|
||
use amp needs: fuse → sets_flag music_on (room 1)
|
||
talk bouncer a choice gated by requires_flag music_on
|
||
"I fixed your amp." → sets_flag on_the_list
|
||
use turntable requires_flag on_the_list → wins: true (room 2)
|
||
```
|
||
|
||
Each step is one field on an object or dialogue choice — no code anywhere:
|
||
|
||
| Mechanic | Where to look |
|
||
|---|---|
|
||
| A takeable item | `fuse` in [`rooms/room0.json`](lost-fuse/rooms/room0.json) |
|
||
| An item lock (`needs`) | `amp` in [`rooms/room1.json`](lost-fuse/rooms/room1.json) |
|
||
| An object setting a flag (`sets_flag`) | same `amp` |
|
||
| A **hidden** dialogue choice (`requires_flag`) | the bouncer's second choice — try talking to it before and after fixing the amp |
|
||
| Dialogue setting a flag | same choice (`sets_flag: on_the_list`) |
|
||
| A flag-locked finale (`requires_flag` + `wins`) | `turntable` in [`rooms/room2.json`](lost-fuse/rooms/room2.json) |
|
||
| Rooms linked by edges (`exits`) | every room: `[N, E, S, W]` room numbers |
|
||
| Painted look + walkability (`strokes`) | every room: `Rect`s with `meaning` `Floor`/`Wall`/`None` |
|
||
| Per-room music moods | `"music": 2/3/4` (eerie street → tense door → jolly club) |
|
||
| Manifest (name, intro, extra verb synonyms) | [`game.json`](lost-fuse/game.json) — try typing `fix amp` |
|
||
|
||
## Dropping lore into a RUNNING game
|
||
|
||
Rooms can be added live over any control surface — this is the "drop JSON
|
||
lore in" workflow. [`lost-fuse/expansion/roof.jsonl`](lost-fuse/expansion/roof.jsonl)
|
||
adds a roof afterparty above the club:
|
||
|
||
```sh
|
||
target/debug/mrpgi-headless --script games/lost-fuse/expansion/roof.jsonl --game games/lost-fuse
|
||
```
|
||
|
||
It upserts room 3 (validated: a room with no walkable spawn, or exits pointing
|
||
at rooms that don't exist, is rejected with an `error` event), then wires
|
||
room 2's north exit to it. The same two commands work over HTTP
|
||
(`POST /rooms/3`, `POST /command`) or MCP (`mrpgi_upsert_room`) against a live
|
||
session.
|
||
|
||
## Asking an LLM for lore
|
||
|
||
The formats are plain serde types, so generated JSON either loads or fails
|
||
loudly. A prompt that works well:
|
||
|
||
> Here is a room from my MRPGI game: *(paste a room JSON)*. Write a new room
|
||
> in exactly this format: *(describe the room, its objects, its puzzle role,
|
||
> which exits connect where)*. Rooms are 160×168; sprites available: altar,
|
||
> barrel, chest, key, orc, sign, villager. Only use `requires_flag`/`sets_flag`
|
||
> names that exist in my game.
|
||
|
||
Or skip the copy-paste entirely: register the MCP server
|
||
(`claude mcp add mrpgi -- mrpgi-headless --mcp --game games/lost-fuse`) and
|
||
the model can upsert rooms, render frames to *see* them, and playtest its own
|
||
puzzle chain. Full command reference: [../docs/CONTROL.md](../docs/CONTROL.md).
|
||
|
||
## Make your own
|
||
|
||
```sh
|
||
mkdir -p games/mygame
|
||
cargo run -p mrpgi-core --bin mrpgi-headless -- --sample --game games/mygame # a starting skeleton
|
||
cargo run -p mrpgi -- --game games/mygame # paint it in the editor
|
||
```
|
||
|
||
Sprites: drop PNGs in `games/mygame/sprites/` (auto-quantized to EGA, alpha =
|
||
transparent, bottom edge = feet). Audio: drop files in `sfx/` / `music/` to
|
||
replace the chiptune synth (see MANUAL.md §13). Everything else is the JSON
|
||
you just read.
|