A bestiary a GM can actually read, and the defect it found immediately

Forty-six creatures and no way to look at them. They live in content.mjs, which is
source code, and in the compendium, which shows one actor at a time behind two clicks.
A GM prepping a case can browse neither, so in practice the bestiary was whatever the
GM happened to remember writing.

docs/BESTIARY.md is generated, never hand-written, for the reason the rules journal is
generated from rules.mjs: a reference that can disagree with the thing it references is
worse than no reference. It opens with a one-page table sorted by how much of a party
each creature puts on the floor - the part that gets printed - then an entry each with
characteristics, attack, the POWER line pulled out of the tactics, and the measured
figure read straight from the lethality baseline. Every number is derived, so the
document cannot drift, and check-lethality already refuses the build if the measurements
move.

IT FOUND SOMETHING IN ITS FIRST RUN. The generic heavy natural attack is keyed `grasp`
and was NAMED "Vesh grasp limb". Twenty-two creatures carry it and five are Vesh, so the
at-a-glance table cheerfully printed "Vesh grasp limb" against a black dog, a kelpie, a
church grim and an apple tree. Renamed to "Grasping limb"; the key is untouched, so
every kit reference and every built pack still resolves. That defect was invisible for
as long as nobody could see the bestiary in one place, which is the argument for the
document.

The caveats are given more room than the numbers, deliberately. The measured column is
SOLO against ONE frozen party, and the document says so three times: encounter lethality
moves with how many there are and, much harder, with who the players brought - the same
fight runs 0% to 100% across party choice. It points at --spread rather than pretending
a single figure is an answer.

