fix(rules): set the slumber hex duration to the witch level

PF1e (APG Slumber): the target "remains asleep for a number of rounds equal to the witch's level" (Will negates). _hex_slumber hardcoded 1 round; it now uses the caster's level. The RAW clause that the hex ends when the target takes damage is not modeled (no wake-on-damage hook in the engine) — documented in README. Two behavioral tests pin the failed-save duration (= level) and the saved case.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-09-12 12:52:52 +02:00
parent f9c369380d
commit 68699ad6c7
3 changed files with 49 additions and 3 deletions
+38
View File
@@ -294,6 +294,44 @@ def test_evil_eye_saved_deals_minus_two_attack_one_round() -> None:
assert hex_buffs[0].modifiers == (StatModifier(target="attack", value=-2),)
def test_slumber_failed_save_puts_target_asleep_for_witch_level() -> None:
"""APG Slumber: the target "remains asleep for a number of rounds equal to
the witch's level". Given: a level-5 witch and a target failing the Will
save (d20 2 +4 < DC 14)
When: the hex is cast
Then: the asleep condition carries rounds_left = 5."""
nairda = _combatant("nairda", resources={"hexes": 5})
goblin = _combatant("goblin", hp_max=6)
engine, me, enemy = _engine(nairda, [goblin], rng_queue=[2])
engine._execute(
me, Action(kind="hex", target_id=enemy[0].combatant.id, hex_name="slumber")
)
asleep = [
ac for ac in enemy[0].active_conditions if ac.condition.name == "asleep"
]
assert len(asleep) == 1
assert asleep[0].rounds_left == 5
def test_slumber_saved_leaves_target_awake() -> None:
"""APG Slumber: Will negates. Given: a target saving (natural 20)
When: the hex is cast
Then: no asleep condition is applied."""
nairda = _combatant("nairda", resources={"hexes": 5})
goblin = _combatant("goblin", hp_max=6)
engine, me, enemy = _engine(nairda, [goblin], rng_queue=[20])
engine._execute(
me, Action(kind="hex", target_id=enemy[0].combatant.id, hex_name="slumber")
)
assert not any(
ac.condition.name == "asleep" for ac in enemy[0].active_conditions
)
# --- tammara: deeds ---