Files
RingBRP/postings.mjs
T
slaguru666andClaude Opus 5 774e95dea8 THROUGH TRAIN — the crossing starter, and two more playtest fixes
A train has been running the same four miles of track since 3 November 1881. It
has never stopped. Sixty-one people are aboard and all of them are alive.

The supernatural is science fiction underneath, which is the point. A railway
company laid track to a filed survey instead of to the ground, then described the
line as being where it was not — ten thousand times, in timetables and waybills
and telegraph orders, for six months, at a constant speed. Reality keeps a record
of what belongs where, and that is the most patient argument there is. The record
gave way with No. 9 inside it, and the RUNNING is what holds the crossing open: a
standing wave sustained by its own motion the way a bow sustains a note.

So the players must board a train that cannot stop, and then find that sixty-one
people at six passes is four hours they do not have. The ending is what they
choose to do about arithmetic they cannot beat, in front of a conductor holding
the manifest. No roll resolves it.

It is also the case that teaches Standing Order 9: NOTHING MODERN GOES THROUGH.
Using a modern object across costs a Coherence and moves the clock; carrying it
costs nothing; anchors are exempt. The catalogue already had the 1881 issue —
Webley, Martini-Henry, oil lantern, brass compass, pocket watch, buff coat,
laudanum — so the constraint needed no new content and gives the table something
to feel in the first twenty minutes.

Ships as docs/scenarios/THROUGH_TRAIN.md and a Foundry Adventure: 7 GM pages, 6
handouts including the survey that started it and a manifest deliberately held
back to Act Three, the case file at Containment 6 / Resources 5 / Clearance 4
with its four legs loaded, four of the people aboard, and 7 plates to show.

Two fixes from playing it:

  - Bhattacharya's RESEARCH was 1%. Placing the new skills last night I swapped
    Occult into Registry's core and took Research out — a records office that
    cannot look anything up. Research is back in core; Antiquities gets its
    Knowledge back the same way.

  - The boarding was unrunnable. At halved skill the set-piece put four agents on
    12–31% and all four missed, which stalls the one scene the scenario is built
    around. It is an average roll now and only a fumble is a fall, with the
    reason written into the text so nobody "fixes" it back. Re-run: 3 of 4 aboard
    on the first pass and one waiting for the next, which is the shape it wanted.

Version 1.3.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 00:25:19 +01:00

