# MRPGI room editor — the dummy's guide You draw a room, tag what's walkable, press a key, and walk around it. That's it. ## Run it ```sh cargo run ``` It opens in **EDIT** mode. Press **`Tab`** any time to flip between **edit** (draw) and **play** (walk). `Esc` quits. ## The one rule (read this twice) Every spot on the screen has **two** properties, and you set them separately: - **LOOK** = the colour (what you see). You pick it from the **palette**. - **MEANING** = what it *is* to the game (walkable? a wall?). You pick it from the **meaning** tags. So a brown floor and a brown wall look identical but behave differently — because **colour is just looks; the tag is the meaning.** When you fill or draw a region, it gets *both*: the current colour **and** the current meaning tag. Meaning tags: - **floor** — walkable (the robot can stand here). Default. - **wall** — blocked (the robot can't enter). - **water** / **trigger** — special (reserved for later). - **none** — paint colour only, don't change walkability. ## Make your first room (the classic 3-band road) 1. Press **`Tab`** until the panel says you're editing (you start here). 2. Click the **fill** tool (or press `4`). 3. Click **blue** in the palette, click the **wall** tag, then click the **top third** → blue sky that blocks. 4. Click **green**, keep **wall**, click the **bottom third** → green ground that blocks. 5. Click **brown**, click the **floor** tag, click the **middle band** → a brown road that's walkable. 6. Press **`Tab`** → you're now playing. Use the **arrow keys** — the robot can only walk the road. 🎉 Tip: tap **`L`** to cycle the **view** — `both` tints walls red so you can *see* what's walkable vs blocked. `look` shows the plain picture; `ctrl` shows the meaning map. ## Tools | Tool | Key | What it does | |------|-----|--------------| | brush | `1` | freehand paint (colour + meaning) | | line | `2` | click points; **right-click or Enter** to finish the line | | rect | `3` | drag a filled box | | fill | `4` | flood-fill a sealed area (the bucket) | | pick | `5` | eyedropper — grab a colour off the canvas | | erase | `6` | rub back to blank + walkable | | image | `7` | stamp a sprite from `sprites/` (`[` `]` choose, `R` reload) | | oval | `8` | drag a filled ellipse | | spawn | `9` | click to set where the robot appears in play | | object | `0` | stamp a kit archetype (`[` `]` picks from 60+) or a blank object; click again to select | Brush/eraser size: **`,`** smaller, **`.`** bigger. The **fill** bucket (`4`) is your fast filler — outline a shape with lines, then click inside it. **Sealed areas:** fill only stays inside lines that fully enclose a space. If a fill suddenly floods the whole screen, your outline has a gap — undo and close it. The status line warns you (`LEAK?`). ## Keys - `Tab` edit ⇄ play · `Esc` quit - `1`–`0` tools · `L` cycle view - `[` `]` choose sprite · `,` `.` brush size · `R` reload sprites - `-` `=` previous / next room (the top strip has `<` `>` too) - `Z` or `Backspace` undo · `C` clear room · `K` save · `O` load - In play: **arrows / click** to walk · **type a command + Enter** (try `talk `) · in a conversation press **1–6** to choose, **Esc** to leave · `F1` CRT · `F2` sound ## Saving `K` saves to `rooms/room.json` (the editable list of your strokes, not flat pixels — so it stays re-openable and tiny). The game **auto-loads** that file on startup, and `O` reloads it. The cyan circle on the canvas is where the robot spawns in play. --- # Bring your own pixel art (Aseprite / Inkscape) The dream loop: **draw a thing → drop the PNG in `sprites/` → press `R` → place it with the image tool (`7`).** ## The spec (what a sprite PNG should be) - **Format:** PNG **with transparency** (alpha). Transparent pixels stay see-through in game; a sprite with no transparency acts like a solid tile. - **Size = game size.** The room is 160×168 "fat" pixels — draw small, at 1:1. Rough guide: a person ≈ 12–20 px tall, a crate ≈ 24 px, a door ≈ 30×50. A 500 px sprite will fill the whole screen. - **Colours:** ideally the MRPGI EGA 16 — load `palettes/mrpgi-ega.gpl` into your tool. Off-palette art still works; it's auto-snapped to the nearest EGA colour on load. - **Name = id.** Lowercase, no spaces: `crate.png`, `barrel.png`, `becky.png`. The filename (minus `.png`) is what shows in the sprite tray. - **Where:** the `sprites/` folder. (Starter `crate` / `barrel` / `sign` are already there — replace them or add your own.) ## Aseprite (pixel art) 1. **Load the palette:** Palette panel → ☰ menu → *Load Palette* → `palettes/mrpgi-ega.gpl`. Now you're painting in the exact game colours. (Bonus: *Sprite → Color Mode → Indexed* = pixel-perfect, zero quantization.) 2. New sprite, small (e.g. 24×24), transparent background. 3. Draw. Leave everything that isn't the object transparent. 4. **Export:** File → *Export Sprite Sheet* or just *Save As* a `.png` into `sprites/`. 5. In MRPGI: press **`R`**, tool **`7`**, **`[` `]`** to your sprite, **click** to place. ## Inkscape (vector → pixel) 1. Draw your art. *File → Document Properties* → set a small px canvas (e.g. 24×24). 2. **Export:** *File → Export* → Page tab, set width/height in **px**, transparent background → export PNG into `sprites/`. 3. Same place step in MRPGI (`R`, `7`, place). ## How a placed sprite behaves The image tool **stamps** the sprite into the room picture and applies your current **meaning** tag underneath it. So: - want a solid crate? pick the **wall** tag *before* you stamp → you can't walk through it. - want a walk-over rug? pick **floor** (or **none** to leave walkability alone). It's baked into the room and saved in `room.json`. (A *live* object — a movable entity with a name + verbs for items/NPCs — is the next slice; just ask.) ## One quirk: fat pixels Game pixels are twice as wide as tall (classic AGI). A perfect circle in Aseprite shows up slightly wide in game. Ignore it early — it's part of the retro look. --- # Build a world (multiple rooms) One room is a screen. A *world* is rooms linked by their edges. - The **top strip** shows `room N` with `<` `>` to move between rooms (also keys `-` / `=`). Going `>` past the last room makes a fresh blank one. Switching rooms **auto-saves** the one you're leaving. - Each room saves to its own file: `rooms/room0.json`, `rooms/room1.json`, … - **Exits** (top strip): the `N E S W` buttons. Click one to cycle its target room number (`N:-` → `N:0` → `N:1` … → off). So `E:1` means "walk off the right edge → arrive in room 1". - **Set the entrance** with the **spawn** tool (`9`): click where the robot should appear. The cyan circle shows it. ## Make two linked rooms 1. In **room 0**, leave a walkable gap at the **right** edge (don't wall it). Set exit **`E:1`**. 2. Press `>` to go to **room 1**, draw it, leave a walkable gap on its **left** edge, set exit **`W:0`**. 3. Press `<` back to room 0, press **`Tab`** to play, walk off the right edge → you're in room 1. Walk back left → room 0. You built a world. 🌍 Tip: if the robot seems stuck after a transition, the edge it arrived at was walled — leave a floor gap there (it otherwise falls back to that room's spawn point). --- # Objects you can talk to (the parser) This is where it becomes a *game*. The **object** tool (`0`) places a sprite as a real thing — and in play you can **type at it.** ## Place an object 1. Tool **`0`** (object). Press **`[` `]`** to flip through the **kit** — 60+ ready-made archetypes (orc, console, cocktail, coffin, sword, spellbook…), shown in the panel as `kit [ ]: `. **Click** the canvas to stamp the selected one — fully written (look/use/needs/wins/synonyms all filled in). Cycle to `(blank)` to instead drop a bare object named after the current sprite. 2. Click an object to **select** it. The inspector has editable fields — **name**, **look text**, **use text**, **needs item**, **synonyms** — plus **takeable / wins** toggles and **delete**. 3. To write its description: click the **look text** field, type your line (a caret shows), press **Enter** to jump to the next field. Click the canvas or press **Esc** to finish typing. 4. `K` saves it with the room. ## Talk to it (in play) Press **`Tab`** to play. There's a **`>` command line** at the bottom — type and hit **Enter**: - `look barrel` → its description - `take key` → into your inventory (if it's takeable) - `inventory` (or `i`) → what you're carrying - `look around` → everything in the room - `help` → the verb list Arrows still walk while you type. The parser is forgiving now: it ignores filler words ("the", "a", "at") and knows verb synonyms — `look` = `examine` = `x` = `check` = `inspect`; `take` = `get` = `grab` = `pick`. And the **synonyms** field lets an object answer to other nouns: put `box wood cargo` on a crate and `examine the box` just works. ## Try it 1. Edit: tool `0`, drop a `crate` and a `barrel`, press `K`. 2. `Tab` to play → type `look around`, then `look crate`, then `take barrel`, then `inventory`. The game answers you. 🤖💬 --- # Make a puzzle (locks, keys, winning) Objects can now *do* things — no code, just fields. Each object's inspector has: - **use text** — what `use ` / `open ` prints. - **needs item** — an item it requires. Empty = no lock. If set, `use` only works when that item is in your inventory; otherwise it says *"It's locked. You need: key."* - **wins** toggle — using it successfully **wins the game** (a YOU WIN banner). ## A complete 30-second game 1. Drop a sprite, select it, set **name** = `key`, **takeable** = on. (That's your key.) 2. Drop another, set **name** = `gate`, **use text** = *"The gate groans open. You're free!"*, **needs item** = `key`, **wins** = yes. 3. `K` to save, `Tab` to play. 4. Type `use gate` → *"It's locked. You need: key."* 5. `take key`, then `use gate` → your line prints + **★ YOU WIN ★** 🏆 `use` also accepts `open`, `unlock`, `push`, `pull`, `turn`. Keys, locks, and a win condition — a real puzzle, authored entirely with fields. --- # Natural language (the local AI lane) When the parser doesn't recognise your verb, it quietly asks a **local LLM** to translate your sentence into one *real* command — then runs THAT through the normal game logic. The AI bends the *language*; your game still decides what's *possible*. It can't invent items or outcomes. It runs on a background thread (the game never freezes) and shows what it decided, e.g. `(≈ open crate)`. ## It's already set up on your Mac Ollama is running with your Gemma models. Because your models have custom names, point the engine at one when you launch: ```sh ./run.sh # (which is just: MRPGI_AI_MODEL="hf.co/OBLITERATUS/gemma-4-E4B-it-OBLITERATED:latest" cargo run ) ``` Then in play, with a `gate` / `key` / `crate` around, try: - `pry the lid off the box` → *(≈ open crate)* - `yank the gate open` → *(≈ use gate)* - `grab that shiny thing` → *(≈ take key)* The bottom bar shows `ai: ollama/` so you know it's wired. ## Settings (env vars) | Var | Default | Meaning | |-----|---------|---------| | `MRPGI_AI` | `ollama` | `ollama` · `openrouter` · `off` | | `MRPGI_AI_MODEL` | `gemma3:4b` | model tag — set to your Ollama tag | | `MRPGI_AI_URL` | `http://localhost:11434/api/generate` | endpoint override | | `OPENROUTER_API_KEY` | — | required when `MRPGI_AI=openrouter` | **OpenRouter instead of local:** ```sh MRPGI_AI=openrouter OPENROUTER_API_KEY=sk-... MRPGI_AI_MODEL=google/gemma-2-9b-it:free cargo run ``` If Ollama isn't running or the model's missing, the AI lane just stays quiet and you get the normal "I don't understand" — nothing breaks. --- # Talk & tunes (NPCs + ambient music) ## Talk to NPCs An object can carry a **branching dialogue tree**. In play, `talk ` (or `speak` / `ask` / `chat` / `greet`) starts a conversation: the NPC speaks, and you pick a reply by pressing its **number key** (`1`–`6`). Choices branch to other lines; some end the chat. **Esc** leaves early. Walking pauses while you talk. Try it: in the fantasy world, head **south** from the forest to the inn and type `talk barkeep` — there are a few branches to explore. Authoring is JSON for now: a `dialogue` array on the object (see the inn villager in `rooms/room3.json`). Each node has `says` + `choices`; each choice has `text` + `goto` (a node index, or `-1` to end). A visual tree-builder is a future step. ## Ambient music Each room can loop a **mood**. In the editor, the top strip has a **♪ button** — click it to cycle: off · calm · eerie · tense · jolly · spooky. It saves with the room (`K`) and plays in play mode, switching as you move between rooms. **F2** mutes music + SFX together.