osrforge.statblocks
Shared structural parsing of printed stat-block lines — AC, Hit Dice, and class-level notations.
These parsers are the pipeline's one reading of a printed block's structure,
shared by two consumers below and above the stage boundary: assembly's
deterministic template mapping (map_stat_block
and its refusal-ladder predicate
usable_stat_block) and the monsters
stage's stat-block veto
(stat_block_veto). They live in their
own module because assemble.py imports monsters.py — the veto could never
import them from assembly without a cycle, and the veto must change the
cached resolution, so it cannot run in assembly.
Parsing is structural transcription of a printed notation, never a rules
judgment: every judgment (AC complement direction hazards, HD-to-MonsterHitDice
anchors, class-table derivations) stays with the consumer that owns it.
ParsedHd
dataclass
A printed Hit Dice line, structurally parsed: count, printed die (if any), modifier, asterisks.
parse_ac
parse_ac(block: RawStatBlock) -> tuple[int, int, bool] | None
Parse the printed AC into (descending, ascending, complement_derived), or None.
Dual notation carries both values as printed; a single value converts by
the 19-complement (the B/X identity OSE prints directly: AC 5 [14]) in
the direction the block's notation states, defaulting to descending — the
B/X reading — when the notation is unclassified.
parse_class_level
Parse a printed class-level notation (F 3, MU4, "3rd-level cleric") into (class_id, level).
A level below 1 refuses in both forms — a 0-level notation carries no combat math to derive, so it must fall to the refusal ladder, never into mapping (which is total only over parses this function accepts).