Also records the real remaining gap: 21 creatures fight with nothing but their own
bodies and still carry human anatomy, so the barghest can be shot in the left arm. The
machinery to fix that is built and measured; what is missing is anatomy tables for the
shapes they actually are - a quadruped, an immobile object, a swarm.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
slaguru666
2026-09-01 16:43:39 +01:00
co-authored by Claude Opus 5
parent 4b718595fe
commit 322389bc8a
7 changed files with 987 additions and 2 deletions
+1 -1
View File
@@ -181,7 +181,7 @@ The build runs all eight guards before it writes anything:
<!-- guards:start -->
```
check-rules: OK — 103 rules, 32 files scanned, 3 aliases + 46 constant sets checked, 346 formulas verified
check-rules: OK — 103 rules, 33 files scanned, 3 aliases + 46 constant sets checked, 346 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, 995 keys, no leaf/branch collisions
check-templates: OK — 19 templates compile
+773
View File
@@ -0,0 +1,773 @@
# THE CUSTODIANS — bestiary
*Generated by `tools/bestiary.mjs`. Do not edit: every number is derived from the
statblock or read from the lethality baseline, so this cannot disagree with the game.*
46 creatures. 10 of them are not human-shaped.
## At a glance
Sorted by how much of a four-agent party each one puts on the floor, alone. **Solo figures against one fixed party** — compare creatures with each other, never read them as a prediction of your table. See the note at the foot.
| | Creature | Essence | SIZ | Arm | HP | Attack | Down of 4 |
|---|---|---|---|---|---|---|---|
| | **Quarantine unit** | Sent to contain the same thing you were, and it got here first | 14 | 9 | 17 | Unmaker 75% | 3.69 |
| | **Long walker** | It has been coming here for a very long time and is nearly arrived | 22 | 10 | 24 | Grasping limb 80% | 3.33 |
| | **The stanchion** | Something was driven through the floor here to keep the door from shutting | 21 | 12 | 23 | Grasping limb 45% | 2.25 |
| | **Nuckelavee** | It came up out of the firth and everything it breathes on dies | 20 | 5 | 20 | Grasping limb 85% | 1.68 |
| | **The arrears** | Something was borrowed from the far side in 1968 and this is the collection | 19 | 7 | 20 | Grasping limb 80% | 1.58 |
| V | **The courier** | A Vesh carrying something across, and it will not put it down | 16 | 6 | 18 | Grasping limb 80% | 1.37 |
| | **Surveyor** | It is measuring the site and it will finish | 13 | 8 | 16 | Redaction lance 70% | 1.33 |
| | **The apple tree man** | The oldest tree in the orchard, and it has been owed a drink since 1961 | 19 | 8 | 22 | Grasping limb 55% | 1.10 |
| V | **The yield** | It is here for the harvest and the harvest is annual | 18 | 5 | 18 | Grasping limb 75% | 0.78 |
| | **Cuckoo array** | A machine that has decided it is the site | 20 | 7 | 22 | Grasping limb 55% | 0.76 |
| | **Lost property** | It has been collecting for ninety years and it is not only umbrellas now | 18 | 7 | 21 | Grasping limb 60% | 0.75 |
| C | **The relay** | Cadence machinery holding one end of a crossing open | 17 | 8 | 20 | Grasping limb 55% | 0.69 |
| | **Barghest** | The black dog on the road out of the village | 15 | 3 | 16 | Grasping limb 75% | 0.48 |
| | **Redcap** | The small old man in the ruin, and what he dyes his hat with | 7 | 2 | 13 | Halberd 80% | 0.34 |
| | **Spriggan** | The small ugly thing guarding the barrow, until it is not small | 16 | 4 | 17 | Cudgel 55% | 0.30 |
| | **Church grim** | What was buried at the north door to keep the ground | 14 | 5 | 17 | Grasping limb 70% | 0.25 |
| | **Kelpie** | The horse standing at the water that is not a horse | 18 | 2 | 17 | Grasping limb 65% | 0.23 |
| V | **Precedent** | A Vesh that has already attended the incident you are about to file | 14 | 3 | 15 | Grasping limb 60% | 0.17 |
| | **The waiting room** | You will be seen shortly | 17 | 6 | 19 | Grasping limb 40% | 0.17 |
| C | **The overwriter** | It is correcting the record and it does not know the record is us | 15 | 6 | 18 | Grasping limb 35% | 0.17 |
| | **Grindylow** | What is in the still water at the bottom of the lock | 11 | 3 | 14 | Grasping limb 70% | 0.15 |
| | **Revenant** | What is left when something comes through without a body to come through in | 13 | 4 | 15 | Grasping limb 65% | 0.14 |
| V | **The census** | A Vesh counting what is on this side, and it has got to you | 13 | 4 | 15 | Grasping limb 50% | 0.14 |
| | **The auditor** | It has read the file and it has questions | 11 | 4 | 13 | Service pistol 55% | 0.10 |
| | **The night registry** | The filing that gets done after everyone goes home | 13 | 3 | 16 | Grasping limb 50% | 0.09 |
| | **The predecessor** | Whoever had this desk before you never quite handed over | 12 | 2 | 14 | Service pistol 60% | 0.09 |
| | **Cleaner (marksman)** | The one holding the high ground | 12 | 0 | 12 | Marksman rifle 55% | 0.07 |
| | **The carrion file** | A case file that has been eating the cases filed next to it | 9 | 6 | 16 | Grasping limb 45% | 0.06 |
| | **The locum** | Covering a post that nobody appointed and nobody can close | 12 | 1 | 13 | Service pistol 50% | 0.06 |
| | **Duplicate (of an agent)** | The single most expensive thing a team can meet | 12 | 0 | 13 | Service pistol 50% | 0.05 |
| | **The Keepers (waystation)** | Scavengers who bury what comes through — and the only real information network on the far side | 12 | 0 | 13 | Utility knife 55% | 0.04 |
| | **Cleaner (contractor)** | Human, armed, and working for whoever got here first | 12 | 0 | 12 | Service pistol 45% | 0.04 |
| V | **The margin** | It lives in the space around what was written down | 8 | 2 | 11 | Grasping limb 40% | 0.03 |
| | **The Quiet Neighbours** | Near-world locals who have lived beside the threshold for generations | 8 | 0 | 10 | Improvised spear 50% | 0.01 |
| | **The understudy** | It has been practising being you and it is nearly ready | 12 | 2 | 13 | Punch / kick 60% | 0.01 |
| | **Boggart** | The thing in the house that was tolerable until it was not | 5 | 0 | 9 | Punch / kick 35% | 0.00 |
| | **Hollow man** | Somebody who crossed too often and came back thinner each time | 12 | 1 | 13 | Punch / kick 55% | 0.00 |
| | **The tenant** | What moved into the house while it was empty | 10 | 0 | 11 | Punch / kick 25% | 0.00 |
| C | **The choir** | Eleven people who all say the same thing a half second apart | 11 | 1 | 12 | Punch / kick 50% | 0.00 |
| | **The washer at the ford** | A woman washing clothes in the beck, and one of them is yours | 9 | 0 | 11 | Punch / kick 25% | 0.00 |
| | **Lantern man** | A light on the levels that wants you to follow it | 5 | 0 | 8 | Punch / kick 20% | 0.00 |
| C | **Knockers** | The tapping in the workings, which is either a warning or an invitation | 6 | 2 | 11 | Punch / kick 45% | 0.00 |
| | **Hedley Kow** | It is not dangerous and it will ruin your entire evening | 10 | 1 | 12 | Punch / kick 30% | 0.00 |
| C | **The committee** | It went into session in 1953 and has not risen | 12 | 2 | 15 | Punch / kick 30% | 0.00 |
| | **The minutes** | A faithful record of a meeting that has not been held | 4 | 0 | 7 | Punch / kick 10% | 0.00 |
| | **The switchboard** | It is still connecting calls and some of them are answered | 14 | 4 | 17 | Punch / kick 25% | 0.00 |
**V** = Vesh, **C** = Cadence. Everything else is baseline-human anatomy, including
several things that are plainly not human-shaped — see the note at the foot.
---
## Folklore
Older than the department and largely uninterested in it. Most of these are arrangements rather than fights, and the arrangement is nearly always cheaper.
### Nuckelavee
*It came up out of the firth and everything it breathes on dies*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 24 | 20 | 20 | 8 | 19 | 14 | 5 | 20 | 10 | 7 |
**Attacks with** Grasping limb at 85%, 1d6+1 · **dodges** 50%
**THE BLIGHT.** Everything within ten metres withers — crops, stock, and on a failed CONx5 each round, people, who take 1 point that armour does not stop. It will not cross running fresh water and it knows that about itself, which makes every stream on the map a tactical feature.
*Measured alone against the frozen party: 1.68 of 4 down, 16.5% wiped, 7 rounds.*
### The apple tree man
*The oldest tree in the orchard, and it has been owed a drink since 1961*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 19 | 24 | 19 | 12 | 20 | 4 | 8 | 22 | 11 | 7 |
**Attacks with** Grasping limb at 55%, 1d6+1 · **dodges** 10%
**THE RECKONING.** It knows what is buried in its orchard, all of it, and will say so in exchange for the debt being paid — cider poured on the roots, and somebody has to sing. It cannot be made to answer any other way; threats bore it, being nineteen feet of apple wood.
*Measured alone against the frozen party: 1.10 of 4 down, 2.5% wiped, 12 rounds.*
### Barghest
*The black dog on the road out of the village*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 18 | 16 | 15 | 5 | 16 | 17 | 3 | 16 | 8 | 7 |
**Attacks with** Grasping limb at 75%, 1d6+1 · **dodges** 60%
**THE SUMMONS.** Anyone who meets its eyes must make a POWx5 roll or know, with certainty and no evidence, the manner of their own death; failure costs 1 Coherence and the knowledge does not go away. It attacks only when the person it is following is alone and has stopped being frightened.
*Measured alone against the frozen party: 0.48 of 4 down, 0% wiped, 4 rounds.*
### Redcap
*The small old man in the ruin, and what he dyes his hat with*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 17 | 18 | 7 | 11 | 14 | 19 | 2 | 13 | 7 | 7 |
**Attacks with** Halberd at 80%, 1d10+2 · **dodges** 75%
**NOT TIRED.** It ignores the cumulative defence penalty entirely — every parry it makes is at full skill. Scripture read aloud drives it off; the department keeps a laminated card and does not discuss why it works.
*Measured alone against the frozen party: 0.34 of 4 down, 1% wiped, 3 rounds.*
### Spriggan
*The small ugly thing guarding the barrow, until it is not small*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 21 | 18 | 16 | 9 | 15 | 13 | 4 | 17 | 9 | 7 |
**Attacks with** Cudgel at 55%, 1d6+1 · **dodges** 45%
**WHAT IT REALLY IS.** The characteristics above are the LARGE form. Until the barrow is disturbed run it at SIZ 6 and STR 8, harmless and mostly comic; the change is one round and there is no roll to resist it.
*Measured alone against the frozen party: 0.30 of 4 down, 0% wiped, 4 rounds.*
### Church grim
*What was buried at the north door to keep the ground*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 16 | 20 | 14 | 7 | 19 | 11 | 5 | 17 | 9 | 7 |
**Attacks with** Grasping limb at 70%, 1d6+1 · **dodges** 30%
**THE GROUND IS MINE.** Any agent who digs, opens, or removes something from its ground takes 1d6 with no roll to avoid and no armour, every round they continue. It has no interest in anybody who leaves.
*Measured alone against the frozen party: 0.25 of 4 down, 0% wiped, 4 rounds.*
### Kelpie
*The horse standing at the water that is not a horse*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 21 | 15 | 18 | 9 | 18 | 13 | 2 | 17 | 9 | 7 |
**Attacks with** Grasping limb at 65%, 1d6+1 · **dodges** 45%
**ADHESION.** Anyone who touches it is stuck fast — a STRx5 roll to pull free, at −20% per round already stuck, and it walks into the water at a stroll. It does not fight; drowning is its whole method, so run the ASPHYXIA rules and not a combat.
*Measured alone against the frozen party: 0.23 of 4 down, 0% wiped, 3 rounds.*
### Grindylow
*What is in the still water at the bottom of the lock*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 17 | 16 | 11 | 7 | 12 | 15 | 3 | 14 | 7 | 7 |
**Attacks with** Grasping limb at 70%, 1d6+1 · **dodges** 50%
**THE PULL.** Against a target in water it attacks at +40% and a hit means grappled, not damaged; a grappled target is under and rolling CONx5 each round to keep breathing. Out of water it is slow, half-blind and frankly pitiable — the entire fight is about whether anybody is standing where they should not be.
*Measured alone against the frozen party: 0.15 of 4 down, 0% wiped, 3 rounds.*
### Boggart
*The thing in the house that was tolerable until it was not*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 10 | 12 | 5 | 13 | 17 | 16 | 0 | 9 | 5 | 7 |
**Attacks with** Punch / kick at 35%, 1d3 · **dodges** 65%
**THE WRONG NAME.** Once a scene it addresses an agent by a name that is not theirs but is on a document somewhere; that agent loses 1 Coherence and every roll against the boggart is at −20% for the rest of the scene, because it plainly knows something you do not. Naming it correctly ends it.
*Measured alone against the frozen party: 0.00 of 4 down, 0% wiped, 1 rounds.*
### The washer at the ford
*A woman washing clothes in the beck, and one of them is yours*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 8 | 12 | 9 | 15 | 22 | 11 | 0 | 11 | 6 | 7 |
**Attacks with** Punch / kick at 25%, 1d3 · **dodges** 35%
**THE COLLAR.** Any agent who looks closely enough to read it learns, truthfully, how they die — not when. That agent takes −20% to every roll for the rest of the session and may not be talked out of it; the knowledge is correct.
*Measured alone against the frozen party: 0.00 of 4 down, 0% wiped, 1 rounds.*
### Lantern man
*A light on the levels that wants you to follow it*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 6 | 10 | 5 | 12 | 18 | 20 | 0 | 8 | 4 | 7 |
**Attacks with** Punch / kick at 20%, 1d3 · **dodges** 75%
**THE SHORTER WAY.** Every ten minutes of following, each agent rolls Navigate; on a failure the party is one step further into water, bog or a drop they cannot see. Three failures and somebody is in it.
*Measured alone against the frozen party: 0.00 of 4 down, 0% wiped, 2 rounds.*
### Knockers
*The tapping in the workings, which is either a warning or an invitation*
> **Cadence** — five bodies, no vital, no head. Cannot be dropped; each body lost costs it −10% to everything.
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 9 | 15 | 6 | 13 | 14 | 16 | 2 | 11 | 6 | 5 |
**Attacks with** Punch / kick at 45%, 1d3 · **dodges** 55%
**THE KNOCK.** Once a round they tap on rock; every agent who hears it rolls Listen. On a success the tap is a warning and they learn one true fact about the workings — a bad roof, a flooded level, a way out.
*Measured alone against the frozen party: 0.00 of 4 down, 0% wiped, 2 rounds.*
### Hedley Kow
*It is not dangerous and it will ruin your entire evening*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 12 | 13 | 10 | 16 | 17 | 18 | 1 | 12 | 6 | 7 |
**Attacks with** Punch / kick at 30%, 1d3 · **dodges** 70%
**THE SWAP.** Once per scene it becomes an object or a person the party has already seen, and the party's own gear is what changes: a torch is a milk bottle, a warrant card is somebody else's, a set of keys is a handful of pebbles. Each swap is a genuine loss until found.
*Measured alone against the frozen party: 0.00 of 4 down, 0% wiped, 2 rounds.*
---
## Horror
The department's own. Every one is a piece of administration that kept going after the reason for it stopped.
### Lost property
*It has been collecting for ninety years and it is not only umbrellas now*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 20 | 23 | 18 | 6 | 16 | 5 | 7 | 21 | 11 | 7 |
**Attacks with** Grasping limb at 60%, 1d6+1 · **dodges** 10%
**UNCLAIMED.** Anything an agent sets down in the room is the room's after one round, and cannot be picked up again without a STR roll against STR 20. That includes a rifle put down to open a door, and it will include a person who sits down.
*Measured alone against the frozen party: 0.75 of 4 down, 1.5% wiped, 8 rounds.*
### The waiting room
*You will be seen shortly*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 15 | 21 | 17 | 11 | 22 | 6 | 6 | 19 | 10 | 7 |
**Attacks with** Grasping limb at 40%, 1d6+1 · **dodges** 15%
**SHORTLY.** Every agent who sits down rolls POWx5 at the end of each scene; on a failure they do not want to leave yet, and will explain reasonably why not. Three failures and they are one of the four.
*Measured alone against the frozen party: 0.17 of 4 down, 0% wiped, 6 rounds.*
### The night registry
*The filing that gets done after everyone goes home*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 13 | 18 | 13 | 16 | 21 | 9 | 3 | 16 | 8 | 7 |
**Attacks with** Grasping limb at 50%, 1d6+1 · **dodges** 25%
**CORRECTLY FILED.** Anything left in the building overnight is put where it belongs — which is not where anybody left it, and for a person means the personnel files. An agent who sleeps in the building rolls POWx5; on a failure they wake up on the record as staff from 1961, with that year's clearances and none of their own.
*Measured alone against the frozen party: 0.09 of 4 down, 0% wiped, 3 rounds.*
### The predecessor
*Whoever had this desk before you never quite handed over*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 13 | 15 | 12 | 17 | 20 | 13 | 2 | 14 | 7 | 7 |
**Attacks with** Service pistol at 60%, 1d8+2 · **dodges** 50%
**HANDOVER.** Once a round it performs a task that agent was about to perform, correctly and first. Mechanically that agent loses their action; the thing still gets done, which is what makes it hard to object to.
*Measured alone against the frozen party: 0.09 of 4 down, 0% wiped, 3 rounds.*
### The carrion file
*A case file that has been eating the cases filed next to it*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 14 | 22 | 9 | 14 | 21 | 6 | 6 | 16 | 8 | 7 |
**Attacks with** Grasping limb at 45%, 1d6+1 · **dodges** 15%
**AMENDMENT.** Once a round it may amend one fact about one agent who has read from it — a qualification, a posting, a next of kin — and the amendment is TRUE. Mechanically: it removes one trained skill, or one talent, or one relationship, permanently, and the agent gets no roll.
*Measured alone against the frozen party: 0.06 of 4 down, 0% wiped, 5 rounds.*
### The locum
*Covering a post that nobody appointed and nobody can close*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 12 | 14 | 12 | 15 | 18 | 14 | 1 | 13 | 7 | 7 |
**Attacks with** Service pistol at 50%, 1d8+2 · **dodges** 55%
**OF COURSE.** It may assert one credential per scene and it is believed — by NPCs automatically, and by an agent unless they beat it on Insight against its Persuade. It is not hostile until challenged in front of witnesses, at which point it becomes extremely hostile and extremely plausible about it.
*Measured alone against the frozen party: 0.06 of 4 down, 0% wiped, 2 rounds.*
### The understudy
*It has been practising being you and it is nearly ready*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 13 | 14 | 12 | 14 | 15 | 15 | 2 | 13 | 7 | 7 |
**Attacks with** Punch / kick at 60%, 1d3 · **dodges** 60%
**REHEARSED.** It always acts immediately before the agent it is copying in the reaction order, regardless of the roll, because it has already decided. Kill it and the copy is over; kill the original in front of it and it stops being a copy and becomes the only one, which is worse and is a campaign.
*Measured alone against the frozen party: 0.01 of 4 down, 0% wiped, 2 rounds.*
### Hollow man
*Somebody who crossed too often and came back thinner each time*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 12 | 14 | 12 | 12 | 20 | 14 | 1 | 13 | 7 | 7 |
**Attacks with** Punch / kick at 55%, 1d3 · **dodges** 55%
**THE FILE IS YOURS NOW.** Once per scene it may attempt to swap its own record with an agent's: opposed POWx5. If it wins, the agent loses 2 Coherence and the hollow man gains them; if the agent reaches 0 this way, the two are simply exchanged and the case has a new problem.
*Measured alone against the frozen party: 0.00 of 4 down, 0% wiped, 2 rounds.*
### The tenant
*What moved into the house while it was empty*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 8 | 11 | 10 | 16 | 18 | 9 | 0 | 11 | 6 | 7 |
**Attacks with** Punch / kick at 25%, 1d3 · **dodges** 35%
**TENANCY.** Anybody who spends an hour under its roof must make a POWx5 roll or begin to agree that it lives there; on a failure they will argue the point with their own team. Removing it is a Borrowed Authority problem, not a combat, and the correct answer is to make the record say it never had the tenancy.
*Measured alone against the frozen party: 0.00 of 4 down, 0% wiped, 1 rounds.*
### The choir
*Eleven people who all say the same thing a half second apart*
> **Cadence** — five bodies, no vital, no head. Cannot be dropped; each body lost costs it −10% to everything.
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 11 | 13 | 11 | 9 | 16 | 12 | 1 | 12 | 6 | 5 |
**Attacks with** Punch / kick at 50%, 1d3 · **dodges** 45%
**ONE VOICE.** Every round they are all still standing, every agent within earshot rolls POWx5 or loses 1 Coherence; the roll is at −10% per body still upright. Reducing the choir below six bodies ends the power for good.
*Measured alone against the frozen party: 0.00 of 4 down, 0% wiped, 2 rounds.*
### The committee
*It went into session in 1953 and has not risen*
> **Cadence** — five bodies, no vital, no head. Cannot be dropped; each body lost costs it −10% to everything.
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 9 | 17 | 12 | 18 | 19 | 8 | 2 | 15 | 8 | 5 |
**Attacks with** Punch / kick at 30%, 1d3 · **dodges** 20%
**RESOLVED.** Once per scene the committee passes a motion about the party — that they are not cleared for this floor, that their warrant is withdrawn, that one of them was never appointed. The motion is TRUE from the moment it carries, and it carries unless an agent argues it down with Persuade or Status at −20%.
*Measured alone against the frozen party: 0.00 of 4 down, 0% wiped, 2 rounds.*
### The minutes
*A faithful record of a meeting that has not been held*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 3 | 10 | 4 | 20 | 23 | 12 | 0 | 7 | 4 | 7 |
**Attacks with** Punch / kick at 10%, 1d3 · **dodges** 30%
**AS AGREED.** The minutes record decisions the party will make later in the session. When a recorded decision comes up, the agent may either take it — free, correct, and the minutes were right — or refuse it, and lose 1 Coherence for stepping outside the record.
*Measured alone against the frozen party: 0.00 of 4 down, 0% wiped, 1 rounds.*
### The switchboard
*It is still connecting calls and some of them are answered*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 10 | 19 | 14 | 14 | 24 | 16 | 4 | 17 | 9 | 7 |
**Attacks with** Punch / kick at 25%, 1d3 · **dodges** 35%
**PUTTING YOU THROUGH.** Any agent who picks up is connected to somebody who is dead, or somewhere that is not there, or to themselves earlier in the case. The information is always TRUE and always costs 1 Coherence to have heard.
*Measured alone against the frozen party: 0.00 of 4 down, 0% wiped, 4 rounds.*
---
## The far side
The far side, and what it sends. This is where the non-human anatomies are: a Vesh has no head to shoot off, a Cadence has no vital at all.
### Quarantine unit
*Sent to contain the same thing you were, and it got here first*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 18 | 19 | 14 | 13 | 11 | 16 | 9 | 17 | 9 | 7 |
**Attacks with** Unmaker at 75%, 1d10+30 · **dodges** 65%
**STERILISATION ORDER.** If the team refuses to withdraw, the unit begins a countdown the GM tracks openly — six rounds — after which the site is rendered, and everyone still in it is in a BLAST of 6d6 with a radius of the whole location. They can be argued down with a higher authorisation, which is a Borrowed Authority problem.
*Measured alone against the frozen party: 3.69 of 4 down, 85.5% wiped, 8 rounds.*
### Long walker
*It has been coming here for a very long time and is nearly arrived*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 24 | 25 | 22 | 11 | 24 | 8 | 10 | 24 | 12 | 7 |
**Attacks with** Grasping limb at 80%, 1d6+1 · **dodges** 20%
**DISTANCE MEANS NOTHING.** It cannot be outrun on foot, ever; only a vehicle, a crossing, or a stepping disc breaks contact. Damage slows it and does not stop it: every 10 points it takes costs it one round of movement and nothing else.
*Measured alone against the frozen party: 3.33 of 4 down, 68% wiped, 15 rounds.*
### The stanchion
*Something was driven through the floor here to keep the door from shutting*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 22 | 25 | 21 | 4 | 21 | 2 | 12 | 23 | 12 | 7 |
**Attacks with** Grasping limb at 45%, 1d6+1 · **dodges** 5%
**DRIVEN.** While it stands the crossing beside it cannot be closed by any means, including the Quiet Arts. It has 12 natural armour, so small arms do literally nothing and the party will need the cutter, the demolition charge, or an idea.
*Measured alone against the frozen party: 2.25 of 4 down, 26% wiped, 19 rounds.*
### The arrears
*Something was borrowed from the far side in 1968 and this is the collection*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 21 | 21 | 19 | 14 | 22 | 14 | 7 | 20 | 10 | 7 |
**Attacks with** Grasping limb at 80%, 1d6+1 · **dodges** 55%
**THE PRINCIPAL.** It knows precisely what the department took and from whom; the debt is real and the file confirming it exists in the Registry. Settling it ends the encounter instantly and costs the department something the players will not want to give.
*Measured alone against the frozen party: 1.58 of 4 down, 7.5% wiped, 10 rounds.*
### The courier
*A Vesh carrying something across, and it will not put it down*
> **Vesh** — no head, so no killing shot; the sensory ridge is the vital and is hit on 3 of 20.
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 18 | 19 | 16 | 12 | 17 | 19 | 6 | 18 | 9 | 6 |
**Attacks with** Grasping limb at 80%, 1d6+1 · **dodges** 70%
**THE CONSIGNMENT.** Everything it carries is in the single grasp limb and it will not use that limb to fight while it is carrying — so it attacks with the brace limb at HALF the rating above until the consignment is taken from it. Disable the grasp limb and it drops the consignment and fights properly, at full rating and furious.
*Measured alone against the frozen party: 1.37 of 4 down, 6% wiped, 9 rounds.*
### Surveyor
*It is measuring the site and it will finish*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 15 | 18 | 13 | 17 | 12 | 14 | 8 | 16 | 8 | 7 |
**Attacks with** Redaction lance at 70%, 1d4+6 · **dodges** 50%
**ALREADY SURVEYED.** It knows the ground perfectly: no cover applies against it, and it may not be ambushed. Damaging its instrument makes it leave; damaging the body does not, because there are more bodies.
*Measured alone against the frozen party: 1.33 of 4 down, 7% wiped, 11 rounds.*
### The yield
*It is here for the harvest and the harvest is annual*
> **Vesh** — no head, so no killing shot; the sensory ridge is the vital and is hit on 3 of 20.
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 20 | 18 | 18 | 10 | 16 | 15 | 5 | 18 | 9 | 6 |
**Attacks with** Grasping limb at 75%, 1d6+1 · **dodges** 60%
**THE COUNT.** It takes four. Not five, not three — if the party stops it taking a fourth it will keep working until it has one, and it will not leave without them.
*Measured alone against the frozen party: 0.78 of 4 down, 1% wiped, 6 rounds.*
### Cuckoo array
*A machine that has decided it is the site*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 20 | 24 | 20 | 19 | 14 | 5 | 7 | 22 | 11 | 7 |
**Attacks with** Grasping limb at 55%, 1d6+1 · **dodges** 5%
**HOUSE RULES.** Any device or vehicle brought into the building answers to it within one round unless it is mechanical, sealed, or older than the array — which is why the department still issues an oil lantern and a brass compass.
*Measured alone against the frozen party: 0.76 of 4 down, 1% wiped, 8 rounds.*
### The relay
*Cadence machinery holding one end of a crossing open*
> **Cadence** — five bodies, no vital, no head. Cannot be dropped; each body lost costs it −10% to everything.
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 14 | 22 | 17 | 16 | 23 | 10 | 8 | 20 | 10 | 5 |
**Attacks with** Grasping limb at 55%, 1d6+1 · **dodges** 25%
**WHILE QUORATE.** The crossing holds while three or more bodies stand. Take it to two and the crossing begins to close over a minute; take it to one and it closes now, with whatever is halfway through still halfway through.
*Measured alone against the frozen party: 0.69 of 4 down, 0.5% wiped, 11 rounds.*
### Precedent
*A Vesh that has already attended the incident you are about to file*
> **Vesh** — no head, so no killing shot; the sensory ridge is the vital and is hit on 3 of 20.
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 13 | 15 | 14 | 14 | 18 | 17 | 3 | 15 | 8 | 6 |
**Attacks with** Grasping limb at 60%, 1d6+1 · **dodges** 65%
**COUNTERSIGNED.** Any document an agent files about this scene is found to already bear a second signature, in the agent's own hand, dated earlier. The agent gets no roll; the paperwork is simply already done and already wrong.
*Measured alone against the frozen party: 0.17 of 4 down, 0% wiped, 3 rounds.*
### The overwriter
*It is correcting the record and it does not know the record is us*
> **Cadence** — five bodies, no vital, no head. Cannot be dropped; each body lost costs it −10% to everything.
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 11 | 20 | 15 | 22 | 25 | 12 | 6 | 18 | 9 | 5 |
**Attacks with** Grasping limb at 35%, 1d6+1 · **dodges** 30%
**THE CORRECTION.** Once a round it corrects one FACT the party is relying on — an address, a name in a file, which door the key opens, who signed the warrant. The correction is retroactive and true, and no roll resists it; the party simply finds the world has always been slightly different.
*Measured alone against the frozen party: 0.17 of 4 down, 0% wiped, 6 rounds.*
### The census
*A Vesh counting what is on this side, and it has got to you*
> **Vesh** — no head, so no killing shot; the sensory ridge is the vital and is hit on 3 of 20.
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 12 | 16 | 13 | 18 | 20 | 16 | 4 | 15 | 8 | 6 |
**Attacks with** Grasping limb at 50%, 1d6+1 · **dodges** 55%
**ENUMERATED.** When it counts an agent — one round, no roll, it simply looks — that agent is on a list on the far side. Thereafter anything from the far side knows where they are, permanently, and the department cannot get them off it.
*Measured alone against the frozen party: 0.14 of 4 down, 0% wiped, 4 rounds.*
### The auditor
*It has read the file and it has questions*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 11 | 14 | 11 | 21 | 20 | 12 | 4 | 13 | 7 | 7 |
**Attacks with** Service pistol at 55%, 1d8+2 · **dodges** 40%
**THE DISCREPANCY.** It names one thing an agent has actually done this case — a Quiet Art used in front of a witness, a credential stretched, a body left. That agent rolls POWx5; on a failure the discrepancy is entered and they lose 1 Coherence permanently to it, because it is now on the record and the record is real.
*Measured alone against the frozen party: 0.10 of 4 down, 0% wiped, 3 rounds.*
### The margin
*It lives in the space around what was written down*
> **Vesh** — no head, so no killing shot; the sensory ridge is the vital and is hit on 3 of 20.
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 9 | 13 | 8 | 19 | 24 | 21 | 2 | 11 | 6 | 6 |
**Attacks with** Grasping limb at 40%, 1d6+1 · **dodges** 80%
**NOT MENTIONED.** It can only be perceived by an agent who is NOT currently looking for it; anybody actively searching rolls Spot at −50%, and anybody who has stopped searching sees it immediately. It steals documents and it does not steal anything else.
*Measured alone against the frozen party: 0.03 of 4 down, 0% wiped, 3 rounds.*
---
## Uncategorised
People, mostly — contractors, locals, and the ones who were already here.
### Revenant
*What is left when something comes through without a body to come through in*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 16 | 16 | 13 | 8 | 17 | 14 | 4 | 15 | 8 | 7 |
**Attacks with** Grasping limb at 65%, 1d6+1 · **dodges** 40%
*Measured alone against the frozen party: 0.14 of 4 down, 0% wiped, 3 rounds.*
### Cleaner (marksman)
*The one holding the high ground*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 14 | 12 | 12 | 11 | 14 | 12 | 0 | 12 | 6 | 7 |
**Attacks with** Marksman rifle at 55%, 1d10+2 · **dodges** 35%
*Measured alone against the frozen party: 0.07 of 4 down, 0% wiped, 2 rounds.*
### Duplicate (of an agent)
*The single most expensive thing a team can meet*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 12 | 13 | 12 | 14 | 13 | 14 | 0 | 13 | 7 | 7 |
**Attacks with** Service pistol at 50%, 1d8+2 · **dodges** 45%
*Measured alone against the frozen party: 0.05 of 4 down, 0% wiped, 2 rounds.*
### The Keepers (waystation)
*Scavengers who bury what comes through — and the only real information network on the far side*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 13 | 14 | 12 | 13 | 12 | 13 | 0 | 13 | 7 | 7 |
**Attacks with** Utility knife at 55%, 1d4+2 · **dodges** 45%
*Measured alone against the frozen party: 0.04 of 4 down, 0% wiped, 2 rounds.*
### Cleaner (contractor)
*Human, armed, and working for whoever got here first*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 13 | 12 | 12 | 11 | 10 | 12 | 0 | 12 | 6 | 7 |
**Attacks with** Service pistol at 45%, 1d8+2 · **dodges** 40%
*Measured alone against the frozen party: 0.04 of 4 down, 0% wiped, 2 rounds.*
### The Quiet Neighbours
*Near-world locals who have lived beside the threshold for generations*
| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |
|---|---|---|---|---|---|---|---|---|---|
| 9 | 12 | 8 | 11 | 11 | 16 | 0 | 10 | 5 | 7 |
**Attacks with** Improvised spear at 50%, 1d8+1 · **dodges** 68%
*Measured alone against the frozen party: 0.01 of 4 down, 0% wiped, 2 rounds.*
---
## Reading the measured column
Every figure comes from `tools/lethality-baseline.json`, measured over 200 runs at seed
11 against a frozen party of 4: holloway, okonkwo, nkemdirim, ferriby.
`check-lethality` refuses the build if any of them drifts, so these cannot go stale.
**They are solo figures and they are not a prediction.** Two things move them hard:
- **How many there are.** One Keeper is nothing; six are a 36% chance of a wiped party.
- **Who the players brought.** This is the big one. The same fight measured across every
party the duty roster can field runs from 0% to 100% wiped — Okonkwo alone is worth
forty-three points. Run `node tools/simulate.mjs --creature <key> --count N --spread`
before you decide a fight is survivable.
The harness models banding, graded defences, hit locations, major wounds and the dying
clock. It does **not** model bleeding, panic, Coherence, cover, range bands or fire
modes, and every one of those makes a fight worse for whoever is losing. Read all of it
as a floor.
## A known gap
21 creatures fight with nothing but their own bodies and still carry
baseline-human anatomy. Some of those are people and that is fine. Several plainly are
not — a black dog, a case file that eats the cases filed next to it, a machine that has
decided it is the site — and all of them are hit-located as people, so you can shoot the
barghest in the left arm and open the carrion file's chest.
The machinery to fix it exists, works, and is measured: see any Vesh or Cadence entry
above. What is missing is the anatomy tables for the shapes those creatures actually
are — a quadruped, an immobile object, a swarm — and the statblocks to go with them.
*Private convention play materials — not for sale or distribution.*
+1
View File
@@ -7,6 +7,7 @@
"build": "node tools/build-packs.mjs && node tools/update-readme.mjs",
"icons": "node tools/make-icons.mjs",
"portraits": "node tools/make-portraits.mjs",
"bestiary": "node tools/bestiary.mjs",
"mj": "node tools/mj-queue.mjs",
"simulate": "node tools/simulate.mjs",
"check": "node tools/check-rules.mjs && node tools/check-kits.mjs && node tools/check-lang.mjs && node tools/check-templates.mjs && node tools/check-behaviour.mjs && node tools/check-scenarios.mjs && node tools/check-creatures.mjs && node tools/check-lethality.mjs",
Binary file not shown.
Binary file not shown.
+207
View File
@@ -0,0 +1,207 @@
/**
* The bestiary as a document a GM can read before a session.
*
* There are forty-six creatures and, until this, no way to look at them. They live in
* content.mjs, which is source code, and in the compendium, which shows one actor at a
* time behind two clicks. A GM prepping a case cannot browse either, so in practice the
* bestiary is whatever the GM happens to remember writing.
*
* Generated, never hand-written, for the reason the rules journal is generated from
* rules.mjs: a reference that can disagree with the thing it references is worse than
* no reference. Every number here is derived from the spec or read from the lethality
* baseline, so the document cannot drift from the game.
*
* node tools/bestiary.mjs write docs/BESTIARY.md
* node tools/bestiary.mjs --check fail if it is out of date (for the guards)
*
* The measured column comes from tools/lethality-baseline.json — the same frozen party
* check-lethality uses — so a GM reading "2.1 of 4 down" is reading a number the build
* refuses to let drift. It is a SOLO figure against one fixed party: read it to compare
* creatures with each other, never as a prediction of your table. Encounter lethality
* depends on how many there are and who the players brought, and `simulate --spread`
* exists because that second one swings a fight by up to a hundred points.
*/
import { writeFile, readFile } from "node:fs/promises";
import { existsSync } from "node:fs";
import path from "node:path";
import { NPCS } from "./content.mjs";
import { hitPointsFor, majorWoundFor, locationsFor } from "../rules.mjs";
import { buildCombatant } from "./simulate.mjs";
import { MONSTER_TAGS, carriesNothingManufactured } from "./make-portraits.mjs";
const ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1")), "..");
const OUT = path.join(ROOT, "docs", "BESTIARY.md");
const BASELINE = path.join(ROOT, "tools", "lethality-baseline.json");
const CHECK = process.argv.includes("--check");
const base = existsSync(BASELINE)
? JSON.parse(await readFile(BASELINE, "utf8"))
: { creatures: {}, party: [], runs: 0, seed: 0 };
/* ---------------------------------------------------------------- shaping */
const TAG_ORDER = ["FOLKLORE", "HORROR", "FORWARD", ""];
const TAG_TITLE = {
FOLKLORE: "Folklore",
HORROR: "Horror",
FORWARD: "The far side",
"": "Uncategorised"
};
const TAG_BLURB = {
FOLKLORE: "Older than the department and largely uninterested in it. Most of these are "
+ "arrangements rather than fights, and the arrangement is nearly always cheaper.",
HORROR: "The department's own. Every one is a piece of administration that kept going "
+ "after the reason for it stopped.",
FORWARD: "The far side, and what it sends. This is where the non-human anatomies are: "
+ "a Vesh has no head to shoot off, a Cadence has no vital at all.",
"": "People, mostly — contractors, locals, and the ones who were already here."
};
const tagOf = spec => (String(spec.role ?? "").match(/^([A-Z]{3,})\b/) ?? [, ""])[1] ?? "";
const essenceOf = spec => String(spec.role ?? "").replace(/^[A-Z]{3,}[^.]*\.\s*/, "").trim() || String(spec.role ?? "");
/** The POWER line is the mechanic a GM needs in front of them; the rest is staging. */
function powerOf(spec) {
const m = String(spec.tactics ?? "").match(/POWER:\s*([A-Z][A-Z '’-]*)\.\s*([^]*?)(?=\s*(?:POWER:|$))/);
if (!m) return null;
let body = m[2].trim().replace(/\s+/g, " ");
// Trim to the first two sentences: the rule, and the qualification on it.
const parts = body.split(/(?<=[.!?])\s+/);
return { name: m[1].trim(), rule: parts.slice(0, 2).join(" ") };
}
const SPECIES_NOTE = {
vesh: "**Vesh** — no head, so no killing shot; the sensory ridge is the vital and is hit on 3 of 20.",
cadence: "**Cadence** — five bodies, no vital, no head. Cannot be dropped; each body lost costs it −10% to everything.",
baseline: null
};
function rowFor(spec) {
const c = buildCombatant(spec, { side: "enemy" });
const arm = c.arms[0];
const measured = base.creatures[spec.key] ?? null;
return {
spec, c, arm, measured,
tag: tagOf(spec),
essence: essenceOf(spec),
power: powerOf(spec),
hp: hitPointsFor(spec.ch.con, spec.ch.siz),
locs: locationsFor(spec.species ?? "baseline").length
};
}
const rows = NPCS.map(rowFor);
const danger = r => r.measured ? r.measured.down : -1;
/* Which of them are the wrong shape.
*
* Counting "baseline creatures that carry a category tag" was the first attempt and it
* over-counted badly: the locum and the predecessor are tagged HORROR and are both
* shaped exactly like a man in a lanyard. The structural test is the one mj-queue uses —
* a monster is a thing that was issued nothing by anybody and fights with its own body —
* which catches the black dog and the case file and leaves the people alone. */
const unmodelled = rows.filter(r =>
(r.spec.species ?? "baseline") === "baseline"
&& MONSTER_TAGS.includes(r.tag)
&& carriesNothingManufactured(r.spec));
/* ---------------------------------------------------------------- document */
const esc = s => String(s).replace(/\|/g, "\\|");
const pad2 = n => n.toFixed(2);
let md = `# THE CUSTODIANS — bestiary\n\n`
+ `*Generated by \`tools/bestiary.mjs\`. Do not edit: every number is derived from the\n`
+ `statblock or read from the lethality baseline, so this cannot disagree with the game.*\n\n`
+ `${rows.length} creatures. ${rows.filter(r => (r.spec.species ?? "baseline") !== "baseline").length} of them are not human-shaped.\n\n`;
/* --- the one-page table, which is the part that gets printed --- */
md += `## At a glance\n\n`
+ `Sorted by how much of a four-agent party each one puts on the floor, alone. `
+ `**Solo figures against one fixed party** — compare creatures with each other, never `
+ `read them as a prediction of your table. See the note at the foot.\n\n`
+ `| | Creature | Essence | SIZ | Arm | HP | Attack | Down of 4 |\n`
+ `|---|---|---|---|---|---|---|---|\n`;
for (const r of [...rows].sort((a, b) => danger(b) - danger(a))) {
const sp = (r.spec.species ?? "baseline");
const mark = sp === "vesh" ? "V" : sp === "cadence" ? "C" : "";
md += `| ${mark} | **${esc(r.spec.name)}** | ${esc(r.essence)} | ${r.spec.ch.siz} | `
+ `${Number(r.spec.naturalArmour) || 0} | ${r.hp} | ${esc(r.arm?.w.name ?? "—")} ${r.arm?.rating ?? 0}% | `
+ `${r.measured ? pad2(r.measured.down) : "—"} |\n`;
}
md += `\n**V** = Vesh, **C** = Cadence. Everything else is baseline-human anatomy, including\n`
+ `several things that are plainly not human-shaped — see the note at the foot.\n\n---\n\n`;
/* --- the entries themselves --- */
for (const tag of TAG_ORDER) {
const group = rows.filter(r => r.tag === tag).sort((a, b) => danger(b) - danger(a));
if (!group.length) continue;
md += `## ${TAG_TITLE[tag]}\n\n${TAG_BLURB[tag]}\n\n`;
for (const r of group) {
const sp = r.spec.species ?? "baseline";
md += `### ${r.spec.name}\n\n`
+ `*${esc(r.essence)}*\n\n`;
if (SPECIES_NOTE[sp]) md += `> ${SPECIES_NOTE[sp]}\n\n`;
md += `| STR | CON | SIZ | INT | POW | DEX | Armour | HP | Major wound | Locations |\n`
+ `|---|---|---|---|---|---|---|---|---|---|\n`
+ `| ${r.spec.ch.str} | ${r.spec.ch.con} | ${r.spec.ch.siz} | ${r.spec.ch.int} | `
+ `${r.spec.ch.pow} | ${r.spec.ch.dex} | ${Number(r.spec.naturalArmour) || 0} | ${r.hp} | `
+ `${majorWoundFor(r.hp)} | ${r.locs} |\n\n`;
md += `**Attacks with** ${r.arm ? `${r.arm.w.name} at ${r.arm.rating}%, ${r.arm.w.dmg}` : "nothing"}`
+ `${r.c.dodge ? ` · **dodges** ${r.c.dodge}%` : ""}\n\n`;
if (r.power) md += `**${r.power.name}.** ${esc(r.power.rule)}\n\n`;
if (r.measured) {
md += `*Measured alone against the frozen party: ${pad2(r.measured.down)} of 4 down, `
+ `${r.measured.wipe}% wiped, ${r.measured.rounds} rounds.*\n\n`;
}
}
md += `---\n\n`;
}
/* --- the caveats, which matter more than the numbers --- */
md += `## Reading the measured column\n\n`
+ `Every figure comes from \`tools/lethality-baseline.json\`, measured over ${base.runs} runs at seed\n`
+ `${base.seed} against a frozen party of ${base.party.length}: ${base.party.map(k => k.replace(/^pc_/, "")).join(", ")}.\n`
+ `\`check-lethality\` refuses the build if any of them drifts, so these cannot go stale.\n\n`
+ `**They are solo figures and they are not a prediction.** Two things move them hard:\n\n`
+ `- **How many there are.** One Keeper is nothing; six are a 36% chance of a wiped party.\n`
+ `- **Who the players brought.** This is the big one. The same fight measured across every\n`
+ ` party the duty roster can field runs from 0% to 100% wiped — Okonkwo alone is worth\n`
+ ` forty-three points. Run \`node tools/simulate.mjs --creature <key> --count N --spread\`\n`
+ ` before you decide a fight is survivable.\n\n`
+ `The harness models banding, graded defences, hit locations, major wounds and the dying\n`
+ `clock. It does **not** model bleeding, panic, Coherence, cover, range bands or fire\n`
+ `modes, and every one of those makes a fight worse for whoever is losing. Read all of it\n`
+ `as a floor.\n\n`
+ `## A known gap\n\n`
+ `${unmodelled.length} creatures fight with nothing but their own bodies and still carry\n`
+ `baseline-human anatomy. Some of those are people and that is fine. Several plainly are\n`
+ `not — a black dog, a case file that eats the cases filed next to it, a machine that has\n`
+ `decided it is the site — and all of them are hit-located as people, so you can shoot the\n`
+ `barghest in the left arm and open the carrion file's chest.\n\n`
+ `The machinery to fix it exists, works, and is measured: see any Vesh or Cadence entry\n`
+ `above. What is missing is the anatomy tables for the shapes those creatures actually\n`
+ `are — a quadruped, an immobile object, a swarm — and the statblocks to go with them.\n\n`
+ `*Private convention play materials — not for sale or distribution.*\n`;
/* ---------------------------------------------------------------- write */
if (CHECK) {
const existing = existsSync(OUT) ? await readFile(OUT, "utf8") : "";
if (existing !== md) {
console.error("bestiary: FAILED — docs/BESTIARY.md is out of date. Run `npm run bestiary`.");
process.exit(1);
}
console.log(`bestiary: OK — ${rows.length} creatures, document current`);
process.exit(0);
}
await writeFile(OUT, md, "utf8");
console.log(`bestiary: wrote ${path.relative(ROOT, OUT)} — ${rows.length} creatures across `
+ `${TAG_ORDER.filter(t => rows.some(r => r.tag === t)).length} groupings, `
+ `${rows.filter(r => r.measured).length} with measured lethality`);
+5 -1
View File
@@ -104,7 +104,11 @@ export const WEAPONS = [
{ key: "prybar", name: "Entry bar", cls: "melee", fam: "melee_weapon", spec: "prybar", dmg: "1d10", wound: "blunt", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 3, trad: "tradition_agency" },
{ key: "machete", name: "Machete", cls: "melee", fam: "melee_weapon", spec: "sword", dmg: "1d8+1", wound: "edged", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.1 },
{ key: "spear1h", name: "Improvised spear", cls: "melee", fam: "melee_weapon", spec: "spear", dmg: "1d8+1", wound: "piercing", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 1.8 },
{ key: "grasp", name: "Vesh grasp limb", cls: "melee", fam: "brawl", spec: "", dmg: "1d6+1", wound: "blunt", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 0 },
// Named for the Vesh until the generated bestiary put "Vesh grasp limb" on a black dog,
// a kelpie, a church grim and an apple tree. Twenty-two creatures carry this and five
// of them are Vesh; it is the generic heavy natural attack and now says so. The KEY is
// unchanged, so every kit reference and every built pack still resolves.
{ key: "grasp", name: "Grasping limb", cls: "melee", fam: "brawl", spec: "", dmg: "1d6+1", wound: "blunt", mod: true, ranges: [0,0,0], fire: "", cap: 0, mass: 0 },
{ key: "shortbow", name: "Hunting bow", cls: "bow", fam: "missile_weapon",spec: "bow", dmg: "1d6+1", wound: "piercing", mod: false, ranges: [30,60,90], fire: "single", cap: 12, mass: 1 },
{ key: "pistol_light", name: "Compact pistol", cls: "firearm", fam: "firearm", spec: "pistol", dmg: "1d6+2", wound: "piercing", mod: false, ranges: [10,30,90], fire: "rapid", cap: 8, mass: 0.7, trad: "tradition_agency" },
{ key: "pistol_med", name: "Service pistol", cls: "firearm", fam: "firearm", spec: "pistol", dmg: "1d8+2", wound: "piercing", mod: false, ranges: [10,30,90], fire: "rapid", cap: 15, mass: 1.1, trad: "tradition_agency" },