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:
2026-09-17 23:26:45 +02:00
parent a144423522
commit 0c3f5fd907
7 changed files with 92 additions and 11 deletions
+34
View File
@@ -551,6 +551,40 @@ class TestHoldPerson:
assert any("negated" in line for line in engine._transcript)
class TestConditionDurationScaling:
"""Given: a ConditionEffect with duration_rounds_per_level (SRD hold person
"1 round/level", doom "1 min./level", vanish "1 round/level (maximum 5)")
When: the spell is cast
Then: the condition lasts caster_level * per_level rounds, capped at max."""
def test_hold_person_scales_with_caster_level(self) -> None:
caster = _make_caster(level=5)
target = _make_target()
engine, c, t = _make_engine(caster, target, [2])
engine._cast_spell(c, t, "Hold Person")
ac = next(ac for ac in t.active_conditions if ac.condition.name == "paralyzed")
assert ac.rounds_left == 5 # 1 round/level
def test_vanish_caps_at_maximum(self) -> None:
caster = _make_caster(level=8)
target = _make_target()
# Vanish is range touch: the target must be adjacent (5 ft).
engine, c, t = _make_engine(
caster, target, [2], target_pos=(1, 0), target_side="players"
)
engine._cast_spell(c, t, "Vanish")
ac = next(ac for ac in t.active_conditions if ac.condition.name == "invisible")
assert ac.rounds_left == 5 # 1 round/level, maximum 5
def test_doom_scales_to_minutes(self) -> None:
caster = _make_caster(level=5)
target = _make_target()
engine, c, t = _make_engine(caster, target, [2])
engine._cast_spell(c, t, "Doom")
ac = next(ac for ac in t.active_conditions if ac.condition.name == "shaken")
assert ac.rounds_left == 50 # 1 min/level = 10 rounds/level
class TestFear:
"""Given: a caster casting Fear (SRD spells/fear.md: panicked unless the
Will save succeeds; a successful save makes the creature shaken 1 round)