Issue riot shields to Containment and the Night Warden
Both postings draw a riot shield, and both are trained to use it — issuing one without the skill would have been R-212 again with a different item, the Antiquities Officer who drew a flintlock and rolled 5% with it. melee_weapon:shield is SWAPPED into each support list rather than added, so five core and five support are preserved and the shield arrives without a free power bump. Containment drops stealth (a posting whose job is being the thing in the doorway was always the least stealthy in the department); the Night Warden drops navigate (they sit with one site all night). check-kits now requires the Shield skill for an issued shield, the same way it has always required training for an issued weapon. Verified by removing the skill and watching the build refuse. Four generated agents: shield skill at 25-30%, nobody encumbered, though a Containment officer lands at 32.9 of 33 kg. The shield ships slung — raising it is the choice, and for the Warden it is the difference between 2 points of armour and 5. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0c2636d543
commit
53eb72c100
@@ -4617,3 +4617,39 @@ two defects found while building it.
|
||||
Worth noting for anyone issuing shields: a riot shield is `torsoArms`, and in melee
|
||||
**legs and head are 10 of 20**. A shield is not a suit of armour and this fight is what
|
||||
that sentence costs.
|
||||
|
||||
## Riot shields for Containment and the Night Warden
|
||||
|
||||
Both postings now draw a **riot shield** from stores, and both are trained to use it.
|
||||
|
||||
Issuing a shield without the skill would have been R-212 again with a different item —
|
||||
the Antiquities Officer who drew a flintlock and rolled 5% with it — so
|
||||
`melee_weapon:shield` goes into each posting's support list. It is **swapped in, not
|
||||
added**: keeping five core and five support means the shield arrives without a free
|
||||
power bump, which is not what was asked for.
|
||||
|
||||
* **Containment** drops `stealth`. A posting whose blurb is "goes through the door,
|
||||
holds the corridor" was always the least stealthy thing in the department.
|
||||
* **Night Warden** drops `navigate`. They sit with one site all night; they are not
|
||||
going anywhere.
|
||||
|
||||
**check-kits now covers shields.** The guard has always required a posting to be
|
||||
trained in the weapons it carries, and a shield is armour you defend *with*, so it
|
||||
needs its skill for exactly the same reason. Verified by removing the skill from the
|
||||
Warden and watching the build refuse:
|
||||
|
||||
check-kits: FAILED
|
||||
warden (Night Warden): issued Riot shield, trains no melee_weapon:shield
|
||||
|
||||
**What it does to the two postings.** Four generated agents, shield skill landing at
|
||||
25–30% (the support tier), and none of them encumbered — though a Containment officer
|
||||
came out at 32.9 of 33 kg, which is as close to the line as this kit should get.
|
||||
|
||||
| | slung | raised |
|
||||
|---|---|---|
|
||||
| Containment (breaching suit, `all` 7) | 7 everywhere | torso and arms **10**, legs and head 7 |
|
||||
| Night Warden (stab vest, `torso` 2) | torso 2, all else 0 | torso **5**, arms **3**, legs and head 0 |
|
||||
|
||||
The shield ships **slung**. Raising it is a choice made at the table, which is the whole
|
||||
design — and for the Warden it is the difference between two points of armour and a
|
||||
real one.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.919810 17373b000 Delete type=3 #1
|
||||
2026/08/11-21:36:45.974918 171407000 Delete type=3 #1
|
||||
|
||||
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.954955 173f47000 Delete type=3 #1
|
||||
2026/08/11-21:36:46.010315 1703ef000 Delete type=3 #1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.921916 172723000 Delete type=3 #1
|
||||
2026/08/11-21:36:45.977183 171407000 Delete type=3 #1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.938436 172723000 Delete type=3 #1
|
||||
2026/08/11-21:36:45.995509 171c13000 Delete type=3 #1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.946701 172723000 Delete type=3 #1
|
||||
2026/08/11-21:36:46.003934 1703ef000 Delete type=3 #1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.928648 172723000 Delete type=3 #1
|
||||
2026/08/11-21:36:45.985591 171c13000 Delete type=3 #1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.951456 172f2f000 Delete type=3 #1
|
||||
2026/08/11-21:36:46.008640 171c13000 Delete type=3 #1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.912459 172f2f000 Delete type=3 #1
|
||||
2026/08/11-21:36:45.965730 171c13000 Delete type=3 #1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.945043 17373b000 Delete type=3 #1
|
||||
2026/08/11-21:36:46.002345 1703ef000 Delete type=3 #1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.943087 17373b000 Delete type=3 #1
|
||||
2026/08/11-21:36:46.000570 170bfb000 Delete type=3 #1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.915613 173f47000 Delete type=3 #1
|
||||
2026/08/11-21:36:45.970370 1703ef000 Delete type=3 #1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.924112 172723000 Delete type=3 #1
|
||||
2026/08/11-21:36:45.980477 171c13000 Delete type=3 #1
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026/08/11-18:22:31.917625 172f2f000 Delete type=3 #1
|
||||
2026/08/11-21:36:45.972739 171c13000 Delete type=3 #1
|
||||
|
||||
+4
-4
@@ -3774,9 +3774,9 @@ export const ROLES = {
|
||||
heavy: { label: "Containment",
|
||||
blurb: "Containment. Goes through the door, holds the corridor, and puts things in boxes that do not want to be in boxes.", stat: "str",
|
||||
core: ["firearm:rifle","brawl","melee_weapon:prybar","athletics","dodge"],
|
||||
support: ["demolition","first_aid","repair:mechanical","spot","stealth"],
|
||||
support: ["demolition","first_aid","repair:mechanical","spot","melee_weapon:shield"],
|
||||
talents: ["hard_landing","chain_custody","first_through","clean_scene"],
|
||||
kit: ["rifle_med","breach_suit","prybar","restraints","climbing_kit", "bolt_croppers", "cordon_kit", "ear_defenders"] },
|
||||
kit: ["rifle_med","breach_suit","prybar","riot_shield","restraints","climbing_kit", "bolt_croppers", "cordon_kit", "ear_defenders"] },
|
||||
/* ---------------------------------------------------------------
|
||||
The rest of the establishment.
|
||||
|
||||
@@ -3820,9 +3820,9 @@ export const ROLES = {
|
||||
warden: { label: "Night Warden",
|
||||
blurb: "Sits with a site overnight so that nobody else has to. Listens, watches, and writes down the times.", stat: "con",
|
||||
core: ["listen","spot","stealth","dodge","brawl"],
|
||||
support: ["first_aid","navigate","athletics","melee_weapon:club","anomaly_lore"],
|
||||
support: ["first_aid","melee_weapon:shield","athletics","melee_weapon:club","anomaly_lore"],
|
||||
talents: ["unblinking","out_of_step","first_through","clean_scene"],
|
||||
kit: ["oil_lantern","ward","cudgel","stab_vest","torch", "vacuum_flask", "stopwatch", "blanket"] },
|
||||
kit: ["oil_lantern","ward","cudgel","riot_shield","stab_vest","torch", "vacuum_flask", "stopwatch", "blanket"] },
|
||||
|
||||
stores: { label: "Stores Officer",
|
||||
blurb: "Requisition, custody and the paperwork that moves materiel. Can get you a thing the department says it does not have.", stat: "edu",
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
*/
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { SKILL_CATALOGUE, TALENTS, GEAR, WEAPONS, ARMOURS, DEVICES } from "./content.mjs";
|
||||
import { SHIELD } from "../rules.mjs";
|
||||
|
||||
const WEAPON_BY_KEY = new Map(WEAPONS.map(w => [w.key, w]));
|
||||
const ARMOUR_BY_KEY = new Map(ARMOURS.map(a => [a.key, a]));
|
||||
|
||||
const src = await readFile(new URL("../ringbrp.mjs", import.meta.url), "utf8");
|
||||
const ROLES = eval("(" + src.match(/export const ROLES = (\{[\s\S]*?\n\});/)[1] + ")");
|
||||
@@ -44,6 +46,17 @@ for (const [id, r] of Object.entries(ROLES)) {
|
||||
const need = w.spec ? `${w.fam}:${w.spec}` : w.fam;
|
||||
if (!trained.has(need)) problems.push(`${where}: issued ${w.name}, trains no ${need}`);
|
||||
}
|
||||
// A shield is armour you defend WITH, so it needs its skill for exactly the same
|
||||
// reason a weapon does — a posting issued one and untrained in it parries at the
|
||||
// 5% base and would be better off with both hands free.
|
||||
const shieldSkill = `${SHIELD.parryFamily}:${SHIELD.parrySpec}`;
|
||||
for (const k of r.kit) {
|
||||
const a = ARMOUR_BY_KEY.get(k);
|
||||
if (!a?.shield) continue;
|
||||
if (!trained.has(shieldSkill)) {
|
||||
problems.push(`${where}: issued ${a.name}, trains no ${shieldSkill}`);
|
||||
}
|
||||
}
|
||||
const sig = JSON.stringify([...r.kit].sort());
|
||||
if (kitSets.has(sig)) problems.push(`${where}: identical loadout to ${kitSets.get(sig)}`);
|
||||
kitSets.set(sig, id);
|
||||
|
||||
Reference in New Issue
Block a user