diff --git a/art/maps/bh-control.svg b/art/maps/bh-control.svg new file mode 100644 index 0000000..c95ea31 --- /dev/null +++ b/art/maps/bh-control.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + MAIN CORRIDOR + + CONTROL ROOM + Controller's floor + 7 + + CONSOLE · DIALS · TANNOY DESK + + + + + + + + + SITUATION MAP · REGION 12 + + + + + + + + SCOPE + SEALED 1974 — by order + + CONTROLLER + E. Sowerby + + DESK + + + + letters from Centre + + STUDIO + broadcast · 1962 + + + + TAPE DECK + + + SAFE + + MIXER + + + MIC + new tape rec'd from Centre 2019 + + PIPE ROOM + Centre's in-tray + 11 + + PIPE + + IN-TRAY + every 90 days + + COMMS + teleprinters · switchboard + + TP + + TP + + SWITCHBOARD + + + no line out + + + + + + + + + + + + + + + KEY + + + DOOR + + 7 + LOCATION No. + pencil + = AMENDED AT THE SEAT, 1974–2026 + + = UNLINED MINE WORKINGS + 1 SQUARE = 5 FT · N ↑ + + + + + REGIONAL SEAT OF GOVERNMENT 12 · BELLHOUSE + SHEET 2 OF 7 · LEVEL 2 · GOVERNMENT + CONTROL ROOM + SCALE: ONE SQUARE = 5 FT + DRG RSG12/02 · ISSUED 1962 · COPY NOT TO LEAVE THE SEAT + diff --git a/art/maps/bh-control.webp b/art/maps/bh-control.webp new file mode 100644 index 0000000..9879017 Binary files /dev/null and b/art/maps/bh-control.webp differ diff --git a/art/maps/bh-creche.svg b/art/maps/bh-creche.svg new file mode 100644 index 0000000..26a9a19 --- /dev/null +++ b/art/maps/bh-creche.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + WELFARE CORRIDOR + + CLOAKS + + + + + + + STAFF + K. Marlow + + + + DESK + + SCHOOLROOM + 10 + + BLACKBOARD + + TEACHER + + + + + + + + + + + + + atlas: 1971 edition + + PLAYROOM + + pinned drawings along this wall + + RUG + + + + + + TOYS + + DORMITORY + under-twelves + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + speaker fitted 2019 — 03:00 nightly + + WASHROOM + + + + + + + BATHS + + + + + + + + + + + + + + + + + KEY + + + DOOR + + 7 + LOCATION No. + pencil + = AMENDED AT THE SEAT, 1974–2026 + + = UNLINED MINE WORKINGS + 1 SQUARE = 5 FT · N ↑ + + + + + REGIONAL SEAT OF GOVERNMENT 12 · BELLHOUSE + SHEET 5 OF 7 · LEVEL 3 · WELFARE + CRECHE & SCHOOL + SCALE: ONE SQUARE = 5 FT + DRG RSG12/05 · ISSUED 1962 · COPY NOT TO LEAVE THE SEAT + diff --git a/art/maps/bh-creche.webp b/art/maps/bh-creche.webp new file mode 100644 index 0000000..5b6ad64 Binary files /dev/null and b/art/maps/bh-creche.webp differ diff --git a/art/maps/bh-lobby.svg b/art/maps/bh-lobby.svg new file mode 100644 index 0000000..c058b7d --- /dev/null +++ b/art/maps/bh-lobby.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + FROM ADIT (SEALED 1975) + + BLAST LOCK + outer lock + + + + air goes wrong here + + DECONTAM. + showers · lockers + + + + + + + LOBBY + public waiting + 6 + + ENQUIRIES COUNTER + + + + + + + + + + + + + + + NOTICEBOARD + housing list — see Mr Ogden + + ENQUIRIES + Mr Ogden + + DESK + + + + + ☎ + + INTERVIEW + the door does not lock + + TABLE + + + + + + WARDENS' POST + + + truncheon rack + + MAIN + CORRIDOR + + + + + + + + + + + + + + + + KEY + + + DOOR + + 7 + LOCATION No. + pencil + = AMENDED AT THE SEAT, 1974–2026 + + = UNLINED MINE WORKINGS + 1 SQUARE = 5 FT · N ↑ + + + + + REGIONAL SEAT OF GOVERNMENT 12 · BELLHOUSE + SHEET 1 OF 7 · LEVEL 1 · ENTRY + LOBBY & ENQUIRIES + SCALE: ONE SQUARE = 5 FT + DRG RSG12/01 · ISSUED 1962 · COPY NOT TO LEAVE THE SEAT + diff --git a/art/maps/bh-lobby.webp b/art/maps/bh-lobby.webp new file mode 100644 index 0000000..da5163f Binary files /dev/null and b/art/maps/bh-lobby.webp differ diff --git a/art/maps/bh-registry.svg b/art/maps/bh-registry.svg new file mode 100644 index 0000000..3a714bd --- /dev/null +++ b/art/maps/bh-registry.svg @@ -0,0 +1,127 @@ + + + + + + + + + + + + MAIN CORRIDOR + + PUBLIC COUNTER + 8 + + COUNTER + + + + + + TAKE A NUMBER + complaints: allow 11 weeks + + RECORDS + + + + + + + + + + + + + + + BIRTHS · DEATHS · HOUSING · RATIONS · 1974– + + REGISTRAR + A. Pennyfeather + + DESK + + + STRONGROOM + standing orders + + + SAFE + + + + + + TYPING POOL + + + + + + + + + + + + + + + + + + + + + + KEY + + + DOOR + + 7 + LOCATION No. + pencil + = AMENDED AT THE SEAT, 1974–2026 + + = UNLINED MINE WORKINGS + 1 SQUARE = 5 FT · N ↑ + + + + + REGIONAL SEAT OF GOVERNMENT 12 · BELLHOUSE + SHEET 3 OF 7 · LEVEL 2 · GOVERNMENT + REGISTRY + SCALE: ONE SQUARE = 5 FT + DRG RSG12/03 · ISSUED 1962 · COPY NOT TO LEAVE THE SEAT + diff --git a/art/maps/bh-registry.webp b/art/maps/bh-registry.webp new file mode 100644 index 0000000..d6dadb8 Binary files /dev/null and b/art/maps/bh-registry.webp differ diff --git a/art/maps/bh-sickbay.svg b/art/maps/bh-sickbay.svg new file mode 100644 index 0000000..12b1f65 --- /dev/null +++ b/art/maps/bh-sickbay.svg @@ -0,0 +1,175 @@ + + + + + + + + + + + + WELFARE CORRIDOR + + RECEPTION + 9 + + DESK + + + + + + GENERAL WARD + eighteen beds + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SIDE ROOM + Mrs Marlow + + + + + + + DISPENSARY + + + + MEDICAL OFFICER + Dr Larkhall + + DESK + + + + + DELIVERY + maternity + + + + COT + Cotter — due Thurs + + THEATRE + + TABLE + + + + + ISOLATION + + + + + + + unused since '78 + + + + + + + + + + + + + + + + + + + + + + + + + KEY + + + DOOR + + 7 + LOCATION No. + pencil + = AMENDED AT THE SEAT, 1974–2026 + + = UNLINED MINE WORKINGS + 1 SQUARE = 5 FT · N ↑ + + + + + REGIONAL SEAT OF GOVERNMENT 12 · BELLHOUSE + SHEET 4 OF 7 · LEVEL 3 · WELFARE + SICK BAY + SCALE: ONE SQUARE = 5 FT + DRG RSG12/04 · ISSUED 1962 · COPY NOT TO LEAVE THE SEAT + diff --git a/art/maps/bh-sickbay.webp b/art/maps/bh-sickbay.webp new file mode 100644 index 0000000..d7d1385 Binary files /dev/null and b/art/maps/bh-sickbay.webp differ diff --git a/art/maps/bh-sump.svg b/art/maps/bh-sump.svg new file mode 100644 index 0000000..6189942 --- /dev/null +++ b/art/maps/bh-sump.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + No.2 COAL ROAD + growing beds under lamps + 14 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + workings beyond: not surveyed + + + + No.3 COAL ROAD + trout tanks + + TANK + + TANK + + TANK + + TANK + + HEN RUN + + + + + + + eggs → Welfare, Tues/Fri + + + SUMP STAIR + + THE SUMP + 15 + + + + + CELL 1 + + + + + CELL 2 + + + + + CELL 3 + + + + + CELL 4 + + + + + + WARDEN + locks: 1962 pattern — oil them + + + + + + + + + + ← to Welfare stair + + + KEY + + + DOOR + + 7 + LOCATION No. + pencil + = AMENDED AT THE SEAT, 1974–2026 + + = UNLINED MINE WORKINGS + 1 SQUARE = 5 FT · N ↑ + + + + + REGIONAL SEAT OF GOVERNMENT 12 · BELLHOUSE + SHEET 7 OF 7 · LEVEL 4 · WORKINGS + TUNNELS & SUMP + SCALE: ONE SQUARE = 5 FT + DRG RSG12/07 · ISSUED 1962 · COPY NOT TO LEAVE THE SEAT + diff --git a/art/maps/bh-sump.webp b/art/maps/bh-sump.webp new file mode 100644 index 0000000..1cf649d Binary files /dev/null and b/art/maps/bh-sump.webp differ diff --git a/art/maps/bh-vigil.svg b/art/maps/bh-vigil.svg new file mode 100644 index 0000000..24948b1 --- /dev/null +++ b/art/maps/bh-vigil.svg @@ -0,0 +1,273 @@ + + + + + + + + + + + + VIGIL HALL + 13 + + PLATFORM + + lectern + + ROLL OF HONOUR + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 999 seats — add one + + CORR. + + PLANT FLOOR + 12 + + COAL BOILER + + GEN 1 + + GEN 2 + + DUCTING + + PUMPS + + FILTERS + coal from No.2 road + + TRANSMITTER + feed to mast + + + valve racks + + PANEL + + MAST CABLE ↑ MOOR + + + + + + + + + + + + + KEY + + + DOOR + + 7 + LOCATION No. + pencil + = AMENDED AT THE SEAT, 1974–2026 + + = UNLINED MINE WORKINGS + 1 SQUARE = 5 FT · N ↑ + + + + + REGIONAL SEAT OF GOVERNMENT 12 · BELLHOUSE + SHEET 6 OF 7 · LEVEL 3 · ASSEMBLY + VIGIL HALL & PLANT + SCALE: ONE SQUARE = 5 FT + DRG RSG12/06 · ISSUED 1962 · COPY NOT TO LEAVE THE SEAT + diff --git a/art/maps/bh-vigil.webp b/art/maps/bh-vigil.webp new file mode 100644 index 0000000..929825f Binary files /dev/null and b/art/maps/bh-vigil.webp differ diff --git a/docs/scenarios/STANDING_ORDER.md b/docs/scenarios/STANDING_ORDER.md index fdfa23f..6a58a6c 100644 --- a/docs/scenarios/STANDING_ORDER.md +++ b/docs/scenarios/STANDING_ORDER.md @@ -609,8 +609,35 @@ is much harder at four**, and the table above says how much. ## Locations — quick reference -| # | Location | Act | One line | -|---|---|---|---| +**The underground is seven blueprint scenes** in the Adventure, one sheet each, drawn as +the 1962 drawing office issued them with fifty years of pencil amendments. They are +2800×2000 at five feet to the square, so tokens and the Foundry grid line up. **Nothing on +a sheet gives away a GM secret**; the pencil notes are what the people below wrote. +The section drawing (SO-H04) is the overview. + +| # | Location | Act | Blueprint scene | One line | +|---|---|---|---|---| +| 1 | Wetherlaw farm | 1 | — | Coal soot, and Joan with a brush | +| 2 | The soot edge | 1 | — | A straight line of soot across the fields | +| 3 | The vent | 1 | — | Warm, smells of coal; the crossing | +| 4 | The postal pipe | 1/2 | — | How Centre's letters arrive | +| 5 | The adit | 1 | — | Filled with rubble in 1975 | +| 6 | Lobby and Enquiries | 1 | **Sheet 1** | Mr Ogden; the crossing lands in the blast lock | +| 7 | Control Room and studio | 2/3 | **Sheet 2** | Sowerby, the letters, the safe, the tape | +| 8 | Registry | 2 | **Sheet 3** | Pennyfeather and the Order, in the strongroom | +| 9 | Sick bay | 2/3 | **Sheet 4** | Marlow's side room, Larkhall's office, the delivery room | +| 10 | Crèche | 2/3 | **Sheet 5** | Kit, Nell, the drawings, the dormitory speaker | +| 11 | Pipe room | 2 | **Sheet 2** | Centre's in-tray | +| 12 | Plant floor | 3 | **Sheet 6** | The transmitter room — the mast route | +| 13 | Vigil hall | 2/3 | **Sheet 6** | The chant; Thursday's assembly | +| 14 | The vegetable tunnels | 2 | **Sheet 7** | Lamps, beds, trout tanks, hens — the run route | +| 15 | The Sump | 2 | **Sheet 7** | Four cells; the detention ends here | + +**Which sheet when:** Sheet 1 for Act One's arrival and interview; Sheets 7 and 1–3 for the +detention, wherever the guards catch them; Sheet 2 for getting the tape; Sheet 5 for the +cure; Sheet 6 for the broadcast. + +---|---|---|---| | 1 | Wetherlaw farm | 1 | Coal soot, and Joan with a brush | | 2 | The soot edge | 1 | A straight line of soot across the fields | | 3 | The vent | 1 | Warm, smells of coal; the crossing | diff --git a/docs/scenarios/STANDING_ORDER_ART.md b/docs/scenarios/STANDING_ORDER_ART.md index f338f3b..60ecc8c 100644 --- a/docs/scenarios/STANDING_ORDER_ART.md +++ b/docs/scenarios/STANDING_ORDER_ART.md @@ -14,6 +14,11 @@ and the **quarantine unit** — are bestiary entries and their prompts live in the art; only the uses below changed. **Mr Smith must never be drawn** — a face is the one thing the case says nobody can recall — and no prompt for him belongs in this sheet. +**v1.1 added seven blueprint scenes** of the underground, `art/maps/bh-*.webp`. They are +drawn, not generated, by `tools/bellhouse-plans.mjs` (white line on blueprint blue, Courier +lettering, pencil amendments in yellow); edit the script and run it with `--render`. No +prompt belongs here for them. + --- ## Art direction for this scenario diff --git a/packs/standingorder/000003.log b/packs/standingorder/000003.log index c25efb8..5bf1397 100644 Binary files a/packs/standingorder/000003.log and b/packs/standingorder/000003.log differ diff --git a/tools/bellhouse-plans.mjs b/tools/bellhouse-plans.mjs new file mode 100644 index 0000000..b161914 --- /dev/null +++ b/tools/bellhouse-plans.mjs @@ -0,0 +1,428 @@ +/** + * STANDING ORDER — the Bellhouse blueprints: seven floor plans of the Seat, one per + * Foundry scene. + * + * Drawn from declared rooms rather than generated, for culland-hall.svg's reason: a room, + * a door and a label are load-bearing, and a generator cannot be trusted with any of them. + * Every plan is 2800x2000 at 100px to the square (5 ft), so the Foundry grid lands on the + * drawn one. Labels are what a 1962 drawing office would have written, plus the pencil + * amendments of fifty years below; nothing on a plan tells the players a GM secret. + * + * node tools/bellhouse-plans.mjs write art/maps/bh-*.svg + * node tools/bellhouse-plans.mjs --render and render each to .webp (rsvg-convert, cwebp) + */ +import { writeFileSync } from "node:fs"; +import { execFileSync } from "node:child_process"; +import path from "node:path"; + +const ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), ".."); +const OUT = path.join(ROOT, "art", "maps"); +const S = 100, W = 28, H = 20; + +const esc = s => String(s).replace(/&/g, "&").replace(//g, ">"); +const p = n => +(n * S).toFixed(1); + +/* ---------------------------------------------------------------- primitives */ + +function sheet() { + const g = []; + const api = { + g, + room(x, y, w, h, label, { sub, n, cls = "rm", lx = 0.3, ly = 0.75 } = {}) { + g.push(``); + if (label) g.push(`${esc(label)}`); + if (sub) g.push(`${esc(sub)}`); + if (n != null) { + g.push(`` + + `${n}`); + } + }, + /* A door on a wall: `v` for a vertical wall at x, else horizontal at y. A gap in the + wall and a quarter-circle swing, the way a drawing office draws one. */ + door(x, y, v, len = 1, flip = false) { + const L = p(len), X = p(x), Y = p(y), d = flip ? -1 : 1; + if (v) { + g.push(``, + ``); + } else { + g.push(``, + ``); + } + }, + /* An open archway: just the gap. */ + arch(x, y, v, len = 2, cls = "gap") { + const X = p(x), Y = p(y), L = p(len); + g.push(v ? `` + : ``); + }, + box(x, y, w, h, label, size = 20) { + g.push(``); + if (label) g.push(`${esc(label)}`); + }, + chair(x, y) { g.push(``); }, + bed(x, y, vert = true, w = 0.9, l = 2) { + const [bw, bh] = vert ? [w, l] : [l, w]; + g.push(``); + g.push(vert ? `` + : ``); + }, + shelf(x, y, w, h) { + g.push(``); + const lines = []; + if (w >= h) for (let i = x + 0.25; i < x + w; i += 0.25) lines.push(`M${p(i)} ${p(y)}V${p(y + h)}`); + else for (let j = y + 0.25; j < y + h; j += 0.25) lines.push(`M${p(x)} ${p(j)}H${p(x + w)}`); + g.push(``); + }, + reels(x, y, label = "TAPE") { + g.push(``, + ``, + ``, + `${esc(label)}`); + }, + safe(x, y) { + g.push(``, + ``, + `SAFE`); + }, + speaker(x, y) { + g.push(``, + ``); + }, + round(x, y, r, label) { + g.push(``); + if (label) g.push(`${esc(label)}`); + }, + stairs(x, y, w, h, label = "STAIR") { + g.push(``); + const d = []; + for (let j = y + 0.3; j < y + h; j += 0.3) d.push(`M${p(x)} ${p(j)}H${p(x + w)}`); + g.push(``, + `${esc(label)}`); + }, + blast(x, y, h) { + g.push(``); + const d = []; + for (let j = y; j < y + h; j += 0.2) d.push(`M${p(x) - 22} ${p(j) + 20}l44 -20`); + g.push(``); + }, + /* The drawing office's own lettering, outside a room. */ + text(x, y, t, cls = "sub", extra = "") { + g.push(`${esc(t)}`); + }, + /* Pencil: fifty years of amendments in a different hand. */ + pencil(x, y, t, rot = -2) { + g.push(`${esc(t)}`); + }, + arrow(x1, y1, x2, y2) { + g.push(``); + }, + raw(s) { g.push(s); } + }; + return api; +} + +const STYLE = ` + .rm { fill:#154a8a; stroke:#e8f1fb; stroke-width:7; } + .rm2 { fill:#11417d; stroke:#e8f1fb; stroke-width:5; } + .rock { fill:#0e3668; stroke:#9fbde0; stroke-width:4; stroke-dasharray:18 10; } + .gap { stroke:#154a8a; stroke-width:12; } + .rgap { stroke:#0e3668; stroke-width:12; } + .swing { fill:none; stroke:#e8f1fb; stroke-width:3; } + .fur { fill:#1b579c; stroke:#cfe0f3; stroke-width:3; } + .fine { fill:none; stroke:#cfe0f3; stroke-width:2; } + .blast { fill:#0a2f5c; stroke:#e8f1fb; stroke-width:4; } + .arw { stroke:#e8f1fb; stroke-width:4; } + .grid { stroke:#2a5d9c; stroke-width:1; } + .numc { fill:#e8f1fb; } + .num { font-family:'Courier New',Courier,monospace; font-weight:700; font-size:36px; + fill:#123f78; text-anchor:middle; } + .lbl { font-family:'Courier New',Courier,monospace; font-weight:700; font-size:30px; + fill:#f4f8fd; letter-spacing:2px; } + .sub { font-family:'Courier New',Courier,monospace; font-size:21px; fill:#b9d0ea; } + .fl { font-family:'Courier New',Courier,monospace; font-size:18px; fill:#e8f1fb; + text-anchor:middle; } + .ttl { font-family:'Courier New',Courier,monospace; font-weight:700; font-size:34px; + fill:#f4f8fd; letter-spacing:3px; } + .tb { font-family:'Courier New',Courier,monospace; font-size:20px; fill:#dbe8f6; } + .pen { font-family:'Bradley Hand','Noteworthy','Marker Felt',cursive; font-size:27px; + fill:#ffe98a; } +`; + +function render(no, title, level, draw, { legend = [1, 15.6] } = {}) { + const s = sheet(); + draw(s); + + const grid = []; + for (let i = 1; i < W; i++) grid.push(`M${i * S} 0V${H * S}`); + for (let j = 1; j < H; j++) grid.push(`M0 ${j * S}H${W * S}`); + + // Title block, bottom right, as a drawing office would box it. + const tb = [19, 16.5, 8.7, 3.3]; + const [tx, ty, tw, th] = tb.map(p); + const block = ` + + + + REGIONAL SEAT OF GOVERNMENT 12 · BELLHOUSE + SHEET ${no} OF 7 · ${esc(level)} + ${esc(title)} + SCALE: ONE SQUARE = 5 FT + DRG RSG12/${String(no).padStart(2, "0")} · ISSUED 1962 · COPY NOT TO LEAVE THE SEAT`; + + // Legend, bottom left. + const [lx, ly] = legend.map(p); + const key = ` + + KEY + + + DOOR + + 7 + LOCATION No. + pencil + = AMENDED AT THE SEAT, 1974–2026 + + = UNLINED MINE WORKINGS + 1 SQUARE = 5 FT · N ↑`; + + return ` + + + + + + + + + + ${s.g.join("\n ")} + ${key} + ${block} + +`; +} + +/* ---------------------------------------------------------------- the sheets */ + +export const PLANS = [ + +{ key: "bh-lobby", no: 1, title: "LOBBY & ENQUIRIES", level: "LEVEL 1 · ENTRY", draw: s => { + s.text(0.3, 0.6, "FROM ADIT (SEALED 1975)"); + s.room(1, 6, 4, 6, "BLAST LOCK", { sub: "outer lock" }); + s.blast(1, 8, 2); + s.raw(``); + s.pencil(1.6, 11.6, "air goes wrong here", -3); + s.room(5, 6, 4, 6, "DECONTAM.", { sub: "showers · lockers" }); + for (const y of [8, 9.3, 10.6]) s.round(6, y, 0.3); + s.shelf(7.9, 7.4, 0.8, 4.2); + s.room(9, 3, 10, 12, "LOBBY", { n: 6, sub: "public waiting" }); + s.box(14.5, 5.2, 3.8, 0.8, "ENQUIRIES COUNTER"); + s.box(17.5, 6, 0.8, 2.4); + for (const x of [10, 11, 12]) for (const y of [9, 11, 13]) { s.chair(x, y); } + s.box(9.8, 8.4, 2.9, 0.4); s.box(9.8, 10.4, 2.9, 0.4); s.box(9.8, 12.4, 2.9, 0.4); + s.box(15, 14.4, 3.6, 0.35, "NOTICEBOARD", 14); + s.pencil(14.6, 13.9, "housing list — see Mr Ogden", -1); + s.room(19, 3, 5, 5, "ENQUIRIES", { sub: "Mr Ogden" }); + s.box(20, 4.6, 2, 1, "DESK"); s.chair(21, 5.8); s.shelf(23.1, 3.6, 0.7, 3.6); + s.round(20.3, 7.2, 0.25, "☎"); + s.room(19, 8, 5, 4, "INTERVIEW", { sub: "the door does not lock" }); + s.box(20.4, 9.8, 2.2, 1.1, "TABLE"); + s.chair(20.6, 9.3); s.chair(21.8, 9.3); s.chair(20.6, 11); s.chair(21.8, 11); + s.room(19, 12, 5, 3, "WARDENS' POST"); + s.shelf(19.4, 13.4, 2.5, 0.5); s.text(19.4, 14.6, "truncheon rack", "sub"); + s.room(12, 0, 3, 3, null, { cls: "rm2" }); s.text(12.2, 1.3, "MAIN", "lbl"); s.text(12.2, 1.9, "CORRIDOR", "sub"); + s.arrow(13.5, 2.6, 13.5, 0.3); + s.door(5, 8.5, true, 1); s.door(9, 8.5, true, 1); + s.door(19, 4.8, true, 1, true); s.door(19, 9.2, true, 1, true); s.door(19, 13, true, 1, true); + s.arch(12.5, 3, false, 2); + s.arrow(0.5, 0.9, 0.5, 5.5); +}}, + +{ key: "bh-control", no: 2, title: "CONTROL ROOM", level: "LEVEL 2 · GOVERNMENT", draw: s => { + s.room(0.5, 1, 27, 2, "MAIN CORRIDOR", { cls: "rm2", ly: 1.25 }); + s.room(1, 4, 12, 9, "CONTROL ROOM", { n: 7, sub: "Controller's floor" }); + s.box(1.8, 5.5, 10.4, 0.9, "CONSOLE · DIALS · TANNOY DESK"); + for (let x = 2.5; x < 12; x += 1.4) s.chair(x, 6.6); + s.box(3.5, 8, 6, 2.6, "SITUATION MAP · REGION 12", 20); + for (const [x, y] of [[3.8, 7.4], [5.6, 7.4], [7.4, 7.4], [3.8, 10.8], [5.6, 10.8], [7.4, 10.8]]) s.chair(x, y); + s.round(11.4, 11.4, 0.55, "SCOPE"); + s.pencil(9.8, 12.6, "SEALED 1974 — by order", -2); + s.room(14, 4, 6, 5, "CONTROLLER", { sub: "E. Sowerby" }); + s.box(15.2, 5.8, 2.4, 1.1, "DESK"); s.chair(16.1, 7.1); + s.shelf(19.1, 4.6, 0.7, 3.8); s.text(17.4, 8.7, "letters from Centre", "sub"); + s.room(14, 9, 6, 6, "STUDIO", { sub: "broadcast · 1962" }); + s.reels(14.6, 10.6, "TAPE DECK"); + s.safe(18.6, 10.2); + s.box(15, 12.6, 2.6, 0.9, "MIXER"); s.chair(15.9, 13.7); + s.round(18.8, 13.6, 0.3, "MIC"); + s.pencil(14.3, 14.7, "new tape rec'd from Centre 2019", -1); + s.room(21, 4, 6, 5, "PIPE ROOM", { n: 11, sub: "Centre's in-tray" }); + s.round(24, 6.6, 0.55, "PIPE"); + s.box(21.5, 6.1, 1.8, 0.8, "IN-TRAY"); + s.pencil(21.4, 8.7, "every 90 days", -2); + s.room(21, 9, 6, 6, "COMMS", { sub: "teleprinters · switchboard" }); + s.box(21.6, 10.8, 1.3, 1, "TP"); s.box(23.2, 10.8, 1.3, 1, "TP"); + s.box(21.6, 12.6, 4.8, 0.9, "SWITCHBOARD"); s.chair(22.3, 13.8); s.chair(24.3, 13.8); + s.pencil(24.6, 10.6, "no line out", 4); + s.door(3, 4, false, 1, true); s.door(16, 4, false, 1, true); s.door(23, 4, false, 1, true); + s.door(14, 11, true, 1, true); s.door(14.8, 9, false, 1, true); s.door(23.5, 9, false, 1, true); +}}, + +{ key: "bh-registry", no: 3, title: "REGISTRY", level: "LEVEL 2 · GOVERNMENT", draw: s => { + s.room(0.5, 1, 27, 2, "MAIN CORRIDOR", { cls: "rm2", ly: 1.25 }); + s.room(1, 4, 9, 7, "PUBLIC COUNTER", { n: 8 }); + s.box(1, 7.4, 6.5, 0.7, "COUNTER"); + for (const x of [2, 3.5, 5, 6.5]) s.chair(x, 5.6); + s.box(5.4, 4.3, 2, 0.45, "TAKE A NUMBER", 13); + s.pencil(1.4, 10.6, "complaints: allow 11 weeks", -2); + s.room(10, 4, 12, 11, "RECORDS"); + for (let x = 11; x < 21.5; x += 1.5) s.shelf(x, 5.6, 0.6, 7.6); + s.text(10.4, 14.5, "BIRTHS · DEATHS · HOUSING · RATIONS · 1974–", "sub"); + s.room(22, 4, 5, 5, "REGISTRAR", { sub: "A. Pennyfeather" }); + s.box(23, 5.8, 2.2, 1, "DESK"); s.chair(23.8, 7.1); + s.room(22, 9, 5, 6, "STRONGROOM", { sub: "standing orders" }); + s.safe(25.6, 9.9); s.shelf(22.5, 11.2, 3.8, 0.7); s.shelf(22.5, 13.3, 3.8, 0.7); + s.room(1, 11, 9, 4, "TYPING POOL"); + for (const x of [1.8, 4.3, 6.8]) { s.box(x, 12.3, 1.8, 0.8); s.chair(x + 0.7, 13.4); } + s.door(3.6, 4, false, 1, true); s.door(24, 4, false, 1, true); + s.door(10, 5.2, true, 1, true); s.door(22, 6, true, 1, true); s.door(24.8, 9, false, 0.9, true); + s.arch(8, 7.4, true, 0.7); + s.door(4, 11, false, 1); +}}, + +{ key: "bh-sickbay", no: 4, title: "SICK BAY", level: "LEVEL 3 · WELFARE", draw: s => { + s.room(0.5, 1, 27, 2, "WELFARE CORRIDOR", { cls: "rm2", ly: 1.25 }); + s.room(1, 4, 6, 5, "RECEPTION", { n: 9 }); + s.box(1.6, 5.7, 3, 0.7, "DESK"); + for (const x of [1.6, 2.6, 3.6, 4.6]) s.chair(x, 7.1); + s.room(7, 4, 12, 6, "GENERAL WARD", { sub: "eighteen beds" }); + for (let x = 7.5; x < 17; x += 1.1) { s.bed(x, 5.2); s.bed(x, 7.9, true, 0.9, 1.9); } + s.room(19, 4, 4, 3, "SIDE ROOM", { sub: "Mrs Marlow" }); + s.bed(21.8, 4.3, true, 0.9, 1.8); s.chair(21, 5.4); s.shelf(19.3, 6.2, 1.6, 0.5); + s.room(23, 4, 4, 3, "DISPENSARY"); + s.shelf(23.3, 5.5, 3.4, 0.6); + s.room(19, 7, 8, 3, "MEDICAL OFFICER", { sub: "Dr Larkhall" }); + s.box(23, 8.2, 2, 1, "DESK"); s.shelf(26.1, 7.3, 0.6, 2.4); s.chair(23.7, 9.3); + s.room(7, 10, 7, 5, "DELIVERY", { sub: "maternity" }); + s.bed(10, 11.8, false, 1, 2.2); s.round(12.9, 12.4, 0.35, "COT"); + s.pencil(7.4, 14.6, "Cotter — due Thurs", -2); + s.room(14, 10, 6, 5, "THEATRE"); + s.box(15.8, 11.6, 2.4, 1, "TABLE"); s.round(18.9, 11, 0.4); s.shelf(14.3, 14, 3, 0.6); + s.room(1, 9, 6, 6, "ISOLATION"); + s.room(1, 11, 3, 4, null); s.room(4, 11, 3, 4, null); + s.bed(1.8, 12.4); s.bed(4.8, 12.4); + s.pencil(1.3, 10.6, "unused since '78", -1); + s.door(3.5, 4, false, 1, true); s.door(24.5, 4, false, 1, true); + s.door(7, 6, true, 1, true); s.door(19, 5, true, 1, true); s.door(19, 8.2, true, 1, true); + s.door(10, 10, false, 1); s.door(16.2, 10, false, 1); + s.door(3.2, 9, false, 1, true); s.door(2.5, 11, false, 0.8); s.door(5.2, 11, false, 0.8); + s.door(21.2, 7, false, 0.8, true); +}}, + +{ key: "bh-creche", no: 5, title: "CRECHE & SCHOOL", level: "LEVEL 3 · WELFARE", draw: s => { + s.room(0.5, 1, 27, 2, "WELFARE CORRIDOR", { cls: "rm2", ly: 1.25 }); + s.room(1, 4, 5, 4, "CLOAKS"); + for (let y = 5.3; y < 7.8; y += 0.5) s.raw(``); + s.room(1, 8, 5, 5, "STAFF", { sub: "K. Marlow" }); + s.bed(1.5, 10.2); s.box(3.4, 9.6, 1.8, 0.8, "DESK"); + s.room(6, 4, 10, 7, "SCHOOLROOM", { n: 10 }); + s.box(7, 5.2, 5, 0.25, "", 12); s.text(7, 5.9, "BLACKBOARD", "sub"); + s.box(12.8, 5.6, 2, 0.9, "TEACHER"); + for (let x = 7; x < 15; x += 2) for (let y = 6.9; y < 10; y += 1.2) { s.box(x, y, 1.3, 0.6); } + s.pencil(12.4, 10.7, "atlas: 1971 edition", -2); + s.room(16, 4, 11, 7, "PLAYROOM"); + s.raw(``); + s.text(16.3, 5.4, "pinned drawings along this wall", "sub"); + s.box(18, 6.6, 4, 2.6, "RUG", 20); + for (const [x, y] of [[23.5, 7], [25.4, 6.4], [24.6, 8.8], [17.2, 9.9]]) s.round(x, y, 0.35); + s.box(25.3, 9.6, 1.4, 1.1, "TOYS", 16); + s.room(6, 11, 14, 5, "DORMITORY", { sub: "under-twelves" }); + for (let x = 6.6; x < 19.5; x += 0.95) { s.bed(x, 12.3, true, 0.7, 1.3); s.bed(x, 14.3, true, 0.7, 1.3); } + s.speaker(13, 11.35); + s.pencil(13.8, 11.95, "speaker fitted 2019 — 03:00 nightly", -1); + s.room(20, 11, 7, 5, "WASHROOM"); + for (let x = 21.8; x < 26.8; x += 1.2) s.round(x, 12.9, 0.3); + s.box(21, 14, 5, 0.8, "BATHS"); + s.door(3, 4, false, 1, true); s.door(6, 5, true, 1); s.door(16, 6.4, true, 1); + s.door(10.4, 11, false, 1); s.door(2.8, 8, false, 1); s.door(6, 11.6, true, 1, true); + s.door(20, 13, true, 1); +}, legend: [0.3, 16.1] }, + +{ key: "bh-vigil", no: 6, title: "VIGIL HALL & PLANT", level: "LEVEL 3 · ASSEMBLY", draw: s => { + s.room(1, 1, 14, 13, "VIGIL HALL", { n: 13, ly: 12.5 }); + s.box(3, 1.5, 10, 1.8, "PLATFORM", 22); + s.box(7.6, 3.4, 0.8, 0.5, "", 12); s.text(8.6, 3.9, "lectern", "sub"); + s.box(3.5, 1.1, 5, 0.3, "", 10); + s.text(9, 1.35, "ROLL OF HONOUR", "sub"); + for (let y = 4.8; y < 11.5; y += 0.8) for (let x = 2; x < 12.8; x += 0.55) { + if (x > 7.4 && x < 8.3) continue; + s.raw(``); + } + s.speaker(1.5, 4.5); s.speaker(1.5, 10); + s.pencil(9.6, 12.4, "999 seats — add one", -2); + s.room(15, 1, 2, 18, null, { cls: "rm2" }); + s.text(15.3, 17.4, "CORR.", "sub"); + s.room(17, 1, 10, 9, "PLANT FLOOR", { n: 12 }); + s.box(17.8, 2.4, 3.4, 2.6, "COAL BOILER"); + s.box(22, 2.4, 2.2, 2, "GEN 1"); s.box(24.6, 2.4, 2.2, 2, "GEN 2"); + s.box(17.8, 6.2, 8.6, 0.6, "DUCTING"); + s.box(17.8, 7.6, 2.4, 1.6, "PUMPS"); s.box(21, 7.6, 2.4, 1.6, "FILTERS"); + s.pencil(23.6, 8.8, "coal from No.2 road", -2); + s.room(17, 10, 10, 5.5, "TRANSMITTER", { sub: "feed to mast" }); + s.shelf(18, 11.8, 5, 0.9); s.text(18, 13.2, "valve racks", "sub"); + s.box(24, 11.6, 2.2, 1.4, "PANEL"); + s.raw(``); + s.text(24.3, 15.1, "MAST CABLE ↑ MOOR", "sub"); + s.door(15, 5.5, true, 1); s.door(15, 11, true, 1); + s.door(17, 4, true, 1, true); s.door(17, 12, true, 1, true); + s.arrow(16, 18.8, 16, 19.9); s.arrow(16, 1.2, 16, 0.1); +}, legend: [1, 15.6] }, + +{ key: "bh-sump", no: 7, title: "TUNNELS & SUMP", level: "LEVEL 4 · WORKINGS", draw: s => { + s.room(0.5, 1.5, 27, 3, "No.2 COAL ROAD", { cls: "rock", n: 14, sub: "growing beds under lamps" }); + for (let x = 6; x < 26; x += 2.4) s.shelf(x, 2.2, 2, 0.6); + for (let x = 6; x < 26; x += 2.4) s.shelf(x, 3.7, 2, 0.6); + s.pencil(20, 1.3, "workings beyond: not surveyed", -1); + s.room(9, 4.5, 2, 3, null, { cls: "rock" }); s.room(17, 4.5, 2, 3, null, { cls: "rock" }); + s.room(0.5, 7.5, 18.5, 3, "No.3 COAL ROAD", { cls: "rock", sub: "trout tanks" }); + for (let x = 6; x < 16.5; x += 2.8) s.box(x, 8.1, 2.3, 1.8, "TANK", 16); + s.room(19, 6.5, 8.5, 5, "HEN RUN", { cls: "rock" }); + for (let x = 20; x < 27; x += 1.3) s.box(x, 9.9, 0.9, 0.9); + s.pencil(20.3, 8.6, "eggs → Welfare, Tues/Fri", -2); + s.stairs(13, 10.5, 3, 4, "SUMP STAIR"); + s.room(1, 11.5, 12, 2, "THE SUMP", { n: 15, ly: 1.3 }); + for (const x of [1, 4, 7, 10]) s.room(x, 13.5, 3, 4.5, null); + for (const [i, x] of [1, 4, 7, 10].entries()) { + s.text(x + 0.3, 14.1, `CELL ${i + 1}`, "sub"); + s.bed(x + 0.5, 15.3); + s.door(x + 1.9, 13.5, false, 0.9); + } + s.box(8.8, 11.9, 2, 0.8, "WARDEN"); + s.pencil(1.3, 18.6, "locks: 1962 pattern — oil them", -1); + s.arch(13.5, 10.5, false, 2, "rgap"); s.arch(13, 12, true, 1); + s.arch(9, 4.5, false, 2, "rgap"); s.arch(9, 7.5, false, 2, "rgap"); + s.arch(17, 4.5, false, 2, "rgap"); s.arch(17, 7.5, false, 2, "rgap"); + s.door(19, 8.5, true, 1); + s.arrow(1.3, 3, 0.1, 3); + s.text(0.6, 1.2, "← to Welfare stair", "sub"); +}, legend: [17.5, 12.1] } +]; + +/* The legend on sheet 7 sits above the title block; the title block never moves. */ + +if (import.meta.url === `file://${process.argv[1]}`) { + const doRender = process.argv.includes("--render"); + for (const pl of PLANS) { + const svg = render(pl.no, pl.title, pl.level, pl.draw, pl.legend ? { legend: pl.legend } : {}); + const svgPath = path.join(OUT, `${pl.key}.svg`); + writeFileSync(svgPath, svg); + if (doRender) { + const png = path.join(OUT, `${pl.key}.png`); + execFileSync("rsvg-convert", ["-w", "2800", "-h", "2000", svgPath, "-o", png]); + execFileSync("cwebp", ["-quiet", "-q", "88", png, "-o", path.join(OUT, `${pl.key}.webp`)]); + execFileSync("rm", [png]); + } + console.log(` ${pl.key}${doRender ? " (+webp)" : ""}`); + } +} diff --git a/tools/build-packs.mjs b/tools/build-packs.mjs index f3fadb9..ea3ed36 100644 --- a/tools/build-packs.mjs +++ b/tools/build-packs.mjs @@ -1058,6 +1058,19 @@ function cullandScene() { color: "#6674d8", alpha: 0, distance: 5, units: "m" }, flags: { ringbrp: { key: "bellhouse" } } }; + const plans = SO.SO_SCENES.map((sc, i) => ({ + ...cullandScene(), + _id: idFor(`scene:${sc.key}`), + name: sc.name, + navName: sc.nav, + background: { src: `systems/ringbrp/${sc.src}` }, + initial: { x: 1400, y: 1000, scale: 0.4 }, + backgroundColor: "#123f78", + grid: { type: 1, size: 100, style: "solidLines", thickness: 1, + color: "#e8f1fb", alpha: 0.08, distance: 5, units: "ft" }, + sort: (i + 1) * 100, + flags: { ringbrp: { key: sc.key } } + })); const advId = idFor("adventure:standing_order"); const adventure = { @@ -1085,14 +1098,14 @@ function cullandScene() { { ...showJournal.doc, pages: showJournal.pages }, { ...facesJournal.doc, pages: facesJournal.pages } ], - scenes: [bellhouse], combats: [], tables: [], macros: [], cards: [], playlists: [], folders: [], + scenes: [bellhouse, ...plans], combats: [], tables: [], macros: [], cards: [], playlists: [], folders: [], sort: 0, ...BASE() }; await writePack("standingorder", [[`!adventures!${advId}`, adventure]]); console.log(` standing STANDING ORDER — ${castDocs.length} cast, ${SO.SO_PAGES.length} GM pages, ` + `${SO.SO_HANDOUTS.length} handouts, ${showJournal.pages.length} plates, ` - + `${facesJournal.pages.length} faces`); + + `${facesJournal.pages.length} faces, ${1 + plans.length} scenes`); } // OPEN DAY — the prologue. A much smaller adventure than BLACK PLATFORM: no case file, diff --git a/tools/scenario-standingorder.mjs b/tools/scenario-standingorder.mjs index e1771e3..71fe86f 100644 --- a/tools/scenario-standingorder.mjs +++ b/tools/scenario-standingorder.mjs @@ -170,6 +170,18 @@ export const SO_PLATES = [ { name: "9 · Bellhouse — section", src: "art/maps/bellhouse-section.webp" } ]; +/* The underground as seven blueprint scenes, drawn by tools/bellhouse-plans.mjs. Numbers + are the Locations table's. 2800x2000 at 100px to the square, like Culland Hall. */ +export const SO_SCENES = [ + { key: "bh_lobby", name: "Bellhouse 1 · Lobby and Enquiries (6)", nav: "Lobby", src: "art/maps/bh-lobby.webp" }, + { key: "bh_control", name: "Bellhouse 2 · Control Room and Pipe Room (7, 11)", nav: "Control", src: "art/maps/bh-control.webp" }, + { key: "bh_registry", name: "Bellhouse 3 · Registry (8)", nav: "Registry", src: "art/maps/bh-registry.webp" }, + { key: "bh_sickbay", name: "Bellhouse 4 · Sick Bay (9)", nav: "Sick Bay", src: "art/maps/bh-sickbay.webp" }, + { key: "bh_creche", name: "Bellhouse 5 · Creche and School (10)", nav: "Creche", src: "art/maps/bh-creche.webp" }, + { key: "bh_vigil", name: "Bellhouse 6 · Vigil Hall and Plant Floor (12, 13)", nav: "Vigil Hall", src: "art/maps/bh-vigil.webp" }, + { key: "bh_sump", name: "Bellhouse 7 · Coal Roads and the Sump (14, 15)", nav: "Sump", src: "art/maps/bh-sump.webp" } +]; + /* The detention detail. Truncheons, not firearms: the Seat's armoury is locked and the Controller holds the key, and the order that sends them says DETAIN. Tactics are written for the GM; the harness does not model restraint, so its figures are the ceiling. */