Ten pages a player reads before session one, in their own compendium at OBSERVER ownership: nine of setting, one cheat sheet. The draft called the organisation "the Bureau"; everything else in the game calls it the department or the agency, so that is what it is called. Thin areas filled rather than padded: the seven character principles as a list, the real Coherence band table instead of a paragraph describing one, and "what continuity is not" pulled out of the middle of a page because it is the most important sentence for a new player. The cheat sheet's numbers are computed from rules.mjs and lang/en.json at build time. A hand-typed one would have been the sixth time this project shipped a number that disagreed with the code, and the one the players were holding. R-250: the design tokens were never on :root. Journals rendered as default parchment, and four things were wrong in sequence — v14's hook is renderJournalEntrySheet; its `element` is the node, so `[0]` returns the first CHILD and put the class on a header button; there is no .journal-page-content in v14; and then the real one: with the selector matching, font-size, line-height and padding all applied while every colour did not, because the palette is declared on .ringbrp-sheet/.ringbrp-chat/.ringbrp-window and never on :root. A journal inherited no tokens, so every var() silently became nothing. A rule that HALF applies is not a specificity problem — I spent three attempts treating it as one, including a version bump on a cache theory that was wrong. Branded: primer, rulebook, starter GM text and handouts. Scoped by flag, so other modules' journals are untouched. Version 0.9.0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
503 lines
32 KiB
JavaScript
503 lines
32 KiB
JavaScript
/**
|
||
* THE PLAYER PRIMER — what a new player reads before session one.
|
||
*
|
||
* Written to be handed out, not studied. Eight pages of setting and one cheat sheet,
|
||
* and the cheat sheet's numbers are computed from rules.mjs at build time so the card
|
||
* a player holds cannot say one thing while the engine does another. That failure has
|
||
* happened five times in this project; a hand-typed cheat sheet would have been the
|
||
* sixth, and it would have been the one the players were looking at.
|
||
*
|
||
* On the voice: the source draft called the organisation "the Bureau". Everything else
|
||
* in the game — twelve rules pages, the starter, every localisation string — calls it
|
||
* "the department" or "the agency", so that is what it is called here. One name.
|
||
*/
|
||
// TRADE_BANDS and INDUCTION are register data, not rules — they live in postings.mjs.
|
||
import { TRADE_BANDS, INDUCTION } from "../postings.mjs";
|
||
import {
|
||
hitPointsFor, majorWoundFor, damageModifierFor, defencePenaltyFor,
|
||
COHERENCE_BANDS, RANGE_LADDER, CIRCUMSTANCE
|
||
} from "../rules.mjs";
|
||
import { readFile } from "node:fs/promises";
|
||
|
||
// Labels come from the language file, the same way the rulebook generator reads them,
|
||
// so the primer prints what the sheet prints rather than a prettified lang key.
|
||
const LANG = JSON.parse(await readFile(new URL("../lang/en.json", import.meta.url), "utf8"));
|
||
const L = key => LANG[key] ?? key;
|
||
|
||
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 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>`;
|
||
const FORM = s => `<div class="rb-form">${s}</div>`;
|
||
const STAMP = s => `<div class="rb-stamp">${s}</div>`;
|
||
const CLOSER = s => `<p class="rb-closer">${s}</p>`;
|
||
const CARDS = xs => `<div class="rb-cards">${xs.map(([t, b]) =>
|
||
`<div class="rb-card"><h4>${t}</h4>${b}</div>`).join("")}</div>`;
|
||
const TWO = s => `<div class="rb-two">${s}</div>`;
|
||
const pc = n => `${n > 0 ? "+" : ""}${n}%`;
|
||
|
||
/* Worked from the same functions the sheet uses, so the primer cannot drift. */
|
||
const EG = { con: 12, siz: 13, str: 12 };
|
||
const egHp = hitPointsFor(EG.con, EG.siz);
|
||
const egMw = majorWoundFor(egHp);
|
||
const egDm = damageModifierFor(EG.str + EG.siz);
|
||
|
||
export const PRIMER_PAGES = [
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
{ name: "1 · You live in the 2020s", content:
|
||
FORM("Departmental Custody Service · <b>Induction pack</b><br>"
|
||
+ "Issued to: <b>new entrant</b> · Retain for the duration of service<br>"
|
||
+ "Classification: <b>restricted</b> — not for disclosure outside the department")
|
||
+ P("You have a phone, an email address, a National Insurance number and opinions "
|
||
+ "about the quickest way through a self-service checkout. You have had jobs, "
|
||
+ "relationships, debts, disappointments and plans. You know the world is troubled "
|
||
+ "and frequently absurd, but you have never had reason to believe it is "
|
||
+ "<em>unreal</em>.")
|
||
+ P("<strong>You are not a wizard, a superhero or a chosen anything.</strong> You "
|
||
+ "cannot see ghosts merely because they are ghosts. Bullets hurt you. A locked door "
|
||
+ "stays locked until somebody opens it. If something with too many teeth reaches "
|
||
+ "you, your advantages are whatever you brought, whoever is standing beside you, "
|
||
+ "and the chance that somebody made a plan.")
|
||
+ P("Until recently you thought that was all there was.")
|
||
+ CLOSER("Then the department found you.")
|
||
},
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
{ name: "2 · The problem", content:
|
||
P("Reality is not as single or as steady as people assume.")
|
||
+ P("There are other versions of the world — places where a different decision was "
|
||
+ "taken, where history bent another way, where life developed under other "
|
||
+ "conditions, or where the rules themselves settled into a shape impossible here. "
|
||
+ "Most stay separate. Occasionally two of them touch.")
|
||
+ P("The department calls that contact a <strong>crossing</strong>.")
|
||
+ P("A crossing might be a door that opens into the wrong building, a road that "
|
||
+ "arrives in a town on no map, or a train running between stations in different "
|
||
+ "histories. It might be no wider than the gap under a filing cabinet. It might "
|
||
+ "last three seconds or stand open for generations.")
|
||
+ H(2, "Crossings do not merely join places. They create contradictions.")
|
||
+ TWO(UL([
|
||
"Two people hold the same birth certificate.",
|
||
"A house stands on ground where its foundations were never laid.",
|
||
"A dead soldier comes back to a family that remembers burying him.",
|
||
"Rain obeying somebody else's physics falls on a field in Yorkshire.",
|
||
"A person goes on living while banks, government systems and their own relatives stop being able to remember them."
|
||
]))
|
||
+ H(2, "The record")
|
||
+ P("The department's oldest surviving explanation is that "
|
||
+ "<strong>reality keeps a record of what belongs where</strong>.")
|
||
+ P("It is not a literal ledger held by a god or a machine. It is the closest language "
|
||
+ "anyone has found for how the world behaves. People, places and events have an "
|
||
+ "identity: they are recognised by other people, by physical history, and by the "
|
||
+ "thousand systems around them.")
|
||
+ P("<strong>A crossing introduces something the record cannot file.</strong> Sometimes "
|
||
+ "reality rejects the intrusion. Sometimes it alters the intruder. Sometimes it "
|
||
+ "alters everything around the intruder until the contradiction goes away. None of "
|
||
+ "those is reliably safe.")
|
||
+ P("The department uses the theory of crossings because it is useful, not because it "
|
||
+ "has been proved. A door into another history is plainly a crossing. A dead woman "
|
||
+ "appearing in mirrors, a family curse that outlives the family, or one dream shared "
|
||
+ "by six strangers is less easily explained.")
|
||
+ P("The old hands avoid the argument. Whatever a thing <em>is</em>, the questions are "
|
||
+ "the same:")
|
||
+ READ("What does it do? What makes it worse? What is holding it here? And how do we "
|
||
+ "stop it reaching anybody else?")
|
||
},
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
{ name: "3 · Why the department exists", content:
|
||
P("Because crossings have always happened.")
|
||
+ P("Its offices today are fluorescent-lit government rooms with grey carpet, "
|
||
+ "computers and secure cabinets. Its predecessors worked out of royal "
|
||
+ "observatories, monasteries, counting houses, naval offices and rooms behind "
|
||
+ "temples. Some job titles are modern. Others have lasted centuries because nobody "
|
||
+ "has ever been confident enough to say the old work has stopped being necessary.")
|
||
+ P("Governments have renamed it, split it, hidden it inside other departments and "
|
||
+ "occasionally tried to abolish it. The work carried on under every arrangement. "
|
||
+ "<strong>An organisation can be closed. The next impossible doorway still has to be "
|
||
+ "dealt with.</strong>")
|
||
+ P("Nobody knows when it began. The archive holds Roman inventories of objects that "
|
||
+ "cast shadows the wrong way, medieval payments to wardens of roads that did not "
|
||
+ "always reach the same county, and eighteenth-century orders about a lighthouse "
|
||
+ "visible only to ships already lost. The oldest documents refer to earlier "
|
||
+ "custodians as though <em>they</em> were ancient.")
|
||
+ P("So the department has reached an institutional conclusion: <strong>the job did not "
|
||
+ "begin with us, and it will not end with us.</strong>")
|
||
+ H(2, "What it cannot do")
|
||
+ UL(["Permanently repair reality.",
|
||
"Find every crossing before somebody walks through one.",
|
||
"Destroy everything that arrives — many arrivals are people, and destruction can make a contradiction worse.",
|
||
"Tell the public, which would create panic, exploitation and, worst of all, millions of new records confirming that the anomaly exists."])
|
||
+ H(2, "What it does instead")
|
||
+ UL(["Finds crossings and charts where they go.",
|
||
"Contains things that should not be here.",
|
||
"Recovers people who have gone somewhere else.",
|
||
"Negotiates with whoever lives on the other side.",
|
||
"Closes routes that have become dangerous.",
|
||
"Leaves alone the arrangements that are safer undisturbed.",
|
||
"Alters, suppresses or completes records until reality has one answer it can accept.",
|
||
"Comes back tomorrow, when yesterday's solution starts to fail."])
|
||
+ CLOSER("This is not a war that can be won. It is maintenance, on an impossible scale.")
|
||
},
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
{ name: "4 · What is out there", content:
|
||
P("The things the department deals with are not one species and share no single "
|
||
+ "origin. Some are hostile. Some are animals behaving normally somewhere humans are "
|
||
+ "unprepared. Some are people defending their homes. Some are processes with no "
|
||
+ "intention at all. A few are mistakes left by the department's own earlier attempts "
|
||
+ "at containment.")
|
||
+ P("<em>Agents use rough, unofficial categories. None of them is in the manual.</em>")
|
||
+ H(2, "Things that crossed")
|
||
+ P("A predator following prey through a temporary opening. A growth spreading through "
|
||
+ "concrete because concrete does not exist where it evolved. A person who crossed by "
|
||
+ "accident and is dangerous only because our world is poison to them — or because "
|
||
+ "their being here is erasing somebody else.")
|
||
+ H(2, "Echoes, duplicates and revenants")
|
||
+ P("A crossing sometimes repeats a person instead of moving them. Two adults with the "
|
||
+ "same childhood, the same fingerprints and twenty years of different memories. A "
|
||
+ "dead porter who walks the same platform every night. A rescue beacon transmitted "
|
||
+ "by the teammate they watched die.")
|
||
+ P("<strong>The department does not assume a duplicate is false or a revenant "
|
||
+ "mindless.</strong> Working out what something is — and whether it can be talked "
|
||
+ "to — is the job.")
|
||
+ H(2, "Wrong places")
|
||
+ P("A government office with a thirteenth floor reachable only during fire alarms. A "
|
||
+ "village on two maps in different counties that physically moves each winter. A "
|
||
+ "service tunnel that gets longer every time somebody is sent to measure it.")
|
||
+ P("<strong>Wrong places are the dangerous ones, because people relax indoors.</strong> "
|
||
+ "A room with a kettle, a desk and a fire-exit sign goes on feeling ordinary long "
|
||
+ "after it has stopped obeying the rules.")
|
||
+ H(2, "Objects and procedures")
|
||
+ P("A brass date stamp that makes a document true from the date applied. A field "
|
||
+ "medical unit that heals a wound by moving it to the nearest blood relative. A road "
|
||
+ "sign that creates the place printed on it.")
|
||
+ P("Much of this is <strong>transposed materiel</strong>. Agents are trained not to "
|
||
+ "operate unfamiliar equipment merely because it has a switch.")
|
||
+ H(2, "People with an interest")
|
||
+ P("The department is not the only one that knows. Collectors buy things that should "
|
||
+ "never be catalogued. Contractors called <strong>Cleaners</strong> remove evidence "
|
||
+ "for employers whose names rarely survive an investigation. Rival offices bury "
|
||
+ "incidents to protect budgets and careers. People living beside a stable crossing "
|
||
+ "may depend on it for food, medicine or faith.")
|
||
+ P("They use guns, vehicles, surveillance, lawyers, political weight and correct "
|
||
+ "paperwork. <strong>They are usually more immediately dangerous than the "
|
||
+ "anomaly.</strong>")
|
||
+ H(2, "The dead who do not leave")
|
||
+ P("The department does not use <em>ghost</em> as a classification, because the word "
|
||
+ "assumes an answer. A haunting might be a surviving person, an impression left on a "
|
||
+ "place, somebody displaced from a history where they did not die, or a pattern that "
|
||
+ "has learned to do what the dead are expected to do.")
|
||
+ P("<strong>The distinction matters.</strong> A surviving person can be reasoned with. "
|
||
+ "A recording can only repeat. A predatory pattern may imitate grief because grief "
|
||
+ "brings people close enough.")
|
||
+ H(2, "Curses and inherited conditions")
|
||
+ P("A curse is rarely a beam of hostile energy. It is usually <strong>a rule the world "
|
||
+ "has started enforcing</strong>. The eldest child stays in the house. Every owner of "
|
||
+ "a certain ring dies before their spouse. Nobody appointed keeper of a particular "
|
||
+ "bridge leaves the county alive.")
|
||
+ P("These last centuries because generations of observance have made them part of the "
|
||
+ "record. Breaking the ritual may end it, release whatever it was holding down, or "
|
||
+ "move the obligation onto whoever interfered.")
|
||
+ P("<em>This is where well-meaning agents do the most damage. An old practice can look "
|
||
+ "cruel or absurd and still be the only thing standing under something worse.</em>")
|
||
+ H(2, "Ideas that travel")
|
||
+ P("Not everything needs a body. A dream can spread between sleepers. A proof can "
|
||
+ "describe a geometry that starts appearing around anyone who understands it. An "
|
||
+ "image can gain detail with every copy until it shows the room the copy is being "
|
||
+ "viewed in.")
|
||
+ P("The department files these as <strong>cognitive anomalies</strong>, which does "
|
||
+ "nothing whatever to make them safer. It is also why publicity is feared: attention "
|
||
+ "does not only expose an anomaly, it can feed one, define one, or hold one steady.")
|
||
+ H(2, "The things behind the stories")
|
||
+ P("There is no official category for gods, because an official category implies "
|
||
+ "somebody knows what is being categorised. Agents say <strong>mythos case</strong> "
|
||
+ "for incidents that repeat the same shapes across cultures that never met: the "
|
||
+ "sleeper under the water, the king whose face must not be seen, the black star, the "
|
||
+ "messenger who arrives before the disaster.")
|
||
+ P("Some intelligences appear to work on a scale that makes individual people hard to "
|
||
+ "notice. Their smallest movements can produce religions, extinctions or changes in "
|
||
+ "physical law.")
|
||
+ P("<strong>They are not necessarily evil.</strong> A storm is not evil. That is little "
|
||
+ "comfort to anyone underneath one.")
|
||
+ P("These are not solved by learning a creature's statistics and shooting it. Agents "
|
||
+ "break the ritual, clear the site, spoil the alignment, close the route, deal with "
|
||
+ "an intermediary, or stop the thing becoming present enough to act. Sometimes the "
|
||
+ "most that can be done is to reinforce an old containment and leave instructions "
|
||
+ "for the next generation.")
|
||
+ H(2, "UNRESOLVED")
|
||
+ STAMP("Unresolved")
|
||
+ P("Some files defeat every model. There are rooms that cannot be entered twice by the "
|
||
+ "same route, photographs of agents who never existed, and one recurring Wednesday. "
|
||
+ "There are procedures whose purpose has been forgotten, because every attempt to "
|
||
+ "write the purpose down removes another person from the archive.")
|
||
+ P("<strong>Unresolved does not mean harmless.</strong> It means somebody found a "
|
||
+ "procedure that limits the damage without understanding why it works. A Night "
|
||
+ "Warden checks the seal. A Registry Officer confirms the names. Somebody replaces "
|
||
+ "the bowl of milk, winds the silent clock, reads the number over a secure line, or "
|
||
+ "leaves one chair empty.")
|
||
+ CLOSER("Some of these duties are older than the explanation for them.")
|
||
},
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
{ name: "5 · Why you were recruited", content:
|
||
P("Most people cannot work near crossings for long.")
|
||
+ P("They look past contradictions. Their memories quietly update to match the latest "
|
||
+ "version of events. They are violently sick, or they dissociate, or they accept an "
|
||
+ "impossibility as though it had always been ordinary. This is usually protective. "
|
||
+ "Human minds are very good at continuing to function.")
|
||
+ P("<strong>Yours does something slightly different.</strong>")
|
||
+ P("The department calls it <strong>continuity</strong>, and does not know what it is.")
|
||
+ P("It runs in families without following any clean pattern of inheritance. Certain "
|
||
+ "genetic markers turn up more often among agents and none of them predicts it. "
|
||
+ "Older texts describe an unusually <em>well-seated</em> soul. A twentieth-century "
|
||
+ "programme argued that consciousness leaves a persistent informational pattern. "
|
||
+ "Another department maintains that continuity is simply social: people who are "
|
||
+ "strongly remembered resist being rewritten.")
|
||
+ P("All of those have been tested. None of them explains everybody.")
|
||
+ H(2, "What it means in practice")
|
||
+ UL(["When reality changes its account, <strong>you are more likely to remember the previous one</strong>.",
|
||
"You can go through a controlled crossing and come back recognisably yourself.",
|
||
"You can look at two mutually exclusive facts and know the contradiction is real."])
|
||
+ H(2, "What it is not")
|
||
+ P("<strong>It is not a superpower.</strong> You are not immune to crossings. You can "
|
||
+ "still be hurt, altered, duplicated, forgotten or killed. Continuity does not make "
|
||
+ "you stronger, faster or braver, and it does not tell you what an anomaly is or how "
|
||
+ "to stop it.")
|
||
+ P("It means that when the impossible happens you have a better chance of noticing — "
|
||
+ "and of carrying the memory home.")
|
||
+ CLOSER("For the department, that is enough to build a career on.")
|
||
},
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
{ name: "6 · Who your character is", content:
|
||
P("A modern adult whose life was recognisable before the department turned up in it.")
|
||
+ P("They might have been a doctor, an engineer, an academic, a police officer, a "
|
||
+ "construction worker, an IT specialist, a scientist, a linguist, an entertainer or "
|
||
+ "a criminal. They might already have served inside the department in one of its "
|
||
+ "field postings. Either way, <strong>what they are good at comes from work, "
|
||
+ "education and hard practice — not from destiny.</strong>")
|
||
+ P("A doctor is valuable because they are a doctor. A burglar understands locks "
|
||
+ "because they spent years opening them. A builder can tell when a building is "
|
||
+ "carrying weight wrongly. A police officer can control a dangerous scene. An "
|
||
+ "entertainer can hold a room that does not want to listen.")
|
||
+ H(2, "The department adds six weeks")
|
||
+ P("Induction: how to recognise a crossing, set a cordon, handle evidence, fire the "
|
||
+ "issued weapon, survive first contact, and complete the forms that will very likely "
|
||
+ "matter more than the gun.")
|
||
+ P("<strong>Six weeks does not make anybody an expert.</strong> A surgeon recruited "
|
||
+ "last year is still a far better surgeon than they are a Custodian. Your prior "
|
||
+ "career sits at <strong>"
|
||
+ `${TRADE_BANDS.core[0]}–${TRADE_BANDS.core[1]}%</strong>; what the department taught `
|
||
+ `you starts at <strong>${INDUCTION.bandByTier.probationary[0]}–`
|
||
+ `${INDUCTION.bandByTier.probationary[1]}%</strong> and climbs with service.`)
|
||
+ P("<em>That gap is deliberate, and it is often frightening.</em>")
|
||
+ H(2, "Why you stayed")
|
||
+ P("You may have come willingly. You may have survived an incident and learned too "
|
||
+ "much to be let go. You may have been offered a choice whose other option was not "
|
||
+ "really a choice. The department might have lost a conviction, saved a relative, "
|
||
+ "bought out a contract, or simply been the first organisation to believe you.")
|
||
+ P("<strong>You were not picked for being fearless.</strong> You were picked because "
|
||
+ "you can remember, because you have a useful human skill, and because there are "
|
||
+ "never enough people for the work waiting tomorrow morning.")
|
||
+ H(2, "Seven principles for building one")
|
||
+ OL(["<strong>You are from the 2020s.</strong> Your references, assumptions, work and relationships are contemporary.",
|
||
"<strong>You had a life before this.</strong> Decide what you did well enough that the department needed it.",
|
||
"<strong>You are not superhuman.</strong> Training, teamwork, equipment and preparation keep you alive.",
|
||
"<strong>Continuity is not immunity.</strong> You notice changes better than most people. The changes can still happen to you.",
|
||
"<strong>You have a reason to stay.</strong> Duty, debt, curiosity, guilt, protection, belonging — or knowing nobody else will do it.",
|
||
"<strong>You need the team.</strong> No posting or trade holds every answer. The lowest-ranked person in the room is often the only real expert in it.",
|
||
"<strong>Decide what anchors you.</strong> Name a person, an object, a place or a habit that reminds you who you are when the records disagree."])
|
||
+ CLOSER("The department does not need heroes. It needs people who will turn up, look "
|
||
+ "straight at the impossible, and still remember what they came to do.")
|
||
},
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
{ name: "7 · What the job is actually like", content:
|
||
P("An operation usually starts with an incomplete briefing.")
|
||
+ P("Something has happened. A person has vanished without leaving. An impossible "
|
||
+ "object has been recovered. An old containment has failed. Somebody has opened a "
|
||
+ "route that was supposed to stay shut. You get an objective, equipment, a cover "
|
||
+ "story, and as much authority as the department is willing to admit it sent.")
|
||
+ P("<strong>Then you find out what the briefing got wrong.</strong>")
|
||
+ P("You may go through records, talk to witnesses, cross into another version of the "
|
||
+ "world, walk unfamiliar ground, make contact with whoever lives there, recover "
|
||
+ "people or evidence, and contain what is immediately dangerous. Sometimes that is a "
|
||
+ "negotiation. Sometimes it is engineering. Sometimes it is holding a corridor with a "
|
||
+ "rifle and a shield while somebody else repairs the only way home.")
|
||
+ P("Fighting is dangerous and often unavoidable, and <strong>killing is rarely the "
|
||
+ "whole answer</strong>. Shoot the creature and the crossing that produced it is "
|
||
+ "still open. Beat the Cleaner and the evidence they came for is still lying there. "
|
||
+ "Cases close when there is an answer reality can live with.")
|
||
+ H(2, "Then you come home")
|
||
+ P("You are debriefed. Reports are compared. Equipment goes back, except what was "
|
||
+ "lost, broken, or has started behaving differently. The department decides what "
|
||
+ "officially happened. You get rest, if the schedule allows it.")
|
||
+ CLOSER("Sooner or later, another file arrives.")
|
||
},
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
{ name: "8 · What it costs", content:
|
||
P("Crossing leaves a mark.")
|
||
+ P("The department measures your connection to your own reality as "
|
||
+ "<strong>Coherence</strong>. It is not sanity and it is not morality. "
|
||
+ "<strong>It is how firmly the world still recognises that you belong here.</strong>")
|
||
+ P("Watching a paradox, using transposed equipment, breaking the physics of another "
|
||
+ "place, meeting another version of yourself, or coming back badly all cost you some.")
|
||
+ H(2, "How it goes")
|
||
+ TABLE(["Coherence", "Where you are", "What it costs you"],
|
||
COHERENCE_BANDS.map((b, i) => {
|
||
const hi = i === 0 ? 10 : COHERENCE_BANDS[i - 1].min - 1;
|
||
const eff = [b.all ? `${pc(b.all)} to everything` : "",
|
||
b.comm ? `${pc(b.comm)} to talking to people` : ""]
|
||
.filter(Boolean).join(", ") || "nothing yet";
|
||
return [b.min === hi ? `${b.min}` : `${hi}–${b.min}`,
|
||
`<strong>${L(b.label)}</strong>`, eff];
|
||
}))
|
||
+ P("Early on it is small. People mishear your name. Automatic doors hesitate. You look "
|
||
+ "very slightly misplaced in photographs. Later, records disagree about where you "
|
||
+ "work, people you love remember conversations differently, and the way home gets "
|
||
+ "harder to aim.")
|
||
+ H(2, "Getting it back")
|
||
+ P("Debriefing, time at home, and contact with people or things that remember you "
|
||
+ "correctly. <strong>Recovery is slow, and some of it never entirely comes back.</strong>")
|
||
+ P("<em>This is what the anchor in your kit is for. It is one object that remembers "
|
||
+ "you as you were, and it is the cheapest medicine the department issues.</em>")
|
||
+ H(2, "The Quiet Arts")
|
||
+ P("Very occasionally a crossing leaves somebody able to commit a small impossibility "
|
||
+ "on purpose. The department calls these the <strong>Quiet Arts</strong>.")
|
||
+ P("They are not gifts. They cannot be chosen at recruitment. They always cost more of "
|
||
+ "your connection to the world. Most Custodians never get one.")
|
||
+ P("<strong>Those who do are not superheroes. They are injured people who have learned "
|
||
+ "how to press on the injury.</strong>")
|
||
},
|
||
|
||
/* ---------------------------------------------------------------- */
|
||
{ name: "9 · The whole game, in one page", content:
|
||
P("You play ordinary adults in the modern world, pulled into an old and quiet "
|
||
+ "government department because you stay yourselves when reality goes wrong.")
|
||
+ P("You investigate crossings, recover the lost, face hostile people and impossible "
|
||
+ "things, negotiate with strangers, contain what can be contained, and decide what "
|
||
+ "the official record will say happened. You carry modern tools, professional "
|
||
+ "experience, an issued weapon and incomplete information.")
|
||
+ P("You can fight. Violence alone rarely closes a case. You can come home, and every "
|
||
+ "journey makes home a little less certain.")
|
||
+ P("The department has done this for longer than any living government, and expects to "
|
||
+ "carry on long after you.")
|
||
+ READ("There will always be another file.<br>"
|
||
+ "There will always be something here that should not be.<br>"
|
||
+ "<strong>Your job is to go there and sort it out.</strong>")
|
||
},
|
||
|
||
/* ---------------------------------------------------------------- *
|
||
* The cheat sheet. Numbers computed, not typed.
|
||
* ---------------------------------------------------------------- */
|
||
{ name: "10 · Cheat sheet — everything you need at the table", content:
|
||
FORM("Departmental Custody Service · <b>Field aide-memoire</b><br>"
|
||
+ "One page. Keep it beside you. <b>You do not need to read anything else to play.</b>")
|
||
|
||
+ H(2, "The only rule you must know")
|
||
+ P("<span class=\"rb-big-number\">Roll 1d100. Get equal to or under your skill.</span>"
|
||
+ "That is the whole engine. Everything else changes that number, or is a consequence "
|
||
+ "of the result.")
|
||
+ TABLE(["Roll", "Result", "What it means"], [
|
||
["01 to a twentieth of your skill", "<strong>Critical</strong>", "the best version of what you wanted"],
|
||
["up to a fifth of your skill", "<strong>Special</strong>", "notably better than you asked for"],
|
||
["up to your skill", "<strong>Success</strong>", "you do it"],
|
||
["over your skill", "Failure", "you do not"],
|
||
["the top 5% of the range", "<strong>Fumble</strong>", "you do it wrong, and it costs"]
|
||
])
|
||
+ P("<strong>The sheet prints those four numbers next to every skill</strong>, so you "
|
||
+ "never work them out. A skill of 60 criticals on 01–03, specials to 12, succeeds to "
|
||
+ "60 and fumbles on 98–00.")
|
||
+ P("Two rules beat everything: <strong>96–99 never succeed</strong>, however good you "
|
||
+ "are, and <strong>00 is always a fumble</strong>. No skill is ever certain — and "
|
||
+ "none is ever hopeless either, because the floor is 1%.")
|
||
|
||
+ H(2, "The three things that change your number")
|
||
+ CARDS([
|
||
["1 · Difficulty",
|
||
P("Set by the GM <em>before</em> you roll.")
|
||
+ P("<strong>Easy</strong> doubles your skill. <strong>Average</strong> leaves it "
|
||
+ "alone. <strong>Difficult</strong> halves it.")],
|
||
["2 · Circumstance",
|
||
P("The situation, up to " + pc(Math.max(...CIRCUMSTANCE.map(c => c.mod)))
|
||
+ " in your favour or " + pc(Math.min(...CIRCUMSTANCE.map(c => c.mod))) + " against.")
|
||
+ P("At most <strong>two</strong> apply — the best good one and the worst bad one — "
|
||
+ "and they cap at ±40%.")],
|
||
["3 · Your condition",
|
||
P("Wounds, what you are carrying and how far you have drifted.")
|
||
+ P("<strong>All three are already on your sheet and applied for you.</strong>")]
|
||
])
|
||
+ P("<em>Difficulty first, then everything else. A skill can never drop below 1%.</em>")
|
||
|
||
+ H(2, "Fighting")
|
||
+ CARDS([
|
||
["Who goes first",
|
||
P("<strong>Reaction</strong>, re-rolled every round including the first. Your "
|
||
+ "printed number plus a d6. Highest acts first.")],
|
||
["Attacking",
|
||
P("Roll the weapon's skill. The dialog asks you the questions — range, cover, "
|
||
+ "light, how you are firing — and does the arithmetic.")],
|
||
["Defending",
|
||
P("<strong>The first defence each round is free.</strong> Each one after that is "
|
||
+ pc(defencePenaltyFor(1)) + ", then " + pc(defencePenaltyFor(2)) + ".")],
|
||
["Defences are graded",
|
||
P("A defence stops a blow of its own quality or worse. Against something better it "
|
||
+ "only drags it down a step.")
|
||
+ P("<strong>Only a critical stops a critical.</strong>")]
|
||
])
|
||
+ TABLE(["Range", "To hit"],
|
||
RANGE_LADDER.map(r => [L(`RINGBRP.Range.${r.id}`),
|
||
r.mod === null ? "<em>cannot be hit at all</em>" : pc(r.mod)]))
|
||
|
||
+ H(2, "Getting hurt")
|
||
+ CARDS([
|
||
["Hit points",
|
||
P("<span class=\"rb-big-number\">" + egHp + "</span>"
|
||
+ "(CON + SIZ) ÷ 2, rounded up. The example agent has CON " + EG.con + " and SIZ "
|
||
+ EG.siz + ".")],
|
||
["Major Wound",
|
||
P("<span class=\"rb-big-number\">" + egMw + "</span>"
|
||
+ "Half your hit points in <strong>one blow</strong>. Roll on the table and "
|
||
+ "something specific and lasting happens.")],
|
||
["Damage modifier",
|
||
P("<span class=\"rb-big-number\">" + egDm + "</span>"
|
||
+ "STR + SIZ on a ladder. Added to what you hit with.")],
|
||
["Zero hit points",
|
||
P("<strong>You are dying, not dead.</strong> A clock starts, equal to your Major "
|
||
+ "Wound number, and somebody can still reach you.")]
|
||
])
|
||
+ P("Damage comes off your total <strong>and</strong> the part of you it hit. Armour "
|
||
+ "only counts where it actually covers — a helmet does nothing for your legs.")
|
||
|
||
+ H(2, "Coherence")
|
||
+ P("Ten down to zero. How firmly the world still agrees you belong here. It is not "
|
||
+ "sanity. Spend it, lose it to paradoxes, get it back slowly at home.")
|
||
+ P("<strong>Watch the band, not the number</strong> — the sheet tells you which one you "
|
||
+ "are in and what it is costing you.")
|
||
|
||
+ H(2, "Six things new players ask")
|
||
+ TABLE(["", ""], [
|
||
["<strong>Can I just shoot it?</strong>",
|
||
"Often, yes. It rarely closes the case — the crossing that produced it is still open."],
|
||
["<strong>What do I roll?</strong>",
|
||
"Say what you are doing. The GM names the skill. It is on your sheet with its four numbers beside it."],
|
||
["<strong>I failed. Now what?</strong>",
|
||
"The story continues. A failure costs time, resources, position or clarity — it does not stop the case."],
|
||
["<strong>Can I help somebody?</strong>",
|
||
"Yes, and you should. Assisting is a real action, and most specialist scenes want a second pair of hands."],
|
||
["<strong>My skill is 5%. Why?</strong>",
|
||
"You are untrained at it. That is honest, not a mistake. Ask whoever <em>is</em> trained."],
|
||
["<strong>Am I going to die?</strong>",
|
||
"You can. You are much more likely to come home changed, out of pocket, and holding a form you do not want to sign."]
|
||
])
|
||
+ CLOSER("Roll under. Ask questions. Take the shield.")
|
||
}
|
||
];
|