feat(rules): add alignment field to Combatant with axis gating flags
Adds the PF1e two-axis alignment code (LG/NG/CG/LN/N/CN/LE/NE/CE, default N) to the Combatant model with a strict validator, derived is_lawful/is_chaotic/is_good/is_evil properties, exposure in the observation snapshot, and alignment values for all monsters and PCs sourced from the bestiary KB and the Foundry sheets.
This commit is contained in:
@@ -281,6 +281,15 @@ class DamageReduction(_FrozenModel):
|
||||
bypass: frozenset[str] = frozenset()
|
||||
|
||||
|
||||
_ALIGNMENT_CODES: frozenset[str] = frozenset(
|
||||
{"LG", "NG", "CG", "LN", "N", "CN", "LE", "NE", "CE"}
|
||||
)
|
||||
_LAWFUL_CODES: frozenset[str] = frozenset({"LG", "LN", "LE"})
|
||||
_CHAOTIC_CODES: frozenset[str] = frozenset({"CG", "CN", "CE"})
|
||||
_GOOD_CODES: frozenset[str] = frozenset({"LG", "NG", "CG"})
|
||||
_EVIL_CODES: frozenset[str] = frozenset({"LE", "NE", "CE"})
|
||||
|
||||
|
||||
class Combatant(_FrozenModel):
|
||||
"""A fully parsed combatant, ready for the engine."""
|
||||
|
||||
@@ -320,3 +329,37 @@ class Combatant(_FrozenModel):
|
||||
# begin." Unaware combatants do not act in the surprise round. Default
|
||||
# True keeps every existing encounter on a full first round.
|
||||
aware: bool = True
|
||||
# PF1e two-axis alignment (SRD "Alignment"): law-good axis codes, one of
|
||||
# LG/NG/CG/LN/N/CN/LE/NE/CE. Default "N" (true neutral).
|
||||
alignment: str = "N"
|
||||
|
||||
@field_validator("alignment")
|
||||
@classmethod
|
||||
def _validate_alignment(cls, value: str) -> str:
|
||||
if value not in _ALIGNMENT_CODES:
|
||||
msg = (
|
||||
f"alignment must be one of {', '.join(sorted(_ALIGNMENT_CODES))}, "
|
||||
f"got {value!r}"
|
||||
)
|
||||
raise ValueError(msg)
|
||||
return value
|
||||
|
||||
@property
|
||||
def is_lawful(self) -> bool:
|
||||
"""Law axis: LG/LN/LE."""
|
||||
return self.alignment in _LAWFUL_CODES
|
||||
|
||||
@property
|
||||
def is_chaotic(self) -> bool:
|
||||
"""Law axis: CG/CN/CE."""
|
||||
return self.alignment in _CHAOTIC_CODES
|
||||
|
||||
@property
|
||||
def is_good(self) -> bool:
|
||||
"""Good axis: LG/NG/CG."""
|
||||
return self.alignment in _GOOD_CODES
|
||||
|
||||
@property
|
||||
def is_evil(self) -> bool:
|
||||
"""Evil axis: LE/NE/CE."""
|
||||
return self.alignment in _EVIL_CODES
|
||||
|
||||
Reference in New Issue
Block a user