Commit Graph
16 Commits
Author SHA1 Message Date
slaguru666andClaude Opus 5 cdbb2e34ee R-273: the opposed roll, built where the authority lives
The content has called for 'opposed POWx5' since before the rule existed -- the
hollow man's tactics, CLEAN GROUND twice, slice-text three times -- and rules.mjs
defined none. A scenario carried a local ruling that said in its own text it was a
ruling and not a rule.

Generalises that ruling rather than inventing another: both sides roll, the better
band wins, only the ladder the game already has. Ties go to whoever is being acted
upon, which is what defenceOutcomeFor has always said; the scenario's 'favour the
agent' gave the same answer only because no agent ever initiates one. Neither side
succeeding leaves the contest unsettled rather than won, which the two beats need
in opposite directions.

Two exports at the scenario session's request: opposedOutcomeFor compares graded
levels and carries both, so a caller can price a fumbled attempt without this file
deciding what a fumble costs; opposedContestFor runs it from ratings and rolls with
per-side difficulty, so 'resists at Difficult' does not put applyDifficulty back
into a document. Spot-checked against the real Act Four beat: 55 against 85 at
Difficult, which is 42.

Page 1 states it by asking it -- the tie-break and the margin are computed from the
rule at build time, so the book cannot drift from the engine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 10:42:17 +01:00
slaguru666andClaude Opus 5 24b1aaa682 Development: skills improve from what beat you, not what worked
Reversed experience. A skill is marked when it FAILS - failure or fumble - and
never when it works, and the improvement roll is the same reversal: roll OVER
your rating and the skill goes up 1d6. Nobody learns anything from the lock that
opened first time.

The two halves pull against each other on purpose, so ratings converge instead of
running away. Simulated over 2000 campaigns: a 10% and an 85% skill start 75
points apart and are 11 apart after 60 cases.

- rules.mjs owns it: DEVELOPMENT, developmentMarksOn, developmentImproves,
  developmentCeiling, developmentGainFor
- trainingCap has been on the skill schema and the item sheet since it was
  written and nothing has ever read it. Development reads it now: a skill stops
  at its own cap, and everything else stops at DEVELOPMENT.ceiling, because a
  d6 gain could otherwise push a 98% skill past 100
- GM opens the phase from a GM-only toggle in the token controls; it posts a
  card naming every agent and their marked count, and puts a Development button
  on each sheet. Players press their own
- the toggle re-reads the setting on change, since getSceneControlButtons only
  fires at load and the button would otherwise lie if the phase were opened by
  the API or a second GM
- rules journal and player primer rewritten from the tables; the old text
  described the pre-reversal rule on both halves
- 7 spot-checks, 4 behaviour tests; verified end to end in a running Foundry

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 23:23:03 +01:00
slaguru666andClaude Opus 5 5aaae186e0 A fumbled relief attempt puts a point on
Trying to steady somebody and making it worse is the most familiar thing on that
list, and until now it was the only outcome that cost nothing.

Done as a NEGATIVE relief rather than a second code path: panicReliefFor returns
-1 on a fumble, and easePanic already subtracts what it is given, so subtracting
a negative raises the track. One number, one direction, no branch that could
drift from the other. The clamp still holds — fumbling at 5 stays at 5.

The chat card had to be told, because otherwise it prints the word "Psychology"
over a number that has just gone UP and the table reads that as a bug rather than
as the rule. It now leads with a red FUMBLED tag.

Guarded three ways: a spot-check in check-rules for the -1 itself, and two
behaviour tests — one that the sign survives easePanic's subtraction and
actually raises the track, one that it cannot push past the top. A test on the
constant alone would have passed even if easePanic had healed on a fumble.

Verified live: 2 → fumble → 3 → success → 2 → special → 0, and a fumble at 5
staying at 5, with the cards reading correctly.

Version 1.1.2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 23:25:46 +01:00
slaguru666andClaude Opus 5 20306d83d9 Play a scene with panic; tighten one reference row
Ran LAST ADMISSION's east corridor with the six civilians and real dice. The
track works end to end and, more importantly, the penalty REACHES things:
Ferriby at panic 3 swung at Old Marrow with Brawl 25% printed and 15% effective,
while Sharrock at panic 1 rolled his full 58%. That is the whole point of the
track and it is the part that is usually decoration.

