From 7f8355f0d0702c35614e9e9460a62dba269ac5ee Mon Sep 17 00:00:00 2001 From: slaguru666 <111923774+slaguru666@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:19:41 +0100 Subject: [PATCH] Add the player primer and cheat sheet, and brand every journal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- README.md | 2 +- docs/REVIEW_LOG.md | 60 ++++ package.json | 4 +- packs/armour/LOG | 10 +- packs/armour/LOG.old | 2 +- packs/expedition/LOG | 10 +- packs/expedition/LOG.old | 2 +- packs/gear/LOG | 10 +- packs/gear/LOG.old | 2 +- packs/npcs/LOG | 10 +- packs/npcs/LOG.old | 2 +- packs/powers/LOG | 10 +- packs/powers/LOG.old | 2 +- packs/pregens/LOG | 10 +- packs/pregens/LOG.old | 2 +- packs/primer/000005.ldb | Bin 0 -> 21613 bytes packs/primer/000006.log | Bin 0 -> 33306 bytes packs/primer/CURRENT | 1 + packs/primer/LOG | 5 + packs/primer/LOG.old | 1 + packs/primer/MANIFEST-000004 | Bin 0 -> 147 bytes packs/rules/000005.ldb | Bin 33473 -> 33484 bytes packs/rules/000006.log | Bin 68294 -> 68318 bytes packs/rules/LOG | 10 +- packs/rules/LOG.old | 2 +- packs/rules/MANIFEST-000004 | Bin 147 -> 147 bytes packs/skills/LOG | 10 +- packs/skills/LOG.old | 2 +- packs/slice/000005.ldb | Bin 16892 -> 16902 bytes packs/slice/000006.log | Bin 27943 -> 27967 bytes packs/slice/LOG | 10 +- packs/slice/LOG.old | 2 +- packs/slice/MANIFEST-000004 | Bin 147 -> 147 bytes packs/starter/000005.ldb | Bin 82274 -> 82299 bytes packs/starter/000006.log | Bin 561564 -> 561588 bytes packs/starter/LOG | 10 +- packs/starter/LOG.old | 2 +- packs/starter/MANIFEST-000004 | Bin 130 -> 130 bytes packs/tables/LOG | 10 +- packs/tables/LOG.old | 2 +- packs/talents/LOG | 10 +- packs/talents/LOG.old | 2 +- packs/vehicles/LOG | 10 +- packs/vehicles/LOG.old | 2 +- packs/weapons/LOG | 10 +- packs/weapons/LOG.old | 2 +- ringbrp.mjs | 32 +++ styles/ringbrp.css | 149 ++++++++++ system.json | 9 +- tools/build-packs.mjs | 17 ++ tools/primer-text.mjs | 502 ++++++++++++++++++++++++++++++++++ 51 files changed, 862 insertions(+), 88 deletions(-) create mode 100644 packs/primer/000005.ldb create mode 100644 packs/primer/000006.log create mode 100644 packs/primer/CURRENT create mode 100644 packs/primer/LOG create mode 100644 packs/primer/LOG.old create mode 100644 packs/primer/MANIFEST-000004 create mode 100644 tools/primer-text.mjs diff --git a/README.md b/README.md index ecd202f..531adae 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ The build runs all three guards before it writes anything: ``` -check-rules: OK — 87 rules, 16 files scanned, 3 aliases + 41 constant sets checked, 275 formulas verified +check-rules: OK — 87 rules, 17 files scanned, 3 aliases + 41 constant sets checked, 275 formulas verified check-kits: OK — 25 roles, 10 trades, 218 catalogue items, every kit key resolves, every posting can use what it carries, every loadout distinct check-lang: OK — en.json, 927 keys, no leaf/branch collisions check-behaviour: OK — 38 behavioural tests diff --git a/docs/REVIEW_LOG.md b/docs/REVIEW_LOG.md index 5fd2a31..fa5154d 100644 --- a/docs/REVIEW_LOG.md +++ b/docs/REVIEW_LOG.md @@ -5070,3 +5070,63 @@ species bonus." Checked afterwards that every localisation key still referenced by the engine or a template exists; the six apparent misses are Handlebars concatenation prefixes rather than lookups. + +## The player primer, and the journals finally look like the game + +Ten pages a player reads before session one, in their own compendium at OBSERVER +ownership: nine of setting and one cheat sheet. Plus the branding that all four +journals in the system had been going without. + +**The voice was the first thing to fix.** The draft called the organisation "the +Bureau" throughout. Everything else in the game — twelve rules pages, the starter, 927 +localisation strings — calls it *the department* or *the agency*. One name, and it is +not Bureau. + +**Where the draft was thin, it got filled rather than padded.** The character section +now carries the seven principles as an ordered list a player can actually work from; +"what it costs" gets the real Coherence band table rather than a paragraph describing +one, and says what the anchor in the kit is for; and the recruitment page separates +*what continuity means in practice* from *what it is not*, because "it is not a +superpower" is the single most important sentence for a new player and it was buried. + +**The cheat sheet's numbers are computed, not typed.** Hit points, Major Wound, damage +modifier, the defence penalties, the range ladder and the Coherence bands all come out +of `rules.mjs` and `lang/en.json` at build time. A hand-typed cheat sheet would have +been the sixth time this project shipped a number that disagreed with the code — and it +would have been the one the players were holding. It closes on six questions new +players actually ask, including "am I going to die?" answered honestly. + +### R-250. The design tokens were never on `:root` + +The journals rendered as Foundry's default parchment, and chasing why took four wrong +guesses that are worth recording, because each one looked right. + +1. **The hook name.** v14's journal sheet is an ApplicationV2: the hook is + `renderJournalEntrySheet`, not `renderJournalSheet`. +2. **`element` is the node.** On AppV2 it is the root element, not a jQuery wrapper. + Reaching for `[0]` silently returns the first *child* — which is how the first + version appeared to work, put the class on a header button, and changed nothing. +3. **The page container.** There is no `.journal-page-content` in v14. The prose sits + directly inside `article.journal-entry-page`. +4. **And then the real one.** With the class on the right element and the selector + matching, `font-size`, `line-height` and `padding` from my rule were all applying — + and every colour was not. `--rb-deep` resolved to nothing. The palette is declared + on `.ringbrp-sheet, .ringbrp-chat, .ringbrp-window` and **never on `:root`**, so a + journal carrying a new class inherited no tokens at all. Every `var()` silently + became nothing, which CSS treats as "unset" rather than as an error. + +The tell was that the *numeric* properties from the same rule worked while the coloured +ones did not. A rule that half-applies is not a specificity problem, and I spent three +attempts treating it as one — including bumping the system version on a cache theory +that was wrong. + +Adding `.ringbrp-journal` to the token block fixed all of it at once. + +**Now branded:** the primer, the generated rulebook, the starter's GM text and its +handouts. Scoped by a flag, so another module's journals in the same world are +untouched. The contents rail is the yellow-on-navy of the sheet tabs, read-aloud gets a +spot-colour margin rule, diagrams are monospaced in a bordered block, and the cheat +sheet is a grid of cards so it can be skimmed under pressure rather than read. + +Version bumped to 0.9.0 — which, incidentally, is what makes Foundry re-fetch the +stylesheet for anyone updating. diff --git a/package.json b/package.json index 5a06a4a..7e3276f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ringbrp", - "version": "0.8.0", - "description": "The Custodians \u2014 a Basic Roleplaying game of crossings, for Foundry VTT", + "version": "0.9.0", + "description": "The Custodians — a Basic Roleplaying game of crossings, for Foundry VTT", "main": "ringbrp.mjs", "scripts": { "build": "node tools/build-packs.mjs && node tools/update-readme.mjs", diff --git a/packs/armour/LOG b/packs/armour/LOG index b150376..64122b1 100644 --- a/packs/armour/LOG +++ b/packs/armour/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.855265 1754e3000 Recovering log #3 -2026/08/12-00:06:16.855669 1754e3000 Level-0 table #5: started -2026/08/12-00:06:16.855836 1754e3000 Level-0 table #5: 4591 bytes OK -2026/08/12-00:06:16.856081 1754e3000 Delete type=0 #3 -2026/08/12-00:06:16.856115 1754e3000 Delete type=3 #2 +2026/08/12-10:15:09.925114 17200b000 Recovering log #3 +2026/08/12-10:15:09.925148 17200b000 Level-0 table #5: started +2026/08/12-10:15:09.925283 17200b000 Level-0 table #5: 4591 bytes OK +2026/08/12-10:15:09.925570 17200b000 Delete type=0 #3 +2026/08/12-10:15:09.925615 17200b000 Delete type=3 #2 diff --git a/packs/armour/LOG.old b/packs/armour/LOG.old index 76d96d2..359bf9b 100644 --- a/packs/armour/LOG.old +++ b/packs/armour/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.690846 171b57000 Delete type=3 #1 +2026/08/12-10:14:43.782384 173eef000 Delete type=3 #1 diff --git a/packs/expedition/LOG b/packs/expedition/LOG index 2720361..d6d3173 100644 --- a/packs/expedition/LOG +++ b/packs/expedition/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.873912 1754e3000 Recovering log #3 -2026/08/12-00:06:16.874024 1754e3000 Level-0 table #5: started -2026/08/12-00:06:16.874152 1754e3000 Level-0 table #5: 4129 bytes OK -2026/08/12-00:06:16.874423 1754e3000 Delete type=0 #3 -2026/08/12-00:06:16.874466 1754e3000 Delete type=3 #2 +2026/08/12-10:15:09.941304 173023000 Recovering log #3 +2026/08/12-10:15:09.941329 173023000 Level-0 table #5: started +2026/08/12-10:15:09.941465 173023000 Level-0 table #5: 4129 bytes OK +2026/08/12-10:15:09.941748 173023000 Delete type=0 #3 +2026/08/12-10:15:09.941781 173023000 Delete type=3 #2 diff --git a/packs/expedition/LOG.old b/packs/expedition/LOG.old index 0d1e32e..c189aa3 100644 --- a/packs/expedition/LOG.old +++ b/packs/expedition/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.732633 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.827491 1726cb000 Delete type=3 #1 diff --git a/packs/gear/LOG b/packs/gear/LOG index d212fb2..90124f5 100644 --- a/packs/gear/LOG +++ b/packs/gear/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.857059 174cd7000 Recovering log #3 -2026/08/12-00:06:16.857573 174cd7000 Level-0 table #5: started -2026/08/12-00:06:16.857903 174cd7000 Level-0 table #5: 31614 bytes OK -2026/08/12-00:06:16.858145 174cd7000 Delete type=0 #3 -2026/08/12-00:06:16.858196 174cd7000 Delete type=3 #2 +2026/08/12-10:15:09.926306 173023000 Recovering log #3 +2026/08/12-10:15:09.926421 173023000 Level-0 table #5: started +2026/08/12-10:15:09.926814 173023000 Level-0 table #5: 31614 bytes OK +2026/08/12-10:15:09.927163 173023000 Delete type=0 #3 +2026/08/12-10:15:09.927207 173023000 Delete type=3 #2 diff --git a/packs/gear/LOG.old b/packs/gear/LOG.old index c8def97..c88d7d9 100644 --- a/packs/gear/LOG.old +++ b/packs/gear/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.692998 170b3f000 Delete type=3 #1 +2026/08/12-10:14:43.784415 173eef000 Delete type=3 #1 diff --git a/packs/npcs/LOG b/packs/npcs/LOG index b7730b8..2b7df33 100644 --- a/packs/npcs/LOG +++ b/packs/npcs/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.840426 174cd7000 Recovering log #3 -2026/08/12-00:06:16.842114 174cd7000 Level-0 table #5: started -2026/08/12-00:06:16.843749 174cd7000 Level-0 table #5: 225945 bytes OK -2026/08/12-00:06:16.844107 174cd7000 Delete type=0 #3 -2026/08/12-00:06:16.844201 174cd7000 Delete type=3 #2 +2026/08/12-10:15:09.914246 173023000 Recovering log #3 +2026/08/12-10:15:09.915233 173023000 Level-0 table #5: started +2026/08/12-10:15:09.916771 173023000 Level-0 table #5: 225945 bytes OK +2026/08/12-10:15:09.917162 173023000 Delete type=0 #3 +2026/08/12-10:15:09.917219 173023000 Delete type=3 #2 diff --git a/packs/npcs/LOG.old b/packs/npcs/LOG.old index 0fc6a18..1b98b67 100644 --- a/packs/npcs/LOG.old +++ b/packs/npcs/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.708940 170b3f000 Delete type=3 #1 +2026/08/12-10:14:43.800859 1726cb000 Delete type=3 #1 diff --git a/packs/powers/LOG b/packs/powers/LOG index 5981400..9cbef14 100644 --- a/packs/powers/LOG +++ b/packs/powers/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.850448 1754e3000 Recovering log #3 -2026/08/12-00:06:16.850937 1754e3000 Level-0 table #5: started -2026/08/12-00:06:16.851096 1754e3000 Level-0 table #5: 3295 bytes OK -2026/08/12-00:06:16.851406 1754e3000 Delete type=0 #3 -2026/08/12-00:06:16.851447 1754e3000 Delete type=3 #2 +2026/08/12-10:15:09.922245 17200b000 Recovering log #3 +2026/08/12-10:15:09.922265 17200b000 Level-0 table #5: started +2026/08/12-10:15:09.922421 17200b000 Level-0 table #5: 3295 bytes OK +2026/08/12-10:15:09.922681 17200b000 Delete type=0 #3 +2026/08/12-10:15:09.922713 17200b000 Delete type=3 #2 diff --git a/packs/powers/LOG.old b/packs/powers/LOG.old index 2107343..ced2e69 100644 --- a/packs/powers/LOG.old +++ b/packs/powers/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.725493 171b57000 Delete type=3 #1 +2026/08/12-10:14:43.821081 1726cb000 Delete type=3 #1 diff --git a/packs/pregens/LOG b/packs/pregens/LOG index 50fb7ad..42ee2a9 100644 --- a/packs/pregens/LOG +++ b/packs/pregens/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.836787 174cd7000 Recovering log #3 -2026/08/12-00:06:16.837779 174cd7000 Level-0 table #5: started -2026/08/12-00:06:16.838453 174cd7000 Level-0 table #5: 58792 bytes OK -2026/08/12-00:06:16.838760 174cd7000 Delete type=0 #3 -2026/08/12-00:06:16.838812 174cd7000 Delete type=3 #2 +2026/08/12-10:15:09.911544 173023000 Recovering log #3 +2026/08/12-10:15:09.911759 173023000 Level-0 table #5: started +2026/08/12-10:15:09.912426 173023000 Level-0 table #5: 58792 bytes OK +2026/08/12-10:15:09.912801 173023000 Delete type=0 #3 +2026/08/12-10:15:09.912846 173023000 Delete type=3 #2 diff --git a/packs/pregens/LOG.old b/packs/pregens/LOG.old index 967ffa0..2c2de79 100644 --- a/packs/pregens/LOG.old +++ b/packs/pregens/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.699399 170b3f000 Delete type=3 #1 +2026/08/12-10:14:43.791044 173eef000 Delete type=3 #1 diff --git a/packs/primer/000005.ldb b/packs/primer/000005.ldb new file mode 100644 index 0000000000000000000000000000000000000000..669e7b173f0a4676a6ac91069b266ec11096b74e GIT binary patch literal 21613 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 GU;aOH#%Kos literal 0 HcmV?d00001 diff --git a/packs/primer/000006.log b/packs/primer/000006.log new file mode 100644 index 0000000000000000000000000000000000000000..daa37bb530476b123e2409fa8e13b0f9b9086a5e GIT binary patch literal 33306 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 literal 0 HcmV?d00001 diff --git a/packs/primer/CURRENT b/packs/primer/CURRENT new file mode 100644 index 0000000..cacca75 --- /dev/null +++ b/packs/primer/CURRENT @@ -0,0 +1 @@ +MANIFEST-000004 diff --git a/packs/primer/LOG b/packs/primer/LOG new file mode 100644 index 0000000..a50ac4a --- /dev/null +++ b/packs/primer/LOG @@ -0,0 +1,5 @@ +2026/08/12-10:15:09.929600 17382f000 Recovering log #3 +2026/08/12-10:15:09.929643 17382f000 Level-0 table #5: started +2026/08/12-10:15:09.929903 17382f000 Level-0 table #5: 21613 bytes OK +2026/08/12-10:15:09.930174 17382f000 Delete type=0 #3 +2026/08/12-10:15:09.930216 17382f000 Delete type=3 #2 diff --git a/packs/primer/LOG.old b/packs/primer/LOG.old new file mode 100644 index 0000000..6de6949 --- /dev/null +++ b/packs/primer/LOG.old @@ -0,0 +1 @@ +2026/08/12-10:14:43.817678 1726cb000 Delete type=3 #1 diff --git a/packs/primer/MANIFEST-000004 b/packs/primer/MANIFEST-000004 new file mode 100644 index 0000000000000000000000000000000000000000..2ce4ec2b66f2267c89df19cb59a3fb9116603836 GIT binary patch literal 147 zcmWIhx#Ncn10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAeo+Yn@4QR~MkY2+24;2^ zZgvLNw<{PG6|?e7i}Dh46eFqvlJfIIBb>`qiiS1t&WsXDMVWc&Nks)pR@F*LMTvPSN>(LBrKz=( z%NRACH!^bQnHZWaV_;$AQ9WpS$WDR5@{o_Y!lCU7L8)n}MX7nosY*IZC6xt=w|GiY zD@qvocrr_JQW-Z26ldg@E3q!s+5D982qSa)(wxm}m=7^CT5ir~FJt!B09se8qg0le zlA6yaD9*M)8Q>-LqBF delta 293 zcmX@p%5<=miT${74TIu0ritv@jF}saof#+hF>30}WaQ8@F*NIAU}5A@U1_??PJzL4 zm5;f?q3sGmscET2sd>q%N;*m*T#}lrWL3>5&XQlm=OS)mXkehDlwY2g zT2!2oS-|MWl9DPl*_B&`<%gh4(dJz4#4@3&O-wC}3_t)TYF@|YPJYm+r+HV5L6fCU zpMk}NkyTgZ|Nlo~GgP_^7#Ms74S4=rZ7~M1BLxj4c1$*JQjncBgYmsAgJzQh14|ww n?*)avZH#Zt7&uv#1O){eCYLm+a9-V`v1?v4lhM`53!Ah7e8*Q@ diff --git a/packs/rules/000006.log b/packs/rules/000006.log index 2d0501fd150e1cf74122e60b8f406828b00ab4b4..7b08998e16a6d340c27377f36cbd1b55f7a71551 100644 GIT binary patch delta 61 zcmX>$mF3=4mIl@tEm5A=x3V%eaWG!p-oe2b%_ylFR8*j3Rjrg%l$e*IWK~jB Rnp#^sx#6kA^go=8rvS(17i|Cl delta 37 tcmcaNmF3t}mIhYo`RU8|Z)Ig{;$Ymny@P`>nvt<~a>G-J=^|W=rvMY?4VVA` diff --git a/packs/rules/LOG b/packs/rules/LOG index cb74d2a..e4d9c12 100644 --- a/packs/rules/LOG +++ b/packs/rules/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.861054 174cd7000 Recovering log #3 -2026/08/12-00:06:16.861635 174cd7000 Level-0 table #5: started -2026/08/12-00:06:16.861956 174cd7000 Level-0 table #5: 33473 bytes OK -2026/08/12-00:06:16.862206 174cd7000 Delete type=0 #3 -2026/08/12-00:06:16.862237 174cd7000 Delete type=3 #2 +2026/08/12-10:15:09.930884 17200b000 Recovering log #3 +2026/08/12-10:15:09.930957 17200b000 Level-0 table #5: started +2026/08/12-10:15:09.931274 17200b000 Level-0 table #5: 33484 bytes OK +2026/08/12-10:15:09.931485 17200b000 Delete type=0 #3 +2026/08/12-10:15:09.931513 17200b000 Delete type=3 #2 diff --git a/packs/rules/LOG.old b/packs/rules/LOG.old index 3d704dc..9568411 100644 --- a/packs/rules/LOG.old +++ b/packs/rules/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.729349 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.825718 1726cb000 Delete type=3 #1 diff --git a/packs/rules/MANIFEST-000004 b/packs/rules/MANIFEST-000004 index f38776bef8ec4a54559f188d051d858a3132eab3..15f0607ec8e36e0e10c592dec7f782fb4245ce47 100644 GIT binary patch delta 29 kcmbQtIGJ&RvM`Uz^Sn$3MkY2+24;2^UUml7GZW2X0bu+F1^@s6 delta 29 lcmbQtIGJ&RvhZE0D{7exj7)5t49x5-yzC6D2Pc}v0sw0u24?^O diff --git a/packs/skills/LOG b/packs/skills/LOG index 7db8a54..d732c09 100644 --- a/packs/skills/LOG +++ b/packs/skills/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.846928 1744cb000 Recovering log #3 -2026/08/12-00:06:16.847099 1744cb000 Level-0 table #5: started -2026/08/12-00:06:16.847302 1744cb000 Level-0 table #5: 7590 bytes OK -2026/08/12-00:06:16.847547 1744cb000 Delete type=0 #3 -2026/08/12-00:06:16.847579 1744cb000 Delete type=3 #2 +2026/08/12-10:15:09.920048 17200b000 Recovering log #3 +2026/08/12-10:15:09.920101 17200b000 Level-0 table #5: started +2026/08/12-10:15:09.920292 17200b000 Level-0 table #5: 7590 bytes OK +2026/08/12-10:15:09.920533 17200b000 Delete type=0 #3 +2026/08/12-10:15:09.920569 17200b000 Delete type=3 #2 diff --git a/packs/skills/LOG.old b/packs/skills/LOG.old index 98129dd..a1432a0 100644 --- a/packs/skills/LOG.old +++ b/packs/skills/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.685076 170b3f000 Delete type=3 #1 +2026/08/12-10:14:43.775951 172ed7000 Delete type=3 #1 diff --git a/packs/slice/000005.ldb b/packs/slice/000005.ldb index 4851c7776b407be2adaf18974d2a39dcfae4b361..ac4df01c17327f813320cb08d81d884ef2a582bb 100644 GIT binary patch delta 391 zcmey<%-Gh#$o5CIhCy-NL^d5p)``ZCgOrLg^U{-w3Y4s>m6D1Q^HP+oN{UKTYio6s z^2_s5i;6Qc3mDa1Qc}|rOLIz;tPE;vISdvE>lHA5cM4==(KE98#K6MHteR+=WT(Ku zpk$OZIg(M4v14;JV-6Ez_U0GN+|2b8lysDG6N|D_fJQ1=DJcOB&&*9sPX$^EWR_*7 zq~-&eLMu50it=-cm87n7@Ra4}l=8K3sTk;)0+kdOB`e9Dy$thxF zU;uPu&<;)xUBgse$hcwh0j?qzsUutrlP$P+^F063xnPm&2R8hu{{A{be9MgIS9l(?hWWx&9YBWNJ=$Z?_! f11F1;pg_!z$r~IcIIT{*9$wePX!vCEMMrG_DY1Ej delta 382 zcmZo`Vf@p~$o53FhCy-KL^d5pzKO<AlvgjFE-C|&2WLEVw^|Di7U{Eshnw-I?$XKwsi!q0Z zF?jQLW^QK2h{^FHVo9lD`J4h}nJKCHd|NmYzX%lN=M*bRUFYB_%g-t0%i&Tn&@%x_&uCZFLdVmo+&Co#EXvJ>}imNJX2 z7MmG)f=tD)H8OfK00AS2DEB-ub2H-%22JKk`U)ZLjQ{_$GKnyJ5@*n4sncg*iC|>a z75V@FyZ9Z=E&~RJ96yrhZI S@KzIJ?&OD#vXg&1asvQ8F>w(9 diff --git a/packs/slice/000006.log b/packs/slice/000006.log index c7d9b168eb1ce2bb8ca9746d6d9df4ed8a31806a..c25ac7558a8ac4a545182a0791185eb264dae880 100644 GIT binary patch delta 56 zcmZ2}i*f%gM%Jx&JjE?GvN~roex2-@{aaG0C^IiTsi;87s#+P?@sp2{>@lBc|W_vFEK1?!<|)WY ztZdETloFGX;^kG7mNGJu;z-L$l*^S$(v*^600Kr3o>(w_fdT`E1Csy)3me09QwPR# z=0_S>*MTI#Dj4eDL@i<9WKm-L4*?AO8(86zYj~u(zc;cPt!rYHnC|GvC^6?QRgT1>6kcwgf}F(4)&Nc^F%~IaUNvSZBPl74w46k_P^lzA zDH#SJU<6^k^{X~dcX436VY0e`bsb0uEY8q&XvH)JP8KD`{}8~itbr9SSsAgF;a(%F L(bVYyj*Qv>Rn;=W diff --git a/packs/starter/000006.log b/packs/starter/000006.log index 6c9b64bb0bdd75a9807d88940e64828156d9b431..aaf167cfe262ee6f55b5068d5df74264c8f6dceb 100644 GIT binary patch delta 91 zcmV-h0Hpt%qaw7UA_T#Qrx1|@Edq(6fis0O0fjRHg);+%GX#Y*1%)#Pg);}WGYHLp x2PbuNsjU$Nmrr~M`nLgr2z3sZAdUeH3u1C%Ze$`lbaHiNlabFFw~vnq4FZ&c9|HgY delta 74 zcmV-Q0JZQ!=b^rhX diff --git a/packs/starter/LOG b/packs/starter/LOG index fa2bb45..23a3421 100644 --- a/packs/starter/LOG +++ b/packs/starter/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.864877 1744cb000 Recovering log #3 -2026/08/12-00:06:16.865947 1744cb000 Level-0 table #5: started -2026/08/12-00:06:16.866787 1744cb000 Level-0 table #5: 82274 bytes OK -2026/08/12-00:06:16.867102 1744cb000 Delete type=0 #3 -2026/08/12-00:06:16.867176 1744cb000 Delete type=3 #2 +2026/08/12-10:15:09.933901 172817000 Recovering log #3 +2026/08/12-10:15:09.934300 172817000 Level-0 table #5: started +2026/08/12-10:15:09.935025 172817000 Level-0 table #5: 82299 bytes OK +2026/08/12-10:15:09.935279 172817000 Delete type=0 #3 +2026/08/12-10:15:09.935312 172817000 Delete type=3 #2 diff --git a/packs/starter/LOG.old b/packs/starter/LOG.old index 4e5bd27..b8e48b1 100644 --- a/packs/starter/LOG.old +++ b/packs/starter/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.720012 170333000 Delete type=3 #1 +2026/08/12-10:14:43.811578 1736e3000 Delete type=3 #1 diff --git a/packs/starter/MANIFEST-000004 b/packs/starter/MANIFEST-000004 index b8a7dce1713b5ca580737f1312ef3ecdf8554cb7..87687fc225fe3058111c9880a05b446e7fc6f3e9 100644 GIT binary patch delta 34 ocmZo-Y+{_CENZ(#Cn0F6Wl1^@s6 diff --git a/packs/tables/LOG b/packs/tables/LOG index 8c1f830..c2e3d86 100644 --- a/packs/tables/LOG +++ b/packs/tables/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.872191 173cbf000 Recovering log #3 -2026/08/12-00:06:16.872466 173cbf000 Level-0 table #5: started -2026/08/12-00:06:16.872601 173cbf000 Level-0 table #5: 3739 bytes OK -2026/08/12-00:06:16.872838 173cbf000 Delete type=0 #3 -2026/08/12-00:06:16.872870 173cbf000 Delete type=3 #2 +2026/08/12-10:15:09.940141 17200b000 Recovering log #3 +2026/08/12-10:15:09.940161 17200b000 Level-0 table #5: started +2026/08/12-10:15:09.940281 17200b000 Level-0 table #5: 3739 bytes OK +2026/08/12-10:15:09.940565 17200b000 Delete type=0 #3 +2026/08/12-10:15:09.940598 17200b000 Delete type=3 #2 diff --git a/packs/tables/LOG.old b/packs/tables/LOG.old index e0e34e8..869365b 100644 --- a/packs/tables/LOG.old +++ b/packs/tables/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.713770 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.805210 1726cb000 Delete type=3 #1 diff --git a/packs/talents/LOG b/packs/talents/LOG index 25ac20e..1889c72 100644 --- a/packs/talents/LOG +++ b/packs/talents/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.848619 173cbf000 Recovering log #3 -2026/08/12-00:06:16.848765 173cbf000 Level-0 table #5: started -2026/08/12-00:06:16.848948 173cbf000 Level-0 table #5: 5770 bytes OK -2026/08/12-00:06:16.849247 173cbf000 Delete type=0 #3 -2026/08/12-00:06:16.849307 173cbf000 Delete type=3 #2 +2026/08/12-10:15:09.921227 173023000 Recovering log #3 +2026/08/12-10:15:09.921256 173023000 Level-0 table #5: started +2026/08/12-10:15:09.921405 173023000 Level-0 table #5: 5770 bytes OK +2026/08/12-10:15:09.921672 173023000 Delete type=0 #3 +2026/08/12-10:15:09.921715 173023000 Delete type=3 #2 diff --git a/packs/talents/LOG.old b/packs/talents/LOG.old index fb93ea3..7ba195c 100644 --- a/packs/talents/LOG.old +++ b/packs/talents/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.687537 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.779038 173eef000 Delete type=3 #1 diff --git a/packs/vehicles/LOG b/packs/vehicles/LOG index 0565ef4..247f394 100644 --- a/packs/vehicles/LOG +++ b/packs/vehicles/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.859394 1754e3000 Recovering log #3 -2026/08/12-00:06:16.859688 1754e3000 Level-0 table #5: started -2026/08/12-00:06:16.859874 1754e3000 Level-0 table #5: 6939 bytes OK -2026/08/12-00:06:16.860159 1754e3000 Delete type=0 #3 -2026/08/12-00:06:16.860190 1754e3000 Delete type=3 #2 +2026/08/12-10:15:09.928207 172817000 Recovering log #3 +2026/08/12-10:15:09.928248 172817000 Level-0 table #5: started +2026/08/12-10:15:09.928429 172817000 Level-0 table #5: 6939 bytes OK +2026/08/12-10:15:09.928761 172817000 Delete type=0 #3 +2026/08/12-10:15:09.928810 172817000 Delete type=3 #2 diff --git a/packs/vehicles/LOG.old b/packs/vehicles/LOG.old index 876771f..8fbd016 100644 --- a/packs/vehicles/LOG.old +++ b/packs/vehicles/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.694993 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.786318 173eef000 Delete type=3 #1 diff --git a/packs/weapons/LOG b/packs/weapons/LOG index 7557d5c..7b5de13 100644 --- a/packs/weapons/LOG +++ b/packs/weapons/LOG @@ -1,5 +1,5 @@ -2026/08/12-00:06:16.852833 173cbf000 Recovering log #3 -2026/08/12-00:06:16.853536 173cbf000 Level-0 table #5: started -2026/08/12-00:06:16.853822 173cbf000 Level-0 table #5: 14767 bytes OK -2026/08/12-00:06:16.854096 173cbf000 Delete type=0 #3 -2026/08/12-00:06:16.854134 173cbf000 Delete type=3 #2 +2026/08/12-10:15:09.923574 17382f000 Recovering log #3 +2026/08/12-10:15:09.923739 17382f000 Level-0 table #5: started +2026/08/12-10:15:09.924049 17382f000 Level-0 table #5: 14767 bytes OK +2026/08/12-10:15:09.924348 17382f000 Delete type=0 #3 +2026/08/12-10:15:09.924394 17382f000 Delete type=3 #2 diff --git a/packs/weapons/LOG.old b/packs/weapons/LOG.old index e8dcdd7..2d24c97 100644 --- a/packs/weapons/LOG.old +++ b/packs/weapons/LOG.old @@ -1 +1 @@ -2026/08/12-00:05:23.689273 17134b000 Delete type=3 #1 +2026/08/12-10:14:43.780736 1726cb000 Delete type=3 #1 diff --git a/ringbrp.mjs b/ringbrp.mjs index 83a8c66..f3a0e47 100644 --- a/ringbrp.mjs +++ b/ringbrp.mjs @@ -6259,6 +6259,38 @@ async function migrateFittedGear() { return fixed; } +/** + * Dress this system's journals in the system's own paper. + * + * Twelve pages of generated rulebook, a player primer and a starter scenario were all + * rendering as Foundry's default parchment — the only part of the game that did not + * look like the game. Scoped by a flag rather than applied to every JournalSheet, so a + * module's journals in the same world are left exactly as they were. + */ +/** + * Dress this system's journals in the system's own paper. + * + * Twelve pages of generated rulebook, a ten-page player primer and a starter scenario + * were all rendering as Foundry's default parchment — the only part of the game that + * did not look like the game. Scoped by a flag rather than applied to every journal, so + * a module's entries in the same world are left exactly as they were. + * + * v14 note: the sheet is an ApplicationV2, so the hook is `renderJournalEntrySheet` and + * `element` is the root node itself rather than a jQuery wrapper. Reaching for `[0]` on + * it silently returns the first CHILD — which is how the first version of this appeared + * to work, added the class to a header button, and changed nothing. + */ +const rbBrandJournal = (doc, el) => { + const mine = doc?.flags?.ringbrp?.brand + || (typeof doc?.pack === "string" && doc.pack.startsWith("ringbrp.")) + || doc?.compendium?.metadata?.packageName === "ringbrp"; + const node = el instanceof HTMLElement ? el : (el?.[0] ?? null); + if (mine && node?.classList) node.classList.add("ringbrp-journal"); +}; +Hooks.on("renderJournalEntrySheet", (app, el) => rbBrandJournal(app?.document, el)); +Hooks.on("renderJournalEntryPageSheet", (app, el) => + rbBrandJournal(app?.document?.parent, el)); + Hooks.once("ready", async () => { console.log("RingBRP | ready"); if (!game.user.isGM) return; diff --git a/styles/ringbrp.css b/styles/ringbrp.css index 4b88fdd..9b3e015 100644 --- a/styles/ringbrp.css +++ b/styles/ringbrp.css @@ -36,6 +36,7 @@ .ringbrp-sheet, .ringbrp-chat, +.ringbrp-journal, .ringbrp-window { /* sampled from the 1984 Explorer Book cover */ --rb-void: #0c125b; @@ -423,6 +424,154 @@ .ringbrp-sheet .rb-equip:hover { color: var(--rb-white); } .ringbrp-sheet .rb-equip.on { color: var(--rb-yellow); } +/* ============================================================ + JOURNALS — the department's own paper + ============================================================ + Twelve pages of rulebook and a player primer were rendering as Foundry's default + parchment, which is the one place in the system that did not look like the system. + Scoped to .ringbrp-journal, applied by a hook to this system's entries only, so + other modules' journals are left alone. */ + +.ringbrp-journal .window-content, +.ringbrp-journal .journal-entry-content, +.ringbrp-journal .journal-entry-pages { background: var(--rb-deep); } + +/* The contents rail: this is how a player moves through ten pages. */ +.ringbrp-journal .journal-sidebar { + background: var(--rb-void); border-right: 1px solid var(--rb-line); +} +.ringbrp-journal .journal-sidebar .toc li.page { + font-family: var(--rb-display); font-size: 10px; letter-spacing: .05em; + text-transform: uppercase; color: var(--rb-muted); + border-bottom: 1px solid var(--rb-hairline); +} +.ringbrp-journal .journal-sidebar .toc li.page:hover { color: var(--rb-white); } +.ringbrp-journal .journal-sidebar .toc li.page.active, +.ringbrp-journal .journal-sidebar .toc li.page.readied { + color: var(--rb-void); background: var(--rb-yellow); +} +.ringbrp-journal .journal-header .title { + font-family: var(--rb-display); color: var(--rb-yellow); + background: transparent; border: none; +} + +/* A page. v14 puts the prose straight inside article.journal-entry-page — there is no + .journal-page-content wrapper, which is why the first version of this styled nothing. */ +.ringbrp-journal .journal-entry-page { + background: var(--rb-deep); + color: var(--rb-white); + font-family: var(--rb-body); + font-size: 14px; + line-height: 1.55; + padding: 4px 18px 28px; +} + +.ringbrp-journal .journal-entry-page h1 { + font-family: var(--rb-display); font-size: 19px; letter-spacing: .06em; + text-transform: uppercase; color: var(--rb-yellow); + border: none; border-bottom: 2px solid var(--rb-yellow); padding-bottom: 8px; + margin: 0 0 18px; +} +.ringbrp-journal .journal-entry-page h2 { + font-family: var(--rb-display); font-size: 13px; letter-spacing: .1em; + text-transform: uppercase; color: var(--rb-yellow); + border: none; border-bottom: 1px solid var(--rb-hairline); padding-bottom: 5px; + margin: 26px 0 12px; +} +.ringbrp-journal .journal-entry-page h3 { + font-family: var(--rb-display); font-size: 11px; letter-spacing: .09em; + text-transform: uppercase; color: var(--rb-white); border: none; margin: 20px 0 8px; +} +.ringbrp-journal .journal-entry-page p { margin: 0 0 12px; } +.ringbrp-journal .journal-entry-page strong { color: var(--rb-yellow); font-weight: 700; } +.ringbrp-journal .journal-entry-page em { color: var(--rb-muted); } +.ringbrp-journal .journal-entry-page a { color: var(--rb-yellow); } + +.ringbrp-journal .journal-entry-page ul, +.ringbrp-journal .journal-entry-page ol { margin: 0 0 14px; padding-left: 22px; } +.ringbrp-journal .journal-entry-page li { margin-bottom: 5px; } +.ringbrp-journal .journal-entry-page ul { list-style: none; padding-left: 16px; } +.ringbrp-journal .journal-entry-page ul > li:before { + content: "\25aa"; color: var(--rb-yellow); margin-left: -14px; margin-right: 8px; +} +.ringbrp-journal .journal-entry-page ol > li::marker { color: var(--rb-yellow); font-weight: 700; } + +.ringbrp-journal .journal-entry-page table { + width: 100%; border-collapse: collapse; margin: 0 0 16px; + background: var(--rb-void); border: 1px solid var(--rb-line); +} +.ringbrp-journal .journal-entry-page th { + font-family: var(--rb-display); font-size: 10px; letter-spacing: .08em; + text-transform: uppercase; text-align: left; color: var(--rb-void); + background: var(--rb-yellow); padding: 6px 9px; border: none; +} +.ringbrp-journal .journal-entry-page td { + padding: 6px 9px; border-top: 1px solid var(--rb-hairline); vertical-align: top; +} +.ringbrp-journal .journal-entry-page tbody tr:nth-child(even) { background: var(--rb-panel); } + +/* Read-aloud: the one thing a GM says in somebody else's voice. */ +.ringbrp-journal .rb-readaloud { + margin: 0 0 18px; padding: 12px 16px; + background: var(--rb-void); + border: none; border-left: 3px solid var(--rb-yellow); + color: var(--rb-white); font-size: 15px; line-height: 1.6; +} +.ringbrp-journal .rb-readaloud strong, +.ringbrp-journal .rb-readaloud em { color: var(--rb-yellow); } + +/* Maps and diagrams are typed, not drawn. */ +.ringbrp-journal .rb-map { + background: var(--rb-void); border: 1px solid var(--rb-line); + color: var(--rb-muted); font-family: var(--rb-mono); font-size: 11px; + line-height: 1.45; padding: 12px 14px; margin: 0 0 16px; + overflow-x: auto; white-space: pre; +} + +/* A departmental form: the stamped block a primer page opens with. */ +.ringbrp-journal .rb-form { + background: var(--rb-void); border: 1px solid var(--rb-line); + border-top: 3px solid var(--rb-yellow); + padding: 12px 14px; margin: 0 0 20px; + font-family: var(--rb-mono); font-size: 11px; line-height: 1.7; + color: var(--rb-muted); text-transform: uppercase; letter-spacing: .04em; +} +.ringbrp-journal .rb-form b { color: var(--rb-white); font-weight: 700; } +.ringbrp-journal .rb-stamp { + display: inline-block; border: 2px solid var(--rb-danger); color: var(--rb-danger); + font-family: var(--rb-display); font-size: 11px; letter-spacing: .14em; + text-transform: uppercase; padding: 4px 10px; transform: rotate(-2deg); + margin: 4px 0 14px; +} +/* The line a page lands on. */ +.ringbrp-journal .rb-closer { + font-family: var(--rb-display); font-size: 13px; letter-spacing: .05em; + color: var(--rb-yellow); text-align: center; + border-top: 1px solid var(--rb-hairline); padding-top: 16px; margin-top: 22px; +} +.ringbrp-journal .rb-two { columns: 260px 2; column-gap: 26px; } +.ringbrp-journal .rb-two > * { break-inside: avoid; } + +/* The cheat sheet: a card per rule, so it can be skimmed under pressure. */ +.ringbrp-journal .rb-cards { + display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 12px; margin: 0 0 18px; +} +.ringbrp-journal .rb-card { + background: var(--rb-void); border: 1px solid var(--rb-line); + border-left: 3px solid var(--rb-yellow); padding: 10px 12px; +} +.ringbrp-journal .rb-card h4 { + font-family: var(--rb-display); font-size: 10px; letter-spacing: .09em; + text-transform: uppercase; color: var(--rb-yellow); margin: 0 0 6px; border: none; +} +.ringbrp-journal .rb-card p { margin: 0 0 6px; font-size: 13px; } +.ringbrp-journal .rb-card p:last-child { margin-bottom: 0; } +.ringbrp-journal .rb-big-number { + font-family: var(--rb-display); font-size: 22px; color: var(--rb-white); + line-height: 1.15; display: block; margin-bottom: 6px; +} + /* ============================================================ Shields — armour with a switch, so the switch has to be visible ============================================================ */ diff --git a/system.json b/system.json index b94b754..1278139 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "id": "ringbrp", "title": "The Custodians", "description": "A Basic Roleplaying game of agents who cross the crossing to contain what should not be there — and who come back a little less from here each time.", - "version": "0.8.0", + "version": "0.9.0", "compatibility": { "minimum": 13, "verified": "14.364" @@ -113,6 +113,13 @@ "type": "Item", "system": "ringbrp" }, + { + "name": "primer", + "label": "The Custodians · Read this first (players)", + "path": "packs/primer", + "type": "JournalEntry", + "system": "ringbrp" + }, { "name": "rules", "label": "The Custodians · Rules", diff --git a/tools/build-packs.mjs b/tools/build-packs.mjs index 3c40e0e..8b757e4 100644 --- a/tools/build-packs.mjs +++ b/tools/build-packs.mjs @@ -622,6 +622,7 @@ await writePack("armour", ARMOURS.map(a => { // Handouts are for handing out. A GM who has to change ownership on seven pages // before the session starts will simply read them aloud instead. handouts.doc.ownership = { default: 2 }; + handouts.doc.flags = { ringbrp: { brand: true } }; for (const p of handouts.pages) p.ownership = { default: 2 }; const advId = idFor("adventure:black_platform"); @@ -656,10 +657,25 @@ await writePack("armour", ARMOURS.map(a => { + `${S.STARTER_PAGES.length} GM pages, ${S.STARTER_HANDOUTS.length} handouts`); } +// The player primer. Its own pack, OBSERVER by default, because it is the one thing +// in the system written to be handed to players before anybody has read a rule. +{ + const { PRIMER_PAGES } = await import("./primer-text.mjs"); + const j = journalDoc("The Custodians — Read this first", "primer", PRIMER_PAGES); + j.doc.ownership = { default: 2 }; + j.doc.flags = { ringbrp: { brand: true } }; + for (const pg of j.pages) pg.ownership = { default: 2 }; + const entries = [[`!journal!${j.id}`, j.doc]]; + for (const pg of j.pages) entries.push([`!journal.pages!${j.id}.${pg._id}`, pg]); + await writePack("primer", entries); + console.log(` primer ${PRIMER_PAGES.length} pages, player-visible`); +} + // the slice journal { const { SLICE_PAGES } = await import("./slice-text.mjs"); const j = journalDoc("The Ilfracombe Crossing", "slice", SLICE_PAGES); + j.doc.flags = { ringbrp: { brand: true } }; const entries = [[`!journal!${j.id}`, j.doc]]; for (const p of j.pages) entries.push([`!journal.pages!${j.id}.${p._id}`, p]); await writePack("slice", entries); @@ -693,6 +709,7 @@ await writePack("armour", ARMOURS.map(a => { { const { RULES_PAGES } = await import("./rules-text.mjs"); const j = journalDoc("The Custodians — Rules", "rules", RULES_PAGES); + j.doc.flags = { ringbrp: { brand: true } }; const entries = [[`!journal!${j.id}`, j.doc]]; for (const p of j.pages) entries.push([`!journal.pages!${j.id}.${p._id}`, p]); await writePack("rules", entries); diff --git a/tools/primer-text.mjs b/tools/primer-text.mjs new file mode 100644 index 0000000..4b3c9dd --- /dev/null +++ b/tools/primer-text.mjs @@ -0,0 +1,502 @@ +/** + * 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 => `

