Abaddon
Sovereign of the Abyss
Unit #028
| HP | PWR | CP | Speed | Range | Tier |
|---|---|---|---|---|---|
| 9 (+3) | 3 (+1) | 3 (+2) | Normal | Any | C |
Abilities
Entreat — 1 AP
q: Entreat: 1 AP - b, 1x: Play 1 Nephilim Familiar into Target Lane. (Abaddon has 4 Nephilim Familiars.) e: Abaddon cannot perform actions.
Engine Implementation
def _abaddon_entreat(state: GameState, demon: DemonInstance, targets, choices, rng) -> GameState:
"""#028 Abaddon — Entreat
Action, 1 AP, (ready), 1x: Play 1 Nephilim Familiar into Target Lane.
After deploying, Status: Abaddon cannot perform actions.
Player chooses which Nephilim via choices["nephilim_id"] (e.g., "028_1").
Falls back to first available if not specified.
Target lane from choices["lane"] or first target's lane, else Abaddon's lane.
"""
from engine.operations import deploy_familiar
# Determine target lane
if choices and "lane" in choices:
target_lane = choices["lane"]
elif targets:
target_lane = targets[0].lane
else:
target_lane = demon.lane
# Player chooses which Nephilim to summon
player = state.players[demon.owner]
nephilim_id = None
if choices and "nephilim_id" in choices:
chosen = choices["nephilim_id"]
if chosen in player.familiar_deck and chosen in _NEPHILIM_IDS_ORDERED:
nephilim_id = chosen
# Fallback: first available Nephilim
if nephilim_id is None:
for nid in _NEPHILIM_IDS_ORDERED:
if nid in player.familiar_deck:
nephilim_id = nid
break
if nephilim_id is None:
# No Nephilim available — Status still applies (Abaddon spent the action)
# Apply cannot_act status anyway (the cost was paid by attempting the action)
new_state = apply_status(state, demon, demon, "cannot_act", 1)
return new_state
new_state = deploy_familiar(state, demon.owner, nephilim_id, target_lane)
# Apply "cannot_act" status on Abaddon
abaddon_in_new = next(
(d for d in new_state.demons if d.instance_id == demon.instance_id), None
)
if abaddon_in_new is not None:
new_state = apply_status(new_state, abaddon_in_new, abaddon_in_new, "cannot_act", 1)
return new_state
register_ability("028", 0, _abaddon_entreat)
Super Apotheosis — 2 AP
Super Apotheosis: 2 AP - b: Super Apotheosis may be performed only if Abaddon has at least 3 Local Nephilim. Fuse all Nephilim onto Abaddon.
Engine Implementation
def _abaddon_super_apotheosis(state: GameState, demon: DemonInstance, targets, choices, rng) -> GameState:
"""#028 Abaddon — Super Apotheosis
Action, 2 AP, (ready): Requires at least 3 Local Nephilim. Fuse all Nephilim onto Abaddon.
Finds all Nephilim in Abaddon's lane owned by the same player.
Validates >= 3 are present. Fuses each onto Abaddon by removing Nephilim
from field and adding their fusion stats to Abaddon's effective HP.
"""
from engine.data_loader import FAMILIARS
abaddon = next((d for d in state.demons if d.instance_id == demon.instance_id), None)
if abaddon is None or abaddon.fatally_wounded:
return state
# Find all Nephilim in Abaddon's lane owned by the same player
local_nephilim = [
d for d in state.demons
if d.unit_id in _NEPHILIM_IDS_ORDERED
and d.lane == abaddon.lane
and d.owner == abaddon.owner
and not d.fatally_wounded
]
if len(local_nephilim) < 3:
return state # Precondition not met — no effect
new_state = copy.deepcopy(state)
abaddon_in_new = next(d for d in new_state.demons if d.instance_id == demon.instance_id)
fused_ids = []
for nephilim in local_nephilim:
fam_data = FAMILIARS.get(nephilim.unit_id)
if fam_data is not None:
# Add ALL fusion stats from each Nephilim
abaddon_in_new.current_hp += (getattr(fam_data, 'fhp', 0) or 0)
# fPWR and fCP tracked via get_effective_pwr/get_effective_cp
# which check fused_bottom — we'll store all IDs
fused_ids.append(nephilim.unit_id)
# Remove Nephilim from field (fused into Abaddon)
new_state.demons = [
d for d in new_state.demons if d.instance_id != nephilim.instance_id
]
# Mark Abaddon as fused with ALL Nephilim
# Store comma-separated IDs in fused_bottom so get_passive_modifiers
# and get_effective_pwr/cp can check all fused cards' abilities/stats.
abaddon_in_new = next(d for d in new_state.demons if d.instance_id == demon.instance_id)
abaddon_in_new.is_fused = True
abaddon_in_new.fused_bottom = ",".join(fused_ids)
return new_state
register_ability("028", 1, _abaddon_super_apotheosis)
Passive
If Abaddon is Fused to Nephilim, Abaddon has -1 AP Cost.
Engine Implementation
def _abaddon_nephilim_ap_discount(state: GameState, demon: DemonInstance) -> dict:
"""#028 Abaddon idx=2 — If Fused to Nephilim, -1 AP Cost.
Checks if this demon (Abaddon, unit_id="028") has any Nephilim familiar
in its fused_bottom. Supports multi-fusion (comma-separated IDs from
Super Apotheosis, e.g., "028_1,028_2,028_3").
Nephilim familiar IDs: 028_1, 028_2, 028_3, 028_4.
"""
if not demon.is_fused or not demon.fused_bottom:
return {}
# Check if ANY fused bottom ID is a Nephilim
bottom_ids = [bid.strip() for bid in demon.fused_bottom.split(",") if bid.strip()]
for bid in bottom_ids:
if bid in _NEPHILIM_FAMILIAR_IDS:
return {"ap_cost": -1}
return {}
register_passive("028", 2, _abaddon_nephilim_ap_discount)