The arc played well. Lights out took four of them to 1. The body took Braithwaite
and Ferriby to 2. Enderby counting took three of them again. Braithwaite fumbled
his Psychology roll trying to talk Colin down, then it said his name — 5, broke,
fled, came back at 3. Renshaw steadied herself on POW×5 and dropped to 1.

One thing I got wrong and one thing worth knowing:

  - I flagged a 99 grading as a fumble as a bug. It is not. A 58% skill fumbles
    on 98-00, and both the primer and the rules page say so in those words. The
    "96-99 never succeed / 00 always fumbles" pair are floor rules, not the whole
    fumble range. Only the quick-reference row was ambiguous — it now says
    "never succeeds ... and is a fumble if it is inside your fumble range".

  - The civilians cannot use two of the three new skills. Occult, Religion and
    Psychology sit at 5% on the "(before)" sheets, so in the prologue the only
    relief that works is POW×5 at 50-85%. That is correct — a site foreman is
    not an occultist — but it means the skills are an AGENT'S tools, and the
    prologue is deliberately the game without them. The agents have them where
    they should: Bhattacharya Occult 63, Lindqvist 58, Renshaw Psychology 40,
    Braithwaite Religion 35.

Version 1.1.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 21:58:30 +01:00
slaguru666andClaude Opus 5 cbad87ba98 Add Occult, Religion and Psychology, and the Panic track
From the first game's list. The three skills are not decoration — they are the
levers on the new track, which is why they arrived together.

PANIC, 0 to 5, up. It is the other half of Coherence and the rules page says so
in the first line, because a table that confuses them will make the wrong call
at the worst moment:

    Coherence   what knowing has cost you       weeks     10-0, down
    Panic       what is happening to you NOW    minutes    0-5, up

A trigger gives a point with NO ROLL. Asking for a die to find out whether you
are frightened slows the scene and tells the player how to feel; the die is for
getting rid of it, which is the interesting direction.

    0 steady · 1 rattled · 2 shaken -5% · 3 losing it -10%
    4 overwhelmed -20% · 5 broken

The first point is free on purpose, so the opening shock of a scene costs the
table nothing. At 5 you break — freeze, flee or fixate, choose fast — and come
back at 3, not at 0, because breaking is not a rest.

Relief is where the skills come in. A success takes one point, a special takes
two. Psychology is the only thing that steadies somebody who is NOT you.
Religion steadies you alone and does not care whether you are right. Occult is
the odd one: naming a thing correctly, out loud, helps everybody who can hear —
the department's actual work, and the only relief that reaches a room. Plus
POW×5 to steady yourself, and your anchor object once per case, which is what
that briefing scene was for.

The three skills are placed in six registers rather than left floating: Occult
to the professor and to Registry, Psychology to the doctor and to Interview,
Religion to Antiquities and Pathology.

Guards, because a track nothing reads is this project's oldest failure: the five
new rules carry spot-checks in check-rules, and check-behaviour gains nine tests
— the free first point, monotonic penalties, only 5 breaking, clamping at both
ends, breaking not clearing the track, special taking two, every band/trigger/
relief having a label, and every relief naming a skill the catalogue actually
has.

Verified in a live game: penalty reaches the roll (58 → 58 → 53 → 48 → 38 for
panic 0-4, criticals and specials recomputed with it), the full arc runs 0 → 2 →
4 → eased to 2 → pushed to 5 → breaks → 3 with no errors, the sheet shows the
band, and the rules journal has a Panic page generated from the same tables.

Version 1.1.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 22:55:11 +01:00
slaguru666andClaude Opus 5 43508259ac Consolidation pass after a Codex review
Four real defects, each verified against the source before acting on it.

Trade expertise was coupled to agency rank. A probationary burglar came out at 35-50%
and a veteran at 65-80%, as though fifteen years of picking locks were something the
department conferred. TRADE_BANDS is now fixed at 50-65/30-50 at every rank, and
INDUCTION scales with service instead (20-32 probationary to 45-60 veteran) because
that half genuinely is the department's. The two axes were the wrong way round. This
is the thing I flagged myself after PAPER HARBOUR and then left alone — flagging a
defect is not the same as fixing it.

Bonus points were sprayed across every skill in the game. grantFullSkillList runs
immediately before the loop and puts all fifty-nine skills on the sheet, and the loop
picked from actor.items, so a veteran's ninety points landed anywhere. The comment two
hundred lines above has always said "over the core skills"; the code never did.

