AI lane (ported from MRPGI): unknown typed sentences go to a local LLM (MRPCI_AI: ollama default / openrouter / off) that maps them onto already-legal commands; one in flight, polled per tick, hard-off under --script so replays stay byte-identical. Portraits: NPCs/props gain a portrait sprite drawn beside the dialogue window in the GUI (6x) and annotated frames (2x); sergeant + vend-bot faces in the demo. Also: --script + --render-room renders the frame a replay ends on. Verified: 5 test suites green, deterministic 25/25 playthrough, GUI boots. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
846 lines
15 KiB
JSON
846 lines
15 KiB
JSON
{
|
|
"name": "41st Precinct Lobby",
|
|
"enter_text": "Fluorescents flicker over the duty desk. The evidence locker waits along the east wall.",
|
|
"background": "",
|
|
"ops": [
|
|
{
|
|
"VGradient": {
|
|
"x": 0,
|
|
"y": 0,
|
|
"w": 320,
|
|
"h": 96,
|
|
"ramp": [
|
|
119,
|
|
76
|
|
],
|
|
"ink": {
|
|
"color": 0,
|
|
"pri": "Keep",
|
|
"ctl": {
|
|
"Set": 1
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 0,
|
|
"y": 96,
|
|
"w": 320,
|
|
"h": 4,
|
|
"ink": {
|
|
"color": 153,
|
|
"pri": "Keep",
|
|
"ctl": {
|
|
"Set": 1
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"VGradient": {
|
|
"x": 0,
|
|
"y": 100,
|
|
"w": 320,
|
|
"h": 90,
|
|
"ramp": [
|
|
23,
|
|
21
|
|
],
|
|
"ink": {
|
|
"color": 0,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 0,
|
|
"y": 100,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 64,
|
|
"y": 100,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 128,
|
|
"y": 100,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 192,
|
|
"y": 100,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 256,
|
|
"y": 100,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 32,
|
|
"y": 115,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 96,
|
|
"y": 115,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 160,
|
|
"y": 115,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 224,
|
|
"y": 115,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 288,
|
|
"y": 115,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 0,
|
|
"y": 130,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 64,
|
|
"y": 130,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 128,
|
|
"y": 130,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 192,
|
|
"y": 130,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 256,
|
|
"y": 130,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 32,
|
|
"y": 145,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 96,
|
|
"y": 145,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 160,
|
|
"y": 145,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 224,
|
|
"y": 145,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 288,
|
|
"y": 145,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 0,
|
|
"y": 160,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 64,
|
|
"y": 160,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 128,
|
|
"y": 160,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 192,
|
|
"y": 160,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 256,
|
|
"y": 160,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 32,
|
|
"y": 175,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 96,
|
|
"y": 175,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 160,
|
|
"y": 175,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 224,
|
|
"y": 175,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 288,
|
|
"y": 175,
|
|
"w": 32,
|
|
"h": 15,
|
|
"ink": {
|
|
"color": 118,
|
|
"pri": "Band",
|
|
"ctl": {
|
|
"Set": 0
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 118,
|
|
"y": 96,
|
|
"w": 90,
|
|
"h": 26,
|
|
"ink": {
|
|
"color": 110,
|
|
"pri": "Keep",
|
|
"ctl": {
|
|
"Set": 1
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 118,
|
|
"y": 96,
|
|
"w": 90,
|
|
"h": 4,
|
|
"ink": {
|
|
"color": 153,
|
|
"pri": "Keep",
|
|
"ctl": {
|
|
"Set": 1
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 30,
|
|
"y": 30,
|
|
"w": 20,
|
|
"h": 26,
|
|
"ink": {
|
|
"color": 196,
|
|
"pri": "Keep",
|
|
"ctl": {
|
|
"Set": 1
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 56,
|
|
"y": 30,
|
|
"w": 20,
|
|
"h": 26,
|
|
"ink": {
|
|
"color": 167,
|
|
"pri": "Keep",
|
|
"ctl": {
|
|
"Set": 1
|
|
},
|
|
"hot": null
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"Rect": {
|
|
"x": 140,
|
|
"y": 182,
|
|
"w": 40,
|
|
"h": 8,
|
|
"ink": {
|
|
"color": 147,
|
|
"pri": "Keep",
|
|
"ctl": "Keep",
|
|
"hot": null
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"palette": null,
|
|
"cycles": [],
|
|
"scale": {
|
|
"horizon_y": 88,
|
|
"min_scale": 0.7,
|
|
"full_y": 185
|
|
},
|
|
"spawn": [
|
|
160,
|
|
176
|
|
],
|
|
"exits": [
|
|
null,
|
|
null,
|
|
null,
|
|
null
|
|
],
|
|
"exit_flags": [
|
|
"",
|
|
"",
|
|
"",
|
|
""
|
|
],
|
|
"exit_blocked": [
|
|
"",
|
|
"",
|
|
"",
|
|
""
|
|
],
|
|
"hotspots": [
|
|
{
|
|
"name": "street door",
|
|
"rect": [
|
|
136,
|
|
184,
|
|
48,
|
|
6
|
|
],
|
|
"poly": [],
|
|
"msgs": {
|
|
"look": "Back out to Neon Row."
|
|
},
|
|
"exit_to": 0,
|
|
"arrive": [
|
|
226,
|
|
120
|
|
],
|
|
"requires_flag": "",
|
|
"blocked_text": "",
|
|
"trigger": false,
|
|
"blocks": false
|
|
},
|
|
{
|
|
"name": "duty desk",
|
|
"rect": [
|
|
118,
|
|
96,
|
|
90,
|
|
30
|
|
],
|
|
"poly": [],
|
|
"msgs": {
|
|
"do": "You straighten a stack of incident forms. Order is restored, briefly.",
|
|
"look": "The duty desk. Coffee rings dating back three administrations."
|
|
},
|
|
"exit_to": null,
|
|
"arrive": null,
|
|
"requires_flag": "",
|
|
"blocked_text": "",
|
|
"trigger": false,
|
|
"blocks": false
|
|
},
|
|
{
|
|
"name": "wanted posters",
|
|
"rect": [
|
|
28,
|
|
28,
|
|
52,
|
|
30
|
|
],
|
|
"poly": [],
|
|
"msgs": {
|
|
"look": "WANTED: the Compost Bandit. Last seen fleeing Sickbay with a datacard."
|
|
},
|
|
"exit_to": null,
|
|
"arrive": null,
|
|
"requires_flag": "",
|
|
"blocked_text": "",
|
|
"trigger": false,
|
|
"blocks": false
|
|
}
|
|
],
|
|
"props": [
|
|
{
|
|
"name": "locker",
|
|
"sprite": "locker",
|
|
"x": 286,
|
|
"y": 138,
|
|
"msgs": {
|
|
"look": "Evidence locker 47. The reader-slot blinks, wanting a keycard.",
|
|
"do": "Locked tight. The reader-slot blinks at you, unimpressed."
|
|
},
|
|
"takeable": false,
|
|
"synonyms": "",
|
|
"use_text": "The keycard chirps. Locker 47 clunks open: one data-slate, sealed in an evidence bag.",
|
|
"needs": "keycard",
|
|
"wins": false,
|
|
"requires_flag": "",
|
|
"sets_flag": "locker_open",
|
|
"dialogue": [],
|
|
"portrait": "",
|
|
"points": 10,
|
|
"consumes": false,
|
|
"kills": false,
|
|
"visible_flag": "",
|
|
"hidden_by_flag": "",
|
|
"solid": true,
|
|
"fixed_priority": null,
|
|
"fixed_scale": null
|
|
},
|
|
{
|
|
"name": "terminal",
|
|
"sprite": "terminal",
|
|
"x": 36,
|
|
"y": 130,
|
|
"msgs": {
|
|
"do": "It wants the evidence, not your fingerprints.",
|
|
"look": "The case terminal. Slot: DATA-SLATE. It has been hungry for weeks."
|
|
},
|
|
"takeable": false,
|
|
"synonyms": "",
|
|
"use_text": "The slate slides home. Records unspool. Warrants bloom. Somewhere, the Compost Bandit sneezes.",
|
|
"needs": "evidence",
|
|
"wins": true,
|
|
"requires_flag": "",
|
|
"sets_flag": "",
|
|
"dialogue": [],
|
|
"portrait": "",
|
|
"points": 10,
|
|
"consumes": true,
|
|
"kills": false,
|
|
"visible_flag": "",
|
|
"hidden_by_flag": "",
|
|
"solid": true,
|
|
"fixed_priority": null,
|
|
"fixed_scale": null
|
|
}
|
|
],
|
|
"npcs": [
|
|
{
|
|
"name": "sergeant",
|
|
"sprite": "sergeant",
|
|
"x": 162,
|
|
"y": 132,
|
|
"msgs": {
|
|
"look": "Sergeant Brasso. Chrome polished, patience not."
|
|
},
|
|
"dialogue": [
|
|
{
|
|
"says": "Morp-9. The data-slate case won't close itself.",
|
|
"choices": [
|
|
{
|
|
"text": "Where do I start?",
|
|
"goto": 1,
|
|
"requires_flag": "",
|
|
"sets_flag": "",
|
|
"points": 0,
|
|
"kills": false
|
|
},
|
|
{
|
|
"text": "What do I do with evidence?",
|
|
"goto": 2,
|
|
"requires_flag": "locker_open",
|
|
"sets_flag": "",
|
|
"points": 0,
|
|
"kills": false
|
|
},
|
|
{
|
|
"text": "On it, Sarge.",
|
|
"goto": -1,
|
|
"requires_flag": "",
|
|
"sets_flag": "",
|
|
"points": 0,
|
|
"kills": false
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"says": "Perp dumped a keycard in Rain Alley, east off Neon Row. It opens evidence locker 47.",
|
|
"choices": [
|
|
{
|
|
"text": "Got it.",
|
|
"goto": 0,
|
|
"requires_flag": "",
|
|
"sets_flag": "",
|
|
"points": 0,
|
|
"kills": false
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"says": "Slot the slate into the case terminal, west wall. Then we both go home.",
|
|
"choices": [
|
|
{
|
|
"text": "Copy.",
|
|
"goto": 0,
|
|
"requires_flag": "",
|
|
"sets_flag": "",
|
|
"points": 0,
|
|
"kills": false
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"portrait": "sergeant-face",
|
|
"wander": 0,
|
|
"visible_flag": "",
|
|
"hidden_by_flag": "",
|
|
"fixed_scale": null
|
|
}
|
|
],
|
|
"music": 1,
|
|
"weather": 0,
|
|
"defaults": {},
|
|
"script": "room1.rhai"
|
|
} |