fix(rules): condition durations scale with caster level (hold person, doom, touch of fatigue, vanish)
ConditionEffect gains duration_rounds_per_level and max_duration_rounds (mirroring PenaltyEffect), applied as caster_level * per_level rounds capped at max: hold person 1 rd/lvl, doom 1 min/lvl, touch of fatigue 1 rd/lvl, vanish 1 rd/lvl (max 5). Extend Spell doubles both the per-level rate and the cap. Tests cover scaling and the vanish cap.
This commit is contained in:
@@ -6518,7 +6518,10 @@ class CombatEngine:
|
||||
spell_name=spell_name,
|
||||
)
|
||||
if isinstance(effect, ConditionEffect):
|
||||
return self._apply_condition_effect(effect, target, saved=saved, spell_name=spell_name)
|
||||
return self._apply_condition_effect(
|
||||
effect, target, saved=saved, spell_name=spell_name,
|
||||
caster_level=caster.combatant.level,
|
||||
)
|
||||
if isinstance(effect, HealEffect):
|
||||
return self._apply_heal_effect(
|
||||
effect, target, caster_level=caster.combatant.level,
|
||||
@@ -6669,20 +6672,26 @@ class CombatEngine:
|
||||
*,
|
||||
saved: bool,
|
||||
spell_name: str,
|
||||
caster_level: int = 0,
|
||||
) -> str:
|
||||
duration = effect.duration_rounds
|
||||
if effect.duration_rounds_per_level > 0:
|
||||
duration = max(1, caster_level * effect.duration_rounds_per_level)
|
||||
if effect.max_duration_rounds > 0:
|
||||
duration = min(duration, effect.max_duration_rounds)
|
||||
if saved and effect.save_negates:
|
||||
# PF1e partial save (SRD spells/fear.md): a successful save does
|
||||
# not always spare the target — it may impose a weaker condition
|
||||
# (Fear: shaken for 1 round instead of panicked).
|
||||
if effect.save_partial is not None:
|
||||
name, duration = effect.save_partial
|
||||
applied = self._impose_condition(target, name, duration, spell_name)
|
||||
name, partial_duration = effect.save_partial
|
||||
applied = self._impose_condition(target, name, partial_duration, spell_name)
|
||||
if not applied:
|
||||
return ""
|
||||
return f"{name} ({duration}r) (partial save)"
|
||||
return f"{name} ({partial_duration}r) (partial save)"
|
||||
return f"{effect.condition_name} negated"
|
||||
return self._impose_condition(
|
||||
target, effect.condition_name, effect.duration_rounds, spell_name
|
||||
target, effect.condition_name, duration, spell_name
|
||||
)
|
||||
|
||||
def _impose_condition(
|
||||
@@ -6998,6 +7007,16 @@ class CombatEngine:
|
||||
return effect
|
||||
if isinstance(effect, ConditionEffect):
|
||||
duration = effect.duration_rounds * 2 if has_extend else effect.duration_rounds
|
||||
per_level = (
|
||||
effect.duration_rounds_per_level * 2
|
||||
if has_extend
|
||||
else effect.duration_rounds_per_level
|
||||
)
|
||||
max_rounds = (
|
||||
effect.max_duration_rounds * 2
|
||||
if has_extend
|
||||
else effect.max_duration_rounds
|
||||
)
|
||||
partial = effect.save_partial
|
||||
if partial is not None and has_extend:
|
||||
partial = (partial[0], partial[1] * 2)
|
||||
@@ -7006,6 +7025,8 @@ class CombatEngine:
|
||||
duration_rounds=duration,
|
||||
save_negates=effect.save_negates,
|
||||
save_partial=partial,
|
||||
duration_rounds_per_level=per_level,
|
||||
max_duration_rounds=max_rounds,
|
||||
)
|
||||
if isinstance(effect, BuffEffect):
|
||||
duration = effect.duration_rounds * 2 if has_extend else effect.duration_rounds
|
||||
|
||||
Reference in New Issue
Block a user