✅ Chain blocked when moved demon was already exhausted
| Category | Interaction |
| Status | Passing |
| Test | tests/test_abilities_complex.py::TestGamiginMalphasStolasCombo::test_chain_blocked_when_moved_demon_was_already_exhausted |
Tests interaction between Malphas, Stolas, Murmur.
Preconditions
-
Lane 0: P1's Malphas (#041) — READIED
-
Lane 0: P1's Stolas (#022) — READIED
-
Lane 0: P1's Murmur (#002, HP=9, 0 damage) — bystander
-
Lane 0: P2's Gamigin (#031, HP=6, 0 damage) — EXHAUSTED (already)
Action
- Simulate Possession moving Gamigin from lane 0 to lane 1.
POSTCONDITIONS (expected per rulebook):
-
Gamigin: still EXHAUSTED (no state change — already exhausted)
-
Murmur: 0 damage (Stolas did NOT fire — no exhaust event)
-
Malphas: 0 damage (Stolas did NOT fire)
-
Stolas: 0 damage (always excluded)
result = fire_event(state2, event)
gamigin_after = next(d for d in result.demons if d.unit_id == "031")
murmur_after = next(d for d in result.demons if d.unit_id == "002")
malphas_after = next(d for d in result.demons if d.unit_id == "041")
stolas_after = next(d for d in result.demons if d.unit_id == "022")
Expected Postconditions
- See assertions below.
Assertions
assert gamigin_after.state == DemonState.EXHAUSTED, (
"Gamigin started exhausted and should remain exhausted (no legal state change)."
)
assert murmur_after.damage == 0, (
f"Murmur should take 0 damage: Malphas's exhaust was a no-op on an "
f"already-exhausted target, so Stolas's field should not fire. "
f"Got {murmur_after.damage}."
)
assert malphas_after.damage == 0, (
f"Malphas should take 0 damage — Stolas's field did not fire. "
f"Got {malphas_after.damage}."
)
assert stolas_after.damage == 0, "Stolas always excluded from own trigger."