408 lines
26 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* THE REGISTER — postings, trades, tiers and what stores hands out.
*
* Pure data, and deliberately free of Foundry: the engine imports it, the rulebook
* generator imports it, the guards import it and the tests import it. Until now the
* guards and the rulebook read these tables out of `ringbrp.mjs` with a regular
* expression and `eval`, because that file reaches for `game` on load and cannot be
* imported outside a browser. That worked and it was a trap — a table could be
* reformatted into something the regex no longer matched and every check that
* depended on it would quietly stop checking.
*
* Nothing in this file may import from the runtime or touch a Foundry global. The
* same rule rules.mjs lives by, for the same reason.
*/
/* ---------------- roles ---------------- */
/** Each role is a skill emphasis, a kit, a talent leaning and a rank feel. */
export const ROLES = {
lead: { label: "Field Lead",
blurb: "Runs the team on the ground and signs for what happens to it. Firearms, tradecraft and the nerve to go first.", stat: "dex",
core: ["firearm:pistol","dodge","tradecraft","navigate","athletics","stealth"],
support: ["insight","spot","first_aid","melee_weapon:knife","pilot:ground_car"],
talents: ["dead_reckon","first_through","hard_landing","cover_work"],
kit: ["pistol_med","soft_armour","cover_id","key","torch", "warrant_card", "cordon_kit", "door_wedges"] },
technical: { label: "Technical",
blurb: "Field systems, electronics and the physics of a site that is behaving incorrectly. Builds and breaks the equipment.", stat: "int",
core: ["engineering:field_systems","repair:electronics","computer_use","anomaly_lore","science:physics"],
support: ["repair:mechanical","research","first_aid","firearm:pistol","demolition"],
talents: ["chain_custody","requisition","clean_scene","echo_sense"],
kit: ["pistol_light","stab_vest","toolkit","scanner","power_cell", "density_scanner", "probe", "thermometer"] },
talker: { label: "Liaison",
blurb: "The face the department shows a witness. Reads a room, holds a cover, and gets the sentence nobody meant to say.", stat: "cha",
core: ["insight","persuade","fast_talk","bargain","anthropology","language:trade_cant"],
support: ["tradecraft","xenology:baseline","spot","status","firearm:pistol"],
talents: ["read_room","cover_work","debriefer","wrong_memory"],
kit: ["pistol_light","jacket","cover_id","notebook","camera", "blanket", "clipboard", "vacuum_flask"] },
medic: { label: "Physician",
blurb: "Keeps agents alive and works out what a body has been through. The only posting that can undo a Major Wound.", stat: "int",
core: ["medicine","first_aid","science:biology","insight","xenology:baseline"],
support: ["anthropology","spot","dodge","firearm:pistol","research"],
talents: ["triage","debriefer","read_room","not_quite_here"],
kit: ["pistol_light","stab_vest","medkit","fieldmedic","sample_case", "analgesics", "blanket", "specimen_jars"] },
heavy: { label: "Containment",
blurb: "Containment. Goes through the door, holds the corridor, and puts things in boxes that do not want to be in boxes.", stat: "str",
core: ["firearm:rifle","brawl","melee_weapon:prybar","athletics","dodge"],
support: ["demolition","first_aid","repair:mechanical","spot","melee_weapon:shield"],
talents: ["hard_landing","chain_custody","first_through","clean_scene"],
kit: ["rifle_med","breach_suit","prybar","riot_shield","restraints","climbing_kit", "bolt_croppers", "cordon_kit", "ear_defenders"] },
/* ---------------------------------------------------------------
The rest of the establishment.
Five postings were never the whole agency — they were the ones a
field team fields. These are the other twenty on the books: the
registry that keeps the record crossings are made against, the
archaic postings the agency has never got round to abolishing, and
the specialists nobody calls until the day they are the only thing
that helps. Each carries its own kit, and each kit has at least one
thing no other posting is issued.
--------------------------------------------------------------- */
registry: { label: "Registry Officer",
blurb: "Keeps the record that a crossing is made against. Knows what the file says and, more usefully, what it used to say.", stat: "edu",
core: ["research","occult","knowledge","anomaly_lore","language:own"],
support: ["computer_use","insight","spot","first_aid","tradecraft","firearm:pistol"],
talents: ["chain_custody","wrong_memory","debriefer","quorum"],
kit: ["spectacles","notebook","handset","jacket","pistol_light", "carbon_book", "date_stamp", "seals"] },
survey: { label: "Ground Survey Officer",
blurb: "Reads ground. Establishes where a site actually is, how it is shaped, and which way out will still be there later.", stat: "int",
core: ["navigate","engineering:field_systems","science:physics","spot","athletics"],
support: ["track","stealth","first_aid","repair:mechanical","firearm:pistol"],
talents: ["dead_reckon","first_through","hard_landing","echo_sense"],
kit: ["survey_kit","brass_compass","binocs","oilcloth_coat","rope", "probe", "groundsheet", "chalk"] },
anchor: { label: "Anchor Officer",
blurb: "Holds the door open. Transposition, and the discipline to stay filed correctly while doing it.", stat: "pow",
core: ["transposition","anomaly_lore","insight","listen","dodge"],
support: ["knowledge","spot","first_aid","tradecraft","research"],
talents: ["out_of_step","borrowed_hour","not_quite_here","distributed"],
kit: ["anchor","threshold_key","handset","power_cell","soft_armour", "locator_tags", "cold_light", "blanket"] },
interview: { label: "Interview Officer",
blurb: "Sits with the witness afterwards. Patient, unhurried, and very hard to lie to twice.", stat: "cha",
core: ["insight","persuade","listen","language:own","anthropology"],
support: ["psychology","spot","tradecraft","first_aid","firearm:pistol"],
talents: ["debriefer","read_room","wrong_memory","unblinking"],
kit: ["dictaphone","cover_id","notebook","jacket","pistol_light", "carbon_book", "vacuum_flask", "clipboard"] },
warden: { label: "Night Warden",
blurb: "Sits with a site overnight so that nobody else has to. Listens, watches, and writes down the times.", stat: "con",
core: ["listen","spot","stealth","dodge","brawl"],
support: ["first_aid","melee_weapon:shield","athletics","melee_weapon:club","anomaly_lore"],
talents: ["unblinking","out_of_step","first_through","clean_scene"],
kit: ["oil_lantern","ward","cudgel","riot_shield","stab_vest","torch", "vacuum_flask", "stopwatch", "blanket"] },
stores: { label: "Stores Officer",
blurb: "Requisition, custody and the paperwork that moves materiel. Can get you a thing the department says it does not have.", stat: "edu",
core: ["bargain","status","knowledge","repair:mechanical","computer_use"],
support: ["insight","research","first_aid","firearm:pistol","tradecraft"],
talents: ["requisition","chain_custody","quorum","debriefer"],
kit: ["sealed_cannister","spare_cells","rations","water","jacket", "carbon_book", "seals", "master_keys"] },
transport: { label: "Transport Officer",
blurb: "Drives, flies, and gets a wounded team off a site. Keeps the vehicle running with what is in the boot.", stat: "dex",
core: ["pilot:ground_car","pilot:aircraft","navigate","repair:mechanical","spot"],
support: ["dodge","athletics","first_aid","firearm:pistol","listen"],
talents: ["dead_reckon","hard_landing","first_through","borrowed_hour"],
kit: ["beacon","revolver","impact_vest","torch","rope", "master_keys", "groundsheet", "blanket"] },
pathology: { label: "Pathology Officer",
blurb: "Examines what is left. Establishes what a thing was, which is usually the question the case turns on.", stat: "int",
core: ["medicine","science:biology","xenology:baseline","insight","research"],
support: ["first_aid","spot","religion","dodge","melee_weapon:knife"],
talents: ["triage","chain_custody","unblinking","clean_scene"],
kit: ["chirurgeon_kit","gas_mask","envsuit","sample_case","dagger", "specimen_jars", "swab_kit", "barrier_gloves"] },
materials: { label: "Materials Officer",
blurb: "Substances, residues and the objects a site leaves behind. Handles what nobody else is cleared to touch.", stat: "int",
core: ["science:physics","science:botany","repair:electronics","research","anomaly_lore"],
support: ["engineering:field_systems","spot","first_aid","computer_use","firearm:pistol"],
talents: ["chain_custody","echo_sense","requisition","quorum"],
kit: ["field_kit","geiger","breather","stab_vest","pistol_light", "specimen_jars", "barrier_gloves", "seal_foam"] },
recording: { label: "Recording Officer",
blurb: "Documents the site as found. Photographs, measurements and an exhibit trail that survives a tribunal.", stat: "dex",
core: ["art","spot","computer_use","sleight_of_hand","stealth"],
support: ["repair:electronics","insight","first_aid","listen","firearm:pistol"],
talents: ["clean_scene","chain_custody","cover_work","echo_sense"],
kit: ["optic_visor","data_wafer","evidence_tape","jacket","pistol_light", "uv_lamp", "cordon_kit", "chalk"] },
access: { label: "Access Officer",
blurb: "Gets the team into places the owner has locked, and out again without a record of either.", stat: "dex",
core: ["sleight_of_hand","stealth","repair:mechanical","spot","dodge"],
support: ["computer_use","athletics","first_aid","tradecraft","melee_weapon:knife"],
talents: ["first_through","clean_scene","cover_work","out_of_step"],
kit: ["iron_manacles","monoblade","key","toolkit","soft_armour", "lock_rakes", "master_keys", "door_wedges"] },
disposal: { label: "Disposal Officer",
blurb: "Renders a thing safe, or renders it gone. Demolition, containment and a very steady hand.", stat: "int",
core: ["demolition","repair:electronics","engineering:field_systems","spot","dodge"],
support: ["first_aid","athletics","anomaly_lore","firearm:rifle","melee_weapon:axe"],
talents: ["first_through","hard_landing","chain_custody","unblinking"],
kit: ["field_net","entrenching_tool","hardsuit","toolkit","torch", "seal_foam", "cordon_kit", "ear_defenders"] },
overwatch: { label: "Overwatch Officer",
blurb: "Holds the long angle and tells the team what is coming. Shoots when nothing else will do.", stat: "dex",
core: ["firearm:rifle","spot","stealth","dodge","athletics"],
support: ["navigate","first_aid","listen","track","firearm:pistol"],
talents: ["dead_reckon","unblinking","out_of_step","hard_landing"],
kit: ["rifle_heavy","binocs","soft_armour","rations","torch", "spyglass", "groundsheet", "cold_light"] },
rigging: { label: "Rigging Officer",
blurb: "Height, depth and confined access. Gets people and equipment up and down shafts that were not built for it.", stat: "str",
core: ["athletics","repair:mechanical","engineering:field_systems","dodge","melee_weapon:axe"],
support: ["first_aid","spot","navigate","brawl","stealth"],
talents: ["hard_landing","first_through","requisition","distributed"],
kit: ["boarding_axe","climbing_kit","rope","impact_vest","torch", "bolt_croppers", "probe", "door_wedges"] },
translation: { label: "Translation Officer",
blurb: "Language, sign and the things said in neither. Reads a document nobody else in the building can.", stat: "int",
core: ["language:trade_cant","language:sign","language:own","anthropology","insight"],
support: ["research","knowledge","first_aid","xenology:baseline","firearm:pistol"],
talents: ["debriefer","read_room","quorum","wrong_memory"],
kit: ["wax_tablet","notebook","handset","jacket","pistol_light", "quill_ink", "carbon_book", "spectacles"] },
naturalist: { label: "Field Naturalist",
blurb: "Living things, and things that are pretending to be. Tracks, samples and identifies what came through.", stat: "int",
core: ["science:botany","science:biology","track","scent","spot"],
support: ["navigate","stealth","first_aid","athletics","melee_weapon:sword"],
talents: ["dead_reckon","echo_sense","unblinking","triage"],
kit: ["machete","sample_case","binocs","oilcloth_coat","rations", "specimen_jars", "swab_kit", "groundsheet"] },
antiquities: { label: "Antiquities Officer",
blurb: "An archaic posting the department never abolished. Old objects, older records, and the manners to ask about both.", stat: "edu",
core: ["religion","art","anomaly_lore","research","status"],
support: ["knowledge","insight","spot","first_aid","melee_weapon:sword","firearm:pistol"],
talents: ["chain_custody","wrong_memory","borrowed_hour","quorum"],
kit: ["pocket_watch","tallow_candle","duelling_sword","brigandine","flintlock", "quill_ink", "sealing_wax", "sand_glass"] },
pursuit: { label: "Pursuit Officer",
blurb: "Follows what has left the site. Ground, scent, and the stamina to keep going after it stops being sensible.", stat: "con",
core: ["track","athletics","spot","listen","stealth"],
support: ["navigate","dodge","first_aid","scent","firearm:rifle"],
talents: ["dead_reckon","first_through","out_of_step","unblinking"],
kit: ["carbine","restraints","soft_armour","rations","torch", "locator_tags", "cold_light", "wake_tablets"] },
settlements: { label: "Settlements Officer",
blurb: "Makes the arrangement, files it, and never speaks of the terms again. Most cases close here rather than in a fight.", stat: "cha",
core: ["bargain","status","insight","persuade","knowledge"],
support: ["research","anthropology","first_aid","tradecraft","firearm:pistol"],
talents: ["read_room","debriefer","requisition","quorum"],
kit: ["quiet_ledger","cover_id","notebook","jacket","pistol_light", "carbon_book", "sealing_wax", "vacuum_flask"] },
signals: { label: "Signals Officer",
blurb: "Communications, interception and the electronics of a site that is broadcasting when it should not be.", stat: "int",
core: ["repair:electronics","computer_use","listen","engineering:field_systems","spot"],
support: ["research","first_aid","dodge","firearm:pistol","anomaly_lore"],
talents: ["echo_sense","distributed","quorum","requisition"],
kit: ["survey_drone","handset","power_cell","stab_vest","pistol_light", "field_slate", "locator_tags", "uv_lamp"] }
};
/** Experience tiers: how good, and what the agency calls you. */
/**
* What every officer is issued regardless of posting, what seniority adds, and the
* one thing that is theirs rather than the department's.
*
* An agent used to leave creation with five things and an anchor, which is not what
* a real posting looks like — most of this job is small equipment and paperwork.
*/
/**
* TRADES — where the recruit came from before any of this.
*
* A posting is what the department made of you. A TRADE is what you were, and the
* department does not recruit specialists in crossings because there is no such
* degree: it recruits a doctor, a joiner, a detective sergeant, and puts them
* through six weeks at the training centre.
*
* So a trade character is built in two halves. The trade is genuine expertise, rated
* at the same bands a posting's skills are — a doctor is a real doctor. INDUCTION is
* the thin agency layer on top, and it is deliberately thin, because six weeks is not
* a career and the gap between the two is the whole texture of playing one.
*/
export const TRADES = {
builder: { label: "Construction Worker",
blurb: "Twenty years of sites, scaffold and other people's mistakes. Knows what a building is doing before it does it.", stat: "str",
core: ["athletics","repair:mechanical","melee_weapon:prybar","spot","brawl"],
support: ["demolition","engineering:field_systems","first_aid","listen","dodge"],
talents: ["hard_landing","first_through","clean_scene","unblinking"],
kit: ["prybar","toolkit","ear_defenders","site_overalls","groundsheet"] },
doctor: { label: "Doctor",
blurb: "A&E, mostly. Used to people at their worst and to being the calmest thing in the room.", stat: "edu",
core: ["medicine","first_aid","science:biology","insight","knowledge"],
support: ["research","psychology","persuade","listen","spot"],
talents: ["triage","debriefer","unblinking","clean_scene"],
kit: ["medkit","trauma_unit","analgesics","specimen_jars","swab_kit"] },
professor: { label: "Professor",
blurb: "A chair in something narrow, and a reading list nobody else has finished. Argues for a living.", stat: "edu",
core: ["knowledge","research","occult","language:own","status"],
support: ["insight","persuade","science:botany","listen","art"],
talents: ["debriefer","read_room","requisition","wrong_memory"],
kit: ["carbon_book","notebook","spectacles","clipboard","quill_ink"] },
engineer: { label: "Engineer",
blurb: "Chartered, and unimpressed. Wants to know what it is made of and what happens when it stops.", stat: "int",
core: ["repair:mechanical","repair:electronics","engineering:field_systems","computer_use","demolition"],
support: ["athletics","spot","knowledge","pilot:ground_car","first_aid"],
talents: ["hard_landing","requisition","chain_custody","first_through"],
kit: ["toolkit","spare_cells","probe","power_cell","field_slate"] },
police: { label: "Law Enforcement",
blurb: "Fifteen years on division. Knows how a statement is taken and how a scene is lost.", stat: "con",
core: ["firearm:pistol","spot","insight","brawl","tradecraft"],
support: ["fast_talk","listen","athletics","dodge","first_aid"],
talents: ["read_room","chain_custody","clean_scene","first_through"],
kit: ["revolver","restraints","stab_vest","evidence_tape","clipboard"] },
it: { label: "IT Specialist",
blurb: "Second line, then infrastructure. Has read the logs nobody else reads and believes them over people.", stat: "int",
core: ["computer_use","repair:electronics","research","knowledge","spot"],
support: ["insight","listen","tradecraft","sleight_of_hand","engineering:field_systems"],
talents: ["requisition","chain_custody","debriefer","echo_sense"],
kit: ["data_wafer","scanner","toolkit","cell_stack","field_slate"] },
scientist: { label: "Scientist",
blurb: "Postdoc, a lab, and a method. Will not say a thing is impossible, only that it is not yet measured.", stat: "edu",
core: ["science:physics","science:biology","research","knowledge","repair:electronics"],
support: ["science:botany","computer_use","spot","first_aid","listen"],
talents: ["chain_custody","requisition","debriefer","echo_sense"],
kit: ["scanner","specimen_jars","geiger","thermometer","sample_case"] },
linguist: { label: "Linguist",
blurb: "Six languages properly and four enough to argue in. Hears grammar where other people hear noise.", stat: "edu",
core: ["language:own","language:sign","language:trade_cant","anthropology","insight"],
support: ["research","knowledge","persuade","listen","status"],
talents: ["debriefer","read_room","wrong_memory","cover_work"],
kit: ["dictaphone","notebook","wax_tablet","carbon_book","translator_pin"] },
entertainer: { label: "Entertainer",
blurb: "Clubs, cruise ships and one season on television. Can hold a room that does not want to be held.", stat: "cha",
core: ["art","persuade","fast_talk","status","insight"],
support: ["athletics","sleight_of_hand","listen","language:own","dodge"],
talents: ["cover_work","read_room","debriefer","ambidextrous"],
kit: ["dictaphone","cover_id","camera","pocket_watch","vacuum_flask"] },
criminal: { label: "Criminal",
blurb: "Nothing organised. Doors, locks and other people's assumptions, and a caution the department has quietly lost.", stat: "dex",
core: ["stealth","sleight_of_hand","fast_talk","spot","dodge"],
support: ["brawl","melee_weapon:knife","bargain","insight","athletics"],
talents: ["cover_work","clean_scene","ambidextrous","read_room"],
kit: ["lock_rakes","dagger","master_keys","door_wedges","black_mirror"] }
};
/**
* INDUCTION — the agency half of a trade character.
*
* Six weeks at the training centre: how to hold a cordon, how to write it up, which
* end of the issued sidearm to point, and enough Anomaly Lore to know what you are
* looking at. It is rated LOW on purpose. A doctor recruited last year is still a
* far better doctor than they are a Custodian, and that gap is the point of playing
* one — a posting is a career, this is a course.
*/
/** The eight the data model defines, and what each is rolled with. */
export const CHARACTERISTIC_DICE = {
str: "3d6", con: "3d6", siz: "2d6+6", int: "2d6+6",
pow: "3d6", dex: "3d6", cha: "3d6", edu: "3d6+3"
};
/**
* What a TRADE is worth, independent of Custodian seniority.
*
* Trades used to be rated on the agency tier bands, which had it exactly backwards:
* a probationary burglar came out on 35–50% and a veteran one on 65–80%, as though
* fifteen years of picking locks were something the department conferred. Prior
* career is prior career. It does not improve because somebody was promoted, and it
* does not start low because somebody is new.
*
* Agency rank still governs everything that IS the department's doing: the induction
* band, the talents, the issue and the bonus points.
*/
export const TRADE_BANDS = { core: [50, 65], support: [30, 50] };
export const INDUCTION = {
label: "Induction",
blurb: "Six weeks at the training centre, and a warrant card that is still stiff.",
// Induction is the department's, so unlike the trade it DOES improve with service.
// A veteran who came in through a trade has been on the courses for years.
band: [25, 40],
bandByTier: {
probationary: [20, 32], officer: [25, 40], senior: [35, 50], veteran: [45, 60]
},
skills: ["tradecraft", "anomaly_lore", "first_aid", "firearm:pistol", "dodge"],
kit: ["pistol_light", "stab_vest", "cordon_kit", "cover_id", "ward"]
};
export const STANDING_ISSUE = ["anchor", "handset", "warrant_card", "dressings",
"torch", "chalk", "whistle", "notebook"];
/** Seniority is issued more, and is trusted with more. */
export const TIER_ISSUE = {
probationary: [],
officer: ["cover_id"],
senior: ["cover_id", "seals", "master_keys"],
veteran: ["cover_id", "seals", "master_keys", "carbon_book", "trauma_unit"]
};
/**
* One personal effect. Not issued, not logged, and the reason the anchor works —
* an agent who carries nothing of their own has nothing to be filed against.
*/
export const PERSONAL_EFFECTS = ["pocket_watch", "spectacles", "brass_compass",
"vacuum_flask", "notebook", "camera", "tallow_candle",
"wax_tablet", "sand_glass", "returning_coin"];
export const TIERS = {
probationary: { label: "Probationary", rank: "Probationary", core: [35, 50], support: [20, 35], talents: 1, bonusPts: 0 },
officer: { label: "Field Officer", rank: "Field Officer", core: [45, 60], support: [25, 45], talents: 2, bonusPts: 20 },
senior: { label: "Senior Field Officer", rank: "Senior Field Officer", core: [55, 70], support: [30, 50], talents: 3, bonusPts: 50 },
veteran: { label: "Case Officer", rank: "Case Officer", core: [65, 80], support: [35, 55], talents: 4, bonusPts: 90 }
};
/** NPC threat tiers — bystanders through anomalies, and the things in between. */
/**
* Threat tiers. `attacks` pairs a weapon with the EXACT skill that fires it —
* they are granted together or not at all. Previously the tier chose the weapon
* and an unrelated random role chose the skills, so most generated NPCs could not
* use what they were holding: eight Apexes in ten had no usable attack.
*/
export const THREATS = {
bystander: { label: "Bystander", hpMul: 1.0, armour: 0, skill: [15, 30], talents: 0, attacks: [] },
trained: { label: "Trained", hpMul: 1.0, armour: 1, skill: [30, 45], talents: 0,
attacks: [{ weapon: "dagger", skill: "melee_weapon:knife" }] },
armed: { label: "Armed", hpMul: 1.0, armour: 2, skill: [40, 55], talents: 0,
attacks: [{ weapon: "pistol_med", skill: "firearm:pistol" }] },
dangerous: { label: "Dangerous", hpMul: 1.2, armour: 3, skill: [50, 65], talents: 1,
attacks: [{ weapon: "rifle_med", skill: "firearm:rifle" },
{ weapon: "baton", skill: "melee_weapon:club" }] },
anomalous: { label: "Anomalous", hpMul: 1.5, armour: 5, skill: [55, 75], talents: 2,
attacks: [{ weapon: "grasp", skill: "brawl" }] },
apex: { label: "Apex", hpMul: 2.0, armour: 7, skill: [65, 85], talents: 3,
attacks: [{ weapon: "grasp", skill: "brawl" },
{ weapon: "unmaker", skill: "energy_weapon:rifle" }] }
};
/** Species: characteristic shifts and the location profile they use. */
export const SPECIES = {
baseline: { label: "Baseline", profile: "baseline", shift: {} },
vesh: { label: "Vesh", profile: "vesh", shift: { dex: +2, cha: -2, pow: +1 }, talents: ["unblinking","out_of_step"] },
cadence: { label: "Cadence", profile: "cadence", shift: { con: +2, str: -2, int: +1 }, talents: ["distributed","quorum"] }
};
/* ---------------- name pools ---------------- */
const GIVEN = ["Ceyla","Dunn","Rakhi","Tomas","Ambaro","Nils","Halina","Ottoline","Bez","Marek",
"Sunniva","Idris","Perpetua","Jorge","Nkechi","Vasha","Emeric","Lark","Tobin","Saoirse",
"Anneke","Ruben","Ilse","Cadogan","Mirren","Fenn","Orla","Kester","Zofia","Rune"];
const FAMILY = ["Marspont","Halvorsen","Oyelaran-Vost","Ekwueme","Sandoval","Achterberg","Quist",
"Delacroix-Ng","Bramall","Iwu","Fenwick","Oyelaran","Strand","Adeyemi","Kowalczyk","Rees-Mogg",
"Vanterpool","Okonkwo","Lindqvist","Brennan","Achebe","Dumont","Sarraceno","Halloran","Vance"];
const NPC_NAMES = { bystander:["Local","Witness","Neighbour","Publican","Warden","Ferryman"],
trained:["Constable","Ranger","Fisher","Guard","Surveyor"],
armed:["Contractor","Cleaner","Sentry","Enforcer"],
dangerous:["Team lead","Specialist","Hunter","Marksman"],
anomalous:["Revenant","Echo","Walker","The thing in the water"],
apex:["Displaced","The one that came back","Apex"] };
export const NAME_POOLS = { GIVEN, FAMILY, NPC_NAMES };