Skip to main content

Asmodeus

Demon of Lust

Unit #090

HPPWRCPSpeedRangeTier
9 (+3)3 (+1)3 (+2)FastLocalB

Abilities

Passive

Once per Main Phase, when Asmodues moves at least 1 Lane, you may move 1 Local Demon with Asmodeus.
Engine Implementation
def _asmodeus_drag_ally_trigger(
state: GameState, event: GameEvent, demon: DemonInstance, depth: int
):
"""#090 Asmodeus — Passive trigger: DEMON_MARCHED
Once per Main Phase, when Asmodeus moves at least 1 Lane, may move
1 Local Demon with Asmodeus.

Fires on DEMON_MARCHED when the marching demon is this Asmodeus instance.
"Local Demon" = a demon that was in Asmodeus's ORIGIN lane (event.lane).
Asmodeus is now at his new lane after the march.

"Once per Main Phase" — checked via abilities_used_this_turn.
If already used this turn, returns None.

For deterministic testing, moves the first eligible local demon found
(excluding Asmodeus itself) from the origin lane to Asmodeus's new lane.
A production engine would present a choice to the player.

Re-fetches Asmodeus from state to check fatally_wounded before acting.
"""
import copy as _copy

# Only fire when Asmodeus himself is the demon that marched
if event.source is None:
return None
if event.source.instance_id != demon.instance_id:
return None # A different demon marched — not Asmodeus

# Re-fetch Asmodeus from state
asmodeus_current = next(
(d for d in state.demons if d.instance_id == demon.instance_id), None
)
if asmodeus_current is None or asmodeus_current.fatally_wounded:
return None

# "Once per Main Phase" — check usage tracking
ability_key = "0" # ability index 0
use_count = asmodeus_current.abilities_used_this_turn.get(ability_key, 0)
if use_count >= 1:
return None # Already used once this main phase

# Origin lane = event.lane (where Asmodeus was before the march)
origin_lane = event.lane
if origin_lane is None:
return None

# Find a local demon in the origin lane (excluding Asmodeus himself)
eligible = [
d for d in state.demons
if d.lane == origin_lane
and d.instance_id != asmodeus_current.instance_id
]

if not eligible:
return None # No demon to drag

# Auto-select the first eligible demon (production: player choice)
drag_target = eligible[0]
if drag_target.fatally_wounded:
return None # Cannot move a fatally wounded demon

new_state = _copy.deepcopy(state)

# Move drag_target to Asmodeus's new lane
drag_in_new = next(
(d for d in new_state.demons if d.instance_id == drag_target.instance_id), None
)
if drag_in_new is None:
return None
drag_in_new.lane = asmodeus_current.lane

# Record usage: "once per main phase"
asmodeus_in_new = next(
(d for d in new_state.demons if d.instance_id == demon.instance_id), None
)
if asmodeus_in_new is not None:
asmodeus_in_new.abilities_used_this_turn[ability_key] = use_count + 1

return new_state

register_trigger("090", 0, _asmodeus_drag_ally_trigger)

Temptation — 2 AP

Temptation: 2 AP - a, 1x: Exhaust Target Local Demon. If the targeted Demon has no Local Allied Demons (other than themselves), gain 2 AP and Ready Asmodeus.
Engine Implementation
def _asmodeus_temptation(
state: GameState, demon: DemonInstance, targets, choices, rng
) -> GameState:
"""#090 Asmodeus — Temptation
Action, 2 AP, (exhaust), 1x: Exhaust Target Local Demon.
If the targeted Demon has no Local Allied Demons (other than themselves),
gain 2 AP and Ready Asmodeus.

"Local Allied Demons (other than themselves)" = target's own allied demons
in target's lane, excluding itself. If zero such demons exist, Asmodeus's
controller gains 2 AP and Asmodeus is readied.

CRITICAL: Asmodeus is exhausted by execute_ability (tap_required=True) BEFORE
this handler is called. The "Ready Asmodeus" effect re-readies Asmodeus here.
"""
from engine.operations import exhaust_demon, ready_demon
import copy as _copy

if not targets:
return state

target = targets[0]

# Exhaust the target demon
state = exhaust_demon(state, target)

# Re-fetch target after state change
target_refreshed = next(
(d for d in state.demons if d.instance_id == target.instance_id), None
)
if target_refreshed is None:
return state

# Check if target has NO Local Allied Demons (other than itself)
# "Allied" = same owner as target demon
local_allies_of_target = [
d for d in state.demons
if d.lane == target_refreshed.lane
and d.owner == target_refreshed.owner
and d.instance_id != target_refreshed.instance_id
]

if len(local_allies_of_target) == 0:
# Target is alone — trigger bonus: gain 2 AP and Ready Asmodeus
new_state = _copy.deepcopy(state)
new_state.players[demon.owner].ap += 2

# Ready Asmodeus (he was exhausted by execute_ability tap_required)
asmodeus_in_new = next(
(d for d in new_state.demons if d.instance_id == demon.instance_id), None
)
if asmodeus_in_new is not None:
asmodeus_in_new.state = DemonState.READIED

return new_state

return state

register_ability("090", 1, _asmodeus_temptation)
Asmodeus