"Random species" passed "baseline" into generators that support random perfectly well.

No behavioural tests. The strongest point in the review: the three guards are static
and none of them can tell whether a rule is READ, which is the only kind of defect this
project has ever shipped. tools/check-behaviour.mjs now runs 28 deterministic tests,
gated into the build, covering R-231/232/243/245/246, graded defences and the lamp
rule. Proved it bites by re-breaking R-246.

The register moved to postings.mjs, a Foundry-neutral module the engine, rulebook,
guards and tests all import normally — they were previously pulled out of the engine
with a regex and eval, which worked and was a trap. My first version of that used
`export … from`, which re-exports without local bindings, so ROLES was undefined and
the system threw on init: node --check passes that, loading it in Foundry does not.

Also: the contact doc comment still said "only OFFER moves standing"; check-kits
accepted mas/app, which are the DISPLAY names of siz/cha, so a posting declaring one
would have passed and produced an undefined characteristic; package.json disagreed with
the manifest; README counts were three revisions stale and are now generated at build.

Deferred with reasons: splitting the 6,700-line engine into modules. Right, and a
multi-session refactor whose risk is exactly the silent breakage demonstrated above.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 22:57:20 +01:00
slaguru666andClaude Opus 5 79acc8227f Ten trades, an induction layer, and rolling the stats yourself
TRADES: ten ordinary jobs the department recruits from — construction worker, doctor,
professor, engineer, law enforcement, IT specialist, scientist, linguist, entertainer,
criminal. They are not postings. A posting is what the department made of you; a trade
is what you were before any of it.

A trade character is built in two halves. The trade is genuine expertise on the same
bands a posting's skills use — a doctor is a proper doctor. INDUCTION goes on top at
25-40%: Tradecraft, Anomaly Lore, First Aid, Firearm (Pistol), Dodge, plus a sidearm, a
vest, cordon kit, a cover identity and a ward. The band is low on purpose; six weeks is
not a career, and that gap is most of what it feels like to play one.

Induction never demotes: a former police officer keeps pistol 58 from the trade rather
than being re-taught it at 26.

The creation dialog gains a "Recruited as" switch with its own trade list and card
(which shows both halves), and check-kits now holds trades and induction to the same
standard as postings — both new guard paths verified by breaking them.

Rolling them yourself: a tickbox that walks the eight characteristics one at a time,
each roll announced to chat so the dice actually fall, "Take them" locked until all
eight are down. A hand-rolled character is taken exactly as it fell — no best-of-three
on the key stat, no species shift. Verified both ways.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 21:48:06 +01:00
slaguru666andClaude Opus 5 c61700566c Shields: armour you raise, and the only armour you can defend with
A shield is the one piece of armour you hold, and it protects you exactly as much as
you are currently holding it up. Raised, its points apply to what it covers and it can
parry on a new Shield skill. Lowered, it is weight. The price of keeping it up is that
it occupies a hand and you are shooting around it: -20% to your own ranged attacks,
printed on the card like everything else. Only one shield goes up at a time.

Seven of them, 2-point buckler to 6-point ballistic shield; the pavise and barrier
plate cover legs too because they are walls you carry.

`degradation` finally does something — it has been on every armour item since the packs
were first built and was read by nothing. A blow costs the shield a point of wear for
every step it stood above an ordinary success, so an ordinary hit costs nothing, a
special 1 and a critical 2. At its limit it comes apart, drops, and will not be raised
again.

Two defects found by driving the real functions rather than reading the diff, both
introduced by this change:

- Every shield defence quietly rolled DODGE. "shield" passed through
  defenceTypeAllowed unchanged, so neither parry branch matched and it fell through.
  Invisible in the card; it showed up as eight rolls at a supposed 85% returning six
  failures. Taking a blow on the shield IS a parry, so it is now a flag on a parry
  rather than a defence type of its own.
- The wear rule was unreachable: it fired only on a clean stop, but under graded
  defences only a critical fully stops a critical, so a shield would never have taken
  a scratch. Wear is for what the shield ABSORBED — dragging a critical down to a
  special is exactly when shields splinter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 18:25:30 +01:00
slaguru666andClaude Opus 5 4bfa7110d0 A lamp lights the people standing in it
The goods yard fight made the case: three agents inside the same pool of light shot at
-50% while the fourth, four metres away, shot at -10%.

