Skip to main content

✅ Chain blocked when moved demon was already exhausted

CategoryInteraction
StatusPassing
Testtests/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."