Vine
Architect of Hell
Unit #085
| HP | PWR | CP | Speed | Range | Tier |
|---|---|---|---|---|---|
| 15 (+9) | 2 | 4 (+3) | Normal | Any | C |
Abilities
Passive
q: After Any Other Demon that is worth at least 3 CP dies, you may play a Crystal Parasite Familiar into the dead Demon's Lane. (Vine has 4 Crystal Parasite Familiars.)
Engine Implementation
def _vine_deploy_crystal_parasite_trigger(
state: GameState, event: GameEvent, demon: DemonInstance, depth: int
) -> GameState | None:
"""#085 Vine — Passive trigger: After Any Other 3+ CP Demon dies, deploy Crystal Parasite.
Fires on FATALLY_WOUNDED. Activates if:
- event.target is NOT this Vine instance
- The dying demon's effective CP >= 3
- Vine is NOT fatally_wounded
Effect: Deploy the first available Crystal Parasite familiar (085_1 through 085_4)
into the dead demon's lane (event.target.lane).
CRITICAL (confusion #2): familiars ARE demons — fires on familiar deaths too,
if the familiar is worth >= 3 CP.
"""
from engine.operations import deploy_familiar, get_effective_cp
# Only fire if the dying demon is NOT Vine itself
if event.target is None:
return None
if event.target.instance_id == demon.instance_id:
return None # Vine itself — does not trigger on own death
# Re-fetch Vine from current state to check latest fatally_wounded flag
vine_current = next(
(d for d in state.demons if d.instance_id == demon.instance_id), None
)
if vine_current is None or vine_current.fatally_wounded:
return None # Vine is dead or dying — cannot resolve
# Check the dying demon's CP value (>= 3 threshold)
dying_demon = next(
(d for d in state.demons if d.instance_id == event.target.instance_id), None
)
if dying_demon is None:
# Dying demon may no longer be in state.demons after death resolution —
# use the event.target snapshot for CP check
dying_demon = event.target
# get_effective_cp needs the demon in state, but if already removed, use card data
try:
cp_value = get_effective_cp(state, dying_demon)
except (ValueError, KeyError):
from engine.data_loader import UNITS, FAMILIARS
uid = event.target.unit_id
if uid in UNITS:
cp_value = UNITS[uid].cp or 0
elif uid in FAMILIARS:
cp_value = FAMILIARS[uid].cp or 0
else:
cp_value = 0
if cp_value < 3:
return None # Not worth enough CP — trigger does not fire
# Determine target lane (the lane the dead demon was in)
target_lane = event.target.lane
# Find the first available Crystal Parasite copy in Vine's owner's familiar_deck
CRYSTAL_PARASITE_IDS = ["085_1", "085_2", "085_3", "085_4"]
owner = vine_current.owner
available_id = None
for cpid in CRYSTAL_PARASITE_IDS:
if cpid in state.players[owner].familiar_deck:
available_id = cpid
break
if available_id is None:
return None # All copies already in play or not available
# Deploy Crystal Parasite into the dead demon's lane
return deploy_familiar(state, owner, available_id, target_lane)
register_trigger("085", 0, _vine_deploy_crystal_parasite_trigger)
Crystal Infection — 1 AP
Crystal Infection: 1 AP - a, 1x: Fatally Wound Target Allied Demon. e: Ignore their CP for the purposes of scoring.
Engine Implementation
def _vine_crystal_infection(
state: GameState, demon: DemonInstance, targets, choices, rng
) -> GameState:
"""#085 Vine — Crystal Infection
Action, 1 AP, (exhaust), 1x: Fatally Wound Target Allied Demon.
Status: Ignore their CP for the purposes of scoring.
CRITICAL: fatally_wounded is one-way.
Applies "cp_ignore" status to target (value=1), then sets fatally_wounded.
The scoring system checks "cp_ignore" status to suppress CP gain on death.
"""
from engine.status_effects import apply_status
if not targets:
return state
target = targets[0]
t_current = next(
(d for d in state.demons if d.instance_id == target.instance_id), None
)
if t_current is None or t_current.fatally_wounded:
return state
# Status: ignore CP for scoring (uses cp_override_zero, same as Phoenix/Libra)
state = apply_status(state, demon, t_current, "cp_override_zero", 1)
# Fatally wound the target
new_state = copy.deepcopy(state)
t_in_new = next(
(d for d in new_state.demons if d.instance_id == target.instance_id), None
)
if t_in_new is not None:
t_in_new.fatally_wounded = True
return new_state
register_ability("085", 1, _vine_crystal_infection)