Armour covers what it covers, and Coherence moves to the vitals

Asking for the type of armour per 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 containing sallets,
lobster-tail helmets and three cuirasses, that could not be printed 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 wears it: all, torso, torsoArms, torsoLimbs, head. The
sets expand to location KINDS, so a cuirass covers a baseline torso and a vesh trunk
and ridge without either knowing the other exists. Unstated coverage is `all`, so
anything that does not declare behaves 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 the global worn total PLUS
the body's own armour at that location, which was right while armour was global and
becomes a double count the moment a location knows its own pieces. It reads the
location's total and nothing else, verified by firing fourteen hits of 10 damage
across every location and asserting damage applied == 10 - that location's armour.

A single ARMOUR number no longer exists, so the header shows the torso with "0-8 by
location" beside it when the rest of you is not that. This is a real difficulty
change: limbs are frequently bare and limbs are 12 of 20 on the melee table.

Coherence moves out of the derived strip into the vitals at hit-point size, with its
band under it and the box reddening as it falls.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
slaguru666
2026-08-11 10:33:04 +01:00
co-authored by Claude Opus 5
parent 3421ed4a2e
commit 6ed9ded362
118 changed files with 382 additions and 158 deletions
+27 -8
View File
@@ -38,10 +38,21 @@
<span class="rb-vital-label">{{localize "RINGBRP.Sheet.MajorWound"}}</span>
<span class="rb-big">{{sys.majorWound.value}}</span>
</div>
<div class="rb-vital-coh rb-coh-{{coherence.band.id}}"
data-tooltip="{{localize coherence.band.note}}">
<span class="rb-vital-label">{{localize "RINGBRP.Coh.Label"}}</span>
<span class="rb-coh-row">
<a data-action="coherence-adjust" data-delta="-1" class="rb-cohbtn">&minus;</a>
<span class="rb-big">{{sys.coherence.value}}</span>
<a data-action="coherence-adjust" data-delta="1" class="rb-cohbtn">+</a>
</span>
<span class="rb-cohband">{{localize coherence.band.label}}</span>
</div>
<div class="rb-armour{{#if armourUnworn.length}} rb-unworn{{/if}}"
{{#if armourUnworn.length}}data-tooltip="{{localize "RINGBRP.Sheet.ArmourUnworn"}}"{{/if}}>
<span class="rb-vital-label">{{localize "RINGBRP.Sheet.Armour"}}</span>
<span class="rb-big">{{sys.armourPoints}}</span>
{{#if sys.armourUneven}}<span class="rb-armour-range">{{sys.armourRange.min}}&ndash;{{sys.armourRange.max}} {{localize "RINGBRP.Sheet.ByLocation"}}</span>{{/if}}
{{#if armourUnworn.length}}<span class="rb-unworn-flag">{{localize "RINGBRP.Sheet.NotWorn"}}</span>{{/if}}
</div>
<div class="rb-minibody" data-tooltip="{{localize 'RINGBRP.Sheet.MiniBodyHint'}}">
@@ -86,12 +97,6 @@
<div class="rb-derived-group">
<span class="rb-dl">{{localize "RINGBRP.Sheet.MOV"}}</span><span class="rb-dv">{{sys.mov}}</span>
</div>
<div class="rb-derived-group rb-cohgroup rb-coh-{{coherence.band.id}}"
title="{{localize coherence.band.note}}">
<span class="rb-dl">{{localize "RINGBRP.Coh.Label"}}</span>
<span class="rb-dv"><a data-action="coherence-adjust" data-delta="-1" class="rb-cohbtn">&minus;</a>{{sys.coherence.value}}<a data-action="coherence-adjust" data-delta="1" class="rb-cohbtn">+</a></span>
<span class="rb-cohband">{{localize coherence.band.label}}</span>
</div>
<div class="rb-derived-group">
<span class="rb-dl">{{localize "RINGBRP.Sheet.Carry"}}</span>
<span class="rb-dv {{#if sys.encumbrance.steps}}rb-warn{{/if}}">{{sys.carriedKg}} / {{sys.freeCarryKg}} kg</span>
@@ -329,7 +334,14 @@
<td class="rb-col-num">{{l.melee}}</td>
<td class="rb-col-num">{{l.ranged}}</td>
<td class="rb-col-num">{{l.taken}}/{{l.max}}</td>
<td class="rb-col-num">{{l.armour}}</td>
<td class="rb-col-ap">
<span class="rb-ap-num">{{l.armour}}</span>
{{#if l.armourFrom.length}}
<span class="rb-ap-from">{{#each l.armourFrom as |a|}}<span class="rb-ap-piece" data-tooltip="{{a.name}} — {{a.points}}">{{a.name}}</span>{{/each}}</span>
{{else}}
<span class="rb-ap-bare">{{localize "RINGBRP.Sheet.Unarmoured"}}</span>
{{/if}}
</td>
</tr>
{{/each}}
</tbody>
@@ -527,7 +539,14 @@
<td class="rb-col-num">{{l.melee}}</td>
<td class="rb-col-num">{{l.ranged}}</td>
<td class="rb-col-num">{{l.taken}}/{{l.max}}</td>
<td class="rb-col-num">{{l.armour}}</td>
<td class="rb-col-ap">
<span class="rb-ap-num">{{l.armour}}</span>
{{#if l.armourFrom.length}}
<span class="rb-ap-from">{{#each l.armourFrom as |a|}}<span class="rb-ap-piece">{{a.name}} <b>{{a.points}}</b></span>{{/each}}</span>
{{else}}
<span class="rb-ap-bare">{{localize "RINGBRP.Sheet.Unarmoured"}}</span>
{{/if}}
</td>
</tr>
{{/each}}
</tbody>
+7
View File
@@ -54,6 +54,8 @@
<span class="rb-stat-value">{{sys.massKg}} kg</span></div>
<div class="rb-stat"><span class="rb-stat-label">{{localize "RINGBRP.Item.Equipped"}}</span>
<span class="rb-stat-value">{{#if sys.equipped}}{{localize "RINGBRP.Item.Worn"}}{{else}}&mdash;{{/if}}</span></div>
<div class="rb-stat"><span class="rb-stat-label">{{localize "RINGBRP.Item.Coverage"}}</span>
<span class="rb-stat-value rb-stat-small">{{localize coverageLabel}}</span></div>
<div class="rb-stat rb-stat-wide"><span class="rb-stat-label">{{localize "RINGBRP.Item.IgnoredBy"}}</span>
<span class="rb-stat-value rb-stat-small">{{#each sys.ignoredBy as |x|}}{{x}}{{#unless @last}}, {{/unless}}{{else}}&mdash;{{/each}}</span></div>
</section>
@@ -272,6 +274,11 @@
<label>{{localize "RINGBRP.Item.Points"}}<input type="number" name="system.points" value="{{sys.points}}"/></label>
<label>{{localize "RINGBRP.Item.Mass"}}<input type="number" step="0.1" name="system.massKg" value="{{sys.massKg}}"/></label>
<label class="rb-check">{{localize "RINGBRP.Item.Equipped"}}<input type="checkbox" name="system.equipped" {{checked sys.equipped}}/></label>
<label>{{localize "RINGBRP.Item.Coverage"}}
<select name="system.coverage">
{{#each RINGBRP.coverage as |c key|}}<option value="{{key}}" {{#if (rbEq key ../sys.coverage)}}selected{{/if}}>{{localize c.label}}</option>{{/each}}
</select>
</label>
</div>
<p class="rb-hint">{{localize "RINGBRP.Item.ArmourNote"}}</p>
{{/if}}