Sharur
Unit #068
| HP | PWR | CP | Speed | Range | Tier |
|---|---|---|---|---|---|
| 15 (+9) | 4 (+2) | 4 (+3) | Slow | Distant | C |
Abilities
Passive
After Sharur resolves an action targeting Any Other Demon(s), move the targeted Demon(s) 1 Lane Away From Sharur.
Engine Implementation
def _sharur_post_action_push(
state: GameState, event: GameEvent, demon: DemonInstance, depth: int
):
"""#068 Sharur idx=0 — Field Passive: Post-Action Push.
After Sharur resolves an action targeting Any Other Demon(s), move the
targeted Demon(s) 1 Lane Away From Sharur.
Fires on ABILITY_USED. Checks event.source is this Sharur instance.
Determines push direction based on Sharur's lane vs each target's lane.
Clamps lane to [0, 2]. Skips fatally_wounded targets.
"""
from engine.constants import LANE_COUNT
# Only fire if this Sharur is the ability user
if event.source is None or event.source.instance_id != demon.instance_id:
return None
# Re-fetch Sharur from current state
sharur_current = next(
(d for d in state.demons if d.instance_id == demon.instance_id), None
)
if sharur_current is None or sharur_current.fatally_wounded:
return None
# The event.target holds the triggered target (single target); for multi-target
# abilities, the engine may fire ABILITY_USED once per target or with a list.
# We handle event.target as a single target here (standard engine behavior).
if event.target is None:
return None
if event.target.instance_id == demon.instance_id:
return None # Cannot push Sharur itself
target_current = next(
(d for d in state.demons if d.instance_id == event.target.instance_id), None
)
if target_current is None or target_current.fatally_wounded:
return None # Target gone or dying
# Determine push direction: away from Sharur
if target_current.lane > sharur_current.lane:
new_lane = min(target_current.lane + 1, LANE_COUNT - 1)
elif target_current.lane < sharur_current.lane:
new_lane = max(target_current.lane - 1, 0)
else:
# Same lane — no clear push direction; do not push
return None
if new_lane == target_current.lane:
return None # Already at boundary — no movement
import copy as _copy
new_state = _copy.deepcopy(state)
t = next(d for d in new_state.demons if d.instance_id == target_current.instance_id)
t.lane = new_lane
return new_state
register_trigger("068", 0, _sharur_post_action_push)
Heavy Impact — 1 AP
g: Heavy Impact: 1 AP - a, 1x: Deal 2 damage to Target Local Demon. e: Sharur's next action ignores a and b costs.
Engine Implementation
def _sharur_heavy_impact(
state: GameState, demon: DemonInstance, targets, choices, rng
) -> GameState:
"""#068 Sharur — Heavy Impact
Quick, 1 AP, (exhaust), 1x: Deal 2 damage to Target Local Demon.
Status: Sharur's next action ignores (exhaust) and (ready) costs.
Status expires end of current main phase.
Quick timing, (exhaust) — exhausts Sharur on use.
Deals 2 damage reduced by DEF (deal_damage, NOT fixed).
After damage, Sharur gets "ignore_exhaust" and "ignore_ready" status.
Targets: [target_local_demon]
"""
target = targets[0]
state = deal_damage(state, demon, target, 2)
sharur_in_new = next(
(d for d in state.demons if d.instance_id == demon.instance_id), None
)
if sharur_in_new is not None:
state = apply_status(state, sharur_in_new, sharur_in_new, "ignore_exhaust", 1)
state = apply_status(state, sharur_in_new, sharur_in_new, "ignore_ready", 1)
return state
register_ability("068", 1, _sharur_heavy_impact)