feat(combat): add saving throws (fort/ref/will, natural 1/20, effect modifiers)

This commit is contained in:
2026-08-17 22:49:50 +02:00
parent 88f11de40f
commit 2cd8a33a4d
3 changed files with 221 additions and 9 deletions
+26
View File
@@ -189,6 +189,16 @@ class AttackResult:
base_bonus: int = 0
@dataclass(frozen=True)
class SaveResult:
"""Outcome of one saving throw roll."""
success: bool
roll: int
total: int
dc: int
@dataclass(frozen=True)
class Action:
"""What a policy wants a combatant to do this turn.
@@ -401,6 +411,22 @@ class CombatEngine:
return damage
return max(0, damage - dr.amount)
def resolve_save(
self, state: CombatantState, save_type: Literal["fort", "ref", "will"], dc: int
) -> SaveResult:
"""Roll a saving throw (fort/ref/will) against ``dc``.
PF1e: natural 1 = automatic failure, natural 20 = automatic success.
Effect modifiers (StatModifier with matching target) are applied via
``resolve_modifiers`` — same bonus-type stacking rules as attacks.
"""
roll = self._rng.d20()
base = getattr(state.combatant.saves, save_type)
bonus = resolve_modifiers(e for e in state.effects if e.target == save_type)
total = roll + base + bonus
success = roll != _NATURAL_ONE and (roll == _NATURAL_TWENTY or total >= dc)
return SaveResult(success=success, roll=roll, total=total, dc=dc)
def _roll_initiative(self) -> list[CombatantState]:
rolls: dict[str, tuple[int, int]] = {}
for state in self._states: