fix(data): lich fear aura, paralyzing touch, slot keys
This commit is contained in:
@@ -373,6 +373,7 @@ class CombatEngine:
|
||||
if self.has_condition_flag(state, "cant_act"):
|
||||
self._log(f"round {self._current_round} {state.combatant.id}: wait (cannot act)")
|
||||
return self._winner_side() is not None
|
||||
self._apply_fear_aura(state)
|
||||
state.moved_this_turn = False
|
||||
state.power_attack = False
|
||||
actions = self._policy(self, state)
|
||||
@@ -590,6 +591,62 @@ class CombatEngine:
|
||||
"""True if the combatant has a feature with the given name."""
|
||||
return any(f.name == feat_name for f in state.combatant.features)
|
||||
|
||||
def _is_paralyzing_touch(self, attacker: CombatantState, weapon: AttackSpec) -> bool:
|
||||
"""True if a hit with this weapon should apply the Lich's paralyzing touch.
|
||||
|
||||
Robust check: the attacker has the "Paralyzing Touch" feature and the
|
||||
weapon is a touch attack (or is literally named "Paralyzing Touch").
|
||||
"""
|
||||
if not self._has_feat(attacker, "Paralyzing Touch"):
|
||||
return False
|
||||
return weapon.kind == "touch" or weapon.name == "Paralyzing Touch"
|
||||
|
||||
_FEAR_AURA_DC = 22
|
||||
_FEAR_AURA_RANGE_FT = 30
|
||||
_FEAR_AURA_ROUNDS = 1
|
||||
|
||||
def _apply_fear_aura(self, state: CombatantState) -> None:
|
||||
"""Apply the Lich's Fear Aura: enemies within 30 ft save Will (DC 22) or become shaken.
|
||||
|
||||
Triggered at the start of the aura-bearer's turn (simplification of the
|
||||
PF1e "on range entry" trigger — the lich acts first each round, so this
|
||||
covers entry into range). Only enemies within range who are not already
|
||||
shaken are tested, so the effect does not re-roll on the same enemy each
|
||||
turn. Shaken lasts a fixed 1 round.
|
||||
"""
|
||||
if not self._has_feat(state, "Fear Aura"):
|
||||
return
|
||||
for enemy in self._states:
|
||||
if (
|
||||
not enemy.active
|
||||
or enemy.side == state.side
|
||||
or self._has_condition_named(enemy, "shaken")
|
||||
):
|
||||
continue
|
||||
dist_ft = self._grid.distance(state.pos, enemy.pos) * _SQUARE_FT
|
||||
if dist_ft > self._FEAR_AURA_RANGE_FT:
|
||||
continue
|
||||
save = self.resolve_save(enemy, "will", self._FEAR_AURA_DC)
|
||||
if save.success:
|
||||
self._log(
|
||||
f"round {self._current_round} {state.combatant.id}: fear aura on "
|
||||
f"{enemy.combatant.id} -> SAVED"
|
||||
)
|
||||
continue
|
||||
enemy.active_conditions.append(
|
||||
ActiveCondition(
|
||||
condition=CONDITIONS_BY_NAME["shaken"],
|
||||
rounds_left=self._FEAR_AURA_ROUNDS,
|
||||
source=f"monster ability: fear aura by {state.combatant.id}",
|
||||
)
|
||||
)
|
||||
self._log(
|
||||
f"round {self._current_round} {state.combatant.id}: fear aura on "
|
||||
f"{enemy.combatant.id} -> shaken ({self._FEAR_AURA_ROUNDS}r)"
|
||||
)
|
||||
|
||||
|
||||
|
||||
def _aoo_allowance(self, state: CombatantState) -> int:
|
||||
"""Number of AoOs allowed per round for a combatant.
|
||||
|
||||
@@ -2052,6 +2109,17 @@ class CombatEngine:
|
||||
)
|
||||
if result.hit:
|
||||
line += f" {result.damage} damage ({hp_before}->{target.hp})"
|
||||
if self._is_paralyzing_touch(attacker, weapon):
|
||||
duration = 1 + self._rng.roll_die(4)
|
||||
if not self._has_condition_named(target, "paralyzed"):
|
||||
target.active_conditions.append(
|
||||
ActiveCondition(
|
||||
condition=CONDITIONS_BY_NAME["paralyzed"],
|
||||
rounds_left=duration,
|
||||
source=f"monster ability: paralyzing touch by {attacker.combatant.id}",
|
||||
)
|
||||
)
|
||||
line += f" paralyzed ({duration}r)"
|
||||
self._log(line)
|
||||
if target.dead:
|
||||
self._log(
|
||||
|
||||
Reference in New Issue
Block a user