A lamp now has a reach, per item rather than global, because a weapon lamp and a
vehicle searchlight are not the same offer — 4 m for cold light strips, 6 m for a
weapon lamp, 10 m for the issue field lamp, 30 m for a roof searchlight. Anyone inside
it is in the light and the card names whose lamp it is, so both halves of the rule
travel together: the pool is one position and the whole group is standing in it.

Measured from the tokens. The shot that started this — no lamp of her own, four metres
from somebody else's, in pitch dark — goes from 20% to 60%, while an agent
twenty-five metres out still eats the full -50%.

An UNKNOWN distance is explicitly not lit: Number(null) is 0, so an unmeasured
distance would otherwise have read as standing on top of the lamp and lit any scene
with no tokens placed. The dialog carries a tick instead, pre-set when the canvas could
measure it and the GM's answer when it could not.

Note: template.json is read when Foundry loads the system, so a deployed server needs
a restart and not just a pull before the migration can stamp the new field.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 09:49:30 +01:00
slaguru666andClaude Opus 5 2e10ecced9 Fire modes, fitted sights and lamps, and a tab rail
Selectable fire, with the modifiers on the choice
  Every weapon has carried a fireMode since the packs were first built and nothing
  read it: a musket could rip a ten-round burst and "rapid" bought a weapon nothing.
  FIRE_MODE now gates the burst rules and carries its own attack modifier — slow +10%
  and then you work for the next one, fast a second shot at -20% to both, rapid
  bursts, beam +5% and it can be held on the target for damage instead of hits. The
  gate lives in burstAttack too, so no macro can route round it. `fast` was on five
  catalogue weapons and was not in the system's list of modes at all, so re-saving one
  of them silently blanked it; the list is derived from the rule now.

  burstAttack shipped complete and was reachable from nothing. It is the resolution
  path the selector chooses, and takes the dialog's whole stack rather than charging
  the player twice for the same burst.

Sights and lamps that apply themselves
  A sight is graded by range band, so a telescopic sight is a -10% liability inside
  ten metres and worth +20% at extreme, and it only counts if it fits. The band is
  already known when the modifier is wanted, so nothing is selected and nothing is
  forgotten. The dark costs something now; a carried lamp buys it back to dim, never
  to daylight, and the card says it shows them exactly where you are. A migration
  fits gear that predates the fields, matched on the stamped key rather than by name.

The damage card
  The last card still wearing Foundry's stock dice styling — it posted a bare Roll and
  let the core template dress it. It renders through the module's own card now, with
  the Roll still on the message so dice stay inspectable.

A rail instead of a strip
  Eight tabs across an 820px sheet compressed to 11px type. They run down the side
  now, one line each, with counts as badges; the sheet is 152px wider to pay for it.

Also fixed: any weapon with a Coherence cost could not be attacked with AT ALL — the
handler re-read the weapon after an await, when currentTarget is already null, and the
attack died on a TypeError with nothing shown. And the duplicate-rule guard failed an
honest table because FIRE_MODE and speedBands share two key names; it wants a majority
now, and prints partial overlaps rather than swallowing them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 08:56:04 +01:00
slaguru666andClaude Opus 5 ee9e1f5b73 Codex review pass: three real faults corrected
R-228: Ambidextrous was a compulsory build. 0/-20 gave a full-strength main hand
AND a cheap second attack. It now buys consistency, not a free attack: -20 in both
hands against -20/-40 untrained.

R-229: full auto was a firing squad. Ten independent hits off one critical, each
with its own damage, location and Major Wound check. Hits capped at 3/5/7, and a
burst is ONE wounding event however many rounds connect.

R-230: Engines deleted the pressure it existed to create. Guns +2 and Helm +1
against a vent of 3 made a fighting round heat-neutral, so Heat only mattered when
the engineer failed. Venting is now 2/3/4.

Also: falling halving no longer stacks (soft + controlled quartered the drop);
blast has one formula floored once, so the answer no longer depends on call order.

And the structural note — "giving everyone a roll is not the same as giving
everyone a decision". Sensors, Damage Control and Medical now have mutually
exclusive modes that bite in the engine: mark/spoof/read, patch/brace,
restore/steady.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 08:07:58 +01:00
slaguru666andClaude Opus 5 226f853ee6 Hazards, automatic fire, two weapons, a bestiary, and space combat
Stress test first: 150 characters across every posting, tier and species against
fourteen invariants each, then the edges (characteristics at 1/3/21, every
location destroyed, twelve pikes carried, hp set to -99).

