A player briefing, and the historical range
The generator was already writing the timeline, the cast and the texture and filing all of it behind the GM screen. New PLAYERS page: a read-aloud opening, what it is like there, what is known so far, who is there and what they want — but never what they lie about. Page ownership is now declared by the page rather than guessed from its index, which would have hidden any second player page. Historical range: 38 weapons (from 6) and 14 armours (from 2), each with its period stated, from arming swords and longbows through matchlocks and Brown Bess to the Lee-Enfield and a trench club. Five new skills to hang them on, including Firearm (Muzzle-loader), because a muzzle-loader is not a rifle. 275 icons; every weapon maps to a real skill and every item has art. Catalogue is 206 items across four eras. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
22a5067153
commit
e2d0ed5bb2
+73
-2
@@ -27,6 +27,10 @@ export const SKILL_CATALOGUE = [
|
||||
// The boarding axe and the entrenching tool both declare spec "axe" and the
|
||||
// catalogue had no such skill, so neither could ever be rated above zero.
|
||||
["melee_weapon", "axe", "melee", 5, "Melee Weapon (Axe)"],
|
||||
// The historical range needs somewhere to hang a halberd and a flail. Everything
|
||||
// else fits an existing specialisation: a mace is a club, a dirk is a knife.
|
||||
["melee_weapon", "polearm", "melee", 5, "Melee Weapon (Polearm)"],
|
||||
["melee_weapon", "flail", "melee", 5, "Melee Weapon (Flail)"],
|
||||
["variable_sword", "", "melee", 5, "Variable Sword"],
|
||||
// ranged
|
||||
["firearm", "pistol", "ranged", 5, "Firearm (Pistol)"],
|
||||
@@ -35,6 +39,10 @@ export const SKILL_CATALOGUE = [
|
||||
["energy_weapon", "rifle", "ranged", 5, "Energy Weapon (Rifle)"],
|
||||
["flashlight_laser", "", "ranged", 5, "Flashlight Laser"],
|
||||
["missile_weapon", "bow", "ranged", 5, "Missile Weapon (Bow)"],
|
||||
["missile_weapon", "sling", "ranged", 5, "Missile Weapon (Sling)"],
|
||||
["missile_weapon", "thrown", "ranged", 15, "Missile Weapon (Thrown)"],
|
||||
// A muzzle-loader is not a rifle. Loading is the skill and it is a different one.
|
||||
["firearm", "muzzleloader", "ranged", 5, "Firearm (Muzzle-loader)"],
|
||||
["heavy_weapon", "", "ranged", 5, "Heavy Weapon"],
|
||||
// communication
|
||||
["bargain", "", "comm", 5, "Bargain"],
|
||||
@@ -120,7 +128,55 @@ export const WEAPONS = [
|
||||
/* ---------- FUTURE. Recovered from somewhere ahead. ---------- */
|
||||
{ key: "gauss_pistol",name: "Gauss sidearm", cls: "energy", fam: "energy_weapon", spec: "pistol", dmg: "1d8+4", wound: "piercing", mod: false, ranges: [15,45,120], fire: "single", cap: 24, mass: 0.9, era: "future", trad: "tradition_transposed", energy: 4, desc: "No propellant and no report — a tap, and a hole. Ammunition is not manufacturable here." },
|
||||
{ key: "gauss_rifle", name: "Gauss lance-rifle", cls: "energy", fam: "energy_weapon", spec: "rifle", dmg: "1d12+4", wound: "piercing", mod: false, ranges: [40,120,300], fire: "single", cap: 12, mass: 3.8, era: "future", trad: "tradition_transposed", energy: 8, desc: "Punches an entry wound and an exit wound and very little between them." },
|
||||
{ key: "monoblade", name: "Monofilament blade",cls: "melee", fam: "melee_weapon", spec: "knife", dmg: "1d10+2", wound: "edged", mod: false, mono: true, ranges: [0,0,0], fire: "", cap: 0, mass: 0.4, era: "future", trad: "tradition_transposed", desc: "Cuts armour as though it were not there. Handle with the sheath on." }
|
||||
{ key: "monoblade", name: "Monofilament blade",cls: "melee", fam: "melee_weapon", spec: "knife", dmg: "1d10+2", wound: "edged", mod: false, mono: true, ranges: [0,0,0], fire: "", cap: 0, mass: 0.4, era: "future", trad: "tradition_transposed", desc: "Cuts armour as though it were not there. Handle with the sheath on." },
|
||||
|
||||
/* ==================================================================
|
||||
THE HISTORICAL RANGE
|
||||
|
||||
The department has been running since before it had a name, and it
|
||||
has never thrown anything away. Everything below is either still in
|
||||
a store somewhere in the building, or came back through a crossing
|
||||
with somebody. The period note is not decoration — a GM handing out
|
||||
a matchlock should know it is a matchlock.
|
||||
================================================================== */
|
||||
|
||||
/* --- medieval --- */
|
||||
{ key: "arming_sword", name: "Arming sword", cls: "melee", fam: "melee_weapon", spec: "sword", dmg: "1d8+1", wound: "edged", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.2, era: "antique", trad: "tradition_local", desc: "Medieval. A yard of cross-hilted steel. The plain, correct answer to most of the fifteenth century." },
|
||||
{ key: "longsword", name: "Longsword", cls: "melee", fam: "melee_weapon", spec: "sword", dmg: "1d10+1", wound: "edged", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.6, era: "antique", trad: "tradition_local", desc: "Medieval. Hand and a half. Wants room and rewards someone who has been taught." },
|
||||
{ key: "falchion", name: "Falchion", cls: "melee", fam: "melee_weapon", spec: "sword", dmg: "1d8+2", wound: "edged", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.5, era: "antique", trad: "tradition_local", desc: "Medieval. Heavy at the tip and unsubtle. A cleaver that got above itself." },
|
||||
{ key: "war_hammer", name: "War hammer", cls: "melee", fam: "melee_weapon", spec: "club", dmg: "1d8+2", wound: "blunt", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.7, era: "antique", trad: "tradition_local", desc: "Medieval. For plate, which it does not cut so much as dent inwards." },
|
||||
{ key: "mace", name: "Mace", cls: "melee", fam: "melee_weapon", spec: "club", dmg: "1d8+1", wound: "blunt", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.4, era: "antique", trad: "tradition_local", desc: "Medieval. Flanged. Requires no skill worth the name and never breaks." },
|
||||
{ key: "flail", name: "Military flail", cls: "melee", fam: "melee_weapon", spec: "flail", dmg: "1d10", wound: "blunt", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 2.0, era: "antique", trad: "tradition_local", desc: "Medieval. Goes round a shield and is nearly as dangerous behind you as in front." },
|
||||
{ key: "poleaxe", name: "Poleaxe", cls: "melee", fam: "melee_weapon", spec: "polearm", dmg: "1d10+2", wound: "edged", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 3.0, era: "antique", trad: "tradition_local", desc: "Medieval. Axe, hammer and spike on six feet of ash. The best answer to armour anyone found before gunpowder." },
|
||||
{ key: "halberd", name: "Halberd", cls: "melee", fam: "melee_weapon", spec: "polearm", dmg: "1d10+2", wound: "edged", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 3.2, era: "antique", trad: "tradition_local", desc: "Medieval. Cut, thrust or pull a rider off a horse. Useless indoors and the department keeps eleven." },
|
||||
{ key: "billhook", name: "Billhook", cls: "melee", fam: "melee_weapon", spec: "polearm", dmg: "1d8+2", wound: "edged", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 2.6, era: "antique", trad: "tradition_local", desc: "Medieval. A hedging tool with ambitions. Every parish had a rack of them." },
|
||||
{ key: "pike", name: "Pike", cls: "melee", fam: "melee_weapon", spec: "spear", dmg: "1d10+1", wound: "piercing", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 4.5, era: "antique", trad: "tradition_local", desc: "Medieval to Civil War. Sixteen feet. Magnificent in a field, absurd in a corridor." },
|
||||
{ key: "quarterstaff", name: "Quarterstaff", cls: "melee", fam: "melee_weapon", spec: "club", dmg: "1d8", wound: "blunt", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.8, era: "antique", trad: "tradition_local", desc: "Medieval. Six foot of ash. Legal to carry, which is most of the point." },
|
||||
{ key: "dirk", name: "Dirk", cls: "melee", fam: "melee_weapon", spec: "knife", dmg: "1d4+2", wound: "piercing", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 0.4, era: "antique", trad: "tradition_local", desc: "Medieval onward. Long in the blade for a knife and worn where a knife is not expected." },
|
||||
{ key: "longbow", name: "Longbow", cls: "bow", fam: "missile_weapon", spec: "bow", dmg: "1d10+1", wound: "piercing", mod: false, ranges: [30,90,180], fire: "fast", cap: 1, mass: 1.0, era: "antique", trad: "tradition_local", desc: "Medieval. Yew, and a draw weight that deforms the man who uses it. Faster than any firearm here." },
|
||||
{ key: "arbalest", name: "Arbalest", cls: "bow", fam: "missile_weapon", spec: "bow", dmg: "1d12", wound: "piercing", mod: false, ranges: [25,60,130], fire: "slow", cap: 1, mass: 5.0, era: "antique", trad: "tradition_local", desc: "Medieval. Steel prod, windlass span. One shot, and it goes through what it hits." },
|
||||
{ key: "sling", name: "Sling", cls: "bow", fam: "missile_weapon", spec: "sling", dmg: "1d8", wound: "blunt", mod: false, ranges: [20,50,110], fire: "fast", cap: 1, mass: 0.1, era: "antique", trad: "tradition_local", desc: "Ancient, and never actually obsolete. Ammunition is whatever is on the ground." },
|
||||
{ key: "javelin", name: "Javelin", cls: "thrown", fam: "missile_weapon", spec: "thrown", dmg: "1d8+1", wound: "piercing", mod: true, ranges: [10,20,40], fire: "fast", cap: 1, mass: 0.9, era: "antique", trad: "tradition_local", desc: "Ancient. Thrown, and then it is on the ground and somebody else has it." },
|
||||
|
||||
/* --- early modern --- */
|
||||
{ key: "rapier", name: "Rapier", cls: "melee", fam: "melee_weapon", spec: "sword", dmg: "1d8+1", wound: "piercing", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.1, era: "antique", trad: "tradition_local", desc: "Early modern. A yard and a half of point. For duels and for men who expect to be attacked in a street." },
|
||||
{ key: "main_gauche", name: "Main gauche", cls: "melee", fam: "melee_weapon", spec: "knife", dmg: "1d4+1", wound: "piercing", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 0.5, era: "antique", trad: "tradition_local", desc: "Early modern. The left-hand dagger. Its real job is catching the other man's blade." },
|
||||
{ key: "matchlock", name: "Matchlock musket", cls: "firearm", fam: "firearm", spec: "muzzleloader", dmg: "1d10+2", wound: "piercing", mod: false, ranges: [15,40,90], fire: "slow", cap: 1, mass: 4.8, era: "antique", trad: "tradition_local", desc: "Early modern. A burning cord and a prayer. Announces itself for a hundred yards before it fires." },
|
||||
{ key: "wheellock", name: "Wheellock pistol", cls: "firearm", fam: "firearm", spec: "muzzleloader", dmg: "1d8+1", wound: "piercing", mod: false, ranges: [8,18,35], fire: "slow", cap: 1, mass: 1.6, era: "antique", trad: "tradition_local", desc: "Early modern. Clockwork ignition, ruinously expensive, and it works in the rain." },
|
||||
{ key: "blunderbuss", name: "Blunderbuss", cls: "firearm", fam: "firearm", spec: "muzzleloader", dmg: "2d6+2", wound: "piercing", mod: false, ranges: [5,12,25], fire: "slow", cap: 1, mass: 4.0, era: "antique", trad: "tradition_local", desc: "Early modern. Load it with whatever is to hand. Terrible past twenty feet and decisive within it." },
|
||||
{ key: "boarding_pike", name: "Boarding pike", cls: "melee", fam: "melee_weapon", spec: "spear", dmg: "1d8+2", wound: "piercing", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 2.4, era: "antique", trad: "tradition_local", desc: "Early modern. Short enough for a deck. The department has them because the department used to have ships." },
|
||||
|
||||
/* --- Napoleonic and Victorian --- */
|
||||
{ key: "sabre", name: "Cavalry sabre", cls: "melee", fam: "melee_weapon", spec: "sword", dmg: "1d8+2", wound: "edged", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.3, era: "antique", trad: "tradition_local", desc: "Napoleonic. Curved, and meant to be used going past somebody at speed." },
|
||||
{ key: "smallsword", name: "Smallsword", cls: "melee", fam: "melee_weapon", spec: "sword", dmg: "1d6+1", wound: "piercing", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 0.6, era: "antique", trad: "tradition_local", desc: "Georgian. Worn with a coat, not with armour. Kills quietly and leaves very little to see." },
|
||||
{ key: "cutlass", name: "Cutlass", cls: "melee", fam: "melee_weapon", spec: "sword", dmg: "1d8+1", wound: "edged", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.1, era: "antique", trad: "tradition_local", desc: "Georgian. Short, heavy, and it does not care what it hits on the backswing." },
|
||||
{ key: "brown_bess", name: "Brown Bess", cls: "firearm", fam: "firearm", spec: "muzzleloader", dmg: "1d10+3", wound: "piercing", mod: false, ranges: [20,50,100], fire: "slow", cap: 1, mass: 4.4, era: "antique", trad: "tradition_local", desc: "Napoleonic. Smoothbore, inaccurate, and it will take an arm off at fifty yards." },
|
||||
{ key: "baker_rifle", name: "Baker rifle", cls: "firearm", fam: "firearm", spec: "muzzleloader", dmg: "1d10+2", wound: "piercing", mod: false, ranges: [40,110,250], fire: "slow", cap: 1, mass: 4.2, era: "antique", trad: "tradition_local", desc: "Napoleonic. Rifled, and slow to load precisely because it is. The first weapon here that rewards patience." },
|
||||
{ key: "bayonet", name: "Socket bayonet", cls: "melee", fam: "melee_weapon", spec: "knife", dmg: "1d6+1", wound: "piercing", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 0.5, era: "antique", trad: "tradition_local", desc: "Napoleonic onward. On the end of a musket it is a spear; off it, an awkward knife." },
|
||||
{ key: "martini", name: "Martini-Henry", cls: "firearm", fam: "firearm", spec: "rifle", dmg: "2d6+2", wound: "piercing", mod: false, ranges: [50,150,350], fire: "slow", cap: 1, mass: 4.0, era: "antique", trad: "tradition_local", desc: "Victorian. Single shot, falling block, and a recoil that has bruised generations." },
|
||||
{ key: "webley", name: "Webley revolver", cls: "firearm", fam: "firearm", spec: "pistol", dmg: "1d10", wound: "piercing", mod: false, ranges: [10,25,50], fire: "fast", cap: 6, mass: 1.1, era: "antique", trad: "tradition_local", desc: "Victorian to the Great War. Breaks open, ejects all six at once, and is still in a drawer upstairs." },
|
||||
{ key: "lee_enfield", name: "Lee-Enfield", cls: "firearm", fam: "firearm", spec: "rifle", dmg: "2d6+2", wound: "piercing", mod: false, ranges: [60,200,500], fire: "fast", cap: 10, mass: 4.0, era: "antique", trad: "tradition_local", desc: "Great War. Ten rounds and a bolt a trained man works without looking. The best rifle in this list." },
|
||||
{ key: "trench_club", name: "Trench club", cls: "melee", fam: "melee_weapon", spec: "club", dmg: "1d8+1", wound: "blunt", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.2, era: "antique", trad: "tradition_local", desc: "Great War. Made in the line out of a table leg and some nails. Quiet, which was the point." }
|
||||
];
|
||||
|
||||
/* ---------- armour (v0.5 §4.8) ---------- */
|
||||
@@ -138,7 +194,22 @@ export const ARMOURS = [
|
||||
|
||||
{ key: "oilcloth_coat", name: "Oilcloth coat", points: 1, mass: 3.0, era: "antique", trad: "tradition_local", desc: "Keeps the weather out and very little else." },
|
||||
{ key: "brigandine", name: "Brigandine", points: 4, mass: 9.0, era: "antique", trad: "tradition_local", desc: "Plates riveted between cloth. Heavy, quiet, and older than the agency." },
|
||||
{ key: "hardsuit", name: "Sealed hardsuit", points: 9, mass: 12.0, era: "future", trad: "tradition_transposed", desc: "Sealed, powered and not from here. Also a breathing set — see Gear." }
|
||||
{ key: "hardsuit", name: "Sealed hardsuit", points: 9, mass: 12.0, era: "future", trad: "tradition_transposed", desc: "Sealed, powered and not from here. Also a breathing set — see Gear." },
|
||||
|
||||
/* --- the historical range. Weight is the point: everything here protects
|
||||
well and costs you the ability to run in it. --- */
|
||||
{ key: "gambeson", name: "Gambeson", points: 2, mass: 4.5, era: "antique", trad: "tradition_local", desc: "Medieval. Quilted linen, thirty layers. Worn alone by the poor and under everything by everyone else." },
|
||||
{ key: "maille_shirt", name: "Maille shirt", points: 4, mass: 7.5, era: "antique", trad: "tradition_local", desc: "Medieval. Stops a cut completely and a spike not at all. Wear it over the gambeson or regret it." },
|
||||
{ key: "coat_of_plates", name: "Coat of plates", points: 6, mass: 11, era: "antique", trad: "tradition_local", desc: "Medieval. Iron plates riveted inside a fabric coat. The compromise that held for a century." },
|
||||
{ key: "cuirass", name: "Cuirass", points: 6, mass: 9, era: "antique", trad: "tradition_local", desc: "Early modern. Breast and back. Proof against a pistol at any sensible distance, and stated so by the armourer." },
|
||||
{ key: "harness", name: "Full harness", points: 9, mass: 25, era: "antique", trad: "tradition_local", desc: "Medieval. Head to foot, articulated, and far more wearable than people think — until the third hour." },
|
||||
{ key: "buff_coat", name: "Buff coat", points: 3, mass: 5, era: "antique", trad: "tradition_local", desc: "Civil War. Thick ox hide to the knee. Turns a sword, ignores a ball, and never dries out." },
|
||||
{ key: "sallet", name: "Sallet and bevor", points: 5, mass: 3.2, era: "antique", trad: "tradition_local", desc: "Medieval. Covers the head and the throat and takes most of your hearing with it." },
|
||||
{ key: "lobster_pot", name: "Lobster-tail helmet", points: 4, mass: 2.6, era: "antique", trad: "tradition_local", desc: "Civil War. Three bars across the face. You can see out; that is all that can be said for it." },
|
||||
{ key: "jack_of_plate", name: "Jack of plate", points: 4, mass: 6, era: "antique", trad: "tradition_local", desc: "Tudor. Small iron plates stitched between canvas. Looks like a coat until somebody hits it." },
|
||||
{ key: "cuirassier", name: "Cuirassier armour", points: 8, mass: 18, era: "antique", trad: "tradition_local", desc: "Early modern. Three-quarter plate for a man on a horse. On foot it is a punishment." },
|
||||
{ key: "brodie", name: "Brodie helmet", points: 3, mass: 1.3, era: "antique", trad: "tradition_local", desc: "Great War. A steel plate on a strap. Designed against shrapnel from above and honest about it." },
|
||||
{ key: "flak_jacket", name: "Flak jacket", points: 4, mass: 8.5, era: "antique", trad: "tradition_local", desc: "Second War. Manganese plates in a waistcoat. Heavy, hot, and it has saved a great many people." }
|
||||
];
|
||||
|
||||
/* ---------- gear ---------- */
|
||||
|
||||
+30
-1
@@ -147,7 +147,36 @@ export const ICON_MAP = {
|
||||
|
||||
/* ---- borrowed authority ---- */
|
||||
authority:["folder","device",0], authority_flagged:["folder","device",26],
|
||||
authority_burned:["folder","device",-26]
|
||||
authority_burned:["folder","device",-26],
|
||||
/* ---- the historical range: medieval ---- */
|
||||
arming_sword:["sword","melee",-4,"antique"], longsword:["sword","melee",-12,"antique"],
|
||||
falchion:["sword","melee",20,"antique"], war_hammer:["club","melee",-30,"antique"],
|
||||
mace:["club","melee",30,"antique"], flail:["club","melee",-36,"antique"],
|
||||
poleaxe:["axe","melee",-18,"antique"], halberd:["spear","melee",-26,"antique"],
|
||||
billhook:["axe","melee",26,"antique"], pike:["spear","melee",34,"antique"],
|
||||
quarterstaff:["bar","melee",-22,"antique"], dirk:["blade","melee",-16,"antique"],
|
||||
longbow:["bow","weapon",-30,"antique"], arbalest:["crossbow","weapon",-24,"antique"],
|
||||
sling:["rope","weapon",38,"antique"], javelin:["spear","weapon",18,"antique"],
|
||||
|
||||
/* ---- early modern ---- */
|
||||
rapier:["sword","melee",-40,"antique"], main_gauche:["blade","melee",40,"antique"],
|
||||
matchlock:["musket","weapon",-34,"antique"], wheellock:["flintlock","weapon",28,"antique"],
|
||||
blunderbuss:["shotgun","weapon",-44,"antique"], boarding_pike:["spear","melee",-32,"antique"],
|
||||
|
||||
/* ---- Napoleonic, Victorian, and the Great War ---- */
|
||||
sabre:["sword","melee",44,"antique"], smallsword:["sword","melee",-48,"antique"],
|
||||
cutlass:["sword","melee",48,"antique"], brown_bess:["musket","weapon",36,"antique"],
|
||||
baker_rifle:["musket","weapon",-38,"antique"], bayonet:["blade","melee",32,"antique"],
|
||||
martini:["rifle","weapon",-42,"antique"], webley:["revolver","weapon",42,"antique"],
|
||||
lee_enfield:["rifle","weapon",46,"antique"], trench_club:["club","melee",22,"antique"],
|
||||
|
||||
/* ---- historical armour ---- */
|
||||
gambeson:["jacket","armour",-16,"antique"], maille_shirt:["mail","armour",-22,"antique"],
|
||||
coat_of_plates:["vest","armour",-30,"antique"], cuirass:["plate","armour",16,"antique"],
|
||||
harness:["plate","armour",-36,"antique"], buff_coat:["jacket","armour",34,"antique"],
|
||||
sallet:["mask","armour",-42,"antique"], lobster_pot:["mask","armour",42,"antique"],
|
||||
jack_of_plate:["vest","armour",24,"antique"], cuirassier:["plate","armour",-48,"antique"],
|
||||
brodie:["mask","armour",30,"antique"], flak_jacket:["vest","armour",-24,"antique"]
|
||||
};
|
||||
|
||||
/** Skill category -> icon key. */
|
||||
|
||||
+58
-1
@@ -244,8 +244,64 @@ export function generateMission({ seed = null, rnd = null, ...opts } = {}) {
|
||||
|
||||
const esc = s => String(s ?? "").replace(/&/g, "&").replace(/</g, "<");
|
||||
const ul = xs => `<ul>${xs.map(x => `<li>${esc(x)}</li>`).join("")}</ul>`;
|
||||
/** A table, escaped. Cells may carry markup only when the caller has escaped it. */
|
||||
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>`;
|
||||
|
||||
/** The player-facing brief. Everything here is true as far as the agency knows. */
|
||||
/**
|
||||
* The players' page. Everything on it is something an agent would be told, or would
|
||||
* see on arrival — the cast's names and what they want, but never what they lie
|
||||
* about; the texture of the place, but never why it is like that.
|
||||
*
|
||||
* The generator was already writing all of this and filing every word of it behind
|
||||
* the GM screen: the timeline, the people, and the two lines of texture that are the
|
||||
* best writing in the whole document. A player brief that opens on a classification
|
||||
* note is a memo. This is a briefing.
|
||||
*/
|
||||
export function introPage(m) {
|
||||
const first = m.timeline[0];
|
||||
// The LAST timeline entry is the team's own arrival — "today: the team crosses" —
|
||||
// which makes nonsense of "since then, ...". Use the last thing that happened
|
||||
// before they did.
|
||||
const prior = m.timeline.filter(t => !/team crosses/i.test(t.what));
|
||||
const recent = prior[prior.length - 1] ?? first;
|
||||
return `
|
||||
<h2>Read this out</h2>
|
||||
<p><em>${esc(m.classification.note)}</em></p>
|
||||
<p>It is <strong>${esc(m.place)}</strong>. You have <strong>${esc(m.duration)}</strong>,
|
||||
and the department has been clear that this is the window and not an estimate.
|
||||
${esc(first.when.charAt(0).toUpperCase() + first.when.slice(1))}, ${esc(first.what.toLowerCase())}
|
||||
Since then it has not stopped. Most recently, ${esc(recent.what.toLowerCase())}</p>
|
||||
<p>You are going because ${esc(m.anomaly.containment.toLowerCase().replace(/\.$/, ""))},
|
||||
and because somebody has to be able to say afterwards that a department attended.</p>
|
||||
|
||||
<h2>What it is like there</h2>
|
||||
${ul(m.texture)}
|
||||
<p>None of that is in the file. It is what you will notice in the first ten minutes,
|
||||
and the file was written by somebody who was not there.</p>
|
||||
|
||||
<h2>What is known so far</h2>
|
||||
${table(["When", "What"], m.timeline.map(t => [esc(t.when), esc(t.what)]))}
|
||||
|
||||
<h2>Who is there</h2>
|
||||
${table(["Name", "Who they are", "What they want from you"],
|
||||
m.cast.map(c => [`<strong>${esc(c.name)}</strong>`, esc(c.role), esc(c.wants)]))}
|
||||
<p>They are not adversaries. Two of them will be helpful and at least one of them is
|
||||
not telling you everything, which is ordinary and is not the same as lying.</p>
|
||||
|
||||
<h2>Before you go</h2>
|
||||
<ul>
|
||||
<li>Draw your kit. What you do not sign for, you do not have.</li>
|
||||
<li>Somebody had better be able to make an arrangement, because most cases close that
|
||||
way and this one is no exception.</li>
|
||||
<li>Your anchor stays on you. It is the way back and it is the reason you are still
|
||||
you when you get there.</li>
|
||||
</ul>`;
|
||||
}
|
||||
|
||||
export function briefPage(m) {
|
||||
// The brief used to open on a classification note and never say where the site
|
||||
// was, how long the team had, what was likely to be in the way, or how they were
|
||||
@@ -368,7 +424,8 @@ ${m.timeline.map(t => `<tr><td><strong>${esc(t.when)}</strong></td><td>${esc(t.w
|
||||
/** The whole case as journal pages, ready to be written into a compendium. */
|
||||
export function missionPages(m) {
|
||||
return [
|
||||
{ name: `${m.codename} · Brief`, content: briefPage(m) },
|
||||
{ name: `${m.codename} · Briefing`, content: introPage(m), players: true },
|
||||
{ name: `${m.codename} · Orders`, content: briefPage(m), players: true },
|
||||
{ name: `${m.codename} · The truth`, content: truthPage(m) },
|
||||
{ name: `${m.codename} · Opposition`, content: castPage(m) },
|
||||
{ name: `${m.codename} · Phases`, content: phasesPage(m) },
|
||||
|
||||
Reference in New Issue
Block a user