Nothing validated creature specs. check-kits validates postings and check-scenarios validates prose; buildActor throws on an unknown skill or item key and is silent about everything else, so species, marksmanship style, characteristic blocks, species-locked talents and misspelt field names could all be wrong and still build, pack and play. Every packed actor once shipped as species "hominid" and the whole cast was hit-located as something the rules do not contain. tools/creature-schema.mjs derives every allowed value from the catalogues rather than retyping them: skills from SKILL_CATALOGUE, kit from the item catalogues, species from SPECIES, stats from CHARACTERISTIC_DICE, and the two marksmanship styles out of the language file. It reports every problem with a spec rather than dying on the first, and names the nearest real key. It also reports fields buildActor never reads, because "armours:" is not an error, it is an actor that silently equips nothing. On its first run it found six baseline humans carrying vesh biology. "unblinking" is cat: species, species: vesh, and its own rule text reads "A Vesh has no face to read". Out of Step is reclassified as anomalous with a Coherence cost, which is what every talent in that category has and what the Anchor who is three years older than his birthday says always wanted to be; the other five are swapped to agency and field talents that fit them. Not fixed here: the root cause is upstream in postings.mjs, where twelve posting talent pools still offer unblinking, distributed or quorum to any agent. Picking replacements across those is a design decision, not a mechanical one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
615 lines
38 KiB
JavaScript
615 lines
38 KiB
JavaScript
/**
|
||
* BLACK PLATFORM — the starter scenario, as data.
|
||
*
|
||
* Shipped as a Foundry ADVENTURE so the whole thing imports in one click: the GM text,
|
||
* the player handouts as separate pages a GM can reveal one at a time, the six pregens
|
||
* with their scenario jobs already in their biographies, the enemy roster, the two
|
||
* casualties, and the case file with its tracks and phases already set.
|
||
*
|
||
* The handouts are their own journal at OBSERVER ownership, because a handout a GM has
|
||
* to copy out of the scenario text is a handout that does not get used. The GM journal
|
||
* stays hidden.
|
||
*
|
||
* This is an ACTION starter: descend, fight for the platform, board, rescue, fight
|
||
* along a moving train, stop it. One short clue scene and no social subsystem — which
|
||
* is also why it carries no contact group and no Borrowed Authority.
|
||
*/
|
||
|
||
const P = s => `<p>${s}</p>`;
|
||
const H = (n, s) => `<h${n}>${s}</h${n}>`;
|
||
const UL = xs => `<ul>${xs.map(x => `<li>${x}</li>`).join("")}</ul>`;
|
||
const OL = xs => `<ol>${xs.map(x => `<li>${x}</li>`).join("")}</ol>`;
|
||
const PRE = s => `<pre class="rb-map">${s}</pre>`;
|
||
const TABLE = (head, rows) =>
|
||
`<table><thead><tr>${head.map(h => `<th>${h}</th>`).join("")}</tr></thead><tbody>`
|
||
+ rows.map(r => `<tr>${r.map(c => `<td>${c}</td>`).join("")}</tr>`).join("")
|
||
+ `</tbody></table>`;
|
||
const READ = s => `<blockquote class="rb-readaloud">${s}</blockquote>`;
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
/* The GM scenario */
|
||
/* ---------------------------------------------------------------- */
|
||
|
||
export const STARTER_PAGES = [
|
||
|
||
{ name: "1 · Run this first", content:
|
||
P("<strong>BLACK PLATFORM</strong> is a six-player action starter for The Custodians. "
|
||
+ "Three to four hours. Classification <strong>Near</strong>.")
|
||
+ READ("A train is running through a station whose rails were taken out in 1976. Two "
|
||
+ "engineers boarded it and have not come back. It returns every eleven minutes, and "
|
||
+ "every time it comes back there are more people on it.")
|
||
+ P("<strong>The case is a straight line:</strong> go down, take the platform, get "
|
||
+ "aboard, find the engineers, fight forward along a moving train, and stop it before "
|
||
+ "it reaches a terminus that does not exist in this world.")
|
||
+ H(2, "What each scene teaches")
|
||
+ TABLE(["Scene", "Introduces"], [
|
||
["Briefing", "case tracks, kit and objectives"],
|
||
["Descent", "one skill check with a real hazard"],
|
||
["Platform", "reaction lanes, cover, attacks, graded defences"],
|
||
["Boarding", "movement and the action economy"],
|
||
["Rescue carriage", "First Aid, wounds, a locked door"],
|
||
["Moving train", "range, ammunition, shooting past bystanders"],
|
||
["Driver's cab", "four jobs at once, against a clock"],
|
||
["Return", "coming home, Coherence and experience"]
|
||
])
|
||
+ P("<strong>No failed roll hides the way forward.</strong> A failure makes the next "
|
||
+ "thing harder or more expensive. It never removes the route.")
|
||
+ H(2, "Keep it moving")
|
||
+ P("Once the players understand a place, give them a sound — doors chiming, wheels "
|
||
+ "speeding up, ticket punches getting closer — and ask <em>what do you do now?</em>")
|
||
+ P("<strong>You do not have to kill everything.</strong> Inspectors withdraw, doors "
|
||
+ "lock, the Conductor can be held off. The job is to stop the train.")
|
||
+ P("The picture to aim at: six agents thrown forward as the brake takes, the hurt "
|
||
+ "engineer strapped between the seats, the Conductor hammering on a raised riot "
|
||
+ "shield, and the indicator clicking from <strong>FINAL TERMINUS</strong> to "
|
||
+ "<strong>HOME</strong>.")
|
||
},
|
||
|
||
{ name: "2 · The briefing", content:
|
||
READ("At 00:17 this morning, signalling equipment picked up a passenger train entering "
|
||
+ "Black Platform, beneath Wych Street. The platform closed in 1976. The rails were "
|
||
+ "lifted and both tunnels were filled with concrete.<br><br>"
|
||
+ "The train stood there ninety seconds and left into the eastern tunnel. The cameras "
|
||
+ "show twelve passengers. Three are dressed for 1950. One is dressed as a nurse. None "
|
||
+ "of them moves while the train is stopped.<br><br>"
|
||
+ "At 00:28 it came back.<br><br>"
|
||
+ "Two Network Rail engineers went down at 01:06. At 01:12 one of them transmitted: "
|
||
+ "<em>“It has our names on the board.”</em> Both boarded at 01:23. The train has gone "
|
||
+ "round seven times since.<br><br>"
|
||
+ "The next one arrives in eleven minutes.")
|
||
+ H(2, "Orders")
|
||
+ OL(["Get <strong>Leah Hall</strong> and <strong>Martin Cole</strong> back.",
|
||
"Board the train.",
|
||
"Find and remove whatever is holding the route open.",
|
||
"Stop the service before it reaches Final Terminus.",
|
||
"Come back with nothing left running under central London."])
|
||
+ P("<strong>Cover:</strong> emergency electrical-response team. The station and the "
|
||
+ "access tunnel are already shut to the public, so there is nobody to talk past.")
|
||
+ H(2, "Starting state")
|
||
+ P("<strong>Containment 9 · Resources 8 · Clearance 5</strong> · Terminus clock 0/6 · "
|
||
+ "everyone at Coherence 10. The case file in this adventure is already set to these.")
|
||
+ H(2, "Issued for this case")
|
||
+ P("On top of normal kit: six sets of ear defenders, two locator tags, a recovery "
|
||
+ "strop, insulated bolt-cutters, and a paper diagram of the closed platform.")
|
||
},
|
||
|
||
{ name: "3 · The truth", content:
|
||
P("The train is the <strong>00:17 Wych Street evacuation service</strong>, from a Near "
|
||
+ "world where London was abandoned after something went wrong in 1958. It went into a "
|
||
+ "tunnel crossing and never arrived anywhere.")
|
||
+ P("<strong>The passengers are echoes.</strong> They are not dangerous and they cannot "
|
||
+ "be saved: take one off the train and it stops existing. The conductor and the "
|
||
+ "inspectors are parts of the service rather than people. They enforce three rules:")
|
||
+ OL(["Nobody travels without a valid destination.",
|
||
"Nobody gets off between stations.",
|
||
"The service reaches the terminus."])
|
||
+ P("A brass <strong>route plate</strong> in the driver's cab is the physical anchor. It "
|
||
+ "lists stations from both worlds, and it keeps quietly convincing reality that the "
|
||
+ "route joins them up.")
|
||
+ H(2, "The engineers")
|
||
+ P("Both alive, in the rear service compartment. <strong>Leah Hall</strong> has a broken "
|
||
+ "leg and is bleeding slowly. <strong>Martin Cole</strong> is concussed and on his "
|
||
+ "feet. They worked out how to shut it down before they were attacked:")
|
||
+ OL(["Open the route cabinet.",
|
||
"Reverse the field regulator.",
|
||
"Take out the brass route plate.",
|
||
"Pull the manual brake when the indicator says <strong>HOME</strong>."])
|
||
+ P("<strong>The Conductor will try to stop every one of those.</strong>")
|
||
},
|
||
|
||
{ name: "4 · Pressure — the Terminus clock", content:
|
||
P("Move it at the listed moments, on a fumbled phase, and whenever the group stands "
|
||
+ "arguing while something dangerous is happening.")
|
||
+ TABLE(["Clock", "What happens"], [
|
||
["<strong>0 — Due</strong>", "The team is at the station. The train is eleven minutes out."],
|
||
["<strong>1 — Arriving</strong>", "Headlights inside a tunnel filled with concrete. The live rail comes on."],
|
||
["<strong>2 — Departed</strong>", "They are aboard. Mark the case <strong>Across</strong>. The platform outside is gone."],
|
||
["<strong>3 — Between</strong>", "The windows show a dark, empty London. Everyone aboard witnesses a paradox: <strong>−1 Coherence</strong>, once."],
|
||
["<strong>4 — Inspection</strong>", "Two ticket inspectors come forward from the rear."],
|
||
["<strong>5 — Final approach</strong>", "It speeds up. Everything physical or fiddly is at <strong>−10%</strong>."],
|
||
["<strong>6 — Terminus</strong>", "The white station fills the windows. One last round, then the emergency ending."]
|
||
])
|
||
+ P("Normally it moves once after each big scene — and <strong>once every round during "
|
||
+ "the cab sequence</strong>.")
|
||
},
|
||
|
||
{ name: "5 · Phase one — the descent", content:
|
||
P("In through a maintenance door and down 140 steps. The old posters are still tiled to "
|
||
+ "the walls, and every one of them has been changed to advertise the 00:17 service.")
|
||
+ P("At the bottom, the traction rail that was taken out in 1976 is back, and it is live. "
|
||
+ "The access gate has dropped across the stairwell. Past it, the platform lights are "
|
||
+ "coming on one at a time.")
|
||
+ H(2, "The obstacle")
|
||
+ P("Ten metres of wet floor beside a live rail, and a steel gate to get up, before the "
|
||
+ "train arrives. <strong>Pick one lead:</strong>")
|
||
+ UL(["<strong>Engineer</strong> — Repair (Electronics), to kill the rail.",
|
||
"<strong>Criminal</strong> — Sleight of Hand, to open the gate control without stepping in the water.",
|
||
"<strong>Containment</strong> — Athletics, to hold the gate up while everyone goes under.",
|
||
"<strong>Lead</strong> — Tradecraft, to run the whole thing: insulation, line, order of movement."])
|
||
+ TABLE(["Result", "What happens"], [
|
||
["<strong>Success</strong>", "Everyone crosses."],
|
||
["<strong>Special or critical</strong>", "Everyone crosses and picks good ground: <strong>+10%</strong> on the first reaction or attack roll."],
|
||
["<strong>Failure</strong>", "Everyone crosses. One agent, chosen at random, takes <strong>1d3 damage, ignoring armour</strong>."],
|
||
["<strong>Fumble</strong>", "As failure, the lights go out, and Terminus advances."]
|
||
])
|
||
+ P("The doctor can treat that immediately. It is a small, safe introduction to damage "
|
||
+ "and healing before anybody is shooting.")
|
||
+ P("<strong>Advance Terminus to 1 — Arriving.</strong>")
|
||
},
|
||
|
||
{ name: "6 · Phase two — take the platform", content:
|
||
P("Headlights come through solid concrete. The train arrives in complete silence and only "
|
||
+ "becomes audible when the doors open.")
|
||
+ P("Four ticket inspectors step out. Dark blue uniforms, blank faces under peaked caps, "
|
||
+ "each with a wooden ticket punch held like a short baton.")
|
||
+ READ("No destination shown.")
|
||
+ P("Then they come forward.")
|
||
+ H(2, "The platform")
|
||
+ PRE("WEST TUNNEL 40 m PLATFORM EAST TUNNEL\n"
|
||
+ "=================[ rear ][ centre ][ front/cab ]=================\n"
|
||
+ " stairs/gate pillars every 8 m signal box\n"
|
||
+ " team starts here partial cover train doors")
|
||
+ UL(["Tiled pillars are solid partial cover.",
|
||
"The train is 15 m from the stair gate.",
|
||
"The platform edge is a two-metre drop onto the live track.",
|
||
"Shoved over the edge? Athletics or Dodge to catch the lip. Failure is 1d6 and prone."])
|
||
+ H(2, "The inspectors")
|
||
+ P("Four of them. The statblock is in this adventure.")
|
||
+ UL(["They hit with ticket punches — treat as a cudgel.",
|
||
"They go for the nearest agent still standing, and ignore anyone already down.",
|
||
"They dodge. They have no firearms.",
|
||
"<strong>When three are down, the last one withdraws.</strong>"])
|
||
+ H(2, "Teach the fight in this order")
|
||
+ OL(["Roll reaction lanes.",
|
||
"Show Callum how to raise the riot shield.",
|
||
"Point out the pillars <em>before</em> anyone attacks.",
|
||
"Let each hit stand as a blow, so the defender can answer it.",
|
||
"Resolve armour, hit location and wounds normally.",
|
||
"Remind them that moving does not use up their attack."])
|
||
+ H(2, "Getting aboard")
|
||
+ P("When three inspectors are down the doors start chiming. <strong>Two rounds to "
|
||
+ "board.</strong>")
|
||
+ UL(["An agent on their feet just walks on.",
|
||
"Carrying somebody down needs a second person or the recovery strop.",
|
||
"Still outside when the doors close? Force them with Athletics, the entry bar or the bolt-cutters.",
|
||
"<strong>Nobody gets left behind.</strong> A failed attempt still gets them aboard, and costs <strong>Resources −1</strong> in dropped kit."])
|
||
+ P("<strong>Advance Terminus to 2 — Departed, and mark the case Across.</strong>")
|
||
},
|
||
|
||
{ name: "7 · Phase three — seize the train", content:
|
||
PRE("[ REAR SERVICE ] -- [ PASSENGER CARRIAGE ] -- [ FRONT / DRIVER'S CAB ]\n"
|
||
+ " trapped engineers echo passengers route plate\n"
|
||
+ " locked door inspectors enter here conductor")
|
||
+ P("They can stay together, but splitting is faster:")
|
||
+ UL(["<strong>Rescue group</strong> — doctor, criminal and one bodyguard, going back.",
|
||
"<strong>Assault group</strong> — lead, containment, overwatch and/or engineer, going forward."])
|
||
+ P("<strong>Cut between the two groups every action or two.</strong> Nobody should sit "
|
||
+ "out a whole scene.")
|
||
+ H(2, "The rear service compartment")
|
||
+ P("The door is locked and has no handle on this side.")
|
||
+ UL(["Sleight of Hand opens it.",
|
||
"An entry bar and Athletics force it.",
|
||
"Shooting the lock opens it and <strong>advances Terminus immediately</strong>."])
|
||
+ P("A failure still opens the door. It just takes long enough that "
|
||
+ "<strong>Inspection arrives early</strong>.")
|
||
+ H(3, "Leah Hall")
|
||
+ P("Pinned under a folded maintenance seat. Left leg disabled, <strong>4 hit "
|
||
+ "points</strong>, bleeding slowly.")
|
||
+ UL(["Lift the seat: Athletics, or an entry bar.",
|
||
"Stop the bleeding: First Aid.",
|
||
"Move her safely: the recovery strop, or two people."])
|
||
+ P("First Aid works normally: success stops the bleeding and gives hit points back; "
|
||
+ "failure does neither, and <strong>that wound has had its one attempt</strong>. She "
|
||
+ "can still be carried while somebody keeps pressure on, but she goes on bleeding at "
|
||
+ "the end of each round until she is treated another way or the case ends.")
|
||
+ H(3, "Martin Cole")
|
||
+ P("Concussed, <strong>7 hit points</strong>, awake and frightened. He knows the four "
|
||
+ "steps. Calm him or treat him and he says it clearly; otherwise he blurts it in the "
|
||
+ "wrong order and <strong>they still get all four</strong>.")
|
||
+ H(2, "The passenger carriage")
|
||
+ P("Twelve echoes sitting still. Their tickets are for places demolished decades ago.")
|
||
+ P("Walking through is safe until Terminus 4. Searching turns up a route diagram showing "
|
||
+ "<strong>HOME</strong> between Wych Street and Final Terminus, a first-aid box worth "
|
||
+ "one use of dressings, and two locked connecting doors — the criminal opens those "
|
||
+ "quietly, and forcing one gives the Conductor warning.")
|
||
+ P("At <strong>Terminus 3 — Between</strong>, the windows show an empty London under a "
|
||
+ "white sky. Witnessed paradox, once, for everyone aboard.")
|
||
+ H(2, "The inspection fight")
|
||
+ P("At Terminus 4, three inspectors come in from the rear. If the one from the platform "
|
||
+ "got away, it comes with them.")
|
||
+ UL(["Seats are partial cover.",
|
||
"Anything further off than one carriage is medium range.",
|
||
"<strong>Shooting down a carriage with echoes in it is −20%</strong>, and on a fumble the shot destroys an echo: <strong>Containment −1</strong>.",
|
||
"They try to grab Leah or Martin and mark them <strong>RETURNED</strong>.",
|
||
"An inspector withdraws at 2 hit points, or when restrained."])
|
||
+ P("<strong>The carriage is why everyone has a melee weapon.</strong> A rifle owns the "
|
||
+ "long aisle, but an inspector that reaches the rescue group is close enough that a "
|
||
+ "knife, a cudgel, an entry bar, a shield or bare hands is the cleaner answer. Let the "
|
||
+ "players pick — do not tell them which one is correct.")
|
||
+ P("Move to the cab as soon as the engineers can walk and somebody reaches the forward "
|
||
+ "door. <strong>Do not make them clear the carriage first.</strong>")
|
||
},
|
||
|
||
{ name: "8 · Phase four — stop the service", content:
|
||
P("The cab is bigger inside than the front of the train. Brass levers cover one wall. The "
|
||
+ "speed indicator has station names on it instead of numbers.")
|
||
+ P("The <strong>Conductor</strong> is at the controls: tall, black uniform, a polished "
|
||
+ "face with nothing on it. Its gloved hand has fused around the throttle.")
|
||
+ READ("This service terminates. All passengers remain aboard.")
|
||
+ P("Then it attacks.")
|
||
+ H(2, "The Conductor")
|
||
+ UL(["It goes for whoever is working a control.",
|
||
"In order: the route plate first, then the regulator, then the brake.",
|
||
"It does not chase anyone backing off toward the rear.",
|
||
"It can be restrained. It cannot be talked to.",
|
||
"<strong>At 2 hit points it is driven back, not killed</strong>, and keeps trying to reach the controls at half speed."])
|
||
+ H(2, "The final sequence")
|
||
+ P("Start Terminus at 3 if they got here fast, or wherever it already is. "
|
||
+ "<strong>At the end of every round, add 1.</strong>")
|
||
+ P("Four jobs, and they can all happen at once.")
|
||
+ TABLE(["Job", "Who", "Roll", "What happens"], [
|
||
["<strong>A · Open the route cabinet</strong>", "Criminal", "Sleight of Hand, Average",
|
||
"Success opens it now. Failure opens it at the end of the next round. Fumble opens it, and an arc does 1d3 and knocks something out of their hands."],
|
||
["<strong>B · Reverse the regulator</strong>", "Engineer", "Engineering or Repair, <strong>Difficult</strong>",
|
||
"Needs <strong>3 progress</strong>. Success 1, special 2, critical 3. Failure still gives 1 and does 1d3 — it is being worked out by trial and error. Fumble loses 1 and does 1d3."],
|
||
["<strong>C · Free the manual brake</strong>", "Containment", "Athletics, entry bar or bolt-cutters, Average",
|
||
"Success frees it. Failure frees it at the end of the next round. Fumble frees it and leaves them flat under the lever."],
|
||
["<strong>D · Call HOME</strong>", "Field Lead", "Tradecraft, Navigate or Spot, Average",
|
||
"Success catches the right moment. Special or critical gives the brake <strong>+20%</strong>. Failure still catches it, but so late that the brake roll is Difficult."]
|
||
])
|
||
+ P("Martin's instructions give the engineer <strong>+20%</strong>.")
|
||
+ P("<strong>Everyone else:</strong> overwatch takes the Conductor or the inspectors "
|
||
+ "coming forward; the doctor keeps Leah alive and patches whoever is bleeding; anyone "
|
||
+ "spare can assist, guard a specialist, or hold a door shut.")
|
||
+ H(2, "Pulling the brake")
|
||
+ P("Once the cabinet is open, the regulator has 3 progress and the lead has called HOME: "
|
||
+ "take the plate out — an action, no roll — and pull the brake on Athletics.")
|
||
+ TABLE(["Result", "What happens"], [
|
||
["<strong>Success or better</strong>", "It stops at Black Platform. The crossing is steady for the way home."],
|
||
["<strong>Failure</strong>", "The back half stops at Black Platform and the front half is still Across. Everyone gets home; one piece of carried kit is lost per failed return roll."],
|
||
["<strong>Fumble</strong>", "The lever snaps. Go to the emergency ending."]
|
||
])
|
||
+ H(2, "Emergency ending — Terminus 6")
|
||
+ P("Describe the enormous white station filling the windows, and give them one more "
|
||
+ "round. If the train is not stopped by the end of it — or the lever broke — there is "
|
||
+ "still a way out:")
|
||
+ OL(["Smash or shoot the exposed route plate. One action, no roll.",
|
||
"The crossing tears open for one round.",
|
||
"Everybody makes a normal return roll. Another agent can aim it for them."])
|
||
+ P("The engineers get home if somebody has hold of them. The train and the echoes are "
|
||
+ "destroyed between worlds.")
|
||
+ P("<strong>Containment −2.</strong> Everyone who watches it pays witnessed paradox. "
|
||
+ "Return rolls are Difficult, because the window is closing as they go through.")
|
||
+ P("<em>This is an expensive win, not a wipe.</em>")
|
||
},
|
||
|
||
{ name: "9 · Endings", content:
|
||
H(2, "Clean stop")
|
||
+ P("It brakes into Black Platform. The echoes stay in their seats while daylight comes "
|
||
+ "down the stairwell for the first time in fifty years. The Conductor and the "
|
||
+ "inspectors become empty uniforms.")
|
||
+ P("When the brass plate crosses onto the platform, the train goes. The rails cool and "
|
||
+ "end at concrete again.")
|
||
+ UL(["Both engineers out.", "<strong>Containment +1.</strong>",
|
||
"The route plate recovered as anomalous evidence.",
|
||
"Normal return rolls, and no extra penalty."])
|
||
+ H(2, "Rough stop")
|
||
+ P("Half home. They get the engineers and the plate; some kit — and possibly some "
|
||
+ "evidence — stays Across.")
|
||
+ UL(["Containment unchanged.", "Normal return rolls; failures lose carried kit.",
|
||
"Whether the plate comes back depends on who was holding it."])
|
||
+ H(2, "Emergency closure")
|
||
+ P("The train is destroyed at Final Terminus and they go through a collapsing crossing.")
|
||
+ UL(["Both engineers out, if somebody had hold of them.", "<strong>Containment −2.</strong>",
|
||
"Difficult return rolls.", "A fumbled return may grant a Quiet Art as normal."])
|
||
+ H(2, "Walk away")
|
||
+ P("If they leave without the engineers or the plate, they can still get home. The "
|
||
+ "service is back under Wych Street eleven minutes later with more people on it, and "
|
||
+ "the Terminus clock resets to 2.")
|
||
+ P("<strong>The case stays open.</strong> This is the only ending that does not stop it.")
|
||
},
|
||
|
||
{ name: "10 · Coming home and debrief", content:
|
||
P("Normal return procedure for everyone who was Across. Another agent can aim the return "
|
||
+ "for somebody else. <strong>Nothing strands anyone.</strong>")
|
||
+ P("<strong>None of these six is an Anchor Officer</strong> — only that posting trains "
|
||
+ "Transposition — so they are all aiming at the printed base. Do not roll six dice to "
|
||
+ "discover that. Say they all get home and none of them gets home neatly: wrong "
|
||
+ "street, wrong hour, one of them still holding a ticket punch. Roll it properly only "
|
||
+ "if somebody needs a clean arrival, or if you want a fumble on the table.")
|
||
+ P("Then settle the case tracks, close the case, improve ticked skills, and give back "
|
||
+ "the usual debrief Coherence.")
|
||
+ H(2, "Debrief — one each, quickly")
|
||
+ OL(["<strong>Lead:</strong> who did you send into it first?",
|
||
"<strong>Containment:</strong> what hit the shield hard enough that you still feel it?",
|
||
"<strong>Overwatch:</strong> which shot did you decide not to take?",
|
||
"<strong>Engineer:</strong> was that a machine, or was it following a rule?",
|
||
"<strong>Doctor:</strong> which of them would have died without you?",
|
||
"<strong>Criminal:</strong> what else was in the route cabinet?"])
|
||
+ READ("When the doors opened, why did you get on?")
|
||
},
|
||
|
||
{ name: "11 · GM quick reference", content:
|
||
H(2, "Running order")
|
||
+ OL(["The gate and the live rail.",
|
||
"Four inspectors on the platform.",
|
||
"Board inside two rounds.",
|
||
"Split: rescue at the back, assault at the front.",
|
||
"Get Leah stable, get the four steps out of Martin.",
|
||
"Three or four inspectors in the carriage.",
|
||
"The Conductor, while four jobs happen at once.",
|
||
"Pull the brake. Go home."])
|
||
+ H(2, "Enemies")
|
||
+ TABLE(["Enemy", "Behaviour", "Withdraws when"], [
|
||
["<strong>Platform inspectors ×4</strong>", "Nearest agent still standing. Ticket punches.", "three of them are down"],
|
||
["<strong>Carriage inspectors ×3–4</strong>", "Go for the engineers. Use the seats.", "at 2 hit points, or restrained"],
|
||
["<strong>The Conductor ×1</strong>", "Attacks whoever is working a control.", "driven back at 2, then half speed"]
|
||
])
|
||
+ H(2, "Turning it up or down")
|
||
+ P("<strong>Gentler:</strong> three inspectors on the platform and two in the carriage; "
|
||
+ "enemy attacks at −10%; start the final sequence at Terminus 2; let Martin's "
|
||
+ "instructions make the regulator Average instead of giving +20%.")
|
||
+ P("<strong>Harder:</strong> add one armed figure with a revolver in the passenger "
|
||
+ "carriage; start the final sequence at Terminus 4; let the Conductor call one "
|
||
+ "defeated inspector back into service, once.")
|
||
+ H(2, "Spotlight checklist")
|
||
+ UL(["Lead picked the approach and called HOME.",
|
||
"Containment used the shield and freed the brake.",
|
||
"Overwatch held a long lane, on the platform or down the aisle.",
|
||
"Engineer reversed the regulator.",
|
||
"Doctor stabilised Leah or patched somebody under fire.",
|
||
"Criminal opened the service door and the route cabinet."])
|
||
+ P("If a box is still empty going into the cab, move that job into that player's path.")
|
||
}
|
||
];
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
/* Player handouts */
|
||
/* ---------------------------------------------------------------- */
|
||
|
||
export const STARTER_HANDOUTS = [
|
||
|
||
{ name: "1 · Operational brief", content:
|
||
P("<strong>DEPARTMENTAL CUSTODY SERVICE</strong><br>"
|
||
+ "<strong>CASE:</strong> BP-017 / WYCH STREET<br>"
|
||
+ "<strong>CLASSIFICATION:</strong> NEAR<br>"
|
||
+ "<strong>REPORT TO:</strong> closed maintenance entrance, Wych Street, London")
|
||
+ P("At 00:17, signalling equipment picked up a passenger train entering a platform "
|
||
+ "closed since 1976. The rails were lifted and both tunnels filled with concrete.")
|
||
+ P("<strong>The train comes back every eleven minutes.</strong>")
|
||
+ P("Two Network Rail engineers boarded it. They have not come back.")
|
||
+ H(2, "Orders")
|
||
+ OL(["Get Leah Hall and Martin Cole back.",
|
||
"Board the train.",
|
||
"Find and remove whatever is holding its route open.",
|
||
"Stop it before Final Terminus.",
|
||
"Come back with nothing left running."])
|
||
+ P("<strong>Containment 9 · Resources 8 · Clearance 5</strong>")
|
||
},
|
||
|
||
{ name: "2 · Who can do what", content:
|
||
P("Everyone on this operation can fight. That is deliberate: nobody sits out a fight on "
|
||
+ "a first case.")
|
||
+ TABLE(["Agent", "Firearm", "Melee", "Brawl", "Dodge"], [
|
||
["<strong>Nia Mercer</strong> — Field Lead", "Pistol 55%", "Knife 45%", "40%", "45%"],
|
||
["<strong>Callum Pike</strong> — Containment", "Rifle 55%", "Entry bar 50% · Shield 45%", "50%", "45%"],
|
||
["<strong>Mara Venn</strong> — Overwatch", "Rifle 58%", "Cudgel 45%", "40%", "50%"],
|
||
["<strong>Owen Dey</strong> — Engineer", "Pistol 42%", "Cudgel 45%", "40%", "40%"],
|
||
["<strong>Dr Elin Shaw</strong> — Doctor", "Pistol 42%", "Knife 40%", "40%", "40%"],
|
||
["<strong>Sennen Roake</strong> — Criminal", "Pistol 42%", "Knife 50%", "45%", "50%"]
|
||
])
|
||
+ P("<strong>Use the firearm</strong> across the platform and down the long aisle. "
|
||
+ "<strong>Switch to melee</strong> when something closes on you, when there are echoes "
|
||
+ "in the way of your shot, or when you are guarding somebody at arm's length.")
|
||
+ P("These are floors, not your whole character. Owen is still far better at engineering "
|
||
+ "than at fighting, and Elin is still the only doctor.")
|
||
},
|
||
|
||
{ name: "3 · The closed platform", content:
|
||
PRE("STREET\n"
|
||
+ " |\n"
|
||
+ "140 STEPS\n"
|
||
+ " |\n"
|
||
+ "STEEL ACCESS GATE -- wet floor -- LIVE TRACTION RAIL\n"
|
||
+ " |\n"
|
||
+ "WEST TUNNEL 40 m BLACK PLATFORM EAST TUNNEL\n"
|
||
+ "=================[ rear ][ centre ][ front/cab ]=================\n"
|
||
+ " stairs/gate pillars every 8 m signal box\n"
|
||
+ " team entry partial cover train doors")
|
||
+ P("The train stands at the platform for about <strong>ninety seconds</strong>.")
|
||
},
|
||
|
||
{ name: "4 · The train", content:
|
||
PRE("[ REAR SERVICE ] -- [ PASSENGER CARRIAGE ] -- [ FRONT / DRIVER'S CAB ]\n"
|
||
+ " engineers echo passengers route cabinet\n"
|
||
+ " locked door connecting doors field regulator\n"
|
||
+ " first-aid box long firing lane manual brake")
|
||
},
|
||
|
||
{ name: "5 · Martin Cole's shutdown", content:
|
||
OL(["Open the route cabinet.",
|
||
"Reverse the field regulator.",
|
||
"Take out the brass route plate.",
|
||
"Pull the manual brake when the indicator says <strong>HOME</strong>."])
|
||
+ READ("Not before HOME. If you brake between stations, it opens the doors.")
|
||
},
|
||
|
||
{ name: "6 · The final sequence", content:
|
||
P("All of this happens at once, while the train runs at Final Terminus.")
|
||
+ TABLE(["Job", "Who", "Done"], [
|
||
["Open the route cabinet", "Criminal", "☐"],
|
||
["Reverse the regulator — 1", "Engineer", "☐"],
|
||
["Reverse the regulator — 2", "Engineer", "☐"],
|
||
["Reverse the regulator — 3", "Engineer", "☐"],
|
||
["Free the manual brake", "Containment", "☐"],
|
||
["Call HOME", "Field Lead", "☐"],
|
||
["Keep the specialists alive", "Overwatch", "☐"],
|
||
["Keep the casualties alive", "Doctor", "☐"]
|
||
])
|
||
+ P("<strong>Terminus:</strong> 0 ☐ · 1 ☐ · 2 ☐ · 3 ☐ · 4 ☐ · 5 ☐ · 6 ☐")
|
||
},
|
||
|
||
{ name: "7 · Debrief slip", content:
|
||
P("One line each, before you talk to the debriefing officer.")
|
||
+ UL(["When the doors opened, I got on because ____________________.",
|
||
"The moment I thought we might not come home was ____________________.",
|
||
"What I saw through the train window was ____________________."])
|
||
}
|
||
];
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
/* The team */
|
||
/* ---------------------------------------------------------------- */
|
||
|
||
/**
|
||
* Six pregens. `floors` are the scenario's deliberate starter minimums: every agent
|
||
* carries a firearm, a melee weapon, Brawl and Dodge at a usable rating so nobody
|
||
* becomes a spectator when initiative is rolled. They only ever RAISE a rating, so a
|
||
* posting already better at something stays better.
|
||
*/
|
||
export const STARTER_TEAM = [
|
||
{ key: "bp_nia", name: "Nia Mercer", role: "lead", rank: "Field Officer",
|
||
chosenStyle: "reflex", species: "baseline", age: { chronological: 36, physiological: 36 },
|
||
ch: { str: 11, siz: 12, con: 13, int: 14, pow: 13, dex: 15, cha: 13, edu: 12 },
|
||
talents: ["first_through", "read_room"],
|
||
extraWeapons: ["dagger"],
|
||
floors: { "firearm:pistol": 55, "melee_weapon:knife": 45, brawl: 40, dodge: 45 },
|
||
spotlight: "Run the team, split it when it needs splitting, and call HOME at the right second.",
|
||
note: "Being in charge is deciding who acts — not making every roll yourself." },
|
||
|
||
{ key: "bp_callum", name: "Callum Pike", role: "heavy", rank: "Field Officer",
|
||
chosenStyle: "reflex", species: "baseline", age: { chronological: 34, physiological: 34 },
|
||
ch: { str: 16, siz: 15, con: 15, int: 11, pow: 11, dex: 13, cha: 10, edu: 10 },
|
||
talents: ["hard_landing", "first_through"],
|
||
floors: { "firearm:rifle": 55, "melee_weapon:prybar": 50, "melee_weapon:shield": 45,
|
||
brawl: 50, dodge: 45 },
|
||
spotlight: "Front rank. Hold the door, cover the people doing the work, free the brake.",
|
||
note: "Your riot shield starts SLUNG. Raising it protects torso and arms and costs you -20% on your own shooting. That is a decision, every time." },
|
||
|
||
{ key: "bp_mara", name: "Mara Venn", role: "overwatch", rank: "Field Officer",
|
||
chosenStyle: "deliberate", species: "baseline", age: { chronological: 38, physiological: 38 },
|
||
ch: { str: 12, siz: 12, con: 13, int: 13, pow: 12, dex: 16, cha: 11, edu: 12 },
|
||
talents: ["first_through", "hard_landing"],
|
||
extraWeapons: ["cudgel"],
|
||
floors: { "firearm:rifle": 58, "melee_weapon:club": 45, brawl: 40, dodge: 50 },
|
||
spotlight: "Own the long line — the length of the platform, then the length of the aisle.",
|
||
note: "Deliberate marksmanship: better at range, worse if you move and fire. Shooting past the echoes is -20%." },
|
||
|
||
{ key: "bp_owen", name: "Owen Dey", trade: "engineer", rank: "Probationary",
|
||
chosenStyle: "reflex", species: "baseline", age: { chronological: 29, physiological: 29 },
|
||
ch: { str: 12, siz: 12, con: 12, int: 17, pow: 11, dex: 14, cha: 10, edu: 15 },
|
||
talents: ["hard_landing", "requisition"],
|
||
extraWeapons: ["cudgel"],
|
||
floors: { "firearm:pistol": 42, "melee_weapon:club": 45, brawl: 40, dodge: 40 },
|
||
spotlight: "Kill the rail on the way in, then reverse the regulator with the Conductor on top of you.",
|
||
note: "Martin's instructions are worth +20%. Get them out of him before you touch anything." },
|
||
|
||
{ key: "bp_elin", name: "Dr Elin Shaw", trade: "doctor", rank: "Probationary",
|
||
chosenStyle: "deliberate", species: "baseline", age: { chronological: 31, physiological: 31 },
|
||
ch: { str: 10, siz: 11, con: 11, int: 16, pow: 12, dex: 12, cha: 13, edu: 17 },
|
||
talents: ["triage", "debriefer"],
|
||
extraWeapons: ["dagger"],
|
||
floors: { "firearm:pistol": 42, "melee_weapon:knife": 40, brawl: 40, dodge: 40 },
|
||
spotlight: "Keep Leah alive, keep the team upright, and be the reason both engineers walk out.",
|
||
note: "A wound gets ONE First Aid attempt. Choose when to spend it." },
|
||
|
||
{ key: "bp_sennen", name: "Sennen Roake", trade: "criminal", rank: "Probationary",
|
||
chosenStyle: "reflex", species: "baseline", age: { chronological: 27, physiological: 27 },
|
||
ch: { str: 11, siz: 10, con: 12, int: 13, pow: 11, dex: 17, cha: 14, edu: 9 },
|
||
talents: ["cover_work", "clean_scene"],
|
||
extraWeapons: ["dagger"],
|
||
floors: { "firearm:pistol": 42, "melee_weapon:knife": 50, brawl: 45, dodge: 50 },
|
||
spotlight: "Get the locked service door open, then the route cabinet, without shooting either.",
|
||
note: "Shooting a lock works and advances the clock. Everything you open quietly is time somebody else gets to use." }
|
||
];
|
||
|
||
/** The cast: two casualties, the inspectors, and the thing at the controls. */
|
||
export const STARTER_CAST = [
|
||
{ key: "bp_leah", name: "Leah Hall", role: "CIVILIAN. Network Rail engineer, trapped",
|
||
chosenStyle: "reflex", naturalArmour: 0, species: "baseline",
|
||
ch: { str: 12, siz: 11, con: 11, int: 13, pow: 11, dex: 12, cha: 11, edu: 13 },
|
||
skills: [{ fam: "repair", spec: "mechanical", val: 60 },
|
||
{ fam: "engineering", spec: "field_systems", val: 55 },
|
||
{ fam: "spot", spec: "", val: 40 }],
|
||
weapons: ["punch"],
|
||
tactics: "Pinned under a folded maintenance seat. Left leg disabled, START HER AT 4 HIT POINTS, bleeding slowly. Lifting the seat is Athletics or an entry bar; stopping the bleed is First Aid; moving her safely wants the recovery strop or two people. She is calm, in a great deal of pain, and more worried about Martin than about herself." },
|
||
|
||
{ key: "bp_martin", name: "Martin Cole", role: "CIVILIAN. Network Rail engineer, concussed",
|
||
chosenStyle: "reflex", naturalArmour: 0, species: "baseline",
|
||
ch: { str: 12, siz: 12, con: 12, int: 12, pow: 10, dex: 11, cha: 12, edu: 13 },
|
||
skills: [{ fam: "repair", spec: "mechanical", val: 55 },
|
||
{ fam: "engineering", spec: "field_systems", val: 50 },
|
||
{ fam: "first_aid", spec: "", val: 35 }],
|
||
weapons: ["punch"],
|
||
tactics: "Concussed, START HIM AT 7 HIT POINTS, awake and frightened. He knows the four steps: open the cabinet, reverse the regulator, remove the plate, brake at HOME. Calm or treat him and he says it clearly; otherwise he blurts it in the wrong order and they still get all four. He will not leave without Leah." },
|
||
|
||
{ key: "bp_inspector", name: "Ticket inspector", role: "HORROR. Part of the service, not a person",
|
||
chosenStyle: "reflex", naturalArmour: 2, species: "baseline",
|
||
ch: { str: 13, siz: 12, con: 13, int: 7, pow: 12, dex: 13, cha: 4, edu: 5 },
|
||
skills: [{ fam: "brawl", spec: "", val: 45 },
|
||
{ fam: "melee_weapon", spec: "club", val: 50 },
|
||
{ fam: "dodge", spec: "", val: 40 },
|
||
{ fam: "spot", spec: "", val: 45 }],
|
||
weapons: ["cudgel"],
|
||
tactics: "Dark blue uniform, blank face under a peaked cap, wooden ticket punch held like a baton. USE FOUR ON THE PLATFORM AND THREE IN THE CARRIAGE. It walks at the nearest agent still standing and ignores anyone already down — it is not cruel, it is enforcing a rule. It dodges and never uses a firearm. In the carriage it tries to seize an engineer and mark them RETURNED. It withdraws at 2 hit points or when restrained, and on the platform the last one leaves once three are down. POWER: NO DESTINATION SHOWN. It will not strike anyone holding out a valid ticket, a warrant card presented flat, or any other document formally offered — one round of grace, and waiting costs it nothing." },
|
||
|
||
{ key: "bp_conductor", name: "The Conductor", role: "HORROR. The service itself, wearing a uniform",
|
||
chosenStyle: "reflex", naturalArmour: 4, species: "baseline",
|
||
ch: { str: 16, siz: 14, con: 16, int: 9, pow: 17, dex: 14, cha: 3, edu: 6 },
|
||
skills: [{ fam: "brawl", spec: "", val: 65 },
|
||
{ fam: "melee_weapon", spec: "club", val: 60 },
|
||
{ fam: "dodge", spec: "", val: 45 },
|
||
{ fam: "spot", spec: "", val: 60 }],
|
||
weapons: ["cudgel"],
|
||
tactics: "Tall, black uniform, polished face with nothing on it, one gloved hand fused around the throttle. It attacks whoever is working a control — the route plate first, then the regulator, then the brake — and does not chase anybody retreating toward the rear. It can be restrained and cannot be reasoned with. AT 2 HIT POINTS IT IS DRIVEN BACK, NOT KILLED: it keeps trying to reach the controls at half speed. POWER: ALL PASSENGERS REMAIN ABOARD. Once per fight, as its action, it shuts and seals every door in one carriage. Opening one costs an action and Athletics, an entry bar or the bolt-cutters." }
|
||
];
|
||
|
||
/** No credential on this case — the station is already closed to the public. */
|
||
export const STARTER_AUTHORITY = null;
|
||
|
||
/** No social subsystem on this case, so no groups and no standings. */
|
||
export const STARTER_GROUPS = [];
|
||
|
||
/** The case file, already at the scenario's opening state. */
|
||
export const STARTER_CASE = {
|
||
key: "bp_case",
|
||
name: "BP-017 · Black Platform",
|
||
containment: 9, resources: 8, clearance: 5,
|
||
destination: "Black Platform, beneath Wych Street, London",
|
||
standings: [],
|
||
notes:
|
||
"<p><strong>Terminus clock 0 / 6.</strong> Move it after each big scene, on a fumbled "
|
||
+ "phase, when the group stands arguing in the middle of something dangerous — and "
|
||
+ "<strong>once every round during the cab sequence</strong>.</p>"
|
||
+ "<p>0 Due · 1 Arriving · 2 Departed (mark Across) · 3 Between (−1 Coherence, once) · "
|
||
+ "4 Inspection · 5 Final approach (−10% physical) · 6 Terminus.</p>"
|
||
+ "<p><strong>Issued for this case:</strong> six ear defenders, two locator tags, a "
|
||
+ "recovery strop, insulated bolt-cutters, and a paper diagram of the platform.</p>",
|
||
legs: [
|
||
{ label: "Approach — down to Black Platform", kindId: "approach", difficulty: "average", mod: 0 },
|
||
{ label: "Confrontation — take the platform", kindId: "cordon", difficulty: "average", mod: -5 },
|
||
{ label: "Containment — seize the train", kindId: "containment", difficulty: "difficult", mod: 0 },
|
||
{ label: "Extraction — stop at HOME", kindId: "extraction", difficulty: "average", mod: -15 }
|
||
]
|
||
};
|