${s}

`; +const H = (n, s) => `${s}`; +const UL = xs => `
    ${xs.map(x => `
  • ${x}
  • `).join("")}
`; +const OL = xs => `
    ${xs.map(x => `
  1. ${x}
  2. `).join("")}
`; +const TABLE = (head, rows) => + `${head.map(h => ``).join("")}` + + rows.map(r => `${r.map(c => ``).join("")}`).join("") + + `
${h}
${c}
`; +const READ = s => `
${s}
`; +const FORM = s => `
${s}
`; +const STAMP = s => `
${s}
`; +const CLOSER = s => `

${s}

`; +const CARDS = xs => `
${xs.map(([t, b]) => + `

${t}

${b}
`).join("")}
`; +const TWO = s => `
${s}
`; +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 · Induction pack
" + + "Issued to: new entrant · Retain for the duration of service
" + + "Classification: restricted — 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 " + + "unreal.") + + P("You are not a wizard, a superhero or a chosen anything. 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 crossing.") + + 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 " + + "reality keeps a record of what belongs where.") + + 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("A crossing introduces something the record cannot file. 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 is, 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. " + + "An organisation can be closed. The next impossible doorway still has to be " + + "dealt with.") + + 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 they were ancient.") + + P("So the department has reached an institutional conclusion: the job did not " + + "begin with us, and it will not end with us.") + + 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("Agents use rough, unofficial categories. None of them is in the manual.") + + 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("The department does not assume a duplicate is false or a revenant " + + "mindless. 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("Wrong places are the dangerous ones, because people relax indoors. " + + "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 transposed materiel. 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 Cleaners 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. They are usually more immediately dangerous than the " + + "anomaly.") + + H(2, "The dead who do not leave") + + P("The department does not use ghost 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("The distinction matters. 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 a rule the world " + + "has started enforcing. 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("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.") + + 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 cognitive anomalies, 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 mythos case " + + "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("They are not necessarily evil. 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("Unresolved does not mean harmless. 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("Yours does something slightly different.") + + P("The department calls it continuity, 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 well-seated 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, you are more likely to remember the previous one.", + "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("It is not a superpower. 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, what they are good at comes from work, " + + "education and hard practice — not from destiny.") + + 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("Six weeks does not make anybody an expert. A surgeon recruited " + + "last year is still a far better surgeon than they are a Custodian. Your prior " + + "career sits at " + + `${TRADE_BANDS.core[0]}–${TRADE_BANDS.core[1]}%; what the department taught ` + + `you starts at ${INDUCTION.bandByTier.probationary[0]}–` + + `${INDUCTION.bandByTier.probationary[1]}% and climbs with service.`) + + P("That gap is deliberate, and it is often frightening.") + + 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("You were not picked for being fearless. 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(["You are from the 2020s. Your references, assumptions, work and relationships are contemporary.", + "You had a life before this. Decide what you did well enough that the department needed it.", + "You are not superhuman. Training, teamwork, equipment and preparation keep you alive.", + "Continuity is not immunity. You notice changes better than most people. The changes can still happen to you.", + "You have a reason to stay. Duty, debt, curiosity, guilt, protection, belonging — or knowing nobody else will do it.", + "You need the team. No posting or trade holds every answer. The lowest-ranked person in the room is often the only real expert in it.", + "Decide what anchors you. 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("Then you find out what the briefing got wrong.") + + 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 killing is rarely the " + + "whole answer. 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 " + + "Coherence. It is not sanity and it is not morality. " + + "It is how firmly the world still recognises that you belong here.") + + 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}`, + `${L(b.label)}`, 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. Recovery is slow, and some of it never entirely comes back.") + + P("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.") + + 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 Quiet Arts.") + + 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("Those who do are not superheroes. They are injured people who have learned " + + "how to press on the injury.") +}, + +/* ---------------------------------------------------------------- */ +{ 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.
" + + "There will always be something here that should not be.
" + + "Your job is to go there and sort it out.") +}, + +/* ---------------------------------------------------------------- * + * The cheat sheet. Numbers computed, not typed. + * ---------------------------------------------------------------- */ +{ name: "10 · Cheat sheet — everything you need at the table", content: + FORM("Departmental Custody Service · Field aide-memoire
" + + "One page. Keep it beside you. You do not need to read anything else to play.") + + + H(2, "The only rule you must know") + + P("Roll 1d100. Get equal to or under your skill." + + "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", "Critical", "the best version of what you wanted"], + ["up to a fifth of your skill", "Special", "notably better than you asked for"], + ["up to your skill", "Success", "you do it"], + ["over your skill", "Failure", "you do not"], + ["the top 5% of the range", "Fumble", "you do it wrong, and it costs"] + ]) + + P("The sheet prints those four numbers next to every skill, 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: 96–99 never succeed, however good you " + + "are, and 00 is always a fumble. 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 before you roll.") + + P("Easy doubles your skill. Average leaves it " + + "alone. Difficult 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 two 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("All three are already on your sheet and applied for you.")] + ]) + + P("Difficulty first, then everything else. A skill can never drop below 1%.") + + + H(2, "Fighting") + + CARDS([ + ["Who goes first", + P("Reaction, 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("The first defence each round is free. 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("Only a critical stops a critical.")] + ]) + + TABLE(["Range", "To hit"], + RANGE_LADDER.map(r => [L(`RINGBRP.Range.${r.id}`), + r.mod === null ? "cannot be hit at all" : pc(r.mod)])) + + + H(2, "Getting hurt") + + CARDS([ + ["Hit points", + P("" + egHp + "" + + "(CON + SIZ) ÷ 2, rounded up. The example agent has CON " + EG.con + " and SIZ " + + EG.siz + ".")], + ["Major Wound", + P("" + egMw + "" + + "Half your hit points in one blow. Roll on the table and " + + "something specific and lasting happens.")], + ["Damage modifier", + P("" + egDm + "" + + "STR + SIZ on a ladder. Added to what you hit with.")], + ["Zero hit points", + P("You are dying, not dead. A clock starts, equal to your Major " + + "Wound number, and somebody can still reach you.")] + ]) + + P("Damage comes off your total and 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("Watch the band, not the number — the sheet tells you which one you " + + "are in and what it is costing you.") + + + H(2, "Six things new players ask") + + TABLE(["", ""], [ + ["Can I just shoot it?", + "Often, yes. It rarely closes the case — the crossing that produced it is still open."], + ["What do I roll?", + "Say what you are doing. The GM names the skill. It is on your sheet with its four numbers beside it."], + ["I failed. Now what?", + "The story continues. A failure costs time, resources, position or clarity — it does not stop the case."], + ["Can I help somebody?", + "Yes, and you should. Assisting is a real action, and most specialist scenes want a second pair of hands."], + ["My skill is 5%. Why?", + "You are untrained at it. That is honest, not a mistake. Ask whoever is trained."], + ["Am I going to die?", + "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.") +} +];