diff --git a/docs/REVIEW_LOG.md b/docs/REVIEW_LOG.md index 48b658a..eba895b 100644 --- a/docs/REVIEW_LOG.md +++ b/docs/REVIEW_LOG.md @@ -4425,3 +4425,47 @@ Noted while working: the mini figure inherited `.rb-body-svg { max-width: 180px from further down the stylesheet and blew the header out to 385px tall. Same-specificity selectors, later one wins; the compound `.rb-body-svg.rb-body-mini` fixes it. Worth remembering that this stylesheet is ordered by section rather than by specificity. + +## R-243. A helmet was protecting your legs + +Asking for "armour and the type of armour" on each location turned out not to be a +display request. Every equipped piece added its points to **every** location, so a +Brodie helmet protected your shins and a cuirass protected your skull. With a +catalogue that contains sallets, lobster-tail helmets and three separate cuirasses +that is not a simplification, it is wrong — and it could not be printed on the sheet +without the sheet saying something visibly false. + +Armour now declares **coverage**, as a named set rather than a list of locations, +because a piece has to fit whatever body is wearing it: `all`, `torso`, `torsoArms`, +`torsoLimbs`, `head`. The sets expand to location *kinds*, so a cuirass covers the +torso of a baseline agent and the trunk and ridge of a vesh without either the item or +the wearer knowing the other exists. Unstated coverage is `all`, so anything that does +not declare behaves exactly as everything did before. + +Eighteen of the twenty-five catalogue pieces are not whole-body and now say so. + +**The trap was double counting.** `hitLocationRoll` subtracted `sys.armourPoints + +loc.armour` — the global worn total plus the body's own armour at that location. +That was correct while armour was global and becomes a double count the moment the +location knows its own pieces. It now reads the location's total and nothing else, +checked by firing fourteen hits of 10 damage at every location and asserting the +damage applied equals `10 − that location's armour` each time. All fourteen matched. + +**A single ARMOUR number no longer exists**, so the header shows the torso — which is +what the question means, and where most hits land — with `0–8 by location` beside it +when the rest of you is not that. Worked example from the verification: stab vest, +cuirass and a Brodie helmet gives 8 on the torso, 3 on the head and **0 on both arms +and both legs**, where before it was 11 everywhere. + +**This is a real difficulty change and it is meant to be.** Agents in partial armour +are markedly more fragile than they were an hour ago — limbs are frequently bare, and +limbs are 12 of 20 on the melee table. Anyone who wants the old behaviour sets every +piece to `all` on its item sheet. + +## Coherence, promoted + +Moved out of the derived strip and into the vitals at the top right, at the same size +as hit points, with its band under it and the box itself changing colour as it falls — +yellow at Adrift, red at Unmoored and Displaced. It is the number that measures whether +an agent is still filed as themselves, and it was set in 11px grey between MOV and +carried weight. diff --git a/lang/en.json b/lang/en.json index 99ef446..b694455 100644 --- a/lang/en.json +++ b/lang/en.json @@ -885,5 +885,13 @@ "RINGBRP.Sheet.ReadyToggle": "Ready this weapon — puts it in the strip at the top of the sheet", "RINGBRP.Sheet.ReadyHint": "Click the fist to ready a weapon. Readied weapons appear in the strip under the characteristics, where they can be rolled without opening this tab.", "RINGBRP.Sheet.BodyHead": "The body, and where it gets hit", - "RINGBRP.Sheet.MiniBodyHint": "Every location: damage taken, and the armour covering it." + "RINGBRP.Sheet.MiniBodyHint": "Every location: damage taken, and the armour covering it.", + "RINGBRP.Coverage.all": "all of you", + "RINGBRP.Coverage.torso": "torso", + "RINGBRP.Coverage.torsoArms": "torso and arms", + "RINGBRP.Coverage.torsoLimbs": "torso, arms and legs", + "RINGBRP.Coverage.head": "head", + "RINGBRP.Sheet.Unarmoured": "bare", + "RINGBRP.Sheet.ByLocation": "by location", + "RINGBRP.Item.Coverage": "Covers" } diff --git a/packs/armour/000005.ldb b/packs/armour/000005.ldb index b406921..35545db 100644 Binary files a/packs/armour/000005.ldb 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..c6bd211 Binary files /dev/null and b/packs/armour/000006.log differ diff --git a/packs/armour/000008.ldb b/packs/armour/000008.ldb deleted file mode 100644 index 5281e73..0000000 Binary files a/packs/armour/000008.ldb and /dev/null differ diff --git a/packs/armour/000011.log b/packs/armour/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/armour/CURRENT b/packs/armour/CURRENT index 3051f81..cacca75 100644 --- a/packs/armour/CURRENT +++ b/packs/armour/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/armour/LOG b/packs/armour/LOG index f2c19d1..b6656cb 100644 --- a/packs/armour/LOG +++ b/packs/armour/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.113964 1752cb000 Recovering log #9 -2026/08/11-10:11:58.114393 1752cb000 Delete type=3 #7 -2026/08/11-10:11:58.114432 1752cb000 Delete type=0 #9 +2026/08/11-10:31:15.815927 175f73000 Recovering log #3 +2026/08/11-10:31:15.816054 175f73000 Level-0 table #5: started +2026/08/11-10:31:15.816169 175f73000 Level-0 table #5: 3399 bytes OK +2026/08/11-10:31:15.816387 175f73000 Delete type=0 #3 +2026/08/11-10:31:15.816415 175f73000 Delete type=3 #2 diff --git a/packs/armour/LOG.old b/packs/armour/LOG.old index 016cc23..10115e3 100644 --- a/packs/armour/LOG.old +++ b/packs/armour/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.582527 176517000 Recovering log #6 -2026/08/11-10:01:07.582663 176517000 Level-0 table #8: started -2026/08/11-10:01:07.582827 176517000 Level-0 table #8: 4335 bytes OK -2026/08/11-10:01:07.583142 176517000 Delete type=0 #6 -2026/08/11-10:01:07.583300 176517000 Delete type=3 #4 +2026/08/11-10:29:47.321526 1714a3000 Delete type=3 #1 diff --git a/packs/armour/MANIFEST-000004 b/packs/armour/MANIFEST-000004 new file mode 100644 index 0000000..819d483 Binary files /dev/null and b/packs/armour/MANIFEST-000004 differ diff --git a/packs/armour/MANIFEST-000010 b/packs/armour/MANIFEST-000010 deleted file mode 100644 index 36e3e4a..0000000 Binary files a/packs/armour/MANIFEST-000010 and /dev/null 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/000008.ldb b/packs/expedition/000008.ldb deleted file mode 100644 index 3138bb5..0000000 Binary files a/packs/expedition/000008.ldb and /dev/null differ diff --git a/packs/expedition/000011.log b/packs/expedition/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/expedition/CURRENT b/packs/expedition/CURRENT index 3051f81..cacca75 100644 --- a/packs/expedition/CURRENT +++ b/packs/expedition/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/expedition/LOG b/packs/expedition/LOG index 9888d84..e2c93cc 100644 --- a/packs/expedition/LOG +++ b/packs/expedition/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.123637 174abf000 Recovering log #9 -2026/08/11-10:11:58.124065 174abf000 Delete type=3 #7 -2026/08/11-10:11:58.124216 174abf000 Delete type=0 #9 +2026/08/11-10:31:15.827053 176f8b000 Recovering log #3 +2026/08/11-10:31:15.827202 176f8b000 Level-0 table #5: started +2026/08/11-10:31:15.827356 176f8b000 Level-0 table #5: 4129 bytes OK +2026/08/11-10:31:15.827638 176f8b000 Delete type=0 #3 +2026/08/11-10:31:15.827685 176f8b000 Delete type=3 #2 diff --git a/packs/expedition/LOG.old b/packs/expedition/LOG.old index 52aa937..8713030 100644 --- a/packs/expedition/LOG.old +++ b/packs/expedition/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.594977 176d23000 Recovering log #6 -2026/08/11-10:01:07.595333 176d23000 Level-0 table #8: started -2026/08/11-10:01:07.595474 176d23000 Level-0 table #8: 5069 bytes OK -2026/08/11-10:01:07.595768 176d23000 Delete type=0 #6 -2026/08/11-10:01:07.595810 176d23000 Delete type=3 #4 +2026/08/11-10:29:47.359914 170c97000 Delete type=3 #1 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/expedition/MANIFEST-000010 b/packs/expedition/MANIFEST-000010 deleted file mode 100644 index 2024e35..0000000 Binary files a/packs/expedition/MANIFEST-000010 and /dev/null differ diff --git a/packs/gear/000006.log b/packs/gear/000006.log new file mode 100644 index 0000000..d1deb9b Binary files /dev/null and b/packs/gear/000006.log differ diff --git a/packs/gear/000008.ldb b/packs/gear/000008.ldb deleted file mode 100644 index f6a523e..0000000 Binary files a/packs/gear/000008.ldb and /dev/null differ diff --git a/packs/gear/000011.log b/packs/gear/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/gear/CURRENT b/packs/gear/CURRENT index 3051f81..cacca75 100644 --- a/packs/gear/CURRENT +++ b/packs/gear/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/gear/LOG b/packs/gear/LOG index c1f79f8..198b123 100644 --- a/packs/gear/LOG +++ b/packs/gear/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.115761 175ad7000 Recovering log #9 -2026/08/11-10:11:58.116061 175ad7000 Delete type=3 #7 -2026/08/11-10:11:58.116179 175ad7000 Delete type=0 #9 +2026/08/11-10:31:15.817069 177797000 Recovering log #3 +2026/08/11-10:31:15.817858 177797000 Level-0 table #5: started +2026/08/11-10:31:15.818239 177797000 Level-0 table #5: 31614 bytes OK +2026/08/11-10:31:15.818545 177797000 Delete type=0 #3 +2026/08/11-10:31:15.818601 177797000 Delete type=3 #2 diff --git a/packs/gear/LOG.old b/packs/gear/LOG.old index d5ed446..c8ab21b 100644 --- a/packs/gear/LOG.old +++ b/packs/gear/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.584322 176d23000 Recovering log #6 -2026/08/11-10:01:07.584745 176d23000 Level-0 table #8: started -2026/08/11-10:01:07.585166 176d23000 Level-0 table #8: 38366 bytes OK -2026/08/11-10:01:07.585428 176d23000 Delete type=0 #6 -2026/08/11-10:01:07.585590 176d23000 Delete type=3 #4 +2026/08/11-10:29:47.323743 171caf000 Delete type=3 #1 diff --git a/packs/gear/MANIFEST-000004 b/packs/gear/MANIFEST-000004 new file mode 100644 index 0000000..f7cd73c Binary files /dev/null and b/packs/gear/MANIFEST-000004 differ diff --git a/packs/gear/MANIFEST-000010 b/packs/gear/MANIFEST-000010 deleted file mode 100644 index a0eef85..0000000 Binary files a/packs/gear/MANIFEST-000010 and /dev/null differ diff --git a/packs/npcs/000005.ldb b/packs/npcs/000005.ldb index 434f292..ab23f79 100644 Binary files a/packs/npcs/000005.ldb 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..ed99ff7 Binary files /dev/null and b/packs/npcs/000006.log differ diff --git a/packs/npcs/000008.ldb b/packs/npcs/000008.ldb deleted file mode 100644 index 1b3cc1e..0000000 Binary files a/packs/npcs/000008.ldb and /dev/null differ diff --git a/packs/npcs/000011.log b/packs/npcs/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/npcs/CURRENT b/packs/npcs/CURRENT index 3051f81..cacca75 100644 --- a/packs/npcs/CURRENT +++ b/packs/npcs/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/npcs/LOG b/packs/npcs/LOG index 088a6c5..a035e49 100644 --- a/packs/npcs/LOG +++ b/packs/npcs/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.104873 175ad7000 Recovering log #9 -2026/08/11-10:11:58.105121 175ad7000 Delete type=3 #7 -2026/08/11-10:11:58.105148 175ad7000 Delete type=0 #9 +2026/08/11-10:31:15.803065 177797000 Recovering log #3 +2026/08/11-10:31:15.804714 177797000 Level-0 table #5: started +2026/08/11-10:31:15.806503 177797000 Level-0 table #5: 223539 bytes OK +2026/08/11-10:31:15.806843 177797000 Delete type=0 #3 +2026/08/11-10:31:15.806889 177797000 Delete type=3 #2 diff --git a/packs/npcs/LOG.old b/packs/npcs/LOG.old index 6ef0667..f263391 100644 --- a/packs/npcs/LOG.old +++ b/packs/npcs/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.565661 176d23000 Recovering log #6 -2026/08/11-10:01:07.567596 176d23000 Level-0 table #8: started -2026/08/11-10:01:07.569268 176d23000 Level-0 table #8: 286534 bytes OK -2026/08/11-10:01:07.569897 176d23000 Delete type=0 #6 -2026/08/11-10:01:07.570096 176d23000 Delete type=3 #4 +2026/08/11-10:29:47.341619 170c97000 Delete type=3 #1 diff --git a/packs/npcs/MANIFEST-000004 b/packs/npcs/MANIFEST-000004 new file mode 100644 index 0000000..9793e35 Binary files /dev/null and b/packs/npcs/MANIFEST-000004 differ diff --git a/packs/npcs/MANIFEST-000010 b/packs/npcs/MANIFEST-000010 deleted file mode 100644 index cdba26d..0000000 Binary files a/packs/npcs/MANIFEST-000010 and /dev/null 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/000008.ldb b/packs/powers/000008.ldb deleted file mode 100644 index 6f225ae..0000000 Binary files a/packs/powers/000008.ldb and /dev/null differ diff --git a/packs/powers/000011.log b/packs/powers/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/powers/CURRENT b/packs/powers/CURRENT index 3051f81..cacca75 100644 --- a/packs/powers/CURRENT +++ b/packs/powers/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/powers/LOG b/packs/powers/LOG index 03c3221..44e2293 100644 --- a/packs/powers/LOG +++ b/packs/powers/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.111179 1742b3000 Recovering log #9 -2026/08/11-10:11:58.111621 1742b3000 Delete type=3 #7 -2026/08/11-10:11:58.111656 1742b3000 Delete type=0 #9 +2026/08/11-10:31:15.812365 175f73000 Recovering log #3 +2026/08/11-10:31:15.812699 175f73000 Level-0 table #5: started +2026/08/11-10:31:15.812860 175f73000 Level-0 table #5: 3295 bytes OK +2026/08/11-10:31:15.813123 175f73000 Delete type=0 #3 +2026/08/11-10:31:15.813163 175f73000 Delete type=3 #2 diff --git a/packs/powers/LOG.old b/packs/powers/LOG.old index 05677b9..9e996b0 100644 --- a/packs/powers/LOG.old +++ b/packs/powers/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.578452 176517000 Recovering log #6 -2026/08/11-10:01:07.578743 176517000 Level-0 table #8: started -2026/08/11-10:01:07.578908 176517000 Level-0 table #8: 3619 bytes OK -2026/08/11-10:01:07.579232 176517000 Delete type=0 #6 -2026/08/11-10:01:07.579267 176517000 Delete type=3 #4 +2026/08/11-10:29:47.352685 170c97000 Delete type=3 #1 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/powers/MANIFEST-000010 b/packs/powers/MANIFEST-000010 deleted file mode 100644 index 50a606c..0000000 Binary files a/packs/powers/MANIFEST-000010 and /dev/null differ diff --git a/packs/pregens/000005.ldb b/packs/pregens/000005.ldb index fe8672f..4f39ac7 100644 Binary files a/packs/pregens/000005.ldb 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..327442d Binary files /dev/null and b/packs/pregens/000006.log differ diff --git a/packs/pregens/000008.ldb b/packs/pregens/000008.ldb deleted file mode 100644 index fecb448..0000000 Binary files a/packs/pregens/000008.ldb and /dev/null differ diff --git a/packs/pregens/000011.log b/packs/pregens/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/pregens/CURRENT b/packs/pregens/CURRENT index 3051f81..cacca75 100644 --- a/packs/pregens/CURRENT +++ b/packs/pregens/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/pregens/LOG b/packs/pregens/LOG index 2ae21ef..67b8b8a 100644 --- a/packs/pregens/LOG +++ b/packs/pregens/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.102156 175ad7000 Recovering log #9 -2026/08/11-10:11:58.102452 175ad7000 Delete type=3 #7 -2026/08/11-10:11:58.102485 175ad7000 Delete type=0 #9 +2026/08/11-10:31:15.799594 177797000 Recovering log #3 +2026/08/11-10:31:15.800464 177797000 Level-0 table #5: started +2026/08/11-10:31:15.800988 177797000 Level-0 table #5: 58133 bytes OK +2026/08/11-10:31:15.801383 177797000 Delete type=0 #3 +2026/08/11-10:31:15.801428 177797000 Delete type=3 #2 diff --git a/packs/pregens/LOG.old b/packs/pregens/LOG.old index 8af48ed..b460cd9 100644 --- a/packs/pregens/LOG.old +++ b/packs/pregens/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.561384 176d23000 Recovering log #6 -2026/08/11-10:01:07.562078 176d23000 Level-0 table #8: started -2026/08/11-10:01:07.562682 176d23000 Level-0 table #8: 74653 bytes OK -2026/08/11-10:01:07.563017 176d23000 Delete type=0 #6 -2026/08/11-10:01:07.563204 176d23000 Delete type=3 #4 +2026/08/11-10:29:47.331121 1724bb000 Delete type=3 #1 diff --git a/packs/pregens/MANIFEST-000004 b/packs/pregens/MANIFEST-000004 new file mode 100644 index 0000000..ca194a0 Binary files /dev/null and b/packs/pregens/MANIFEST-000004 differ diff --git a/packs/pregens/MANIFEST-000010 b/packs/pregens/MANIFEST-000010 deleted file mode 100644 index 4bd3bc0..0000000 Binary files a/packs/pregens/MANIFEST-000010 and /dev/null differ diff --git a/packs/rules/000006.log b/packs/rules/000006.log new file mode 100644 index 0000000..5e876ff Binary files /dev/null and b/packs/rules/000006.log differ diff --git a/packs/rules/000008.ldb b/packs/rules/000008.ldb deleted file mode 100644 index 2662cc6..0000000 Binary files a/packs/rules/000008.ldb and /dev/null differ diff --git a/packs/rules/000011.log b/packs/rules/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/rules/CURRENT b/packs/rules/CURRENT index 3051f81..cacca75 100644 --- a/packs/rules/CURRENT +++ b/packs/rules/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/rules/LOG b/packs/rules/LOG index e0cf59d..6dd2eaa 100644 --- a/packs/rules/LOG +++ b/packs/rules/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.118905 174abf000 Recovering log #9 -2026/08/11-10:11:58.119473 174abf000 Delete type=3 #7 -2026/08/11-10:11:58.119498 174abf000 Delete type=0 #9 +2026/08/11-10:31:15.822560 176f8b000 Recovering log #3 +2026/08/11-10:31:15.823036 176f8b000 Level-0 table #5: started +2026/08/11-10:31:15.823351 176f8b000 Level-0 table #5: 30975 bytes OK +2026/08/11-10:31:15.823593 176f8b000 Delete type=0 #3 +2026/08/11-10:31:15.823625 176f8b000 Delete type=3 #2 diff --git a/packs/rules/LOG.old b/packs/rules/LOG.old index 813d9e7..11bb770 100644 --- a/packs/rules/LOG.old +++ b/packs/rules/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.588947 176d23000 Recovering log #6 -2026/08/11-10:01:07.589575 176d23000 Level-0 table #8: started -2026/08/11-10:01:07.589919 176d23000 Level-0 table #8: 31649 bytes OK -2026/08/11-10:01:07.590195 176d23000 Delete type=0 #6 -2026/08/11-10:01:07.590234 176d23000 Delete type=3 #4 +2026/08/11-10:29:47.357907 170c97000 Delete type=3 #1 diff --git a/packs/rules/MANIFEST-000004 b/packs/rules/MANIFEST-000004 new file mode 100644 index 0000000..e2e1bf1 Binary files /dev/null and b/packs/rules/MANIFEST-000004 differ diff --git a/packs/rules/MANIFEST-000010 b/packs/rules/MANIFEST-000010 deleted file mode 100644 index 8d2a88a..0000000 Binary files a/packs/rules/MANIFEST-000010 and /dev/null 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/000008.ldb b/packs/skills/000008.ldb deleted file mode 100644 index c27576b..0000000 Binary files a/packs/skills/000008.ldb and /dev/null differ diff --git a/packs/skills/000011.log b/packs/skills/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/skills/CURRENT b/packs/skills/CURRENT index 3051f81..cacca75 100644 --- a/packs/skills/CURRENT +++ b/packs/skills/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/skills/LOG b/packs/skills/LOG index 6b5f2e2..4ecde2e 100644 --- a/packs/skills/LOG +++ b/packs/skills/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.108810 1742b3000 Recovering log #9 -2026/08/11-10:11:58.109145 1742b3000 Delete type=3 #7 -2026/08/11-10:11:58.109174 1742b3000 Delete type=0 #9 +2026/08/11-10:31:15.809540 175f73000 Recovering log #3 +2026/08/11-10:31:15.809752 175f73000 Level-0 table #5: started +2026/08/11-10:31:15.809950 175f73000 Level-0 table #5: 7486 bytes OK +2026/08/11-10:31:15.810216 175f73000 Delete type=0 #3 +2026/08/11-10:31:15.810251 175f73000 Delete type=3 #2 diff --git a/packs/skills/LOG.old b/packs/skills/LOG.old index 74df031..c4bf034 100644 --- a/packs/skills/LOG.old +++ b/packs/skills/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.573933 17752f000 Recovering log #6 -2026/08/11-10:01:07.574377 17752f000 Level-0 table #8: started -2026/08/11-10:01:07.574672 17752f000 Level-0 table #8: 9877 bytes OK -2026/08/11-10:01:07.575009 17752f000 Delete type=0 #6 -2026/08/11-10:01:07.575053 17752f000 Delete type=3 #4 +2026/08/11-10:29:47.314145 1724bb000 Delete type=3 #1 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/skills/MANIFEST-000010 b/packs/skills/MANIFEST-000010 deleted file mode 100644 index 5c7d963..0000000 Binary files a/packs/skills/MANIFEST-000010 and /dev/null 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/000008.ldb b/packs/slice/000008.ldb deleted file mode 100644 index 0fb9fe3..0000000 Binary files a/packs/slice/000008.ldb and /dev/null differ diff --git a/packs/slice/000011.log b/packs/slice/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/slice/CURRENT b/packs/slice/CURRENT index 3051f81..cacca75 100644 --- a/packs/slice/CURRENT +++ b/packs/slice/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/slice/LOG b/packs/slice/LOG index 6256cf8..be57eab 100644 --- a/packs/slice/LOG +++ b/packs/slice/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.120643 1742b3000 Recovering log #9 -2026/08/11-10:11:58.120895 1742b3000 Delete type=3 #7 -2026/08/11-10:11:58.120916 1742b3000 Delete type=0 #9 +2026/08/11-10:31:15.824364 17677f000 Recovering log #3 +2026/08/11-10:31:15.824536 17677f000 Level-0 table #5: started +2026/08/11-10:31:15.824835 17677f000 Level-0 table #5: 16892 bytes OK +2026/08/11-10:31:15.825060 17677f000 Delete type=0 #3 +2026/08/11-10:31:15.825097 17677f000 Delete type=3 #2 diff --git a/packs/slice/LOG.old b/packs/slice/LOG.old index cf54a47..3be9995 100644 --- a/packs/slice/LOG.old +++ b/packs/slice/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.591406 175d0b000 Recovering log #6 -2026/08/11-10:01:07.591579 175d0b000 Level-0 table #8: started -2026/08/11-10:01:07.591796 175d0b000 Level-0 table #8: 17462 bytes OK -2026/08/11-10:01:07.592037 175d0b000 Delete type=0 #6 -2026/08/11-10:01:07.592183 175d0b000 Delete type=3 #4 +2026/08/11-10:29:47.350616 1714a3000 Delete type=3 #1 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/slice/MANIFEST-000010 b/packs/slice/MANIFEST-000010 deleted file mode 100644 index 4b65ede..0000000 Binary files a/packs/slice/MANIFEST-000010 and /dev/null 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/000008.ldb b/packs/tables/000008.ldb deleted file mode 100644 index 465e211..0000000 Binary files a/packs/tables/000008.ldb and /dev/null differ diff --git a/packs/tables/000011.log b/packs/tables/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/tables/CURRENT b/packs/tables/CURRENT index 3051f81..cacca75 100644 --- a/packs/tables/CURRENT +++ b/packs/tables/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/tables/LOG b/packs/tables/LOG index 0d21302..f29fd17 100644 --- a/packs/tables/LOG +++ b/packs/tables/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.122039 1752cb000 Recovering log #9 -2026/08/11-10:11:58.122569 1752cb000 Delete type=3 #7 -2026/08/11-10:11:58.122614 1752cb000 Delete type=0 #9 +2026/08/11-10:31:15.825859 175f73000 Recovering log #3 +2026/08/11-10:31:15.825973 175f73000 Level-0 table #5: started +2026/08/11-10:31:15.826082 175f73000 Level-0 table #5: 3739 bytes OK +2026/08/11-10:31:15.826284 175f73000 Delete type=0 #3 +2026/08/11-10:31:15.826314 175f73000 Delete type=3 #2 diff --git a/packs/tables/LOG.old b/packs/tables/LOG.old index eb761e9..f1ac225 100644 --- a/packs/tables/LOG.old +++ b/packs/tables/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.593261 17752f000 Recovering log #6 -2026/08/11-10:01:07.593387 17752f000 Level-0 table #8: started -2026/08/11-10:01:07.593525 17752f000 Level-0 table #8: 4143 bytes OK -2026/08/11-10:01:07.593758 17752f000 Delete type=0 #6 -2026/08/11-10:01:07.593895 17752f000 Delete type=3 #4 +2026/08/11-10:29:47.347262 1714a3000 Delete type=3 #1 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/tables/MANIFEST-000010 b/packs/tables/MANIFEST-000010 deleted file mode 100644 index 174d1a5..0000000 Binary files a/packs/tables/MANIFEST-000010 and /dev/null 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/000008.ldb b/packs/talents/000008.ldb deleted file mode 100644 index 4b44900..0000000 Binary files a/packs/talents/000008.ldb and /dev/null differ diff --git a/packs/talents/000011.log b/packs/talents/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/talents/CURRENT b/packs/talents/CURRENT index 3051f81..cacca75 100644 --- a/packs/talents/CURRENT +++ b/packs/talents/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/talents/LOG b/packs/talents/LOG index 84f806e..5bf1264 100644 --- a/packs/talents/LOG +++ b/packs/talents/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.110071 175ad7000 Recovering log #9 -2026/08/11-10:11:58.110287 175ad7000 Delete type=3 #7 -2026/08/11-10:11:58.110314 175ad7000 Delete type=0 #9 +2026/08/11-10:31:15.810995 177797000 Recovering log #3 +2026/08/11-10:31:15.811100 177797000 Level-0 table #5: started +2026/08/11-10:31:15.811254 177797000 Level-0 table #5: 5770 bytes OK +2026/08/11-10:31:15.811516 177797000 Delete type=0 #3 +2026/08/11-10:31:15.811553 177797000 Delete type=3 #2 diff --git a/packs/talents/LOG.old b/packs/talents/LOG.old index 16f0e0e..7f324bc 100644 --- a/packs/talents/LOG.old +++ b/packs/talents/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.576370 175d0b000 Recovering log #6 -2026/08/11-10:01:07.576741 175d0b000 Level-0 table #8: started -2026/08/11-10:01:07.576905 175d0b000 Level-0 table #8: 6447 bytes OK -2026/08/11-10:01:07.577157 175d0b000 Delete type=0 #6 -2026/08/11-10:01:07.577191 175d0b000 Delete type=3 #4 +2026/08/11-10:29:47.318325 1724bb000 Delete type=3 #1 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/talents/MANIFEST-000010 b/packs/talents/MANIFEST-000010 deleted file mode 100644 index 4f68d63..0000000 Binary files a/packs/talents/MANIFEST-000010 and /dev/null 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/000008.ldb b/packs/vehicles/000008.ldb deleted file mode 100644 index dd545f3..0000000 Binary files a/packs/vehicles/000008.ldb and /dev/null differ diff --git a/packs/vehicles/000011.log b/packs/vehicles/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/vehicles/CURRENT b/packs/vehicles/CURRENT index 3051f81..cacca75 100644 --- a/packs/vehicles/CURRENT +++ b/packs/vehicles/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/vehicles/LOG b/packs/vehicles/LOG index 0cfb8ed..fec31df 100644 --- a/packs/vehicles/LOG +++ b/packs/vehicles/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.117614 1752cb000 Recovering log #9 -2026/08/11-10:11:58.117913 1752cb000 Delete type=3 #7 -2026/08/11-10:11:58.117935 1752cb000 Delete type=0 #9 +2026/08/11-10:31:15.819847 17677f000 Recovering log #3 +2026/08/11-10:31:15.820254 17677f000 Level-0 table #5: started +2026/08/11-10:31:15.821322 17677f000 Level-0 table #5: 6939 bytes OK +2026/08/11-10:31:15.821576 17677f000 Delete type=0 #3 +2026/08/11-10:31:15.821605 17677f000 Delete type=3 #2 diff --git a/packs/vehicles/LOG.old b/packs/vehicles/LOG.old index 23e6547..e1200c4 100644 --- a/packs/vehicles/LOG.old +++ b/packs/vehicles/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.587264 176517000 Recovering log #6 -2026/08/11-10:01:07.587412 176517000 Level-0 table #8: started -2026/08/11-10:01:07.587590 176517000 Level-0 table #8: 8283 bytes OK -2026/08/11-10:01:07.587831 176517000 Delete type=0 #6 -2026/08/11-10:01:07.587866 176517000 Delete type=3 #4 +2026/08/11-10:29:47.325901 170c97000 Delete type=3 #1 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/vehicles/MANIFEST-000010 b/packs/vehicles/MANIFEST-000010 deleted file mode 100644 index 03c9e39..0000000 Binary files a/packs/vehicles/MANIFEST-000010 and /dev/null 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/000008.ldb b/packs/weapons/000008.ldb deleted file mode 100644 index 15ab040..0000000 Binary files a/packs/weapons/000008.ldb and /dev/null differ diff --git a/packs/weapons/000011.log b/packs/weapons/000011.log deleted file mode 100644 index e69de29..0000000 diff --git a/packs/weapons/CURRENT b/packs/weapons/CURRENT index 3051f81..cacca75 100644 --- a/packs/weapons/CURRENT +++ b/packs/weapons/CURRENT @@ -1 +1 @@ -MANIFEST-000010 +MANIFEST-000004 diff --git a/packs/weapons/LOG b/packs/weapons/LOG index 0c74260..5fcd2da 100644 --- a/packs/weapons/LOG +++ b/packs/weapons/LOG @@ -1,3 +1,5 @@ -2026/08/11-10:11:58.112542 175ad7000 Recovering log #9 -2026/08/11-10:11:58.112769 175ad7000 Delete type=3 #7 -2026/08/11-10:11:58.112806 175ad7000 Delete type=0 #9 +2026/08/11-10:31:15.814063 177797000 Recovering log #3 +2026/08/11-10:31:15.814421 177797000 Level-0 table #5: started +2026/08/11-10:31:15.814700 177797000 Level-0 table #5: 14767 bytes OK +2026/08/11-10:31:15.814977 177797000 Delete type=0 #3 +2026/08/11-10:31:15.815010 177797000 Delete type=3 #2 diff --git a/packs/weapons/LOG.old b/packs/weapons/LOG.old index e426202..bac01ca 100644 --- a/packs/weapons/LOG.old +++ b/packs/weapons/LOG.old @@ -1,5 +1 @@ -2026/08/11-10:01:07.580288 17752f000 Recovering log #6 -2026/08/11-10:01:07.580621 17752f000 Level-0 table #8: started -2026/08/11-10:01:07.580948 17752f000 Level-0 table #8: 17963 bytes OK -2026/08/11-10:01:07.581296 17752f000 Delete type=0 #6 -2026/08/11-10:01:07.581365 17752f000 Delete type=3 #4 +2026/08/11-10:29:47.320066 170c97000 Delete type=3 #1 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/packs/weapons/MANIFEST-000010 b/packs/weapons/MANIFEST-000010 deleted file mode 100644 index d75b089..0000000 Binary files a/packs/weapons/MANIFEST-000010 and /dev/null differ diff --git a/ringbrp.mjs b/ringbrp.mjs index 63f2520..36b7e43 100644 --- a/ringbrp.mjs +++ b/ringbrp.mjs @@ -33,6 +33,7 @@ import { BLAST, blastBandFor, blastShareFor, BLAST_COVER, blastAfterCover, BURST, burstHitsFor, burstRoundsSpent, BURST_FUMBLE, BURST_ONE_MAJOR_WOUND, BURST_HITS, LAMP, lampReachFor, lampCovers, + COVERAGE, coverageFor, armourCoversKind, locationArmourFor, FIRE_MODE, fireModeFor, burstSizesFor, fireModeAttackFor, secondShotPenaltyFor, SUSTAIN, sustainDamageFor, sustainChargeFor, SIGHT, sightFor, sightBonusFor, sightSeesInDark, @@ -296,6 +297,7 @@ RINGBRP.locationEffects = { // matching option, so opening one of those items and saving it blanked its fire mode. RINGBRP.fireModes = ["", ...Object.keys(FIRE_MODE)]; RINGBRP.sights = SIGHT; +RINGBRP.coverage = COVERAGE; RINGBRP.lighting = LIGHTING; RINGBRP.sustain = SUSTAIN; RINGBRP.weaponClasses = ["melee", "thrown", "bow", "firearm", "energy", "stun", "special"]; @@ -660,14 +662,14 @@ class RingBRPActor extends Actor { from: _reflex >= _aware ? "reflex" : "awareness" }; - // --- Armour: sum of equipped armour points --- - let armour = Number(sys.naturalArmour?.value) || 0; - for (const it of this.items) { - if (it.type !== "armour") continue; - if (!it.system.equipped) continue; - armour += Number(it.system.points) || 0; - } - sys.armourPoints = armour; + // --- Armour: what is worn, and what each piece actually reaches --- + // Every piece used to add to every location, so a Brodie helmet protected your + // legs. Pieces now declare coverage and the total is computed per location. + const naturalArmour = Number(sys.naturalArmour?.value) || 0; + const wornArmour = this.items.filter(i => i.type === "armour" && i.system.equipped) + .map(i => ({ name: i.name, points: Number(i.system.points) || 0, + coverage: i.system.coverage || "all" })); + sys.wornArmour = wornArmour; // --- hit locations (spec §3.6) --- const speciesId = sys.speciesProfile || "baseline"; @@ -682,11 +684,27 @@ class RingBRPActor extends Actor { melee: `${loc.melee[0]}${loc.melee[1] > loc.melee[0] ? `-${loc.melee[1]}` : ""}`, ranged: `${loc.ranged[0]}${loc.ranged[1] > loc.ranged[0] ? `-${loc.ranged[1]}` : ""}`, max, taken: t, remaining: Math.max(0, max - t), - armour: (Number(loc.armour) || 0) + armour, + // The body's own armour here, plus every worn piece that reaches this kind. + armour: locationArmourFor((Number(loc.armour) || 0) + naturalArmour, + wornArmour, loc.kind), + armourFrom: wornArmour.filter(p => armourCoversKind(p.coverage, loc.kind)) + .map(p => ({ name: p.name, points: p.points })), disabled: t >= max, destroyed: t >= max * 2 }; }); + // The header wants ONE number and there is no longer one number. The torso is + // what "how armoured am I" means — it is where most hits land — and the range + // is carried alongside so a sheet can say when the rest of you is not that. + { + const vals = sys.locations.map(l => l.armour); + const torso = sys.locations.find(l => l.kind === "vital") + ?? sys.locations.find(l => l.kind === "body"); + sys.armourPoints = torso ? torso.armour : (vals[0] ?? naturalArmour); + sys.armourRange = { min: Math.min(...vals, sys.armourPoints), + max: Math.max(...vals, sys.armourPoints) }; + sys.armourUneven = sys.armourRange.min !== sys.armourRange.max; + } // Wound effects were printed and never applied: a destroyed leg said "MOV // halved" while MOV stayed where it was. Derive the consequences here so the // penalty text and the numbers agree. @@ -1140,9 +1158,14 @@ export async function hitLocationRoll({ target, damage, mode = "ranged", // armour stacks on the body's, and a critical still bypasses (armourAgainst). let effective = Number(damage) || 0; if (!armourApplied) { - const worn = Number(sys.armourPoints) || 0; - const locArmour = Number(loc.armour) || 0; - effective = Math.max(0, effective - armourAgainst(level, worn + locArmour)); + // The location already knows its own total — the body's armour there plus every + // worn piece that reaches it. Adding sys.armourPoints on top would count the + // torso's armour a second time on every limb now that coverage exists. + const locArmour = live + ? Number(live.armour) || 0 + : locationArmourFor((Number(loc.armour) || 0) + (Number(sys.naturalArmour?.value) || 0), + sys.wornArmour ?? [], loc.kind); + effective = Math.max(0, effective - armourAgainst(level, locArmour)); } const res = resolveLocationHit({ damage: effective, locationMax: max, locationTaken: live?.taken ?? 0, @@ -5475,6 +5498,7 @@ class RingBRPItemSheet extends ItemSheet { ctx.isSkill = this.item.type === "skill"; ctx.isWeapon = this.item.type === "weapon"; ctx.isArmour = this.item.type === "armour"; + ctx.coverageLabel = coverageFor(this.item.system?.coverage).label; ctx.isDevice = this.item.type === "device"; ctx.isGear = this.item.type === "gear"; ctx.isProject = this.item.type === "project"; @@ -6171,13 +6195,29 @@ async function migrateFittedGear() { lightReachM: Number(doc.system.lightReachM) || 0 }); } } - if (!canon.size) return 0; + // Armour that predates coverage defaults to "all", which is what it always was — + // so a helmet on an existing agent would go on protecting their legs until it is + // stamped from the catalogue. + const armourPack = game.packs.get("ringbrp.armour"); + const armourCanon = new Map(); + for (const doc of (await armourPack?.getDocuments()) ?? []) { + const key = doc.flags?.ringbrp?.key; + if (key && doc.system?.coverage) armourCanon.set(key, doc.system.coverage); + } + if (!canon.size && !armourCanon.size) return 0; let fixed = 0; const owners = [...game.actors, ...game.scenes.map(s => s.tokens .filter(t => !t.actorLink && t.actor).map(t => t.actor)).flat()]; for (const actor of owners) { const updates = []; for (const it of actor.items) { + if (it.type === "armour") { + const want = armourCanon.get(it.flags?.ringbrp?.key); + if (want && (it.system.coverage || "all") !== want) { + updates.push({ _id: it.id, "system.coverage": want }); + } + continue; + } if (it.type !== "gear") continue; const want = canon.get(it.flags?.ringbrp?.key); if (!want) continue; diff --git a/rules.mjs b/rules.mjs index 4254bd5..4f08b4f 100644 --- a/rules.mjs +++ b/rules.mjs @@ -727,6 +727,61 @@ export const LIGHTING = { pitch: { id: "pitch", label: "RINGBRP.Lighting.pitch", mod: -50 } }; +/* -------------------------------------------- */ +/* What the armour actually covers */ +/* -------------------------------------------- */ + +/** + * ARMOUR COVERAGE. + * + * Every equipped piece used to add its points to every location, which meant a + * Brodie helmet protected your legs and a cuirass protected your head. With a + * catalogue that contains sallets, lobster-tail helmets and cuirasses that is not a + * simplification, it is wrong — and it could not be shown on the sheet without the + * sheet printing something visibly false. + * + * Coverage is declared as a NAMED SET rather than a list of locations, because armour + * has to fit whatever body is wearing it. The sets expand to location *kinds*, so a + * cuirass covers the torso of a baseline agent and the trunk of a vesh without either + * the item or the wearer knowing about the other. + * + * `all` is the default, so a piece that declares nothing behaves exactly as every + * piece did before this rule existed. + */ +export const COVERAGE = { + all: { id: "all", label: "RINGBRP.Coverage.all", kinds: null }, + torso: { id: "torso", label: "RINGBRP.Coverage.torso", + kinds: ["body", "vital", "ridge", "unit"] }, + torsoArms: { id: "torsoArms", label: "RINGBRP.Coverage.torsoArms", + kinds: ["body", "vital", "ridge", "unit", "arm", "grasp"] }, + torsoLimbs: { id: "torsoLimbs", label: "RINGBRP.Coverage.torsoLimbs", + kinds: ["body", "vital", "ridge", "unit", "arm", "grasp", "leg", "brace"] }, + head: { id: "head", label: "RINGBRP.Coverage.head", kinds: ["head"] } +}; + +export function coverageFor(id) { + return COVERAGE[id] || COVERAGE.all; +} + +/** Does a piece with this coverage protect a location of this kind? */ +export function armourCoversKind(coverageId, kind) { + const kinds = coverageFor(coverageId).kinds; + return kinds === null ? true : kinds.includes(kind); +} + +/** + * The armour on one location: what the body has there anyway, plus every worn piece + * that reaches it. `pieces` is [{ points, coverage }] — worn only; the caller decides + * what "worn" means, because that is a question about the actor and not about armour. + */ +export function locationArmourFor(base, pieces, kind) { + let n = Number(base) || 0; + for (const p of pieces ?? []) { + if (armourCoversKind(p?.coverage, kind)) n += Number(p?.points) || 0; + } + return n; +} + /** A lamp never makes it daylight. This is the best it gets you. */ export const LIGHT_FLOOR = "dim"; diff --git a/styles/ringbrp.css b/styles/ringbrp.css index 1b2de5b..ab019d2 100644 --- a/styles/ringbrp.css +++ b/styles/ringbrp.css @@ -423,6 +423,58 @@ .ringbrp-sheet .rb-equip:hover { color: var(--rb-white); } .ringbrp-sheet .rb-equip.on { color: var(--rb-yellow); } +/* ============================================================ + Coherence, promoted to the vitals — it is a survival number + ============================================================ */ + +.rb-vital-coh { position: relative; } +.rb-coh-row { display: flex; align-items: baseline; justify-content: center; gap: 2px; } +.rb-vital-coh .rb-cohbtn { + font-size: 15px; line-height: 1; padding: 0 4px; color: var(--rb-muted); +} +.rb-vital-coh .rb-cohbtn:hover { color: var(--rb-yellow); } +.rb-vital-coh .rb-cohband { + font-family: var(--rb-display); font-size: 9px; letter-spacing: .08em; + text-transform: uppercase; color: var(--rb-muted); +} +/* Coherence going is how this game kills you slowly, so the box says so. */ +.rb-vital-coh.rb-coh-loose { border-color: var(--rb-yellow-dim); } +.rb-vital-coh.rb-coh-adrift { border-color: var(--rb-yellow); } +.rb-vital-coh.rb-coh-adrift .rb-cohband { color: var(--rb-yellow); } +.rb-vital-coh.rb-coh-unmoored, +.rb-vital-coh.rb-coh-displaced { border-color: var(--rb-danger); } +.rb-vital-coh.rb-coh-unmoored .rb-big, +.rb-vital-coh.rb-coh-displaced .rb-big, +.rb-vital-coh.rb-coh-unmoored .rb-cohband, +.rb-vital-coh.rb-coh-displaced .rb-cohband { color: var(--rb-danger); } + +.rb-armour-range { + font-family: var(--rb-mono); font-size: 9px; color: var(--rb-muted); +} + +/* ============================================================ + Armour, per location — the number and the thing providing it + ============================================================ */ + +.rb-col-ap { white-space: nowrap; text-align: right; } +.rb-ap-num { + font-weight: 700; font-variant-numeric: tabular-nums; color: var(--rb-white); +} +.rb-ap-from { display: inline-flex; gap: 4px; margin-left: 7px; flex-wrap: wrap; } +.rb-ap-piece { + font-size: 9px; letter-spacing: .02em; color: var(--rb-yellow); + border: 1px solid var(--rb-yellow-dim); padding: 0 4px; border-radius: 2px; +} +.rb-ap-piece b { color: var(--rb-white); font-weight: 700; } +.rb-ap-bare { + font-size: 9px; font-style: italic; color: var(--rb-line); margin-left: 7px; +} +/* The compact table IS the combat tab's, and the piece names are the point of the + request — so they stay. They wrap under the number when the column is narrow. */ +.rb-loctable-compact .rb-col-ap { white-space: normal; } +.rb-loctable-compact .rb-ap-from { margin-left: 5px; } +.rb-loctable-compact .rb-ap-piece { font-size: 8px; } + /* ============================================================ Weapons — the first thing on the combat tab, and it should look it ============================================================ */ diff --git a/template.json b/template.json index 5547c9f..59fac7b 100644 --- a/template.json +++ b/template.json @@ -234,6 +234,7 @@ "physical" ], "points": 1, + "coverage": "all", "ignoredBy": [], "degradation": { "current": 0, diff --git a/templates/character-sheet.hbs b/templates/character-sheet.hbs index ef02d50..cb050a5 100644 --- a/templates/character-sheet.hbs +++ b/templates/character-sheet.hbs @@ -38,10 +38,21 @@ {{localize "RINGBRP.Sheet.MajorWound"}} {{sys.majorWound.value}} +
+ {{localize "RINGBRP.Coh.Label"}} + + − + {{sys.coherence.value}} + + + + {{localize coherence.band.label}} +
{{localize "RINGBRP.Sheet.Armour"}} {{sys.armourPoints}} + {{#if sys.armourUneven}}{{sys.armourRange.min}}–{{sys.armourRange.max}} {{localize "RINGBRP.Sheet.ByLocation"}}{{/if}} {{#if armourUnworn.length}}{{localize "RINGBRP.Sheet.NotWorn"}}{{/if}}
@@ -86,12 +97,6 @@
{{localize "RINGBRP.Sheet.MOV"}}{{sys.mov}}
-
- {{localize "RINGBRP.Coh.Label"}} - −{{sys.coherence.value}}+ - {{localize coherence.band.label}} -
{{localize "RINGBRP.Sheet.Carry"}} {{sys.carriedKg}} / {{sys.freeCarryKg}} kg @@ -329,7 +334,14 @@ {{l.melee}} {{l.ranged}} {{l.taken}}/{{l.max}} - {{l.armour}} + + {{l.armour}} + {{#if l.armourFrom.length}} + {{#each l.armourFrom as |a|}}{{a.name}}{{/each}} + {{else}} + {{localize "RINGBRP.Sheet.Unarmoured"}} + {{/if}} + {{/each}} @@ -527,7 +539,14 @@ {{l.melee}} {{l.ranged}} {{l.taken}}/{{l.max}} - {{l.armour}} + + {{l.armour}} + {{#if l.armourFrom.length}} + {{#each l.armourFrom as |a|}}{{a.name}} {{a.points}}{{/each}} + {{else}} + {{localize "RINGBRP.Sheet.Unarmoured"}} + {{/if}} + {{/each}} diff --git a/templates/item-sheet.hbs b/templates/item-sheet.hbs index fc50741..87b027e 100644 --- a/templates/item-sheet.hbs +++ b/templates/item-sheet.hbs @@ -54,6 +54,8 @@ {{sys.massKg}} kg
{{localize "RINGBRP.Item.Equipped"}} {{#if sys.equipped}}{{localize "RINGBRP.Item.Worn"}}{{else}}—{{/if}}
+
{{localize "RINGBRP.Item.Coverage"}} + {{localize coverageLabel}}
{{localize "RINGBRP.Item.IgnoredBy"}} {{#each sys.ignoredBy as |x|}}{{x}}{{#unless @last}}, {{/unless}}{{else}}—{{/each}}
@@ -272,6 +274,11 @@ +

{{localize "RINGBRP.Item.ArmourNote"}}

{{/if}} diff --git a/tools/build-packs.mjs b/tools/build-packs.mjs index c7f40cd..0c4869f 100644 --- a/tools/build-packs.mjs +++ b/tools/build-packs.mjs @@ -100,7 +100,8 @@ function armourItem(a) { coherenceCost: a.coherence ?? 0, description: "", massKg: a.mass, quantity: 1, equipped: false, carried: true, traditionIds: [a.trad ?? "tradition_local"], - points: a.points, ignoredBy: [], degradation: { current: 0, max: 4 } + points: a.points, coverage: a.covers ?? "all", + ignoredBy: [], degradation: { current: 0, max: 4 } }, effects: [], ...BASE(), flags: { ringbrp: { key: a.key, era: a.era ?? "modern" } } diff --git a/tools/check-rules.mjs b/tools/check-rules.mjs index c5213c9..5f95965 100644 --- a/tools/check-rules.mjs +++ b/tools/check-rules.mjs @@ -284,6 +284,29 @@ const checks = [ ["sightFor(nonsense) is none", RULES.sightFor("wat").id, "none"], ["sightSeesInDark(thermal)", RULES.sightSeesInDark("thermal"), true], ["sightSeesInDark(telescopic)", RULES.sightSeesInDark("telescopic"), false], + // A helmet does not protect your legs. Coverage, and what it adds up to. + ["armourCoversKind(head, head)", RULES.armourCoversKind("head","head"), true], + ["armourCoversKind(head, leg)", RULES.armourCoversKind("head","leg"), false], + ["armourCoversKind(torso, vital)", RULES.armourCoversKind("torso","vital"), true], + ["armourCoversKind(torso, arm)", RULES.armourCoversKind("torso","arm"), false], + ["armourCoversKind(torsoArms, arm)", RULES.armourCoversKind("torsoArms","arm"), true], + ["armourCoversKind(torsoArms, leg)", RULES.armourCoversKind("torsoArms","leg"), false], + ["armourCoversKind(torsoLimbs, leg)", RULES.armourCoversKind("torsoLimbs","leg"), true], + ["armourCoversKind(torsoLimbs, head)", RULES.armourCoversKind("torsoLimbs","head"), false], + // Unstated coverage is ALL — a piece that says nothing behaves as it always did. + ["armourCoversKind(all, leg)", RULES.armourCoversKind("all","leg"), true], + ["armourCoversKind(undefined, head)", RULES.armourCoversKind(undefined,"head"), true], + // A torso piece protects a vesh trunk and its ridge without either knowing of the other. + ["armourCoversKind(torso, ridge)", RULES.armourCoversKind("torso","ridge"), true], + ["coverageFor(nonsense) is all", RULES.coverageFor("wat").id, "all"], + // Helmet 5 + cuirass 6 + natural 1: the head gets 6, the chest 7, a leg only 1. + ["locationArmourFor(head)", RULES.locationArmourFor(1, + [{points:5,coverage:"head"},{points:6,coverage:"torso"}], "head"), 6], + ["locationArmourFor(chest)", RULES.locationArmourFor(1, + [{points:5,coverage:"head"},{points:6,coverage:"torso"}], "vital"), 7], + ["locationArmourFor(leg)", RULES.locationArmourFor(1, + [{points:5,coverage:"head"},{points:6,coverage:"torso"}], "leg"), 1], + ["locationArmourFor(none)", RULES.locationArmourFor(2, [], "arm"), 2], // A lamp lights the people NEXT to you, not only the one holding it. ["lampReachFor(default)", RULES.lampReachFor(), 10], ["lampReachFor(30) searchlight", RULES.lampReachFor(30), 30], diff --git a/tools/content.mjs b/tools/content.mjs index 4d793f8..2f10158 100644 --- a/tools/content.mjs +++ b/tools/content.mjs @@ -181,35 +181,35 @@ export const WEAPONS = [ /* ---------- armour (v0.5 §4.8) ---------- */ export const ARMOURS = [ - { key: "jacket", name: "Reinforced jacket", points: 1, mass: 2, trad: "tradition_agency" }, - { key: "stab_vest", name: "Stab vest", points: 2, mass: 3, trad: "tradition_agency" }, - { key: "soft_armour", name: "Concealed soft armour", points: 3, mass: 3.5, trad: "tradition_agency" }, + { key: "jacket", name: "Reinforced jacket", points: 1, covers: "torsoArms", mass: 2, trad: "tradition_agency" }, + { key: "stab_vest", name: "Stab vest", points: 2, covers: "torso", mass: 3, trad: "tradition_agency" }, + { key: "soft_armour", name: "Concealed soft armour", points: 3, covers: "torso", mass: 3.5, trad: "tradition_agency" }, { key: "hide", name: "Cured hide", points: 4, mass: 7 }, - { key: "mail", name: "Mail", points: 5, mass: 9 }, + { key: "mail", name: "Mail", points: 5, covers: "torsoLimbs", mass: 9 }, { key: "plate", name: "Plate", points: 8, mass: 18 }, - { key: "impact_vest", name: "Impact vest", points: 6, mass: 3, trad: "tradition_agency" }, + { key: "impact_vest", name: "Impact vest", points: 6, covers: "torso", mass: 3, trad: "tradition_agency" }, { key: "breach_suit", name: "Breaching suit", points: 7, mass: 11, trad: "tradition_agency" }, { key: "envsuit", name: "Environment suit", points: 4, mass: 8, trad: "tradition_agency" }, { key: "salvage_plate", name: "Salvaged crossing plate", points: 10, mass: 11, trad: "tradition_transposed", coherence: 1 }, - { key: "oilcloth_coat", name: "Oilcloth coat", points: 1, mass: 3.0, era: "antique", trad: "tradition_local", desc: "Keeps the weather out and very little else." }, - { key: "brigandine", name: "Brigandine", points: 4, mass: 9.0, era: "antique", trad: "tradition_local", desc: "Plates riveted between cloth. Heavy, quiet, and older than the agency." }, + { key: "oilcloth_coat", name: "Oilcloth coat", points: 1, covers: "torsoLimbs", mass: 3.0, era: "antique", trad: "tradition_local", desc: "Keeps the weather out and very little else." }, + { key: "brigandine", name: "Brigandine", points: 4, covers: "torso", mass: 9.0, era: "antique", trad: "tradition_local", desc: "Plates riveted between cloth. Heavy, quiet, and older than the agency." }, { key: "hardsuit", name: "Sealed hardsuit", points: 9, mass: 12.0, era: "future", trad: "tradition_transposed", desc: "Sealed, powered and not from here. Also a breathing set — see Gear." }, /* --- the historical range. Weight is the point: everything here protects well and costs you the ability to run in it. --- */ - { key: "gambeson", name: "Gambeson", points: 2, mass: 4.5, era: "antique", trad: "tradition_local", desc: "Medieval. Quilted linen, thirty layers. Worn alone by the poor and under everything by everyone else." }, - { key: "maille_shirt", name: "Maille shirt", points: 4, mass: 7.5, era: "antique", trad: "tradition_local", desc: "Medieval. Stops a cut completely and a spike not at all. Wear it over the gambeson or regret it." }, - { key: "coat_of_plates", name: "Coat of plates", points: 6, mass: 11, era: "antique", trad: "tradition_local", desc: "Medieval. Iron plates riveted inside a fabric coat. The compromise that held for a century." }, - { key: "cuirass", name: "Cuirass", points: 6, mass: 9, era: "antique", trad: "tradition_local", desc: "Early modern. Breast and back. Proof against a pistol at any sensible distance, and stated so by the armourer." }, + { key: "gambeson", name: "Gambeson", points: 2, covers: "torsoArms", mass: 4.5, era: "antique", trad: "tradition_local", desc: "Medieval. Quilted linen, thirty layers. Worn alone by the poor and under everything by everyone else." }, + { key: "maille_shirt", name: "Maille shirt", points: 4, covers: "torsoArms", mass: 7.5, era: "antique", trad: "tradition_local", desc: "Medieval. Stops a cut completely and a spike not at all. Wear it over the gambeson or regret it." }, + { key: "coat_of_plates", name: "Coat of plates", points: 6, covers: "torso", mass: 11, era: "antique", trad: "tradition_local", desc: "Medieval. Iron plates riveted inside a fabric coat. The compromise that held for a century." }, + { key: "cuirass", name: "Cuirass", points: 6, covers: "torso", mass: 9, era: "antique", trad: "tradition_local", desc: "Early modern. Breast and back. Proof against a pistol at any sensible distance, and stated so by the armourer." }, { key: "harness", name: "Full harness", points: 9, mass: 25, era: "antique", trad: "tradition_local", desc: "Medieval. Head to foot, articulated, and far more wearable than people think — until the third hour." }, - { key: "buff_coat", name: "Buff coat", points: 3, mass: 5, era: "antique", trad: "tradition_local", desc: "Civil War. Thick ox hide to the knee. Turns a sword, ignores a ball, and never dries out." }, - { key: "sallet", name: "Sallet and bevor", points: 5, mass: 3.2, era: "antique", trad: "tradition_local", desc: "Medieval. Covers the head and the throat and takes most of your hearing with it." }, - { key: "lobster_pot", name: "Lobster-tail helmet", points: 4, mass: 2.6, era: "antique", trad: "tradition_local", desc: "Civil War. Three bars across the face. You can see out; that is all that can be said for it." }, - { key: "jack_of_plate", name: "Jack of plate", points: 4, mass: 6, era: "antique", trad: "tradition_local", desc: "Tudor. Small iron plates stitched between canvas. Looks like a coat until somebody hits it." }, - { key: "cuirassier", name: "Cuirassier armour", points: 8, mass: 18, era: "antique", trad: "tradition_local", desc: "Early modern. Three-quarter plate for a man on a horse. On foot it is a punishment." }, - { key: "brodie", name: "Brodie helmet", points: 3, mass: 1.3, era: "antique", trad: "tradition_local", desc: "Great War. A steel plate on a strap. Designed against shrapnel from above and honest about it." }, - { key: "flak_jacket", name: "Flak jacket", points: 4, mass: 8.5, era: "antique", trad: "tradition_local", desc: "Second War. Manganese plates in a waistcoat. Heavy, hot, and it has saved a great many people." } + { key: "buff_coat", name: "Buff coat", points: 3, covers: "torsoLimbs", mass: 5, era: "antique", trad: "tradition_local", desc: "Civil War. Thick ox hide to the knee. Turns a sword, ignores a ball, and never dries out." }, + { key: "sallet", name: "Sallet and bevor", points: 5, covers: "head", mass: 3.2, era: "antique", trad: "tradition_local", desc: "Medieval. Covers the head and the throat and takes most of your hearing with it." }, + { key: "lobster_pot", name: "Lobster-tail helmet", points: 4, covers: "head", mass: 2.6, era: "antique", trad: "tradition_local", desc: "Civil War. Three bars across the face. You can see out; that is all that can be said for it." }, + { key: "jack_of_plate", name: "Jack of plate", points: 4, covers: "torso", mass: 6, era: "antique", trad: "tradition_local", desc: "Tudor. Small iron plates stitched between canvas. Looks like a coat until somebody hits it." }, + { key: "cuirassier", name: "Cuirassier armour", points: 8, covers: "torsoArms", mass: 18, era: "antique", trad: "tradition_local", desc: "Early modern. Three-quarter plate for a man on a horse. On foot it is a punishment." }, + { key: "brodie", name: "Brodie helmet", points: 3, covers: "head", mass: 1.3, era: "antique", trad: "tradition_local", desc: "Great War. A steel plate on a strap. Designed against shrapnel from above and honest about it." }, + { key: "flak_jacket", name: "Flak jacket", points: 4, covers: "torso", mass: 8.5, era: "antique", trad: "tradition_local", desc: "Second War. Manganese plates in a waistcoat. Heavy, hot, and it has saved a great many people." } ]; /* ---------- gear ---------- */