R-227: a destroyed head was a nap. The printed effect has always read "For
anything that keeps its brain there, this is death" and the code set unconscious
and stopped. destructionOutcomeFor() now says what destruction means.

THE WORLD: falling (a die per 3 m, armour does not apply), drowning (CON rounds
then a point a round, straight past the Major Wound threshold), fire (a condition
with a size; armour helps on the round you catch and never after), explosives
(one roll at the centre, shared by band, cover beats armour).

AUTOMATIC FIRE: one roll, the success level says how much of the burst arrived,
and the rounds are spent either way. TWO WEAPONS: -20/-40, or 0/-20 with the new
Ambidextrous talent; the off hand takes the lighter weapon and nothing over 2 kg.

BESTIARY: 21 entries in three families — folklore, horror, and what comes back
from further along — each with characteristics, natural armour, tactics and a
POWER written as a rule with a cost.

SPACE: eight stations, each on a skill somebody already has, so the Physician has
a chair. Range is a band; the helm moves one a round, in or out. Heat is the
pressure and took two rounds of playtest tuning to stop being a countdown.

64 rules, 198 spot-checked formulas, a 12-page rulebook in reading order.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 08:02:21 +01:00
slaguru666andClaude Opus 5 5c114601a9 R-224: a body at zero absorbed damage for free
Hit points clamp at zero, so further damage to somebody already there changed
nothing — and a STABILISED agent absorbed it forever, because the count was held
and there was nothing else left to move. You could empty a magazine into someone
bleeding out and the system would not notice.

Damage at zero now breaks the stabilisation and costs a round of the count, and
hitLocationRoll calls died() when that meets the limit.

Found by playing LOW VERGE until it killed somebody: two agents who were
medically stable died in the water on a failed tidal extraction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 22:24:55 +01:00
slaguru666andClaude Opus 5 89ce557355 Death at zero, and a case brief that answers the useful questions
R-223: nothing happened at 0 hit points. An agent was marked down and lay there
forever; the only mention of death in the system was flavour text on a destroyed
head. Zero now starts a clock whose length is the agent's own Major Wound
threshold, ticked from the same hook that charges blood loss. First Aid or
Medicine stabilises and stops the count; healing above zero clears it; heal()
refuses the dead. On death, Coherence decides what the record says — from a
proper death in service down to not being recorded as dead at all.

Case generator: four phases instead of five (the arc drew two interchangeable
middles that read as padding). The brief now leads with Where / When /
Classification / Phases, states the opposition in full, and has a "How you get
back" section. place and duration were generated and never printed. The same
facts are on the case file itself. 300 seeds checked for object leaks; one found
and fixed (group taboo/desire are objects with .text).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 22:13:21 +01:00
slaguru666andClaude Opus 5 cc23fdb7bd Rulebook and compendium refresh
Audited every exported rule in rules.mjs against what the rulebook says and closed
the gaps:

- Dodge starts at DEX x 2 — newly evaluated, and stated nowhere until now
- Encumbrance: free carry, and which skill categories it actually penalises
- Bleeding rates and what stops each kind
- The merge ladder for Borrowed Authority, as a table
- A new page listing all 25 postings, generated from ROLES

The rulebook is now 9 pages and every one is generated from the code it documents.
All packs, 231 icons and the dice textures rebuilt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 20:31:01 +01:00
slaguru666andClaude Opus 5 d0144f744e The Custodians v0.6.1 — full system
A Foundry VTT game system: Basic Roleplaying d100 in a drab British agency that
deals with crossings, where reality keeps a record of what belongs where and can be
made to get it wrong.

Contents:
- rules.mjs as the single authority for every rule formula, with 40 rules and 132
  spot-checked values. Nothing may restate a formula it defines.
- 25 postings, each with a key characteristic, trained skills, talents and its own
  kit; a 175-item catalogue across four eras; 231 generated icons.
- Reaction Lanes initiative, re-rolled every round including the first.
- Coherence, and the Quiet Arts, which only ever arrive from a crossing gone wrong.
- Graded defences: only a critical stops a critical.
- Borrowed Authority — access as a record rather than a hacking roll.
- A case generator, and a rules journal generated from rules.mjs so the book cannot
  drift from the code.

Built compendia are committed so a remote Foundry needs only the files.
node_modules is not; `npm install` restores it for rebuilding content.

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