Skip to main content

Dantalion

The Formless Demon

Unit #106

HPPWRCPSpeedRangeTier
621SlowLocalA

Abilities

Passive

Damage cannot be removed from Dantalion. Dantalion may not be fused onto Demons. Any number of Demons can be Fused onto Dantalion. When Dantalion comes into play, fuse any number of Local Allied Demons. onto Dantalion. When Fused with (as either the top or bottom cards), do not Ready Dantalion.
Engine Implementation
def _dantalion_deploy_noop(state: GameState, demon: DemonInstance) -> dict:
"""#106 Dantalion [0] — Damage cannot be removed from Dantalion.
Dantalion may not be fused onto Demons. Any number of Demons can be Fused onto Dantalion.
When Dantalion comes into play, fuse any number of Local Allied Demons onto Dantalion.
When Fused with, do not Ready Dantalion.
Marker passive — enforcement via remove_damage checks and fusion system.
"""
return {}

register_passive("106", 0, _dantalion_deploy_noop)

Passive

When Local Enemy Demon(s) die, you may Fuse any of their demon cards onto Dantalion (if they can normally fuse with Dantalion).
Engine Implementation
def _dantalion_fuse_enemy_trigger(
state: GameState, event: GameEvent, demon: DemonInstance, depth: int
) -> GameState | None:
"""#106 Dantalion — Passive trigger: When Local Enemy Demon dies, fuse its card.

Fires on FATALLY_WOUNDED. Activates if:
- event.target is a local enemy demon in the same lane as Dantalion
- event.target is NOT a familiar (cannot fuse familiars)
- event.target is NOT Dantalion itself (no self-fusion)
- Dantalion is NOT fatally_wounded

Effect: The dying demon's unit_id is fused onto Dantalion as a new bottom card.
Dantalion allows unlimited fusions (DANTALION_ID exception in fusion.py).
Dantalion DOES NOT ready on fusion (its passive: "do not Ready Dantalion").

CRITICAL: This is a conditional fusion ("you may") — implemented as auto-accept
(always fuse if eligible). A full implementation would prompt the player.
"""
from engine.data_loader import UNITS

# Only fire if the dying demon is a local enemy of Dantalion
if event.target is None:
return None

# Must be an enemy (different owner from Dantalion)
if event.target.owner == demon.owner:
return None # Same-side death — Dantalion does not fuse allies

# Must be in the same lane (Local)
if event.target.lane != demon.lane:
return None # Different lane — not local

# Cannot fuse familiars
if event.target.is_familiar:
return None # Familiars cannot be fused

# Cannot fuse Dantalion onto itself
if event.target.unit_id == "106":
return None # Another Dantalion dying nearby — skip

# Re-fetch Dantalion from current state to check fatally_wounded
dantalion_current = next(
(d for d in state.demons if d.instance_id == demon.instance_id), None
)
if dantalion_current is None or dantalion_current.fatally_wounded:
return None # Dantalion is dead or dying — cannot resolve

# Check if the dying unit exists in UNITS (must be a valid fusible card)
dying_unit_id = event.target.unit_id
if dying_unit_id not in UNITS:
return None # Unknown card — skip

# Apply forced fusion: dying unit becomes Dantalion's new bottom card
# Dantalion allows unlimited fusions — bypass the normal is_fused check
dantalion_unit = UNITS["106"]
new_state = copy.deepcopy(state)

dantalion_in_state = next(
(d for d in new_state.demons if d.instance_id == demon.instance_id), None
)
if dantalion_in_state is None:
return None

# Append to comma-separated fused_bottom (supports unlimited multi-fusion)
if dantalion_in_state.fused_bottom:
dantalion_in_state.fused_bottom += "," + dying_unit_id
else:
dantalion_in_state.fused_bottom = dying_unit_id
dantalion_in_state.is_fused = True

# Recalculate HP from base + ALL fused cards' fhp
from engine.operations import _get_fused_stat
dantalion_in_state.current_hp = dantalion_unit.hp + _get_fused_stat(dantalion_in_state, "fhp")
# CRITICAL: Dantalion does NOT ready on fusion (per its passive ability [0])
# (its state is left unchanged — exhausted remains exhausted, etc.)

return new_state

register_trigger("106", 1, _dantalion_fuse_enemy_trigger)
Dantalion