build_calculate_derived_stats
Calculate PF2e character derived stats: AC, saves, Perception, skill totals, HP, class DC, spell DC/attack. Handles proficiency stacking, worn armor, and potency runes to avoid math errors.
Instructions
Deterministic PF2e math: AC, saves, Perception, skill totals, HP, class DC, and spell DC/attack per casting tradition the character has trained. Never left to model arithmetic -- proficiency stacking (untrained = ability mod only, no level) is easy to get wrong.
AC uses the character's worn armor (Pathbuilder's `armor` list) if
present, else the unarmored baseline, and includes the armor's potency
rune if any. Does not yet include a raised shield's bonus -- see
pf2e_math.armor_ac docstring.
HP's `attributes.ancestryhp`/`attributes.classhp` and AC's
`proficiencies.unarmored` fall back to a lookup against this project's
own ingested `ancestry_boosts`/`class_progression` data (via the
character's `ancestry`/`class` fields) when the caller doesn't supply
them explicitly -- previously a caller-side omission here silently
produced a plausible-looking-but-wrong result (confirmed live: HP
understated by ~90 points, AC by 12, for a real level-10 character
built without these three fields) rather than an error, since Python's
dict.get default masked the difference between "explicitly 0" and
"never set." The explicit-value case is preserved -- these fallbacks
only apply when the key is genuinely absent, not when it's present and
zero (e.g. a real Wizard's `classhp` isn't 0, but nothing in this
system produces a *correct* 0 for these three fields either, so
treating "key absent" as the signal to fall back is safe in practice).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| character | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||