fix(rules): total defense denies attacks of opportunity (SRD Total Defense: allowance drops to 0 while the bonus is active)

This commit is contained in:
2026-09-17 23:00:10 +02:00
parent 6d96779ded
commit a5bd3c5a85
2 changed files with 46 additions and 1 deletions
+14 -1
View File
@@ -744,9 +744,12 @@ class CombatantState:
# granted by total defense (+4) and fighting defensively (+2), and the
# fighting-defensively flag (-4 on attack and crit confirm). Both reset
# at the start of the combatant's NEXT turn, so they last through the
# opponents' turns in between.
# opponents' turns in between. The total_defense flag additionally marks
# that the combatant is using total defense — PF1e (SRD "Total Defense"):
# "You can't make attacks of opportunity while using total defense."
defensive_ac_bonus: int = 0
fight_defensively: bool = False
total_defense: bool = False
# Aid another & run (not in the frozen data model): aid bonuses granted to
# this combatant by an ally's aid another — aid_attack_bonus is consumed by
# its next attack roll, aid_ac_bonus applies against the next attack that
@@ -1776,6 +1779,7 @@ class CombatEngine:
state.power_attack = False
state.defensive_ac_bonus = 0
state.fight_defensively = False
state.total_defense = False
state.aid_attack_bonus = 0
state.aid_ac_bonus = 0
state.running = False
@@ -2693,7 +2697,12 @@ class CombatEngine:
Base is 1. Combat Reflexes adds the DEX modifier on top (clamped to >= 1
so a non-positive DEX mod never reduces the normal single AoO).
PF1e (SRD "Total Defense"): "You can't make attacks of opportunity
while using total defense" — the allowance drops to 0 while the
total-defense bonus is active (until the start of the next turn).
"""
if state.total_defense:
return 0
if not self._has_feat(state, "Combat Reflexes"):
return 1
return max(1, 1 + ((state.combatant.abilities.dex_score - 10) // 2))
@@ -4089,7 +4098,11 @@ class CombatEngine:
def _execute_total_defense(self, state: CombatantState) -> ActionResult:
"""Execute the total defense action (PF1e): standard action granting a
+4 dodge bonus to AC until the start of the combatant's next turn.
PF1e (SRD "Total Defense"): "You can't make attacks of opportunity
while using total defense" — the flag drops the AoO allowance to 0
(see ``_aoo_allowance``).
"""
state.total_defense = True
state.defensive_ac_bonus += _TOTAL_DEFENSE_AC_BONUS
self._log(
f"round {self._current_round} {state.combatant.id}: "