Lucifer
Demon of Pride
Unit #088
| HP | PWR | CP | Speed | Range | Tier |
|---|---|---|---|---|---|
| 15 (+9) | 2 | 4 (+3) | Fast | Local | D |
Abilities
Lucifer's Empathy — 1 AP
g: Lucifer's Empathy: 1 AP - a, 1x: e: When an Enemy action targets a Local Allied Demon, if Lucifer is a Valid target, you may change 1 target to Lucifer.
Engine Implementation
def _lucifer_empathy(
state: GameState, demon: DemonInstance, targets, choices, rng
) -> GameState:
"""#088 Lucifer — Lucifer's Empathy
Quick, 1 AP, (exhaust), 1x: Status: When an Enemy action targets a Local Allied
Demon, if Lucifer is a Valid target, you may change 1 target to Lucifer.
Applies "lucifers_empathy" status marker to Lucifer (value=1).
The action resolution system checks this marker and allows target redirection.
Status expires end of current main phase.
"""
from engine.status_effects import apply_status
state = apply_status(state, demon, demon, "lucifers_empathy", 1)
return state
register_ability("088", 0, _lucifer_empathy)
Passive
c: After Lucifer takes X damage (after n), Lucifer must deal X Fixed Damage to Any Other Local Demon with at least 1 remaining HP.
Engine Implementation
def _lucifer_damage_reflection(
state: GameState, event: GameEvent, demon: DemonInstance, depth: int
):
"""#088 Lucifer idx=1 — Field Passive: Damage Reflection.
After Lucifer takes X damage (after DEF), deal X Fixed Damage to Any
Other Local Demon with at least 1 remaining HP.
Fires on DAMAGE_RECEIVED. Only activates if this Lucifer instance is the
event target (event.target.instance_id == demon.instance_id).
Re-fetches Lucifer from state after deepcopy and checks fatally_wounded
before resolving. Uses depth parameter — stops at MAX_TRIGGER_DEPTH (10).
Reflection target: first eligible local demon (not Lucifer, not fatally_wounded,
remaining HP > 0). "At least 1 remaining HP" means HP - damage >= 1.
Fixed Damage bypasses DEF.
"""
from engine.operations import deal_fixed_damage, get_effective_hp
# Only fire if THIS Lucifer is the damage target
if event.target is None or event.target.instance_id != demon.instance_id:
return None
x = event.value if event.value is not None else 0
if x <= 0:
return None
# Re-fetch Lucifer from current state (state may have been updated by prior handlers)
lucifer_current = next(
(d for d in state.demons if d.instance_id == demon.instance_id), None
)
if lucifer_current is None or lucifer_current.fatally_wounded:
return None # Lucifer dead or dying — cannot resolve
# Find eligible local targets: same lane, not Lucifer itself, not fatally_wounded,
# remaining HP >= 1 (meaning current_hp - damage >= 1 i.e. hp > damage)
eligible = [
d for d in state.demons
if d.lane == lucifer_current.lane
and d.instance_id != lucifer_current.instance_id
and not d.fatally_wounded
and (get_effective_hp(state, d) - d.damage) >= 1
]
if not eligible:
return None # No eligible targets — reflection cannot fire
# Pick first eligible target (non-deterministic choice deferred to real game UI)
target = eligible[0]
# Deal X Fixed Damage to the chosen target
# NOTE: This may recursively trigger DAMAGE_RECEIVED on the target (e.g., another
# Lucifer). The depth parameter is passed to fire_event to enforce MAX_TRIGGER_DEPTH.
new_state = deal_fixed_damage(state, target, x)
# Fire FIXED_DAMAGE_DEALT event so engine can track it (optional, non-recursive)
# We do NOT re-fire DAMAGE_RECEIVED here to avoid double-triggering this handler.
# The deal_fixed_damage function updates damage directly; triggers on that are handled
# by the caller's event loop at the next event boundary.
return new_state
register_trigger("088", 1, _lucifer_damage_reflection)