Anatomy of a defence: AC, saves, DR and the martial panel
From logic/ui-character-sheet.json (Kingmaker.UI.MVVM._VM.ServiceWindows.CharacterInfo) cross-checked against damage-model.json, difficulty-presets.json and unit-resistances.jsonl — build 20212986, patch 2.7.0x.
Anatomy of a hit follows the arrow on its way in. This one is the shield: what the character sheet's defence numbers are actually made of when Owlcat's rules compute them.
Everything on the sheet is a ModifiableValue
AC, the three saves, BAB, CMB, CMD — each is a Stats.* ModifiableValue:
a base plus a stack of named modifiers whose per-descriptor breakdown the
tooltip renders live (StatModifiersBreakdown). Nothing is precomputed:
the sheet value you see is recomputed from the same modifier stacks the
rules use, which is why buffs and gear never disagree with the maths.
Two sheet details worth knowing:
- HP already contains the difficulty scaling.
HitPoints.ModifiedValuefolds in the active preset's enemy stat-adjustmentHPMultiplier— the ×0.4–×1.0 multiplier table from difficulty settings. - Prereq checks read
BaseValue, not the modified value — a temporary buff cannot unlock a feat (prerequisite system).
RuleCalculateAC: the situational matrix
Situational AC lives in RuleCalculateAC. The states the rules engine
encodes:
| state | melee | ranged | |---|---|---| | prone | −4 | +4 | | helpless | −4 | −4 | | blindness | −2 | −2 |
And one weapon property with special authority: brilliant energy strips armor and shield bonuses from the target's AC entirely — the touch-attack cousin of ignoring enhancement.
The three visible AC flavours (normal/touch/flat-footed) are projections of the same modifier stack with different descriptors included.
Saves are three values, not a subsystem
Fortitude, Reflex and Will are plain ModifiableValues
(SaveFortitude/SaveReflex/SaveWill) — same stacking grammar as AC,
which is why buff-layer effects that add
SavingThrowBonus descriptors compose with gear without special cases.
BAB, iteratives and the grapple twins
- BAB sums class progression tables — every class's table contributes (multiclass addition), prestige included.
- Iterative attacks are derived, not stored: attack count comes from
RuleCalculateAttacksCountat one extra iterative per full 5 BAB. - CMB/CMD come from
RuleCalculateCMB/RuleCalculateCMDover the same stats — they are computations on the sheet, not separate progressions.
Per-weapon attack bonus is assembled per swing:
RuleCalculateAttackBonusWithoutTarget = BAB − iterative penalty +
attack stat + enhancement + aggregated modifiers. Crit chance/multiplier
come from RuleCalculateWeaponStats — the other half of
anatomy of a hit.
DR and energy resistance
Damage reduction is a unit part, not a stat: UnitPartDamageReduction
collects DR entries from feats, buffs and items, and the damage pipeline
applies them post-roll (the resistance/hardness step of the
damage model). Energy resistances follow the
same pattern via their own stats — the numbers the
bestiary census counts across monsters.
One UI quirk with rules weight: kinetic blade wielders get their damage
block swapped at the UI layer (WeaponKineticBlade →
AbilityKineticist.CollectUIDamageInfo) — the sheet shows blast math,
not the weapon's nominal dice.
What this explains
- Why a buff's AC bonus can be stripped by a single weapon property (brilliant energy removes whole descriptor groups).
- Why enemies hit absurdly hard on Unfair but don't have more HP than the multiplier says: the preset table only carries what it carries — see enemy brains for how they decide to swing.
- Why feat prerequisites ignore your buffed stats while combat does not: two different reads of the same value object.