All six rooms are now flux_local matte paintings quantized by the engine (basement, gig, alley, office, Roskilde, field), with rooms reduced to invisible sim ops: walkability, depth, water, the footlight chases, and the NO MEANS NO! spray painted OVER the brick painting. The office desk gets a real walk-behind from the priority bands. Soundtrack: tools/gen_music.py synthesizes five loop-safe mood overrides (music/*.wav) in the band's own meters — 7/4 walking bass for the basement, the 9/8 riff floored for gig and Roskilde, chromatic noir for the alley, puck-rock bounce for the office, a 5/4 drone for the field. Fixed the office east-door lane (crates pinched the exit trigger) and removed the alley's unreachable north exit. Playthrough: 60/60, won, byte-identical twice, one intentional death. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
474 lines
21 KiB
Python
Executable File
474 lines
21 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Generate NOMEANSNO QUEST rooms as MRPCI RoomDoc JSON.
|
|
|
|
Every room is a MODELBEAST matte painting (pics/*.png, quantized by the
|
|
engine at load) plus *invisible* ops: walkability, depth, water — and the
|
|
few visible overlays that must move or glow (footlight chases, the spray
|
|
paint). Run from the repo root: python3 tools/gen_rooms.py
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
|
|
OUT = os.path.join(os.path.dirname(__file__), "..", "rooms")
|
|
|
|
def cube(r, g, b):
|
|
return 32 + 36 * r + 6 * g + b
|
|
|
|
def gray(i):
|
|
return 16 + min(i, 15)
|
|
|
|
EMBER = list(range(248, 256))
|
|
KEEP = "Keep"
|
|
|
|
def ink(color=None, pri=KEEP, ctl=KEEP, hot=None):
|
|
return {"color": color, "pri": pri, "ctl": ctl, "hot": hot}
|
|
|
|
def look(c):
|
|
return ink(color=c)
|
|
|
|
def wall(c=None):
|
|
return ink(color=c, ctl={"Set": 1})
|
|
|
|
def open_floor():
|
|
return ink(pri="Band", ctl={"Set": 0})
|
|
|
|
def water(c=None):
|
|
return ink(color=c, ctl={"Set": 2})
|
|
|
|
def band_of(y):
|
|
return min(15, y * 16 // 190)
|
|
|
|
def rect(x, y, w, h, i):
|
|
return {"Rect": {"x": x, "y": y, "w": w, "h": h, "ink": i}}
|
|
|
|
def line(pts, i):
|
|
return {"Line": {"pts": pts, "ink": i}}
|
|
|
|
def ellipse(cx, cy, rx, ry, i):
|
|
return {"Ellipse": {"cx": cx, "cy": cy, "rx": rx, "ry": ry, "ink": i}}
|
|
|
|
def poly(pts, i):
|
|
return {"Polygon": {"pts": pts, "ink": i}}
|
|
|
|
def fbm(x, y, w, h, ramp, scale, octaves, seed, i):
|
|
return {"FbmFill": {"x": x, "y": y, "w": w, "h": h, "ramp": ramp, "scale": scale, "octaves": octaves, "seed": seed, "ink": i}}
|
|
|
|
# The standard sim skeleton over a painting: everything above floor_y is
|
|
# scenery (blocked), everything below walks and depth-sorts by row.
|
|
def sim_base(floor_y):
|
|
return [
|
|
rect(0, 0, 320, floor_y, wall()),
|
|
rect(0, floor_y, 320, 190 - floor_y, open_floor()),
|
|
]
|
|
|
|
# Spray letters for the wall (drawn OVER the painting).
|
|
SEGS = {
|
|
"N": [((0, 6), (0, 0)), ((0, 0), (4, 6)), ((4, 6), (4, 0))],
|
|
"O": [((0, 0), (4, 0)), ((4, 0), (4, 6)), ((4, 6), (0, 6)), ((0, 6), (0, 0))],
|
|
"M": [((0, 6), (0, 0)), ((0, 0), (2, 3)), ((2, 3), (4, 0)), ((4, 0), (4, 6))],
|
|
"E": [((4, 0), (0, 0)), ((0, 0), (0, 6)), ((0, 6), (4, 6)), ((0, 3), (3, 3))],
|
|
"A": [((0, 6), (2, 0)), ((2, 0), (4, 6)), ((1, 4), (3, 4))],
|
|
"S": [((4, 0), (0, 1)), ((0, 1), (4, 5)), ((4, 5), (0, 6))],
|
|
"!": [((0, 0), (0, 4)), ((0, 6), (0, 6))],
|
|
}
|
|
|
|
def spray(text, x0, y0, s, color):
|
|
ops = []
|
|
x = x0
|
|
for ch in text:
|
|
if ch == " ":
|
|
x += 3 * s
|
|
continue
|
|
for (a, b) in SEGS.get(ch, []):
|
|
pts = [[x + a[0] * s, y0 + a[1] * s], [x + b[0] * s, y0 + b[1] * s]]
|
|
ops.append(line(pts, look(color)))
|
|
ops.append(line([[p[0] + 1, p[1]] for p in pts], look(color)))
|
|
x += 6 * s
|
|
return ops
|
|
|
|
def hotspot(name, r=None, msgs=None, **kw):
|
|
h = {"name": name}
|
|
if r:
|
|
h["rect"] = r
|
|
if msgs:
|
|
h["msgs"] = msgs
|
|
h.update(kw)
|
|
return h
|
|
|
|
def prop(name, sprite, x, y, **kw):
|
|
p = {"name": name, "sprite": sprite, "x": x, "y": y}
|
|
p.update(kw)
|
|
return p
|
|
|
|
def npc(name, sprite, x, y, **kw):
|
|
n = {"name": name, "sprite": sprite, "x": x, "y": y}
|
|
n.update(kw)
|
|
return n
|
|
|
|
def node(says, *choices):
|
|
return {"says": says, "choices": list(choices)}
|
|
|
|
def choice(text, goto, **kw):
|
|
c = {"text": text, "goto": goto}
|
|
c.update(kw)
|
|
return c
|
|
|
|
|
|
ROOMS = {}
|
|
|
|
# =============================================================================
|
|
# Room 0 — The Basement, Victoria BC, 1979 (pics/basement.png)
|
|
# =============================================================================
|
|
ops = sim_base(118)
|
|
ops.append(rect(0, 118, 84, 44, wall())) # washer + cabinet footprint
|
|
ops.append(rect(240, 118, 80, 24, wall())) # under-stair clutter line
|
|
# The D.O.A. poster is OUR overlay (the painting left that wall bare).
|
|
ops.append(rect(244, 36, 26, 36, wall(gray(14))))
|
|
ops.append(rect(247, 40, 20, 9, wall(cube(4, 0, 0))))
|
|
ops.append(rect(247, 53, 20, 3, wall(gray(3))))
|
|
ops.append(rect(247, 59, 14, 3, wall(gray(3))))
|
|
ops.append(rect(247, 65, 17, 3, wall(gray(3))))
|
|
|
|
ROOMS[0] = {
|
|
"name": "The Basement, 1979",
|
|
"enter_text": "Wood panel, concrete, one bare bulb. John's kit crowds the rug; the 180-pound Portastudio owns the workbench. Through the wall, Mom's washer keeps better time than most drummers.",
|
|
"background": "basement",
|
|
"ops": ops,
|
|
"scale": {"horizon_y": 100, "min_scale": 0.72, "full_y": 186},
|
|
"spawn": [180, 160],
|
|
"exits": [None, 1, 3, None],
|
|
"exit_flags": ["", "", "demo_done", ""],
|
|
"exit_blocked": ["", "", "No demo, no destiny. The Portastudio is right there.", ""],
|
|
"hotspots": [
|
|
hotspot("gig poster", [242, 34, 30, 40], msgs={
|
|
"look": "D.O.A. — TONIGHT — UVic. Vancouver's finest, one ferry away. John already circled it.",
|
|
"do": "You're going. Obviously you're going. (Up the stairs, east.)",
|
|
}),
|
|
hotspot("washer", [0, 84, 84, 76], msgs={
|
|
"look": "Mom's washing machine, mid-cycle. A wet 4/4 that never rushes and never drags.",
|
|
"listen": "Chunk. Chunk. Chunk. Honestly? Tighter than most bands you've seen.",
|
|
"do": "It's Mom's. Some things are sacred.",
|
|
}),
|
|
hotspot("window", [186, 34, 46, 36], msgs={
|
|
"look": "Grey Victoria daylight through glass that hasn't been washed since the Diefenbaker administration.",
|
|
}),
|
|
hotspot("workbench", [116, 88, 82, 28], msgs={
|
|
"look": "The workbench holds the TEAC four-track like an altar holds a relic.",
|
|
}),
|
|
hotspot("stairs", [244, 60, 76, 56], msgs={
|
|
"look": "Up to daylight, dinner, and — tonight — a ferry to a D.O.A. show.",
|
|
}),
|
|
],
|
|
"props": [
|
|
prop("portastudio", "portastudio", 156, 101,
|
|
synonyms="four-track teac tascam recorder deck",
|
|
msgs={
|
|
"look": "The TEAC Portastudio. 180 pounds of overdubbing possibility. It wants tape and it wants a reason.",
|
|
"do": "It powers up with a hum like a small appliance dreaming big.",
|
|
"listen": "Tape hiss. The sound of potential.",
|
|
}),
|
|
prop("castle box", "castlebox", 218, 154,
|
|
synonyms="box junk castle",
|
|
msgs={
|
|
"look": "A box of gear from Castle, the cover band you both did time in. Cables, setlists nobody needs, and — is that a fresh reel of tape?",
|
|
},
|
|
solid=True),
|
|
prop("drum kit", "drumkit", 112, 150,
|
|
synonyms="drums kit",
|
|
msgs={
|
|
"look": "John's kit, tuned like a jazz kit because he IS a jazz kid. The high school band has no idea what it's incubating.",
|
|
"play": "You are a bassist. There are laws.",
|
|
},
|
|
solid=True),
|
|
],
|
|
"npcs": [
|
|
npc("John", "john", 152, 164, portrait="john-face", wander=10,
|
|
msgs={"look": "Your kid brother. Eight years younger, already swings harder than drummers twice his age."},
|
|
dialogue=[
|
|
node("Sticks spin in his fingers. “So? Are we a band, or are we two guys who own instruments?”",
|
|
choice("We need a sound of our own first.", 1),
|
|
choice("Heard D.O.A. play UVic tonight.", 2),
|
|
choice("Later, John.", -1)),
|
|
node("“No guitar player, eh? Fine. You be the guitar. I'll be the horn section.” He plays a bar of 9/8 like it's nothing.",
|
|
choice("That. Exactly that.", -1)),
|
|
node("“Then what are we still doing in the basement? GO. Take notes. Loud ones.”",
|
|
choice("On it.", -1)),
|
|
]),
|
|
npc("Mom", "mom", 98, 146, portrait="mom-face", wander=6,
|
|
msgs={"look": "Mom, running the laundry room like mission control."},
|
|
dialogue=[
|
|
node("“Play all you like, love — the whites are done at eight.” She pauses. “The loud one in 7/4 was nice.”",
|
|
choice("You could tell it was 7/4?", 1),
|
|
choice("Thanks, Mom.", -1)),
|
|
node("“I've been listening to that washer for twenty years, Robert. I know time when I hear it.”",
|
|
choice("...Mom might be the best musician in the house.", -1)),
|
|
]),
|
|
],
|
|
"music": 1,
|
|
"script": "room0.rhai",
|
|
}
|
|
|
|
# =============================================================================
|
|
# Room 1 — D.O.A. at UVic, 1980 (pics/gig.png)
|
|
# =============================================================================
|
|
ops = sim_base(122)
|
|
# Footlight chase across the painted stage lip.
|
|
for i, x in enumerate(range(44, 276, 12)):
|
|
ops.append(rect(x, 118, 8, 3, wall(EMBER[i % 8])))
|
|
|
|
ROOMS[1] = {
|
|
"name": "UVic — D.O.A., 1980",
|
|
"enter_text": "A university hall pretending it's a bunker. D.O.A. detonate on stage. The floor moves like weather.",
|
|
"background": "gig",
|
|
"ops": ops,
|
|
"cycles": [{"start": 248, "len": 8, "period": 2, "reverse": False, "active": True}],
|
|
"scale": {"horizon_y": 118, "min_scale": 0.8, "full_y": 186},
|
|
"spawn": [160, 165],
|
|
"exits": [None, None, 2, 0],
|
|
"hotspots": [
|
|
hotspot("stage", [40, 10, 240, 110], msgs={
|
|
"do": "Security gives you the look that says: no.",
|
|
"listen": "Loud enough to reset your heartbeat to theirs.",
|
|
}),
|
|
hotspot("pit", [80, 130, 160, 50], trigger=True, msgs={
|
|
"look": "The pit. A weather system with elbows.",
|
|
}),
|
|
],
|
|
"props": [
|
|
prop("flyer", "flyer", 294, 170,
|
|
synonyms="handbill paper",
|
|
msgs={"look": "A gig flyer, boot-printed. You'll keep it forever and lie about why."},
|
|
takeable=True),
|
|
],
|
|
"npcs": [
|
|
npc("Joey", "joey", 150, 116, fixed_scale=0.8,
|
|
msgs={
|
|
"look": "Joey Shithead, mid-war-cry. Vancouver hardcore, delivered at terminal velocity.",
|
|
"talk": "He can't hear you. Nobody will hear anything until Thursday.",
|
|
}),
|
|
],
|
|
"music": 3,
|
|
"script": "room1.rhai",
|
|
}
|
|
|
|
# =============================================================================
|
|
# Room 2 — The alley, and the wall (pics/alley.png)
|
|
# =============================================================================
|
|
ops = sim_base(137)
|
|
ops += spray("NO MEANS NO!", 34, 48, 4, gray(15))
|
|
ops += spray("NO MEANS NO!", 35, 49, 4, gray(12))
|
|
ops.append(ellipse(45, 162, 26, 6, water()))
|
|
ops.append(ellipse(250, 160, 22, 5, water()))
|
|
|
|
ROOMS[2] = {
|
|
"name": "The Alley",
|
|
"enter_text": "Behind the venue, rain stitching the puddles. Someone has written three words on the brick, big enough to be a law.",
|
|
"background": "alley",
|
|
"ops": ops,
|
|
"scale": {"horizon_y": 128, "min_scale": 0.8, "full_y": 186},
|
|
"spawn": [160, 165],
|
|
"exits": [None, None, None, 0],
|
|
"hotspots": [
|
|
hotspot("graffiti", [28, 28, 264, 106], msgs={
|
|
"do": "You touch the brick. It's cold. The words stay.",
|
|
}),
|
|
hotspot("puddle", [16, 150, 90, 22], msgs={
|
|
"look": "The words float upside-down in the puddle, still true both ways.",
|
|
}),
|
|
],
|
|
"props": [
|
|
prop("dumpster", "dumpster", 284, 158,
|
|
msgs={
|
|
"look": "A dumpster keeping the alley's secrets. Every scene in every city has this exact dumpster.",
|
|
"smell": "1980 called. It wants nothing back.",
|
|
},
|
|
solid=True),
|
|
],
|
|
"npcs": [],
|
|
"music": 6,
|
|
"weather": 1,
|
|
"script": "room2.rhai",
|
|
}
|
|
|
|
# =============================================================================
|
|
# Room 3 — Alternative Tentacles, San Francisco, 1987 (pics/office.png)
|
|
# =============================================================================
|
|
ops = sim_base(147)
|
|
ops.append(rect(112, 147, 122, 30, wall())) # the desk: walk behind it, not through it
|
|
# Record crates hug the corners but leave the door lanes open.
|
|
ops.append(rect(0, 160, 66, 30, wall())) # record crates, left
|
|
ops.append(rect(258, 168, 62, 22, wall())) # record crates, right (the east door lane stays open)
|
|
|
|
ROOMS[3] = {
|
|
"name": "Alternative Tentacles, 1987",
|
|
"enter_text": "San Francisco. The office smells of newsprint, coffee, and litigation. Every poster on the wall is somebody's whole life.",
|
|
"background": "office",
|
|
"ops": ops,
|
|
"scale": {"horizon_y": 130, "min_scale": 0.8, "full_y": 186},
|
|
"spawn": [88, 183],
|
|
"exits": [None, 4, None, 0],
|
|
"exit_flags": ["", "signed", "", ""],
|
|
"exit_blocked": ["", "Europe doesn't book the unsigned. Talk to Jello.", "", ""],
|
|
"hotspots": [
|
|
hotspot("poster wall", [104, 0, 216, 100], msgs={
|
|
"look": "Dead Kennedys. D.O.A. Butthole Surfers. A wall of bands that never asked permission.",
|
|
"do": "You straighten one thumbtack. History looks marginally tidier.",
|
|
}),
|
|
hotspot("window", [0, 0, 104, 110], msgs={
|
|
"look": "Fog rolling off the bay, gold light on the bridge. Even the weather here has a record deal.",
|
|
}),
|
|
hotspot("record crates", [0, 148, 74, 42], msgs={
|
|
"look": "Crates of vinyl heading to distributors on four continents. The machine, fed.",
|
|
}),
|
|
hotspot("desk", [110, 100, 126, 76], msgs={
|
|
"look": "The desk: contracts, a mountain of cassettes, and a rubber tarantula used as a paperweight.",
|
|
}),
|
|
],
|
|
"props": [],
|
|
"npcs": [
|
|
npc("Jello", "biafra", 214, 184, portrait="biafra-face", wander=8,
|
|
msgs={"look": "Jello Biafra, sorting demos like a heron reads a river."},
|
|
dialogue=[
|
|
node("The Canadians. The brothers. The ones who sound like — what did Trouser Press say — Wire on psychotic steroids?",
|
|
choice("Slip him the demo tape.", 1, requires_flag="demo_done", sets_flag="signed", points=10),
|
|
choice("We're NoMeansNo. And no means no.", 2),
|
|
choice("Just admiring the tarantula.", -1)),
|
|
node("He plays thirty seconds of Sex Mad. Both eyebrows achieve escape velocity. “Licensed. International. Don't shave, don't die, and tour Europe until Europe apologizes.”",
|
|
choice("Deal.", -1)),
|
|
node("“Good name. Better policy.” He gestures at the demo mountain. “Feed the machine, gentlemen.”",
|
|
choice("(Feed it.)", 0)),
|
|
]),
|
|
],
|
|
"music": 4,
|
|
"script": "room3.rhai",
|
|
}
|
|
|
|
# =============================================================================
|
|
# Room 4 — Roskilde main stage, 1994 (pics/roskilde.png)
|
|
# =============================================================================
|
|
ops = []
|
|
ops.append(rect(0, 0, 320, 112, wall()))
|
|
ops.append(rect(0, 110, 320, 6, wall(gray(1))))
|
|
for i, x in enumerate(range(4, 316, 12)):
|
|
ops.append(rect(x, 113, 8, 4, wall(EMBER[i % 8])))
|
|
ops.append(fbm(0, 118, 320, 72, [cube(1, 0, 0), cube(2, 1, 0), cube(1, 0, 0)], 20.0, 2, 54, ink(color=cube(1, 0, 0), pri="Band", ctl={"Set": 0})))
|
|
for y in range(126, 190, 10):
|
|
ops.append(line([[0, y], [319, y]], look(cube(0, 0, 0))))
|
|
ops.append(poly([[70, 122], [96, 122], [88, 132], [78, 132]], ink(color=gray(3), pri={"Set": band_of(132)})))
|
|
ops.append(poly([[200, 122], [226, 122], [218, 132], [208, 132]], ink(color=gray(3), pri={"Set": band_of(132)})))
|
|
|
|
ROOMS[4] = {
|
|
"name": "Roskilde Main Stage, 1994",
|
|
"enter_text": "Denmark. Sixty thousand people breathing as one animal in the dark. Sepultura's van died in Germany, Peter Gabriel just walked off, and somebody has to be next.",
|
|
"background": "roskilde",
|
|
"ops": ops,
|
|
"cycles": [{"start": 248, "len": 8, "period": 2, "reverse": False, "active": True}],
|
|
"scale": {"horizon_y": 112, "min_scale": 0.8, "full_y": 186},
|
|
"spawn": [50, 160],
|
|
"exits": [None, 5, None, 3],
|
|
"exit_flags": ["", "legend", "", ""],
|
|
"exit_blocked": ["", "Not before the encore. Play the show.", "", ""],
|
|
"hotspots": [
|
|
hotspot("crowd", [0, 30, 320, 80], msgs={
|
|
"look": "A field of lighters to the horizon. Sixty thousand Danes who came for Sepultura and stayed for whatever this is about to be.",
|
|
"listen": "The roar arrives in waves, like surf that learned your name.",
|
|
"talk": "You raise one fist. SIXTY THOUSAND PEOPLE RAISE IT BACK.",
|
|
}),
|
|
hotspot("monitors", [66, 118, 164, 18], msgs={
|
|
"look": "Monitor wedges, mixed for a prog band. John will fix that with volume.",
|
|
}),
|
|
],
|
|
"props": [
|
|
prop("the rig", "rig", 276, 148,
|
|
synonyms="amps amp stack backline",
|
|
msgs={"look": "A borrowed backline the size of a rowhouse. Rob's overdrive will make it honest."},
|
|
solid=True),
|
|
],
|
|
"npcs": [
|
|
npc("stage manager", "stagehand", 96, 150, wander=20,
|
|
msgs={"look": "A Danish stage manager with a clipboard and eleven headaches."},
|
|
dialogue=[
|
|
node("Sepultura is IN A DITCH near Flensburg. I have sixty thousand people and a hole in the schedule after Peter Gabriel. You are either legends tonight, or you are filler.",
|
|
choice("We'll take the main stage.", 1, sets_flag="mainstage", points=10),
|
|
choice("We're... technically the tent act.", 2),
|
|
choice("Give us a minute.", -1)),
|
|
node("“Then GO.” He points at the rig with the clipboard. “And whatever a 'jazzcore' is — do it LOUDLY.”",
|
|
choice("Always.", -1)),
|
|
node("“'Were.'” He crosses something out with terrifying finality.",
|
|
choice("(Reconsider.)", 0)),
|
|
]),
|
|
],
|
|
"music": 3,
|
|
"weather": 3,
|
|
"script": "room4.rhai",
|
|
}
|
|
|
|
# =============================================================================
|
|
# Room 5 — A farm field outside Poznan, 1997 (pics/field.png)
|
|
# =============================================================================
|
|
ops = sim_base(112)
|
|
ops.append(rect(0, 124, 52, 10, wall())) # fence line, left
|
|
ops.append(rect(268, 124, 52, 10, wall())) # fence line, right
|
|
ops.append(ellipse(152, 166, 22, 4, water()))
|
|
ops.append(ellipse(176, 180, 18, 4, water()))
|
|
|
|
ROOMS[5] = {
|
|
"name": "A Field Outside Poznan, 1997",
|
|
"enter_text": "Poland. Dawn the color of dishwater. Your van — your entire livelihood with wheels on it — sits in a farm field, and a man in a tracksuit is leaning on it.",
|
|
"background": "field",
|
|
"ops": ops,
|
|
"scale": {"horizon_y": 106, "min_scale": 0.5, "full_y": 186},
|
|
"spawn": [36, 168],
|
|
"exits": [None, None, None, 4],
|
|
"hotspots": [
|
|
hotspot("farmhouse", [66, 88, 48, 22], msgs={
|
|
"look": "A farmhouse minding its own business at a professional level.",
|
|
}),
|
|
hotspot("crows", [120, 20, 180, 60], msgs={
|
|
"look": "Crows, circling like they've been paid to set the tone.",
|
|
"listen": "They have opinions about your situation.",
|
|
}),
|
|
],
|
|
"props": [
|
|
prop("van", "van", 170, 126,
|
|
synonyms="tourvan vehicle",
|
|
msgs={
|
|
"look": "The van. Every amp, every pedal, every unwashed sleeping bag — the whole band, parked in the wrong country.",
|
|
},
|
|
solid=True),
|
|
],
|
|
"npcs": [
|
|
npc("mobster", "mobster", 226, 146, portrait="mobster-face",
|
|
msgs={"look": "Tracksuit, flat cap, and the calm of a man who has never once hurried."},
|
|
dialogue=[
|
|
node("“Nice van,” he says, in better English than yours. “Shame about the neighborhood. Storage fees in this district are… irregular.”",
|
|
choice("Name your price.", 1),
|
|
choice("Do you KNOW who we are?", 2, kills=True),
|
|
choice("We'll come back.", -1)),
|
|
node("“Two and a half thousand. American. The van, the amps, the little drum machine — all of it, untouched.” He pats the van gently, like a horse.",
|
|
choice("Strike the deal.", 3, sets_flag="deal_struck"),
|
|
choice("Outrageous.", -1)),
|
|
node("In a field outside a town you cannot pronounce, it turns out that nobody, in fact, knows who you are.", ),
|
|
node("“Pleasure doing business with professionals.” He steps away from the van and lights a cigarette against the wind, first try.",
|
|
choice("(Get the money.)", -1)),
|
|
]),
|
|
],
|
|
"music": 2,
|
|
"weather": 1,
|
|
"script": "room5.rhai",
|
|
}
|
|
|
|
|
|
def main():
|
|
os.makedirs(OUT, exist_ok=True)
|
|
for n, doc in ROOMS.items():
|
|
path = os.path.join(OUT, f"room{n}.json")
|
|
with open(path, "w") as f:
|
|
json.dump(doc, f, indent=1, ensure_ascii=False)
|
|
print(f" room{n}.json ({len(doc.get('ops', []))} ops)")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|