diff --git a/docs/REVIEW_LOG.md b/docs/REVIEW_LOG.md index 8135691..f0a977b 100644 --- a/docs/REVIEW_LOG.md +++ b/docs/REVIEW_LOG.md @@ -4128,3 +4128,49 @@ because the crew kept shooting instead of cooling. That is the decision the subs is for. 64 rules, 198 spot-checked formulas, a 12-page rulebook in reading order. + +### The Codex pass, and what it cost me + +Put the night's five subsystems to Codex with the instruction to be blunt. It found +three things that were genuinely wrong and I have fixed all three. + +**R-228 · Ambidextrous was a compulsory build.** At 0/−20 the talent gave a +full-strength main hand AND a cheap second attack — near-free action economy, and +therefore the only sane pick for anybody who could hold two things. The 2 kg limit +stops poleaxes, not optimisation with a pistol and a knife. Ambidextrous now buys +CONSISTENCY rather than a free attack: **−20 in both hands**, against −20/−40 +untrained. Still plainly worth having; no longer mandatory. + +**R-229 · full auto was a firing squad.** Ten independent hits off one critical, each +with its own damage roll, hit location and Major Wound check. Against a hard target it +was the correct answer to everything. Hits are now **capped at 3/5/7** rather than +proportional to the burst, and however many rounds connect, **a burst is one wounding +event** and rolls the Major Wound table at most once. + +**R-230 · Engines deleted the pressure it was supposed to create.** Guns +2 and Helm ++1 against a vent of 3 made a standard fighting round heat-NEUTRAL — the craft cooled +while it fought, and Heat only existed when the engineer failed or was absent. This +is the same fault as my earlier over-correction, in the other direction, and my own +second playtest had shown it sitting at 0 for four rounds without my drawing the +conclusion. Venting is now 2/3/4, so a shooting round costs +1 net. + +Two more taken as written: +- **Falling halving stacked.** Soft ground and a controlled descent both halved, so + together they quartered — the same mitigation counted twice. They no longer stack. +- **Blast ordering was undefined.** Flooring at each step meant the answer depended on + the order the functions were called in. One formula now, floored once: rolled x + range share x cover, rounded down, and only then armour. + +**And the sharpest observation, which I acted on structurally:** "giving everyone a +roll is not the same as giving everyone a decision." Sensors, Damage Control and +Medical were seats that rolled dice while the gunner decided the fight. Each now has +mutually exclusive modes — Sensors marks, spoofs or reads; Damage Control patches or +BRACES so the next hit lands at half; Medical restores a crewman or STEADIES the ship +so the heat penalty does not apply that round. Bracing and steadying both bite in the +engine, not just on the card. + +Not taken tonight, recorded as owed: station fumble tables, Signature as a live +mechanic, mark duration and stacking, hull and system criticals, extinguishing fire, +rescue from drowning, and an explicit interaction table for hazards against armour, +Major Wounds, bleeding, zero and dying. Codex is right that these are implied; they +are a session's work, not a paragraph's. diff --git a/lang/en.json b/lang/en.json index 24c001f..9845edd 100644 --- a/lang/en.json +++ b/lang/en.json @@ -108,6 +108,10 @@ "RINGBRP.Station.Would": "{n} would have gone through, with something to shoot at.", "RINGBRP.Station.Lost": "{name} is finished.", "RINGBRP.Station.Marked": "Marked. The next gunnery roll lands one more.", + "RINGBRP.Station.Spoofed": "Signature down. Harder to find, for a while.", + "RINGBRP.Station.Read": "You know what it is, what it is carrying, and who sent it.", + "RINGBRP.Station.Braced": "Braced. The next hit takes half.", + "RINGBRP.Station.Steadied": "Steady, everyone. The heat penalty does not apply this round.", "RINGBRP.Station.Shed": "Vented {n}. Heat is {now}.", "RINGBRP.Station.Patched": "Patched {n} of the hull.", "RINGBRP.Station.Talking": "They are still listening. That is not nothing.", diff --git a/packs/armour/000003.log b/packs/armour/000003.log deleted file mode 100644 index 5b23416..0000000 Binary files a/packs/armour/000003.log and /dev/null differ diff --git a/packs/armour/000005.ldb b/packs/armour/000005.ldb new file mode 100644 index 0000000..b406921 Binary files /dev/null and b/packs/armour/000005.ldb differ diff --git a/packs/armour/000006.log b/packs/armour/000006.log new file mode 100644 index 0000000..9d3f468 Binary files /dev/null and b/packs/armour/000006.log differ diff --git a/packs/armour/CURRENT b/packs/armour/CURRENT index 1a84852..cacca75 100644 --- a/packs/armour/CURRENT +++ b/packs/armour/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/armour/LOG b/packs/armour/LOG index ab46292..45ee788 100644 --- a/packs/armour/LOG +++ b/packs/armour/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.238506 16fddf000 Delete type=3 #1 +2026/08/11-08:06:46.417544 17416f000 Recovering log #3 +2026/08/11-08:06:46.417572 17416f000 Level-0 table #5: started +2026/08/11-08:06:46.417699 17416f000 Level-0 table #5: 3269 bytes OK +2026/08/11-08:06:46.417964 17416f000 Delete type=0 #3 +2026/08/11-08:06:46.417996 17416f000 Delete type=3 #2 diff --git a/packs/armour/LOG.old b/packs/armour/LOG.old new file mode 100644 index 0000000..f2eefe9 --- /dev/null +++ b/packs/armour/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.255757 171d3f000 Delete type=3 #1 diff --git a/packs/armour/MANIFEST-000002 b/packs/armour/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/armour/MANIFEST-000002 and /dev/null differ diff --git a/packs/armour/MANIFEST-000004 b/packs/armour/MANIFEST-000004 new file mode 100644 index 0000000..1faa5e9 Binary files /dev/null and b/packs/armour/MANIFEST-000004 differ diff --git a/packs/expedition/000003.log b/packs/expedition/000003.log deleted file mode 100644 index 263295b..0000000 Binary files a/packs/expedition/000003.log and /dev/null differ diff --git a/packs/expedition/000005.ldb b/packs/expedition/000005.ldb new file mode 100644 index 0000000..4ff460d Binary files /dev/null and b/packs/expedition/000005.ldb differ diff --git a/packs/expedition/000006.log b/packs/expedition/000006.log new file mode 100644 index 0000000..268b187 Binary files /dev/null and b/packs/expedition/000006.log differ diff --git a/packs/expedition/CURRENT b/packs/expedition/CURRENT index 1a84852..cacca75 100644 --- a/packs/expedition/CURRENT +++ b/packs/expedition/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/expedition/LOG b/packs/expedition/LOG index 4b2937e..43baa34 100644 --- a/packs/expedition/LOG +++ b/packs/expedition/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.272751 16edc7000 Delete type=3 #1 +2026/08/11-08:06:46.424344 175993000 Recovering log #3 +2026/08/11-08:06:46.424368 175993000 Level-0 table #5: started +2026/08/11-08:06:46.424513 175993000 Level-0 table #5: 4129 bytes OK +2026/08/11-08:06:46.424759 175993000 Delete type=0 #3 +2026/08/11-08:06:46.424801 175993000 Delete type=3 #2 diff --git a/packs/expedition/LOG.old b/packs/expedition/LOG.old new file mode 100644 index 0000000..f9488bd --- /dev/null +++ b/packs/expedition/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.282139 171d3f000 Delete type=3 #1 diff --git a/packs/expedition/MANIFEST-000002 b/packs/expedition/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/expedition/MANIFEST-000002 and /dev/null differ diff --git a/packs/expedition/MANIFEST-000004 b/packs/expedition/MANIFEST-000004 new file mode 100644 index 0000000..47fbcd4 Binary files /dev/null and b/packs/expedition/MANIFEST-000004 differ diff --git a/packs/gear/000003.log b/packs/gear/000003.log deleted file mode 100644 index a42777b..0000000 Binary files a/packs/gear/000003.log and /dev/null differ diff --git a/packs/gear/000005.ldb b/packs/gear/000005.ldb new file mode 100644 index 0000000..fedde60 Binary files /dev/null and b/packs/gear/000005.ldb differ diff --git a/packs/gear/000006.log b/packs/gear/000006.log new file mode 100644 index 0000000..4b150b6 Binary files /dev/null and b/packs/gear/000006.log differ diff --git a/packs/gear/CURRENT b/packs/gear/CURRENT index 1a84852..cacca75 100644 --- a/packs/gear/CURRENT +++ b/packs/gear/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/gear/LOG b/packs/gear/LOG index 3b821f8..b0ae8ed 100644 --- a/packs/gear/LOG +++ b/packs/gear/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.240938 16edc7000 Delete type=3 #1 +2026/08/11-08:06:46.418514 17497b000 Recovering log #3 +2026/08/11-08:06:46.418608 17497b000 Level-0 table #5: started +2026/08/11-08:06:46.418879 17497b000 Level-0 table #5: 27954 bytes OK +2026/08/11-08:06:46.419164 17497b000 Delete type=0 #3 +2026/08/11-08:06:46.419211 17497b000 Delete type=3 #2 diff --git a/packs/gear/LOG.old b/packs/gear/LOG.old new file mode 100644 index 0000000..dd3db13 --- /dev/null +++ b/packs/gear/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.257347 170d27000 Delete type=3 #1 diff --git a/packs/gear/MANIFEST-000002 b/packs/gear/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/gear/MANIFEST-000002 and /dev/null differ diff --git a/packs/gear/MANIFEST-000004 b/packs/gear/MANIFEST-000004 new file mode 100644 index 0000000..97d9316 Binary files /dev/null and b/packs/gear/MANIFEST-000004 differ diff --git a/packs/npcs/000003.log b/packs/npcs/000003.log deleted file mode 100644 index c13442d..0000000 Binary files a/packs/npcs/000003.log and /dev/null differ diff --git a/packs/npcs/000005.ldb b/packs/npcs/000005.ldb new file mode 100644 index 0000000..434f292 Binary files /dev/null and b/packs/npcs/000005.ldb differ diff --git a/packs/npcs/000006.log b/packs/npcs/000006.log new file mode 100644 index 0000000..a8f297d Binary files /dev/null and b/packs/npcs/000006.log differ diff --git a/packs/npcs/CURRENT b/packs/npcs/CURRENT index 1a84852..cacca75 100644 --- a/packs/npcs/CURRENT +++ b/packs/npcs/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/npcs/LOG b/packs/npcs/LOG index 662ac36..db03d48 100644 --- a/packs/npcs/LOG +++ b/packs/npcs/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.258004 1705eb000 Delete type=3 #1 +2026/08/11-08:06:46.407760 17497b000 Recovering log #3 +2026/08/11-08:06:46.408666 17497b000 Level-0 table #5: started +2026/08/11-08:06:46.410003 17497b000 Level-0 table #5: 223489 bytes OK +2026/08/11-08:06:46.410364 17497b000 Delete type=0 #3 +2026/08/11-08:06:46.410398 17497b000 Delete type=3 #2 diff --git a/packs/npcs/LOG.old b/packs/npcs/LOG.old new file mode 100644 index 0000000..0863b55 --- /dev/null +++ b/packs/npcs/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.270516 17051b000 Delete type=3 #1 diff --git a/packs/npcs/MANIFEST-000002 b/packs/npcs/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/npcs/MANIFEST-000002 and /dev/null differ diff --git a/packs/npcs/MANIFEST-000004 b/packs/npcs/MANIFEST-000004 new file mode 100644 index 0000000..c64c94d Binary files /dev/null and b/packs/npcs/MANIFEST-000004 differ diff --git a/packs/powers/000003.log b/packs/powers/000003.log deleted file mode 100644 index d723043..0000000 Binary files a/packs/powers/000003.log and /dev/null differ diff --git a/packs/powers/000005.ldb b/packs/powers/000005.ldb new file mode 100644 index 0000000..7f540c6 Binary files /dev/null and b/packs/powers/000005.ldb differ diff --git a/packs/powers/000006.log b/packs/powers/000006.log new file mode 100644 index 0000000..43e306f Binary files /dev/null and b/packs/powers/000006.log differ diff --git a/packs/powers/CURRENT b/packs/powers/CURRENT index 1a84852..cacca75 100644 --- a/packs/powers/CURRENT +++ b/packs/powers/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/powers/LOG b/packs/powers/LOG index 97a2333..2844da0 100644 --- a/packs/powers/LOG +++ b/packs/powers/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.266367 16f5d3000 Delete type=3 #1 +2026/08/11-08:06:46.415299 17416f000 Recovering log #3 +2026/08/11-08:06:46.415324 17416f000 Level-0 table #5: started +2026/08/11-08:06:46.415442 17416f000 Level-0 table #5: 3295 bytes OK +2026/08/11-08:06:46.415703 17416f000 Delete type=0 #3 +2026/08/11-08:06:46.415749 17416f000 Delete type=3 #2 diff --git a/packs/powers/LOG.old b/packs/powers/LOG.old new file mode 100644 index 0000000..79d7e77 --- /dev/null +++ b/packs/powers/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.277189 170d27000 Delete type=3 #1 diff --git a/packs/powers/MANIFEST-000002 b/packs/powers/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/powers/MANIFEST-000002 and /dev/null differ diff --git a/packs/powers/MANIFEST-000004 b/packs/powers/MANIFEST-000004 new file mode 100644 index 0000000..20de082 Binary files /dev/null and b/packs/powers/MANIFEST-000004 differ diff --git a/packs/pregens/000003.log b/packs/pregens/000003.log deleted file mode 100644 index b2a8dce..0000000 Binary files a/packs/pregens/000003.log and /dev/null differ diff --git a/packs/pregens/000005.ldb b/packs/pregens/000005.ldb new file mode 100644 index 0000000..d646217 Binary files /dev/null and b/packs/pregens/000005.ldb differ diff --git a/packs/pregens/000006.log b/packs/pregens/000006.log new file mode 100644 index 0000000..71e3acd Binary files /dev/null and b/packs/pregens/000006.log differ diff --git a/packs/pregens/CURRENT b/packs/pregens/CURRENT index 1a84852..cacca75 100644 --- a/packs/pregens/CURRENT +++ b/packs/pregens/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/pregens/LOG b/packs/pregens/LOG index 0c480c0..dde3e2b 100644 --- a/packs/pregens/LOG +++ b/packs/pregens/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.247709 1705eb000 Delete type=3 #1 +2026/08/11-08:06:46.405358 17497b000 Recovering log #3 +2026/08/11-08:06:46.405609 17497b000 Level-0 table #5: started +2026/08/11-08:06:46.406137 17497b000 Level-0 table #5: 57435 bytes OK +2026/08/11-08:06:46.406463 17497b000 Delete type=0 #3 +2026/08/11-08:06:46.406496 17497b000 Delete type=3 #2 diff --git a/packs/pregens/LOG.old b/packs/pregens/LOG.old new file mode 100644 index 0000000..d41e962 --- /dev/null +++ b/packs/pregens/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.262897 171d3f000 Delete type=3 #1 diff --git a/packs/pregens/MANIFEST-000002 b/packs/pregens/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/pregens/MANIFEST-000002 and /dev/null differ diff --git a/packs/pregens/MANIFEST-000004 b/packs/pregens/MANIFEST-000004 new file mode 100644 index 0000000..a27f077 Binary files /dev/null and b/packs/pregens/MANIFEST-000004 differ diff --git a/packs/rules/000003.log b/packs/rules/000003.log deleted file mode 100644 index 88fda6d..0000000 Binary files a/packs/rules/000003.log and /dev/null differ diff --git a/packs/rules/000005.ldb b/packs/rules/000005.ldb new file mode 100644 index 0000000..e811734 Binary files /dev/null and b/packs/rules/000005.ldb differ diff --git a/packs/rules/000006.log b/packs/rules/000006.log new file mode 100644 index 0000000..72eda75 Binary files /dev/null and b/packs/rules/000006.log differ diff --git a/packs/rules/CURRENT b/packs/rules/CURRENT index 1a84852..cacca75 100644 --- a/packs/rules/CURRENT +++ b/packs/rules/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/rules/LOG b/packs/rules/LOG index 3fc8663..bbc40ff 100644 --- a/packs/rules/LOG +++ b/packs/rules/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.271217 16fddf000 Delete type=3 #1 +2026/08/11-08:06:46.421106 17497b000 Recovering log #3 +2026/08/11-08:06:46.421169 17497b000 Level-0 table #5: started +2026/08/11-08:06:46.421431 17497b000 Level-0 table #5: 28916 bytes OK +2026/08/11-08:06:46.421607 17497b000 Delete type=0 #3 +2026/08/11-08:06:46.421634 17497b000 Delete type=3 #2 diff --git a/packs/rules/LOG.old b/packs/rules/LOG.old new file mode 100644 index 0000000..d977710 --- /dev/null +++ b/packs/rules/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.280795 171533000 Delete type=3 #1 diff --git a/packs/rules/MANIFEST-000002 b/packs/rules/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/rules/MANIFEST-000002 and /dev/null differ diff --git a/packs/rules/MANIFEST-000004 b/packs/rules/MANIFEST-000004 new file mode 100644 index 0000000..2c6a051 Binary files /dev/null and b/packs/rules/MANIFEST-000004 differ diff --git a/packs/skills/000003.log b/packs/skills/000003.log deleted file mode 100644 index e23ff19..0000000 Binary files a/packs/skills/000003.log and /dev/null differ diff --git a/packs/skills/000005.ldb b/packs/skills/000005.ldb new file mode 100644 index 0000000..d613d26 Binary files /dev/null and b/packs/skills/000005.ldb differ diff --git a/packs/skills/000006.log b/packs/skills/000006.log new file mode 100644 index 0000000..aa7dd7d Binary files /dev/null and b/packs/skills/000006.log differ diff --git a/packs/skills/CURRENT b/packs/skills/CURRENT index 1a84852..cacca75 100644 --- a/packs/skills/CURRENT +++ b/packs/skills/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/skills/LOG b/packs/skills/LOG index be98972..409b3dc 100644 --- a/packs/skills/LOG +++ b/packs/skills/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.230403 16f5d3000 Delete type=3 #1 +2026/08/11-08:06:46.413121 17416f000 Recovering log #3 +2026/08/11-08:06:46.413179 17416f000 Level-0 table #5: started +2026/08/11-08:06:46.413357 17416f000 Level-0 table #5: 7486 bytes OK +2026/08/11-08:06:46.413587 17416f000 Delete type=0 #3 +2026/08/11-08:06:46.413622 17416f000 Delete type=3 #2 diff --git a/packs/skills/LOG.old b/packs/skills/LOG.old new file mode 100644 index 0000000..713f3ca --- /dev/null +++ b/packs/skills/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.250466 17051b000 Delete type=3 #1 diff --git a/packs/skills/MANIFEST-000002 b/packs/skills/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/skills/MANIFEST-000002 and /dev/null differ diff --git a/packs/skills/MANIFEST-000004 b/packs/skills/MANIFEST-000004 new file mode 100644 index 0000000..792e8a1 Binary files /dev/null and b/packs/skills/MANIFEST-000004 differ diff --git a/packs/slice/000003.log b/packs/slice/000003.log deleted file mode 100644 index 4a86fe9..0000000 Binary files a/packs/slice/000003.log and /dev/null differ diff --git a/packs/slice/000005.ldb b/packs/slice/000005.ldb new file mode 100644 index 0000000..4851c77 Binary files /dev/null and b/packs/slice/000005.ldb differ diff --git a/packs/slice/000006.log b/packs/slice/000006.log new file mode 100644 index 0000000..c7d9b16 Binary files /dev/null and b/packs/slice/000006.log differ diff --git a/packs/slice/CURRENT b/packs/slice/CURRENT index 1a84852..cacca75 100644 --- a/packs/slice/CURRENT +++ b/packs/slice/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/slice/LOG b/packs/slice/LOG index 6b9b35f..159e9eb 100644 --- a/packs/slice/LOG +++ b/packs/slice/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.264747 1705eb000 Delete type=3 #1 +2026/08/11-08:06:46.422268 17416f000 Recovering log #3 +2026/08/11-08:06:46.422303 17416f000 Level-0 table #5: started +2026/08/11-08:06:46.422611 17416f000 Level-0 table #5: 16892 bytes OK +2026/08/11-08:06:46.422814 17416f000 Delete type=0 #3 +2026/08/11-08:06:46.422839 17416f000 Delete type=3 #2 diff --git a/packs/slice/LOG.old b/packs/slice/LOG.old new file mode 100644 index 0000000..13d38fd --- /dev/null +++ b/packs/slice/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.275784 170d27000 Delete type=3 #1 diff --git a/packs/slice/MANIFEST-000002 b/packs/slice/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/slice/MANIFEST-000002 and /dev/null differ diff --git a/packs/slice/MANIFEST-000004 b/packs/slice/MANIFEST-000004 new file mode 100644 index 0000000..0552c3a Binary files /dev/null and b/packs/slice/MANIFEST-000004 differ diff --git a/packs/tables/000003.log b/packs/tables/000003.log deleted file mode 100644 index f125b7d..0000000 Binary files a/packs/tables/000003.log and /dev/null differ diff --git a/packs/tables/000005.ldb b/packs/tables/000005.ldb new file mode 100644 index 0000000..64baa1c Binary files /dev/null and b/packs/tables/000005.ldb differ diff --git a/packs/tables/000006.log b/packs/tables/000006.log new file mode 100644 index 0000000..d5e06f3 Binary files /dev/null and b/packs/tables/000006.log differ diff --git a/packs/tables/CURRENT b/packs/tables/CURRENT index 1a84852..cacca75 100644 --- a/packs/tables/CURRENT +++ b/packs/tables/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/tables/LOG b/packs/tables/LOG index 9bef2e9..78d3500 100644 --- a/packs/tables/LOG +++ b/packs/tables/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.262751 16f5d3000 Delete type=3 #1 +2026/08/11-08:06:46.423379 175187000 Recovering log #3 +2026/08/11-08:06:46.423401 175187000 Level-0 table #5: started +2026/08/11-08:06:46.423489 175187000 Level-0 table #5: 3739 bytes OK +2026/08/11-08:06:46.423704 175187000 Delete type=0 #3 +2026/08/11-08:06:46.423739 175187000 Delete type=3 #2 diff --git a/packs/tables/LOG.old b/packs/tables/LOG.old new file mode 100644 index 0000000..d87b0ac --- /dev/null +++ b/packs/tables/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.274259 171d3f000 Delete type=3 #1 diff --git a/packs/tables/MANIFEST-000002 b/packs/tables/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/tables/MANIFEST-000002 and /dev/null differ diff --git a/packs/tables/MANIFEST-000004 b/packs/tables/MANIFEST-000004 new file mode 100644 index 0000000..004ff30 Binary files /dev/null and b/packs/tables/MANIFEST-000004 differ diff --git a/packs/talents/000003.log b/packs/talents/000003.log deleted file mode 100644 index 443b7ea..0000000 Binary files a/packs/talents/000003.log and /dev/null differ diff --git a/packs/talents/000005.ldb b/packs/talents/000005.ldb new file mode 100644 index 0000000..fb653de Binary files /dev/null and b/packs/talents/000005.ldb differ diff --git a/packs/talents/000006.log b/packs/talents/000006.log new file mode 100644 index 0000000..29003f7 Binary files /dev/null and b/packs/talents/000006.log differ diff --git a/packs/talents/CURRENT b/packs/talents/CURRENT index 1a84852..cacca75 100644 --- a/packs/talents/CURRENT +++ b/packs/talents/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/talents/LOG b/packs/talents/LOG index 1711d20..3e9a074 100644 --- a/packs/talents/LOG +++ b/packs/talents/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.233773 16f5d3000 Delete type=3 #1 +2026/08/11-08:06:46.414303 17497b000 Recovering log #3 +2026/08/11-08:06:46.414338 17497b000 Level-0 table #5: started +2026/08/11-08:06:46.414485 17497b000 Level-0 table #5: 5770 bytes OK +2026/08/11-08:06:46.414718 17497b000 Delete type=0 #3 +2026/08/11-08:06:46.414751 17497b000 Delete type=3 #2 diff --git a/packs/talents/LOG.old b/packs/talents/LOG.old new file mode 100644 index 0000000..06e0c9d --- /dev/null +++ b/packs/talents/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.252690 17051b000 Delete type=3 #1 diff --git a/packs/talents/MANIFEST-000002 b/packs/talents/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/talents/MANIFEST-000002 and /dev/null differ diff --git a/packs/talents/MANIFEST-000004 b/packs/talents/MANIFEST-000004 new file mode 100644 index 0000000..f8c6b47 Binary files /dev/null and b/packs/talents/MANIFEST-000004 differ diff --git a/packs/vehicles/000003.log b/packs/vehicles/000003.log deleted file mode 100644 index 9950ce5..0000000 Binary files a/packs/vehicles/000003.log and /dev/null differ diff --git a/packs/vehicles/000005.ldb b/packs/vehicles/000005.ldb new file mode 100644 index 0000000..f6b2cd4 Binary files /dev/null and b/packs/vehicles/000005.ldb differ diff --git a/packs/vehicles/000006.log b/packs/vehicles/000006.log new file mode 100644 index 0000000..47800e2 Binary files /dev/null and b/packs/vehicles/000006.log differ diff --git a/packs/vehicles/CURRENT b/packs/vehicles/CURRENT index 1a84852..cacca75 100644 --- a/packs/vehicles/CURRENT +++ b/packs/vehicles/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/vehicles/LOG b/packs/vehicles/LOG index 1c32f30..58e94ca 100644 --- a/packs/vehicles/LOG +++ b/packs/vehicles/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.243041 1705eb000 Delete type=3 #1 +2026/08/11-08:06:46.419951 17416f000 Recovering log #3 +2026/08/11-08:06:46.419979 17416f000 Level-0 table #5: started +2026/08/11-08:06:46.420174 17416f000 Level-0 table #5: 6939 bytes OK +2026/08/11-08:06:46.420458 17416f000 Delete type=0 #3 +2026/08/11-08:06:46.420501 17416f000 Delete type=3 #2 diff --git a/packs/vehicles/LOG.old b/packs/vehicles/LOG.old new file mode 100644 index 0000000..eb3225d --- /dev/null +++ b/packs/vehicles/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.258984 171533000 Delete type=3 #1 diff --git a/packs/vehicles/MANIFEST-000002 b/packs/vehicles/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/vehicles/MANIFEST-000002 and /dev/null differ diff --git a/packs/vehicles/MANIFEST-000004 b/packs/vehicles/MANIFEST-000004 new file mode 100644 index 0000000..d4d73b7 Binary files /dev/null and b/packs/vehicles/MANIFEST-000004 differ diff --git a/packs/weapons/000003.log b/packs/weapons/000003.log deleted file mode 100644 index e1488ed..0000000 Binary files a/packs/weapons/000003.log and /dev/null differ diff --git a/packs/weapons/000005.ldb b/packs/weapons/000005.ldb new file mode 100644 index 0000000..742beba Binary files /dev/null and b/packs/weapons/000005.ldb differ diff --git a/packs/weapons/000006.log b/packs/weapons/000006.log new file mode 100644 index 0000000..4d427a6 Binary files /dev/null and b/packs/weapons/000006.log differ diff --git a/packs/weapons/CURRENT b/packs/weapons/CURRENT index 1a84852..cacca75 100644 --- a/packs/weapons/CURRENT +++ b/packs/weapons/CURRENT @@ -1 +1 @@ -MANIFEST-000002 +MANIFEST-000004 diff --git a/packs/weapons/LOG b/packs/weapons/LOG index eda0de3..c53e472 100644 --- a/packs/weapons/LOG +++ b/packs/weapons/LOG @@ -1 +1,5 @@ -2026/08/11-07:33:59.236342 16edc7000 Delete type=3 #1 +2026/08/11-08:06:46.416237 17497b000 Recovering log #3 +2026/08/11-08:06:46.416299 17497b000 Level-0 table #5: started +2026/08/11-08:06:46.416505 17497b000 Level-0 table #5: 14767 bytes OK +2026/08/11-08:06:46.416784 17497b000 Delete type=0 #3 +2026/08/11-08:06:46.416833 17497b000 Delete type=3 #2 diff --git a/packs/weapons/LOG.old b/packs/weapons/LOG.old new file mode 100644 index 0000000..161ec1b --- /dev/null +++ b/packs/weapons/LOG.old @@ -0,0 +1 @@ +2026/08/11-08:06:24.254252 17051b000 Delete type=3 #1 diff --git a/packs/weapons/MANIFEST-000002 b/packs/weapons/MANIFEST-000002 deleted file mode 100644 index bbbc585..0000000 Binary files a/packs/weapons/MANIFEST-000002 and /dev/null differ diff --git a/packs/weapons/MANIFEST-000004 b/packs/weapons/MANIFEST-000004 new file mode 100644 index 0000000..6a582af Binary files /dev/null and b/packs/weapons/MANIFEST-000004 differ diff --git a/ringbrp.mjs b/ringbrp.mjs index 28d909c..85ecab3 100644 --- a/ringbrp.mjs +++ b/ringbrp.mjs @@ -31,7 +31,7 @@ import { RETURN_CLOCK, returnPenaltyFor, returnIsDifficult, extractionCostFor, FALL, fallDamageFor, ASPHYXIA, breathRoundsFor, FIRE, fireBandFor, BLAST, blastBandFor, blastShareFor, BLAST_COVER, blastAfterCover, - BURST, burstHitsFor, burstRoundsSpent, BURST_FUMBLE, + BURST, burstHitsFor, burstRoundsSpent, BURST_FUMBLE, BURST_ONE_MAJOR_WOUND, SPACE_BANDS, spaceBandRank, spaceBandAfter, STATIONS, HEAT, heatEffectsFor, spaceRangeModFor, spaceHitFor, craftConditionFor, TWO_WEAPON, twoWeaponPenaltyFor, canPairWeapons, @@ -2069,7 +2069,8 @@ export async function manStation(actor, craft, stationId, opts = {}) { const band = sys.band ?? "close"; // Heat is felt by the stations that look and shoot, not by the one shedding it. - const heatPen = ["guns", "sensors"].includes(stationId) ? heat.penalty : 0; + const steadied = !!craft.getFlag?.("ringbrp", "steadied"); + const heatPen = (["guns", "sensors"].includes(stationId) && !steadied) ? heat.penalty : 0; const rangePen = stationId === "guns" ? spaceRangeModFor(band) : 0; if (stationId === "guns" && rangePen === null) { ui.notifications?.warn(game.i18n.localize("RINGBRP.Station.OutOfRange")); @@ -2115,8 +2116,13 @@ export async function manStation(actor, craft, stationId, opts = {}) { break; } case "damage": { - const hits = spaceHitFor(res.level, { marked: !!craft.getFlag("ringbrp", "marked") }); + let hits = spaceHitFor(res.level, { marked: !!craft.getFlag("ringbrp", "marked") }); if (target) { + // A braced target takes half, rounded down but never below one. + if (target.getFlag?.("ringbrp", "braced")) { + hits = Math.max(1, Math.floor(hits / 2)); + await target.unsetFlag("ringbrp", "braced"); + } const t = target.system; const left = Math.max(0, (Number(t.hull?.value) || 0) - hits); await target.update({ "system.hull.value": left }); @@ -2128,20 +2134,38 @@ export async function manStation(actor, craft, stationId, opts = {}) { break; } case "mark": - await craft.setFlag("ringbrp", "marked", true); - said.push(game.i18n.localize("RINGBRP.Station.Marked")); + // Sensors chooses. Marking helps the gunner; spoofing helps everybody. + if (opts.mode === "spoof") { + upd["system.signature"] = Math.max(0, (Number(sys.signature) || 0) - 2); + said.push(game.i18n.localize("RINGBRP.Station.Spoofed")); + } else if (opts.mode === "read") { + said.push(game.i18n.localize("RINGBRP.Station.Read")); + } else { + await craft.setFlag("ringbrp", "marked", true); + said.push(game.i18n.localize("RINGBRP.Station.Marked")); + } break; case "heat": { - const shed = res.level === "critical" ? 5 : (res.level === "special" ? 4 : 3); + // 2/3/4, not 3/4/5. At the old rate a normal round — guns +2, helm +1, vent 3 — + // was heat-NEUTRAL, so the craft cooled while it fought and the pressure only + // existed when the engineer failed. A shooting round should cost something. + const shed = res.level === "critical" ? 4 : (res.level === "special" ? 3 : 2); upd["system.heat"] = Math.max(0, (Number(sys.heat) || 0) - shed); said.push(game.i18n.format("RINGBRP.Station.Shed", { n: shed, now: upd["system.heat"] })); break; } case "hull": { - const mend = res.level === "critical" ? 3 : (res.level === "special" ? 2 : 1); - const max = Number(sys.hull?.max) || Number(sys.hullMax) || 1; - upd["system.hull.value"] = Math.min(max, (Number(sys.hull?.value) || 0) + mend); - said.push(game.i18n.format("RINGBRP.Station.Patched", { n: mend })); + // Damage control chooses: patch the hull, or brace it so the next hit is + // halved. Patching is useless before anything has been hit; bracing is not. + if (opts.mode === "brace") { + await craft.setFlag("ringbrp", "braced", true); + said.push(game.i18n.localize("RINGBRP.Station.Braced")); + } else { + const mend = res.level === "critical" ? 3 : (res.level === "special" ? 2 : 1); + const max = Number(sys.hull?.max) || Number(sys.hullMax) || 1; + upd["system.hull.value"] = Math.min(max, (Number(sys.hull?.value) || 0) + mend); + said.push(game.i18n.format("RINGBRP.Station.Patched", { n: mend })); + } break; } case "talk": @@ -2149,7 +2173,12 @@ export async function manStation(actor, craft, stationId, opts = {}) { ? "RINGBRP.Station.TalkedDown" : "RINGBRP.Station.Talking")); break; case "crew": - said.push(game.i18n.localize("RINGBRP.Station.Crew")); + // Medical chooses: put somebody back at their station, or suppress the + // penalty everybody is working under. It has a job before anyone is hurt. + if (opts.mode === "steady") { + await craft.setFlag("ringbrp", "steadied", true); + said.push(game.i18n.localize("RINGBRP.Station.Steadied")); + } else said.push(game.i18n.localize("RINGBRP.Station.Crew")); break; case "escape": said.push(game.i18n.localize(res.level === "critical" @@ -2324,12 +2353,20 @@ export async function burstAttack(actor, weapon, target, { size = "short", await recordBlow({ attacker: actor, level: res.level, weapon }); const lines = []; + let majorWoundTaken = false; for (let i = 0; i < hits; i++) { // A critical burst puts its FIRST round through armour and the rest normally. const level = (res.level === "critical" && i === 0) ? "critical" : "success"; const dmg = await rollWeaponDamage({ actor, weapon, level }); const hl = await hitLocationRoll({ target, damage: dmg, mode: "ranged", level }); if (hl) lines.push(`${dmg} → ${game.i18n.localize(hl.location.label)}`); + // ONE Major Wound per burst, however many rounds connected. A burst is a single + // wounding event; rolling the table once per round turned automatic fire into a + // machine for producing permanent injuries. + if (hl?.majorWound && !(BURST_ONE_MAJOR_WOUND && majorWoundTaken)) { + await majorWoundRoll({ actor: target }); + majorWoundTaken = true; + } if (target.system?.dying?.dead) break; } await ChatMessage.create({ speaker: ChatMessage.getSpeaker({ actor }), diff --git a/rules.mjs b/rules.mjs index be6f9b7..7ea825f 100644 --- a/rules.mjs +++ b/rules.mjs @@ -537,18 +537,24 @@ export const BURST = { }; /** How many of a burst connect, by the band the one roll produced. */ +// Hits are CAPPED, not proportional. Ten independent damage rolls, ten hit locations +// and ten Major Wound checks off one success is not a burst, it is a firing squad — +// and it made full auto the correct answer to every hard target. +export const BURST_HITS = { short: [1, 2, 3], long: [2, 4, 5], full: [3, 5, 7] }; + export function burstHitsFor(level, size) { - const b = BURST[size] ?? BURST.short; - const third = Math.max(1, Math.floor(b.rounds / 3)); + const cap = BURST_HITS[size] ?? BURST_HITS.short; switch (level) { - case "critical": return b.rounds; // all of it, and the first ignores armour - case "special": return Math.max(1, Math.floor(b.rounds * 2 / 3)); - case "success": return third; - case "fumble": return 0; // and see BURST_FUMBLE - default: return 0; + case "critical": return cap[2]; + case "special": return cap[1]; + case "success": return cap[0]; + default: return 0; // failure and fumble; see BURST_FUMBLE } } +/** However many rounds connect, a burst is ONE wound event for the Major Wound check. */ +export const BURST_ONE_MAJOR_WOUND = true; + /** Every round leaves the weapon regardless. This is the cost of the option. */ export function burstRoundsSpent(size, loaded) { const b = BURST[size] ?? BURST.short; @@ -569,7 +575,11 @@ export const BURST_FUMBLE = ["RINGBRP.Burst.Jam", "RINGBRP.Burst.Empty", "RINGBR * The off-hand weapon must be lighter than the main hand, which is the rule that * stops two poleaxes. */ -export const TWO_WEAPON = { main: -20, off: -40, trainedMain: 0, trainedOff: -20, +// Reviewed and corrected: the trained profile was 0/−20, which is very nearly a free +// second attack and therefore a compulsory pick for anyone who can hold two things. +// Ambidextrous now buys CONSISTENCY, not a free action — both hands at −20 — which is +// still plainly worth having and is no longer the only sane build. +export const TWO_WEAPON = { main: -20, off: -40, trainedMain: -20, trainedOff: -20, offHandMaxKg: 2.0 }; export function twoWeaponPenaltyFor({ trained = false } = {}) { @@ -600,9 +610,10 @@ export function canPairWeapons(mainKg, offKg) { export const FALL = { metresPerDie: 3, die: 6, maxDice: 20 }; export function fallDamageFor(metres, { soft = false, controlled = false } = {}) { + // Halving is not cumulative. Soft ground and a controlled descent are the same + // mitigation twice over, and stacking them turned a lethal drop into a stumble. let m = Math.max(0, Number(metres) || 0); - if (soft) m /= 2; - if (controlled) m /= 2; + if (soft || controlled) m /= 2; const dice = Math.min(FALL.maxDice, Math.floor(m / FALL.metresPerDie)); return { dice, formula: dice > 0 ? `${dice}d${FALL.die}` : "0", ignoresArmour: true }; } @@ -664,9 +675,15 @@ export function blastBandFor(metres, radius) { return null; // outside it entirely } -export function blastShareFor(rolled, band) { +/** + * ONE formula, floored ONCE. Rolled x range share x cover, rounded down, and only + * then does armour come off. Flooring at each step changed the answer depending on + * the order somebody happened to call these in. + */ +export function blastShareFor(rolled, band, cover = "none") { if (!band) return 0; - return Math.max(0, Math.floor((Number(rolled) || 0) * band.share)); + const f = BLAST_COVER[cover] ?? 1; + return Math.max(0, Math.floor((Number(rolled) || 0) * band.share * f)); } /** Cover is the answer to a blast. Armour is only ever half of one. */ diff --git a/tools/check-rules.mjs b/tools/check-rules.mjs index f45fe5e..15b0ad1 100644 --- a/tools/check-rules.mjs +++ b/tools/check-rules.mjs @@ -226,7 +226,7 @@ const checks = [ // the ways the world kills you ["fallDamageFor(6)", RULES.fallDamageFor(6).formula, "2d6"], ["fallDamageFor(30)", RULES.fallDamageFor(30).formula, "10d6"], - ["fallDamageFor(30, soft+controlled)", RULES.fallDamageFor(30,{soft:true,controlled:true}).formula, "2d6"], + ["fall halving does not stack", RULES.fallDamageFor(30,{soft:true,controlled:true}).formula, "5d6"], ["fallDamageFor ignores armour", RULES.fallDamageFor(6).ignoresArmour, true], ["breathRoundsFor(12)", RULES.breathRoundsFor(12), 12], ["breathRoundsFor(12) caught out", RULES.breathRoundsFor(12,{prepared:false}), 6], @@ -236,16 +236,17 @@ const checks = [ ["blastBandFor(11, r6)", RULES.blastBandFor(11,6).id, "far"], ["blastBandFor(40, r6) is outside", RULES.blastBandFor(40,6), null], ["blastShareFor(20, far)", RULES.blastShareFor(20,RULES.blastBandFor(11,6)), 5], + ["blastShareFor(20, far, solid)", RULES.blastShareFor(20,RULES.blastBandFor(11,6),"solid"), 1], ["blastAfterCover(20, solid)", RULES.blastAfterCover(20,"solid"), 5], ["blastAfterCover(20, sealed)", RULES.blastAfterCover(20,"sealed"), 0], // automatic fire: one roll, the band says how much arrived - ["burstHitsFor(critical, full)", RULES.burstHitsFor("critical","full"), 10], + ["burstHitsFor(critical, full) capped", RULES.burstHitsFor("critical","full"), 7], ["burstHitsFor(success, short)", RULES.burstHitsFor("success","short"), 1], ["burstHitsFor(failure, long)", RULES.burstHitsFor("failure","long"), 0], ["burstRoundsSpent(long, 4 loaded)", RULES.burstRoundsSpent("long",4), 4], // two weapons ["twoWeaponPenaltyFor() off hand", RULES.twoWeaponPenaltyFor().off, -40], - ["twoWeaponPenaltyFor(trained) main", RULES.twoWeaponPenaltyFor({trained:true}).main, 0], + ["twoWeaponPenaltyFor(trained) main", RULES.twoWeaponPenaltyFor({trained:true}).main, -20], ["canPairWeapons(1.2, 0.4)", RULES.canPairWeapons(1.2,0.4), true], ["canPairWeapons(3, 3) refuses", RULES.canPairWeapons(3,3), false], // destroying something they cannot live without diff --git a/tools/rules-text.mjs b/tools/rules-text.mjs index a0b9684..c82997d 100644 --- a/tools/rules-text.mjs +++ b/tools/rules-text.mjs @@ -297,8 +297,9 @@ and does nothing at all about a critical.
` },A die of damage for every ${FALL.metresPerDie} metres, to a random location, and armour does not help — the ground is not a weapon. Landing on -something soft halves the distance, and so does a controlled descent; both together -halve it twice, which is what a descent harness is for.
+something soft halves the distance, and so does a controlled descent — but they do not +stack, because they are the same mitigation twice. A descent harness makes any drop a +controlled one, which is what it is for. ${table(["Fall", "Damage"], [3, 6, 12, 20, 30, 45].map(m => [`${m} m`, fallDamageFor(m).formula]))} @@ -318,7 +319,9 @@ ${table(["Fire", "Damage a round", "Burns for"],One roll of damage at the centre, shared out by how close you were. Cover -is the answer; armour is only ever half of one, and only at contact.
+is the answer; armour is only ever half of one, and only at contact. The order +is fixed: rolled × range share × cover, rounded down once, and only then does +armour come off. ${table(["Where you were", "Share of the damage", "Armour"], BLAST.map(b => [L(b.label), `${Math.round(b.share * 100)}%`, b.armour < 1 ? "half of it" : "all of it"]))} @@ -336,8 +339,9 @@ ${table(["Burst", "Rounds", "To hit", "Critical", "Special", "Success"], String(burstHitsFor("critical", b.id)), String(burstHitsFor("special", b.id)), String(burstHitsFor("success", b.id))]))}A critical burst puts its first round through armour and the rest -normally. A fumble is a jam, an empty magazine, or a muzzle that climbed — and the GM -decides what was behind the target.
+normally. However many rounds connect, a burst is one wounding event +and rolls the Major Wound table at most once. A fumble is a jam, an empty magazine, or +a muzzle that climbed — and the GM decides what was behind the target.The off hand is a real second attack and it is meant to cost something. Untrained, @@ -348,8 +352,10 @@ ${table(["", "Main hand", "Off hand"], [ ["Ambidextrous", pc(twoWeaponPenaltyFor({trained:true}).main), pc(twoWeaponPenaltyFor({trained:true}).off)] ])} -
Nothing removes the off-hand penalty altogether, and the off-hand weapon must be -the lighter of the two and no heavier than ${TWO_WEAPON.offHandMaxKg} kg. That is the +
Ambidextrous buys consistency, not a free attack — both hands at +the same penalty rather than a full-strength main hand and a cheap extra, which made it +the only sane build for anyone who could hold two things. The off-hand weapon must be +the lighter of the two and no heavier than ${TWO_WEAPON.offHandMaxKg} kg, which is the rule that stops two poleaxes.
` },