mirror of
https://github.com/Bratah123/Spirit-PTCGO.git
synced 2026-09-10 05:35:47 -05:00
FEAT: implement CRZ cards
This commit is contained in:
@@ -1129,6 +1129,217 @@ def bench_has_room(board, player_id):
|
||||
and len(bench.children) < effective_bench_capacity(board, player_id)
|
||||
|
||||
|
||||
# --- Brandon (SWSH12) -------------------------------------------------------
|
||||
|
||||
def brandon_playable(board, player_id) -> bool:
|
||||
hand = board.find_player_area(player_id, "hand")
|
||||
return bool(hand) and len(hand.children) == 1
|
||||
|
||||
|
||||
async def brandon(ctx):
|
||||
"""Draw a card for each Benched Pokemon (both yours and your opponent's)."""
|
||||
count = len(_bench_pokemon(ctx.board, ctx.player_id)) \
|
||||
+ len(_bench_pokemon(ctx.board, ctx.opponent_id))
|
||||
if count > 0:
|
||||
await ctx.draw_cards(count)
|
||||
|
||||
|
||||
# --- Candice (SWSH12) --------------------------------------------------------
|
||||
|
||||
def is_water_energy_card(card) -> bool:
|
||||
types = card.get_attribute(AttrID.POKEMON_TYPES) or []
|
||||
return is_energy_card(card) and PokemonTypes.WATER.value in types
|
||||
|
||||
|
||||
def candice_predicate(card) -> bool:
|
||||
return is_water_pokemon(card) or is_water_energy_card(card)
|
||||
|
||||
|
||||
# --- Capturing Aroma (SWSH12) ------------------------------------------------
|
||||
|
||||
async def capturing_aroma(ctx):
|
||||
"""Flip a coin: heads searches for an Evolution Pokemon, tails a Basic
|
||||
Pokemon; reveal it and put it into your hand. Then, shuffle your deck."""
|
||||
heads, = await ctx.flip_coins(1, "Capturing Aroma")
|
||||
predicate = is_evolution_pokemon if heads else is_basic_pokemon
|
||||
prompt = "Choose an Evolution Pokémon to put into your hand." if heads \
|
||||
else "Choose a Basic Pokémon to put into your hand."
|
||||
picks = await ctx.search_deck(predicate, count=1, minimum=0, prompt=prompt)
|
||||
await ctx.put_in_hand(picks, reveal=True)
|
||||
await ctx.shuffle_deck()
|
||||
|
||||
|
||||
# --- Earthen Seal Stone (SWSH12) ---------------------------------------------
|
||||
|
||||
async def star_gravity(ctx):
|
||||
"""Put damage counters on each of the opponent's Pokemon V until its
|
||||
remaining HP is 100 (VSTAR Power)."""
|
||||
for pokemon in ctx.opponent_pokemon_in_play():
|
||||
if not is_pokemon_v(pokemon.archetype_id):
|
||||
continue
|
||||
current = pokemon.get_attribute(AttrID.HP, ctx.max_hp(pokemon))
|
||||
if current > 100:
|
||||
await ctx.deal_damage(current - 100, target=pokemon,
|
||||
apply_modifiers=False, as_counters=True)
|
||||
|
||||
|
||||
# --- Emergency Jelly (SWSH12) -------------------------------------------------
|
||||
|
||||
async def emergency_jelly(ctx):
|
||||
"""End of each turn: if the holder has 30 HP or less remaining and any
|
||||
damage counters on it, heal 120 damage from it and discard this card."""
|
||||
pokemon = ctx.source
|
||||
hp = pokemon.get_attribute(AttrID.HP, 0)
|
||||
max_hp = ctx.max_hp(pokemon)
|
||||
if hp <= 30 and hp < max_hp:
|
||||
await ctx.heal(120, target=pokemon)
|
||||
tool = next((t for t, p in ctx.tools_in_play() if p is pokemon), None)
|
||||
if tool is not None:
|
||||
await ctx.discard_cards([tool])
|
||||
|
||||
|
||||
# --- Furisode Girl (SWSH12) ---------------------------------------------------
|
||||
|
||||
async def furisode_girl(ctx):
|
||||
"""Search the deck for a Basic Pokemon and put it onto the Bench; then
|
||||
shuffle. You may switch that Pokemon with your Active Pokemon."""
|
||||
picks = await ctx.search_deck(
|
||||
is_basic_pokemon, count=1, minimum=0,
|
||||
prompt="Choose a Basic Pokémon to put onto your Bench.",
|
||||
)
|
||||
if not picks:
|
||||
await ctx.shuffle_deck()
|
||||
return
|
||||
target = picks[0]
|
||||
await ctx.bench_pokemon(target)
|
||||
await ctx.shuffle_deck()
|
||||
if await ctx.ask_yes_no("Switch that Pokémon with your Active Pokémon?"):
|
||||
await ctx.switch_active(ctx.player_id, target)
|
||||
|
||||
|
||||
# --- Lance (SWSH12) -----------------------------------------------------------
|
||||
|
||||
def is_dragon_pokemon(card) -> bool:
|
||||
types = card.get_attribute(AttrID.POKEMON_TYPES) or []
|
||||
return is_pokemon_card(card) and PokemonTypes.DRAGON.value in types
|
||||
|
||||
|
||||
async def lance(ctx):
|
||||
"""Search the deck for up to 3 Dragon Pokemon, reveal them, and put them
|
||||
into your hand. Then, shuffle your deck."""
|
||||
picks = await ctx.search_deck(
|
||||
is_dragon_pokemon, count=3, minimum=0,
|
||||
prompt="Choose up to 3 Dragon Pokémon to put into your hand.",
|
||||
)
|
||||
await ctx.put_in_hand(picks, reveal=True)
|
||||
await ctx.shuffle_deck()
|
||||
|
||||
|
||||
# --- Leafy Camo Poncho (SWSH12) -----------------------------------------------
|
||||
|
||||
def leafy_camo_poncho_protects(affected_entity, carrier):
|
||||
holder = carrier_pokemon(carrier)
|
||||
return holder is not None and affected_entity is holder
|
||||
|
||||
|
||||
def leafy_camo_poncho_condition(board, carrier):
|
||||
holder = carrier_pokemon(carrier)
|
||||
if holder is None:
|
||||
return False
|
||||
subs = subtypes_for(holder.archetype_id)
|
||||
return "VSTAR" in subs or "VMAX" in subs
|
||||
|
||||
|
||||
# --- Primordial Altar (SWSH12) ------------------------------------------------
|
||||
|
||||
def primordial_altar_condition(board, player_id, stadium):
|
||||
return deck_nonempty(board, player_id)
|
||||
|
||||
|
||||
async def primordial_altar(ctx):
|
||||
"""Once during each player's turn: look at the top card of the deck and
|
||||
may discard it."""
|
||||
top = ctx.deck_top(1)
|
||||
if not top:
|
||||
return
|
||||
card = top[0]
|
||||
idx = await ctx.present_card_choice(
|
||||
card, "Discard the top card of your deck?",
|
||||
["Discard", "Keep it on top"],
|
||||
)
|
||||
if idx == 0:
|
||||
await ctx.discard_cards([card])
|
||||
|
||||
|
||||
PRIMORDIAL_ALTAR_ABILITY = Ability(
|
||||
title="Primordial Altar",
|
||||
game_text="Once during each player's turn, that player may look at the top card of their deck. They may discard that card.",
|
||||
activation=Activations.ONCE_PER_TURN,
|
||||
effect=primordial_altar,
|
||||
condition=primordial_altar_condition,
|
||||
)
|
||||
|
||||
|
||||
# --- Professor Laventon (SWSH12) ----------------------------------------------
|
||||
|
||||
def _is_hisuian_pokemon(card) -> bool:
|
||||
if not is_pokemon_card(card):
|
||||
return False
|
||||
name = getattr(def_for(card.archetype_id), "display_name", "") or ""
|
||||
return "Hisuian" in name
|
||||
|
||||
|
||||
def professor_laventon_playable(board, player_id) -> bool:
|
||||
return any(_is_hisuian_pokemon(c) for c in _discard(board, player_id))
|
||||
|
||||
|
||||
async def professor_laventon(ctx):
|
||||
"""Put up to 3 Pokemon that have "Hisuian" in their names from the
|
||||
discard pile into your hand."""
|
||||
candidates = [c for c in ctx.discard_pile() if _is_hisuian_pokemon(c)]
|
||||
picks = await ctx.choose_cards(
|
||||
candidates, 3, minimum=0,
|
||||
prompt="Choose up to 3 Hisuian Pokémon from your discard pile.",
|
||||
)
|
||||
await ctx.put_in_hand(picks, reveal=False)
|
||||
|
||||
|
||||
# --- Quad Stone (SWSH12) -------------------------------------------------------
|
||||
|
||||
async def quad_stone(ctx):
|
||||
"""Use 1: heal 10 from your Active. Use 4 at once (this + 3 more from
|
||||
hand): heal all damage from each of your Pokemon."""
|
||||
others = [c for c in ctx.hand()
|
||||
if c is not ctx.source and c.archetype_id == ctx.source.archetype_id]
|
||||
use_four = False
|
||||
if len(others) >= 3 and await ctx.ask_yes_no(
|
||||
"Use 3 more Quad Stone cards from your hand to heal all damage from "
|
||||
"each of your Pokémon instead of healing 10 from your Active Pokémon?"
|
||||
):
|
||||
picks = await ctx.choose_cards(
|
||||
others, 3, minimum=3, prompt="Choose 3 more Quad Stone cards to use",
|
||||
)
|
||||
if len(picks) >= 3:
|
||||
await ctx.discard_cards(picks)
|
||||
for pokemon in ctx.my_pokemon_in_play():
|
||||
await ctx.heal(9999, pokemon)
|
||||
use_four = True
|
||||
if not use_four:
|
||||
active = ctx.my_active()
|
||||
if active is not None:
|
||||
await ctx.heal(10, active)
|
||||
|
||||
|
||||
# --- Wallace (SWSH12) ----------------------------------------------------------
|
||||
|
||||
async def wallace(ctx):
|
||||
"""Draw 3 cards. Your opponent may draw a card; if they do, draw 1 more."""
|
||||
await ctx.draw_cards(3)
|
||||
if await ctx.ask_yes_no("Draw a card?", player_id=ctx.opponent_id):
|
||||
await ctx.draw_cards(1, ctx.opponent_id)
|
||||
await ctx.draw_cards(1)
|
||||
|
||||
|
||||
def fossil_search(fossil_predicate, count: int = 2,
|
||||
label: str = "Rare Fossil"):
|
||||
"""Search your deck for up to `count` matching fossil cards and put them
|
||||
|
||||
@@ -376,7 +376,8 @@ class PokemonCardDef(CardDefinition):
|
||||
subtypes: Optional[List[str]] = None,
|
||||
attributes: Optional[dict] = None,
|
||||
passive: Optional[Any] = None,
|
||||
unplayable_from_hand: bool = False
|
||||
unplayable_from_hand: bool = False,
|
||||
setup_as_active: bool = False
|
||||
):
|
||||
super().__init__(guid, key, name, collector_number, set_code, rarity, display_name, searchable_by, subtypes, attributes)
|
||||
# Card-level continuous effect while this Pokemon is top-level in play
|
||||
@@ -384,6 +385,9 @@ class PokemonCardDef(CardDefinition):
|
||||
self.passive = passive
|
||||
# Shedinja: never offered as a hand bench-play (enters play by effect).
|
||||
self.unplayable_from_hand = unplayable_from_hand
|
||||
# Luxray CZ's Explosiveness: may be placed as the opening Active
|
||||
# despite its stage (setup only; bench plays stay Basics-only).
|
||||
self.setup_as_active = setup_as_active
|
||||
|
||||
# Add Pokemon-specific defaults to extra_attributes
|
||||
self.extra_attributes.update({
|
||||
|
||||
@@ -487,16 +487,34 @@ class BoardState:
|
||||
"""
|
||||
return bool(self.basic_pokemon_in_hand(player_id))
|
||||
|
||||
def setup_active_candidates(self, player_id: str) -> List['PokemonEntity']:
|
||||
"""Cards playable as the opening Active: Basics first, then hand
|
||||
Pokemon whose def sets setup_as_active (Luxray CZ's Explosiveness).
|
||||
The bench offer and mid-game bench plays stay Basics-only."""
|
||||
from spirit.game.data_utils import def_for # circular-import guard
|
||||
candidates = self.basic_pokemon_in_hand(player_id)
|
||||
hand_area = self.find_player_area(player_id, "hand")
|
||||
for c in (hand_area.children if hand_area else []):
|
||||
if isinstance(c, PokemonEntity) and c not in candidates \
|
||||
and getattr(def_for(c.archetype_id), "setup_as_active", False):
|
||||
candidates.append(c)
|
||||
return candidates
|
||||
|
||||
def player_has_any_basic(self, player_id: str) -> bool:
|
||||
"""True if the player has a Basic Pokemon anywhere in deck or hand.
|
||||
|
||||
Guards the mulligan loop against decks that can never produce a legal
|
||||
opening hand (which would otherwise reshuffle forever).
|
||||
"""
|
||||
from spirit.game.data_utils import def_for # circular-import guard
|
||||
for area_name in ("deck", "hand"):
|
||||
area = self.find_player_area(player_id, area_name)
|
||||
if area and any(self._is_basic_pokemon(c) for c in area.children):
|
||||
return True
|
||||
for c in (area.children if area else []):
|
||||
if self._is_basic_pokemon(c):
|
||||
return True
|
||||
if isinstance(c, PokemonEntity) \
|
||||
and getattr(def_for(c.archetype_id), "setup_as_active", False):
|
||||
return True
|
||||
return False
|
||||
|
||||
def pokemon_in_play(self, player_id: str) -> List['PokemonEntity']:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import ItemCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.card_effects.support_common import heal_item, requires_damaged_pokemon
|
||||
|
||||
card = ItemCardDef(
|
||||
guid="d73ca4da-dd21-f428-8051-264ab564587c",
|
||||
@@ -7,5 +8,7 @@ card = ItemCardDef(
|
||||
name="com.direwolfdigital.cake.data.archetypes.trainer.Potion.Name",
|
||||
collector_number=100,
|
||||
set_code="BW1",
|
||||
rarity=Rarities.Common
|
||||
rarity=Rarities.Common,
|
||||
condition=requires_damaged_pokemon(),
|
||||
effect=heal_item(30)
|
||||
)
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
import random
|
||||
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
|
||||
|
||||
async def lost_claw(ctx):
|
||||
"""70. Put a random card from your opponent's hand in the Lost Zone."""
|
||||
await ctx.deal_damage()
|
||||
hand = ctx.hand(ctx.opponent_id)
|
||||
if hand:
|
||||
await ctx.move_to_lost_zone([random.choice(hand)])
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="b8a98898-af7d-52a3-a682-ab6a0ff76dae",
|
||||
key="CZ",
|
||||
@@ -28,7 +39,7 @@ card = PokemonCardDef(
|
||||
game_text="Put a random card from your opponent's hand in the Lost Zone.",
|
||||
cost={PokemonTypes.DARKNESS: 1, PokemonTypes.COLORLESS: 2},
|
||||
damage=70,
|
||||
effect=unimplemented,
|
||||
effect=lost_claw,
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,29 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.session.passives import Passive
|
||||
|
||||
|
||||
class CounterPressPassive(Passive):
|
||||
"""Reflects the damage this Pokemon takes onto the attacker as counters."""
|
||||
|
||||
async def damage_interceptor(self, ctx, calc, target, carrier):
|
||||
if not (calc.is_attack and calc.is_opposing and calc.amount > 0):
|
||||
return None
|
||||
if target is not carrier:
|
||||
return None
|
||||
attacker = calc.attacker
|
||||
if attacker is not None:
|
||||
await ctx.deal_damage(calc.amount, target=attacker,
|
||||
apply_modifiers=False, as_counters=True)
|
||||
return None
|
||||
|
||||
|
||||
async def counter_press(ctx):
|
||||
"""90. During your opponent's next turn, a hit on this Pokemon reflects
|
||||
as damage counters on the attacker (even if this Pokemon is KO'd)."""
|
||||
await ctx.deal_damage()
|
||||
ctx.add_passive_through_opponents_turn(ctx.attacker, CounterPressPassive())
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="ede06640-e9fd-56bb-bcf4-a84577370ce7",
|
||||
@@ -25,7 +49,7 @@ card = PokemonCardDef(
|
||||
game_text="During your opponent's next turn, if this Pok\u00e9mon is damaged by an attack (even if this Pok\u00e9mon is Knocked Out), put damage counters on the Attacking Pok\u00e9mon equal to the damage done to this Pok\u00e9mon.",
|
||||
cost={PokemonTypes.METAL: 1, PokemonTypes.COLORLESS: 2},
|
||||
damage=90,
|
||||
effect=unimplemented,
|
||||
effect=counter_press,
|
||||
),
|
||||
Attack(
|
||||
title="Heavy Impact",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import recoil_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="66eca74a-2caf-5210-a324-f4b2aa277233",
|
||||
@@ -29,7 +30,7 @@ card = PokemonCardDef(
|
||||
game_text="This Pok\u00e9mon also does 10 damage to itself.",
|
||||
cost={PokemonTypes.COLORLESS: 2},
|
||||
damage=30,
|
||||
effect=unimplemented,
|
||||
effect=recoil_attack(10),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,27 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import AttrID, PokemonTypes, Rarities
|
||||
from spirit.game.card_effects.trainers import is_energy_card
|
||||
from spirit.game.card_effects.support_common import distribute_energy
|
||||
|
||||
|
||||
def _is_fighting_pokemon(pokemon):
|
||||
types = pokemon.get_attribute(AttrID.POKEMON_TYPES) or []
|
||||
return PokemonTypes.FIGHTING.value in types
|
||||
|
||||
|
||||
async def bea(ctx):
|
||||
"""Discard the top 5 of your deck; attach any Energy discarded this way
|
||||
to your Benched Fighting Pokemon in any way you like."""
|
||||
cards = ctx.deck_top(5)
|
||||
await ctx.discard_cards(cards)
|
||||
energies = [c for c in cards if is_energy_card(c)]
|
||||
if not energies:
|
||||
return
|
||||
candidates = [p for p in ctx.my_bench() if _is_fighting_pokemon(p)]
|
||||
if not candidates:
|
||||
return
|
||||
await distribute_energy(ctx, energies, candidates)
|
||||
|
||||
|
||||
card = SupporterCardDef(
|
||||
guid="5c6b91c9-4040-5658-81f8-ec1351d97293",
|
||||
@@ -11,5 +33,5 @@ card = SupporterCardDef(
|
||||
collector_number=123,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.RareHolo,
|
||||
effect=unimplemented
|
||||
effect=bea
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.card_effects.trainers import bede, bede_playable
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
|
||||
card = SupporterCardDef(
|
||||
@@ -11,5 +12,6 @@ card = SupporterCardDef(
|
||||
collector_number=124,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.RareHolo,
|
||||
effect=unimplemented
|
||||
effect=bede,
|
||||
condition=bede_playable
|
||||
)
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_damage
|
||||
|
||||
|
||||
async def _switch_self(ctx):
|
||||
bench = ctx.my_bench()
|
||||
if not bench:
|
||||
return
|
||||
target = await ctx.choose_pokemon(bench, "Choose your new Active Pokémon")
|
||||
if target is not None:
|
||||
await ctx.switch_active(ctx.player_id, target)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="d57c93dd-02e6-5ad1-9b55-7ea441dd4e43",
|
||||
@@ -25,7 +36,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.GRASS: 1, PokemonTypes.COLORLESS: 1},
|
||||
damage=80,
|
||||
damage_operator="x",
|
||||
effect=unimplemented,
|
||||
effect=flip_damage(coins=3, per_heads=80, also=_switch_self),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,11 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_or_nothing
|
||||
from spirit.game.card_effects.passives_common import prevent_damage_when
|
||||
|
||||
|
||||
def _carefree_pred(calc, carrier):
|
||||
return calc.is_attack and calc.target is carrier and not calc.to_active
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="cc5cc393-6005-5fc0-8114-e5d41ba4c6e4",
|
||||
@@ -21,14 +27,14 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Carefree Countenance",
|
||||
game_text="As long as this Pok\u00e9mon is on your Bench, prevent all damage done to this Pok\u00e9mon by attacks (both yours and your opponent's).",
|
||||
effect=unimplemented,
|
||||
passive=prevent_damage_when(_carefree_pred, attacks_only=False),
|
||||
),
|
||||
Attack(
|
||||
title="Hyper Fang",
|
||||
game_text="Flip a coin. If tails, this attack does nothing.",
|
||||
cost={PokemonTypes.COLORLESS: 2},
|
||||
damage=30,
|
||||
effect=unimplemented,
|
||||
effect=flip_or_nothing(),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.support_common import draw_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="550b78f5-3e2a-50ce-8353-d1a1191b90a9",
|
||||
@@ -25,7 +26,7 @@ card = PokemonCardDef(
|
||||
game_text="Draw 2 cards.",
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
damage=20,
|
||||
effect=unimplemented,
|
||||
effect=draw_attack(2),
|
||||
),
|
||||
Attack(
|
||||
title="Power Edge",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.support_common import search_to_hand, heal_targets
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="9656d298-ea31-505e-adbd-b6bb0bc42a6c",
|
||||
@@ -23,14 +24,14 @@ card = PokemonCardDef(
|
||||
game_text="You may search your deck for up to 2 cards and put them into your hand. Then, shuffle your deck.",
|
||||
cost={PokemonTypes.COLORLESS: 2},
|
||||
damage=30,
|
||||
effect=unimplemented,
|
||||
effect=search_to_hand(count=2, minimum=0, reveal=False),
|
||||
),
|
||||
Attack(
|
||||
title="Bloomshine",
|
||||
game_text="Heal 20 damage from each of your Pok\u00e9mon.",
|
||||
cost={PokemonTypes.GRASS: 1, PokemonTypes.COLORLESS: 2},
|
||||
damage=90,
|
||||
effect=unimplemented,
|
||||
effect=heal_targets(20, scope="each_own"),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, SpecialConditions
|
||||
from spirit.game.card_effects.attacks_common import condition_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="d41fce1f-9097-555b-b507-4504bf9d6d06",
|
||||
@@ -22,14 +23,14 @@ card = PokemonCardDef(
|
||||
title="Festering Saliva",
|
||||
game_text="Your opponent's Active Pok\u00e9mon is now Burned and Poisoned.",
|
||||
cost={PokemonTypes.GRASS: 1},
|
||||
effect=unimplemented,
|
||||
effect=condition_attack(SpecialConditions.BURNED, SpecialConditions.POISONED),
|
||||
),
|
||||
Attack(
|
||||
title="Bind Down",
|
||||
game_text="During your opponent's next turn, the Defending Pok\u00e9mon can't retreat.",
|
||||
cost={PokemonTypes.COLORLESS: 2},
|
||||
damage=40,
|
||||
effect=unimplemented,
|
||||
effect=condition_attack(no_retreat=True),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import bonus_if, has_damage, self_energy_discard_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="ffd5fc1c-42d7-5ff9-9140-707e461a7d8a",
|
||||
@@ -25,14 +26,15 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.FIRE: 2, PokemonTypes.COLORLESS: 1},
|
||||
damage=130,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=bonus_if(has_damage("self"), 100),
|
||||
),
|
||||
Attack(
|
||||
title="Star Blaze",
|
||||
game_text="Discard 2 Energy from this Pok\u00e9mon. (You can't use more than 1 VSTAR Power in a game.)",
|
||||
cost={PokemonTypes.FIRE: 3, PokemonTypes.COLORLESS: 1},
|
||||
damage=320,
|
||||
effect=unimplemented,
|
||||
vstar=True,
|
||||
effect=self_energy_discard_attack(count=2),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,6 +1,17 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
|
||||
|
||||
async def incinerate(ctx):
|
||||
"""Before doing damage, discard all Tools from the opponent's Active."""
|
||||
defender = ctx.defender
|
||||
if defender is not None and not ctx.effects_blocked(defender):
|
||||
tools = [t for t, p in ctx.tools_in_play() if p is defender]
|
||||
if tools:
|
||||
await ctx.discard_cards(tools)
|
||||
await ctx.deal_damage()
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="7c859d59-2894-5783-8c83-60fb3049e133",
|
||||
key="CZ",
|
||||
@@ -23,7 +34,7 @@ card = PokemonCardDef(
|
||||
game_text="Before doing damage, discard all Pok\u00e9mon Tools from your opponent's Active Pok\u00e9mon.",
|
||||
cost={PokemonTypes.FIRE: 2, PokemonTypes.COLORLESS: 1},
|
||||
damage=90,
|
||||
effect=unimplemented,
|
||||
effect=incinerate,
|
||||
),
|
||||
Attack(
|
||||
title="Heat Blast",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.support_common import discard_then_draw
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="f1fbc56e-ecba-5831-94b7-573419e85f04",
|
||||
@@ -23,7 +24,7 @@ card = PokemonCardDef(
|
||||
title="Cycle Draw",
|
||||
game_text="Discard a card from your hand. If you do, draw 2 cards.",
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
effect=unimplemented,
|
||||
effect=discard_then_draw(1, 2, optional=True),
|
||||
),
|
||||
Attack(
|
||||
title="Flap",
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
from spirit.game.data_utils import ItemCardDef, unimplemented
|
||||
from spirit.game.data_utils import ItemCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.card_effects.trainers import opponent_has_energy_attached
|
||||
|
||||
|
||||
async def crushing_hammer(ctx):
|
||||
"""Flip a coin. If heads, discard an Energy from 1 of your opponent's Pokémon."""
|
||||
results = await ctx.flip_coins(1, "Crushing Hammer")
|
||||
if not results or not results[0]:
|
||||
return
|
||||
candidates = [p for p in ctx.opponent_pokemon_in_play() if ctx.attached_energies(p)]
|
||||
if not candidates:
|
||||
return
|
||||
target = await ctx.choose_pokemon(candidates, "Choose 1 of your opponent's Pokémon")
|
||||
if target is None:
|
||||
return
|
||||
await ctx.discard_energy_from(target, 1)
|
||||
|
||||
|
||||
card = ItemCardDef(
|
||||
guid="fdc218bf-196c-5954-bb04-bca1ec80a911",
|
||||
@@ -11,5 +27,6 @@ card = ItemCardDef(
|
||||
collector_number=125,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Uncommon,
|
||||
effect=unimplemented
|
||||
effect=crushing_hammer,
|
||||
condition=opponent_has_energy_attached
|
||||
)
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
|
||||
|
||||
async def digging_duo(ctx):
|
||||
"""Flip a coin: heads look at bottom 8, tails bottom 3; put 1 into hand."""
|
||||
heads, = await ctx.flip_coins(1, "Digging Duo")
|
||||
bottom = ctx.deck()[:8 if heads else 3]
|
||||
if bottom:
|
||||
picks = await ctx.choose_cards(
|
||||
bottom, 1, prompt="Choose a card to put into your hand.",
|
||||
)
|
||||
await ctx.put_in_hand(picks, reveal=False)
|
||||
await ctx.shuffle_deck()
|
||||
|
||||
|
||||
card = SupporterCardDef(
|
||||
guid="bba06028-290f-5617-8d42-9f4927565f2f",
|
||||
key="CZ",
|
||||
@@ -11,5 +24,5 @@ card = SupporterCardDef(
|
||||
collector_number=126,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Uncommon,
|
||||
effect=unimplemented
|
||||
effect=digging_duo,
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.pokemon import SuddenTransformationPassive
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="d561efa6-d36b-5004-b823-04531ff6bbdb",
|
||||
@@ -21,7 +22,7 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Sudden Transformation",
|
||||
game_text="This Pok\u00e9mon can use the attacks of any Basic Pok\u00e9mon in your discard pile, except for Pok\u00e9mon with a Rule Box (Pok\u00e9mon V, Pok\u00e9mon-GX, etc. have Rule Boxes). (You still need the necessary Energy to use each attack.)",
|
||||
effect=unimplemented,
|
||||
passive=SuddenTransformationPassive(),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,19 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, SpecialConditions
|
||||
|
||||
|
||||
def _evolved_this_turn(ctx) -> bool:
|
||||
state = ctx.session.turn_state
|
||||
return state.entered_play_turn.get(ctx.attacker.entity_id) == state.turn_number
|
||||
|
||||
|
||||
async def rocket_poison(ctx):
|
||||
"""Your opponent's Active Pokémon is now Poisoned. If this Pokémon
|
||||
evolved from Skrelp during this turn, put 8 damage counters instead of 1."""
|
||||
counters = 8 if _evolved_this_turn(ctx) else 1
|
||||
await ctx.apply_special_condition(
|
||||
ctx.defender, SpecialConditions.POISONED, poison_counters=counters)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="5b049f74-2e13-5394-bb2d-7ea832d36233",
|
||||
@@ -23,7 +37,7 @@ card = PokemonCardDef(
|
||||
title="Rocket Poison",
|
||||
game_text="Your opponent's Active Pok\u00e9mon is now Poisoned. If this Pok\u00e9mon evolved from Skrelp during this turn, put 8 damage counters on that Pok\u00e9mon instead of 1 during Pok\u00e9mon Checkup.",
|
||||
cost={PokemonTypes.DARKNESS: 1},
|
||||
effect=unimplemented,
|
||||
effect=rocket_poison,
|
||||
),
|
||||
Attack(
|
||||
title="Razor Fin",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_damage, snipe_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="78aee80e-9456-52a3-b2e2-55268181d44b",
|
||||
@@ -24,7 +25,7 @@ card = PokemonCardDef(
|
||||
game_text="This attack also does 10 damage to 1 of your Benched Pok\u00e9mon. (Don't apply Weakness and Resistance for Benched Pok\u00e9mon.)",
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
damage=40,
|
||||
effect=unimplemented,
|
||||
effect=snipe_attack(10, pool="bench", count=1, side="mine", also_base=True),
|
||||
),
|
||||
Attack(
|
||||
title="Rolling Dash",
|
||||
@@ -32,7 +33,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.COLORLESS: 2},
|
||||
damage=60,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=flip_damage(until_tails=True, base=60, per_heads=30),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,22 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.passives_common import prevent_damage_when
|
||||
from spirit.game.models.board import BoardState
|
||||
from spirit.game.session.effects import is_special_energy
|
||||
|
||||
|
||||
def _skyscraper_pred(calc, carrier):
|
||||
if calc.target is not carrier:
|
||||
return False
|
||||
attacker = calc.attacker
|
||||
return attacker is not None and any(
|
||||
is_special_energy(e) for e in BoardState.attached_energies(attacker)
|
||||
)
|
||||
|
||||
|
||||
async def g_max_pulverization(ctx):
|
||||
await ctx.deal_damage(ignore_target_effects=True)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="2b92d3d9-e5bd-5026-88c1-3a99f9c8eb82",
|
||||
@@ -21,14 +38,14 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Skyscraper",
|
||||
game_text="Prevent all damage done to this Pok\u00e9mon by attacks from your opponent's Pok\u00e9mon that have Special Energy attached.",
|
||||
effect=unimplemented,
|
||||
passive=prevent_damage_when(_skyscraper_pred),
|
||||
),
|
||||
Attack(
|
||||
title="G-Max Pulverization",
|
||||
game_text="This attack's damage isn't affected by any effects on your opponent's Active Pok\u00e9mon.",
|
||||
cost={PokemonTypes.FIGHTING: 1, PokemonTypes.METAL: 2},
|
||||
damage=220,
|
||||
effect=unimplemented,
|
||||
effect=g_max_pulverization,
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.passives_common import debuff_defender_attacks
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="87d64657-cb5b-58a6-82c6-11ff214e6cb1",
|
||||
@@ -27,7 +28,7 @@ card = PokemonCardDef(
|
||||
game_text="During your opponent's next turn, the Defending Pok\u00e9mon's attacks do 30 less damage (before applying Weakness and Resistance).",
|
||||
cost={PokemonTypes.FIGHTING: 1, PokemonTypes.METAL: 2},
|
||||
damage=140,
|
||||
effect=unimplemented,
|
||||
effect=debuff_defender_attacks(30),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, SpecialConditions
|
||||
from spirit.game.card_effects.attacks_common import condition_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="fc815258-d645-5146-95f7-6a78443cd444",
|
||||
@@ -25,7 +26,7 @@ card = PokemonCardDef(
|
||||
game_text="Your opponent's Active Pok\u00e9mon is now Confused.",
|
||||
cost={PokemonTypes.PSYCHIC: 1},
|
||||
damage=30,
|
||||
effect=unimplemented,
|
||||
effect=condition_attack(SpecialConditions.CONFUSED),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,17 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, Triggers
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, SpecialConditions
|
||||
|
||||
|
||||
async def ad_hoc_shock(ctx):
|
||||
"""On evolve: you may flip a coin. If heads, the opponent's Active is now Paralyzed."""
|
||||
if not await ctx.ask_yes_no("Flip a coin?"):
|
||||
return
|
||||
results = await ctx.flip_coins(1, "Ad Hoc Shock")
|
||||
if not results or not results[0]:
|
||||
return
|
||||
defender = ctx.defender
|
||||
if defender is not None:
|
||||
await ctx.apply_special_condition(defender, SpecialConditions.PARALYZED)
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="6806e5e1-1032-5db4-8978-3841d7bd6a7d",
|
||||
@@ -22,7 +34,8 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Ad Hoc Shock",
|
||||
game_text="When you play this Pok\u00e9mon from your hand to evolve 1 of your Pok\u00e9mon during your turn, you may flip a coin. If heads, your opponent's Active Pok\u00e9mon is now Paralyzed.",
|
||||
effect=unimplemented,
|
||||
trigger=Triggers.ON_EVOLVE,
|
||||
effect=ad_hoc_shock,
|
||||
),
|
||||
Attack(
|
||||
title="Static Shock",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import bonus_if, defender_is_v
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="1e67d21d-d7f8-5954-b35d-c208ee2eb6e0",
|
||||
@@ -29,7 +30,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.COLORLESS: 3},
|
||||
damage=80,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=bonus_if(defender_is_v, 80),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,34 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.data_utils import SupporterCardDef, subtypes_for
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.card_effects.trainers import is_energy_card
|
||||
|
||||
|
||||
def _is_fusion_strike_energy(card):
|
||||
return is_energy_card(card) and "Fusion Strike" in subtypes_for(card.archetype_id)
|
||||
|
||||
|
||||
async def elesas_sparkle(ctx):
|
||||
"""Choose up to 2 of your Fusion Strike Pokemon. For each of those
|
||||
Pokemon, search your deck for a Fusion Strike Energy card and attach it
|
||||
to that Pokemon. Then, shuffle your deck."""
|
||||
candidates = [
|
||||
p for p in ctx.my_pokemon_in_play()
|
||||
if "Fusion Strike" in subtypes_for(p.archetype_id)
|
||||
]
|
||||
if candidates:
|
||||
targets = await ctx.choose_cards(
|
||||
candidates, 2, minimum=0,
|
||||
prompt="Choose up to 2 of your Fusion Strike Pokémon.",
|
||||
)
|
||||
for pokemon in targets:
|
||||
picks = await ctx.search_deck(
|
||||
_is_fusion_strike_energy, count=1, minimum=0,
|
||||
prompt="Choose a Fusion Strike Energy card to attach.",
|
||||
)
|
||||
for card in picks:
|
||||
await ctx.attach_energy(card, pokemon)
|
||||
await ctx.shuffle_deck()
|
||||
|
||||
|
||||
card = SupporterCardDef(
|
||||
guid="c616a72f-74b1-5f40-bbbc-6337bdcf607c",
|
||||
@@ -11,5 +40,5 @@ card = SupporterCardDef(
|
||||
collector_number=147,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.RareUltra,
|
||||
effect=unimplemented
|
||||
effect=elesas_sparkle
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import condition_attack
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, SpecialConditions
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="3b51afab-da44-58d4-935d-a30e014ed572",
|
||||
@@ -23,7 +24,7 @@ card = PokemonCardDef(
|
||||
game_text="Flip a coin. If heads, your opponent's Active Pok\u00e9mon is now Paralyzed.",
|
||||
cost={PokemonTypes.LIGHTNING: 1},
|
||||
damage=30,
|
||||
effect=unimplemented,
|
||||
effect=condition_attack(SpecialConditions.PARALYZED, flip=True),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,17 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import bonus_if
|
||||
|
||||
|
||||
async def draining_kiss(ctx):
|
||||
"""20. Heal 20 damage from this Pokémon."""
|
||||
await ctx.deal_damage()
|
||||
await ctx.heal(20, ctx.attacker)
|
||||
|
||||
|
||||
def _same_hand_size(ctx):
|
||||
return ctx.hand_size() == ctx.hand_size(ctx.opponent_id)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="fa3103ab-be3e-5b66-a8f1-ea0e4e94d521",
|
||||
@@ -23,7 +35,7 @@ card = PokemonCardDef(
|
||||
game_text="Heal 20 damage from this Pok\u00e9mon.",
|
||||
cost={PokemonTypes.PSYCHIC: 1},
|
||||
damage=20,
|
||||
effect=unimplemented,
|
||||
effect=draining_kiss,
|
||||
),
|
||||
Attack(
|
||||
title="Loving Sympathy",
|
||||
@@ -31,7 +43,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.PSYCHIC: 1, PokemonTypes.COLORLESS: 2},
|
||||
damage=70,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=bonus_if(_same_hand_size, 70),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,4 +1,6 @@
|
||||
from spirit.game.data_utils import ItemCardDef, unimplemented
|
||||
from spirit.game.card_effects.support_common import recover_from_discard, requires_discard
|
||||
from spirit.game.card_effects.trainers import is_basic_energy_card
|
||||
from spirit.game.data_utils import ItemCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
|
||||
card = ItemCardDef(
|
||||
@@ -11,5 +13,6 @@ card = ItemCardDef(
|
||||
collector_number=127,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Common,
|
||||
effect=unimplemented
|
||||
condition=requires_discard(is_basic_energy_card),
|
||||
effect=recover_from_discard(is_basic_energy_card, count=2, minimum=1, to="hand"),
|
||||
)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from spirit.game.data_utils import ItemCardDef, unimplemented
|
||||
from spirit.game.card_effects.support_common import search_to_hand
|
||||
from spirit.game.card_effects.trainers import is_basic_energy_card
|
||||
from spirit.game.data_utils import ItemCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
|
||||
card = ItemCardDef(
|
||||
@@ -11,5 +13,6 @@ card = ItemCardDef(
|
||||
collector_number=128,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Common,
|
||||
effect=unimplemented
|
||||
effect=search_to_hand(is_basic_energy_card, count=1, minimum=0, reveal=True,
|
||||
prompt="Choose a basic Energy card to put into your hand."),
|
||||
)
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
from spirit.game.data_utils import ItemCardDef, unimplemented
|
||||
from spirit.game.card_effects.trainers import is_basic_energy_card
|
||||
from spirit.game.data_utils import ItemCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
|
||||
|
||||
def energy_switch_condition(board, player_id):
|
||||
pokemon = board.pokemon_in_play(player_id)
|
||||
if len(pokemon) < 2:
|
||||
return False
|
||||
return any(any(is_basic_energy_card(e) for e in p.children) for p in pokemon)
|
||||
|
||||
|
||||
async def energy_switch(ctx):
|
||||
"""Move a basic Energy from 1 of your Pokemon to another of your Pokemon."""
|
||||
pokemon = ctx.my_pokemon_in_play()
|
||||
await ctx.move_energy_freely(pokemon, pokemon, predicate=is_basic_energy_card, max_count=1)
|
||||
|
||||
|
||||
card = ItemCardDef(
|
||||
guid="654fda60-9a95-54fd-9f0d-a4df9c7d55a6",
|
||||
key="CZ",
|
||||
@@ -11,5 +26,6 @@ card = ItemCardDef(
|
||||
collector_number=129,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Uncommon,
|
||||
effect=unimplemented
|
||||
condition=energy_switch_condition,
|
||||
effect=energy_switch,
|
||||
)
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.passives_common import retreat_free_when
|
||||
from spirit.game.card_effects.pokemon import energy_provides_type
|
||||
from spirit.game.models.board import BoardState
|
||||
|
||||
|
||||
def _has_fire_energy(pokemon, carrier):
|
||||
return pokemon is carrier and any(
|
||||
energy_provides_type(e, PokemonTypes.FIRE.value)
|
||||
for e in BoardState.attached_energies(pokemon)
|
||||
)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="fae64169-d66c-5a75-a3ec-3aad1982f203",
|
||||
@@ -21,7 +32,7 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Explosive Heat Dash",
|
||||
game_text="If this Pok\u00e9mon has any Fire Energy attached, it has no Retreat Cost.",
|
||||
effect=unimplemented,
|
||||
passive=retreat_free_when(_has_fire_energy),
|
||||
),
|
||||
Attack(
|
||||
title="Claw Slash",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, SpecialConditions
|
||||
from spirit.game.card_effects.attacks_common import condition_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="1997382b-9f81-567f-96c6-d989cb94a6b9",
|
||||
@@ -24,7 +25,7 @@ card = PokemonCardDef(
|
||||
game_text="Flip a coin. If heads, your opponent's Active Pok\u00e9mon is now Paralyzed.",
|
||||
cost={PokemonTypes.PSYCHIC: 1, PokemonTypes.COLORLESS: 1},
|
||||
damage=20,
|
||||
effect=unimplemented,
|
||||
effect=condition_attack(SpecialConditions.PARALYZED, flip=True),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import damage_per, count_energy
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="08260c2c-df89-5676-96ef-75f2b9a433b8",
|
||||
@@ -24,7 +25,9 @@ card = PokemonCardDef(
|
||||
title="Powerful Storm",
|
||||
game_text="This attack does 20 damage for each Energy attached to all of your Pok\u00e9mon.",
|
||||
cost={PokemonTypes.PSYCHIC: 1},
|
||||
effect=unimplemented,
|
||||
damage=20,
|
||||
damage_operator="x",
|
||||
effect=damage_per(count_energy("mine"), 20),
|
||||
),
|
||||
Attack(
|
||||
title="Stampede",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.card_effects.support_common import draw_attack
|
||||
|
||||
card = SupporterCardDef(
|
||||
guid="d48141ff-3e7c-5905-8dc4-7bee4e9abd02",
|
||||
@@ -11,5 +12,5 @@ card = SupporterCardDef(
|
||||
collector_number=130,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Uncommon,
|
||||
effect=unimplemented
|
||||
effect=draw_attack(3)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.card_effects.support_common import draw_attack
|
||||
|
||||
card = SupporterCardDef(
|
||||
guid="b8aab8e6-e710-5acc-90d0-075282434464",
|
||||
@@ -11,5 +12,5 @@ card = SupporterCardDef(
|
||||
collector_number=148,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.RareUltra,
|
||||
effect=unimplemented
|
||||
effect=draw_attack(3)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.card_effects.support_common import draw_attack
|
||||
|
||||
card = SupporterCardDef(
|
||||
guid="f869e481-4a46-5266-901b-900e2022f3ab",
|
||||
@@ -11,5 +12,5 @@ card = SupporterCardDef(
|
||||
collector_number=131,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Uncommon,
|
||||
effect=unimplemented
|
||||
effect=draw_attack(3)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.card_effects.support_common import draw_attack
|
||||
|
||||
card = SupporterCardDef(
|
||||
guid="d73c8c29-ff5d-587d-befd-99ef44c401ba",
|
||||
@@ -11,5 +12,5 @@ card = SupporterCardDef(
|
||||
collector_number=149,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.RareUltra,
|
||||
effect=unimplemented
|
||||
effect=draw_attack(3)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_bonus
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="e86de1ae-68bb-51f3-8a82-b9104424ad7f",
|
||||
@@ -25,7 +26,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.METAL: 1},
|
||||
damage=10,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=flip_bonus(20),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,7 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.support_common import search_to_hand
|
||||
from spirit.game.session.effects import is_item_card
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="48322948-2b21-5927-a13f-b358e3344f77",
|
||||
@@ -27,7 +29,7 @@ card = PokemonCardDef(
|
||||
title="Find It",
|
||||
game_text="Search your deck for an Item card, reveal it, and put it into your hand. Then, shuffle your deck.",
|
||||
cost={PokemonTypes.COLORLESS: 2},
|
||||
effect=unimplemented,
|
||||
effect=search_to_hand(is_item_card, count=1, minimum=0, reveal=True),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_bonus
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="56239d56-0d3b-5411-a04d-1c26d1eae253",
|
||||
@@ -26,7 +27,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.METAL: 1, PokemonTypes.COLORLESS: 1},
|
||||
damage=30,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=flip_bonus(60),
|
||||
),
|
||||
Attack(
|
||||
title="Slash",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, SpecialConditions
|
||||
from spirit.game.card_effects.attacks_common import condition_attack
|
||||
from spirit.game.card_effects.support_common import draw_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="16bda894-1118-547a-9b79-738880e7035f",
|
||||
@@ -23,14 +25,14 @@ card = PokemonCardDef(
|
||||
title="Double Draw",
|
||||
game_text="Draw 2 cards.",
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
effect=unimplemented,
|
||||
effect=draw_attack(2),
|
||||
),
|
||||
Attack(
|
||||
title="Psybeam",
|
||||
game_text="Your opponent's Active Pok\u00e9mon is now Confused.",
|
||||
cost={PokemonTypes.PSYCHIC: 1, PokemonTypes.COLORLESS: 1},
|
||||
damage=30,
|
||||
effect=unimplemented,
|
||||
effect=condition_attack(SpecialConditions.CONFUSED),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,12 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.pokemon import energy_provides_type
|
||||
from spirit.game.card_effects.support_common import search_attach_energy
|
||||
|
||||
|
||||
def _is_water_energy(card):
|
||||
return energy_provides_type(card, PokemonTypes.WATER.value)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="d05205ad-77c3-5629-8d38-9e9878b8182b",
|
||||
@@ -23,7 +30,7 @@ card = PokemonCardDef(
|
||||
game_text="Search your deck for a Water Energy card and attach it to this Pok\u00e9mon. Then, shuffle your deck.",
|
||||
cost={PokemonTypes.WATER: 1},
|
||||
damage=30,
|
||||
effect=unimplemented,
|
||||
effect=search_attach_energy(predicate=_is_water_energy, count=1, to_self=True),
|
||||
),
|
||||
Attack(
|
||||
title="Freezing Wind",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, SpecialConditions
|
||||
from spirit.game.card_effects.attacks_common import condition_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="accabfca-c8d4-571d-b5e3-43380d1f987e",
|
||||
@@ -24,7 +25,7 @@ card = PokemonCardDef(
|
||||
game_text="Your opponent's Active Pok\u00e9mon is now Confused and Poisoned.",
|
||||
cost={PokemonTypes.GRASS: 1, PokemonTypes.COLORLESS: 1},
|
||||
damage=20,
|
||||
effect=unimplemented,
|
||||
effect=condition_attack(SpecialConditions.CONFUSED, SpecialConditions.POISONED),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,22 @@
|
||||
from spirit.game.data_utils import ItemCardDef, unimplemented
|
||||
from spirit.game.data_utils import ItemCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.session.effects import is_pokemon_card
|
||||
|
||||
|
||||
async def great_ball(ctx):
|
||||
"""Look at the top 7 cards of your deck. You may reveal a Pokemon you
|
||||
find there and put it into your hand. Shuffle the other cards back."""
|
||||
top = ctx.deck_top(7)
|
||||
candidates = [c for c in top if is_pokemon_card(c)]
|
||||
# No matches still shows the looked-at cards (nothing selectable).
|
||||
picks = await ctx.choose_cards(
|
||||
candidates, 1, minimum=0,
|
||||
prompt="You may put a Pokémon into your hand.",
|
||||
display_cards=top,
|
||||
)
|
||||
await ctx.put_in_hand(picks, reveal=True)
|
||||
await ctx.shuffle_deck()
|
||||
|
||||
|
||||
card = ItemCardDef(
|
||||
guid="86f22ea3-8a9a-5100-b3e1-a5be7f53f923",
|
||||
@@ -11,5 +28,5 @@ card = ItemCardDef(
|
||||
collector_number=132,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Uncommon,
|
||||
effect=unimplemented
|
||||
effect=great_ball
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, SpecialConditions
|
||||
from spirit.game.card_effects.attacks_common import condition_attack
|
||||
from spirit.game.card_effects.support_common import draw_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="aab2eb28-3de4-5543-80f3-f25e0ebbbbe9",
|
||||
@@ -23,14 +25,14 @@ card = PokemonCardDef(
|
||||
game_text="Flip a coin. If heads, your opponent's Active Pok\u00e9mon is now Paralyzed.",
|
||||
cost={PokemonTypes.COLORLESS: 2},
|
||||
damage=40,
|
||||
effect=unimplemented,
|
||||
effect=condition_attack(SpecialConditions.PARALYZED, flip=True),
|
||||
),
|
||||
Attack(
|
||||
title="Nom-Nom-Nom Incisors",
|
||||
game_text="Draw 3 cards.",
|
||||
cost={PokemonTypes.COLORLESS: 3},
|
||||
damage=120,
|
||||
effect=unimplemented,
|
||||
effect=draw_attack(3),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,8 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_or_nothing
|
||||
from spirit.game.card_effects.support_common import attach_from_discard
|
||||
from spirit.game.card_effects.pokemon import is_lightning_energy
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="da2d4201-db35-5408-bf85-f3d0dad17d1e",
|
||||
@@ -22,14 +25,17 @@ card = PokemonCardDef(
|
||||
title="Energize",
|
||||
game_text="Attach a Lightning Energy card from your discard pile to this Pok\u00e9mon.",
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
effect=unimplemented,
|
||||
effect=attach_from_discard(
|
||||
predicate=is_lightning_energy, count=1, target="self",
|
||||
prompt="Choose a Lightning Energy card to attach.",
|
||||
),
|
||||
),
|
||||
Attack(
|
||||
title="Surprise Attack",
|
||||
game_text="Flip a coin. If tails, this attack does nothing.",
|
||||
cost={PokemonTypes.COLORLESS: 3},
|
||||
damage=50,
|
||||
effect=unimplemented,
|
||||
effect=flip_or_nothing(),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,15 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import bonus_if
|
||||
|
||||
|
||||
def _stakeout_bonus(ctx):
|
||||
active = ctx.opponent_active()
|
||||
if active is None:
|
||||
return False
|
||||
turn_state = ctx.session.turn_state
|
||||
return turn_state.became_active_turn.get(active.entity_id) == turn_state.turn_number - 1
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="e70c910b-dcf4-5666-9b5d-db5ece37d83f",
|
||||
@@ -25,7 +35,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.COLORLESS: 2},
|
||||
damage=30,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=bonus_if(_stakeout_bonus, 120),
|
||||
),
|
||||
Attack(
|
||||
title="Lunge Out",
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, Activations
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, AttrID, SpecialConditions
|
||||
from spirit.game.card_effects.attacks_common import condition_attack
|
||||
from spirit.game.card_effects.support_common import requires_damaged_pokemon
|
||||
|
||||
|
||||
async def witchs_domain(ctx):
|
||||
"""Once during your turn, you may move up to 2 damage counters from your
|
||||
Pokemon to your opponent's Active Pokemon."""
|
||||
candidates = [p for p in ctx.my_pokemon_in_play()
|
||||
if p.get_attribute(AttrID.HP, 0) < ctx.max_hp(p)]
|
||||
if not candidates:
|
||||
return
|
||||
if not await ctx.ask_yes_no(
|
||||
"Move up to 2 damage counters from your Pokémon to your "
|
||||
"opponent's Active Pokémon?"
|
||||
):
|
||||
return
|
||||
source = await ctx.choose_pokemon(
|
||||
candidates, "Choose 1 of your Pokémon to move damage counters from"
|
||||
)
|
||||
if source is None:
|
||||
return
|
||||
target = ctx.opponent_active()
|
||||
if target is None:
|
||||
return
|
||||
await ctx.move_damage_counters(source, target, max_count=2)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="57f38c45-b660-582a-8e3e-318e595a8bea",
|
||||
@@ -23,14 +49,16 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Witch's Domain",
|
||||
game_text="Once during your turn, you may move up to 2 damage counters from your Pok\u00e9mon to your opponent's Active Pok\u00e9mon.",
|
||||
effect=unimplemented,
|
||||
activation=Activations.ONCE_PER_TURN,
|
||||
condition=requires_damaged_pokemon("mine"),
|
||||
effect=witchs_domain,
|
||||
),
|
||||
Attack(
|
||||
title="G-Max Smite",
|
||||
game_text="Your opponent's Active Pok\u00e9mon is now Confused.",
|
||||
cost={PokemonTypes.PSYCHIC: 1, PokemonTypes.COLORLESS: 2},
|
||||
damage=150,
|
||||
effect=unimplemented,
|
||||
effect=condition_attack(SpecialConditions.CONFUSED),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,24 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.support_common import switch_self_attack
|
||||
from spirit.game.card_effects.trainers import is_energy_card
|
||||
|
||||
|
||||
async def horoscope(ctx):
|
||||
"""Look at the top 3 cards of your deck. You may attach any number of
|
||||
Energy cards you find there to this Pokemon. Put the other cards back."""
|
||||
top = ctx.deck_top(3)
|
||||
if not top:
|
||||
return
|
||||
energies = [c for c in top if is_energy_card(c)]
|
||||
picks = await ctx.choose_cards(
|
||||
energies, max(len(energies), 1), minimum=0,
|
||||
prompt="Choose Energy cards to attach to this Pokémon.",
|
||||
display_cards=top,
|
||||
)
|
||||
for card in picks:
|
||||
await ctx.attach_energy(card, ctx.attacker)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="81227f69-d3c2-58fa-98e1-25ea982eb0ba",
|
||||
@@ -23,14 +42,14 @@ card = PokemonCardDef(
|
||||
title="Horoscope",
|
||||
game_text="Look at the top 3 cards of your deck. You may attach any number of Energy cards you find there to this Pok\u00e9mon. Put the other cards back in any order.",
|
||||
cost={PokemonTypes.PSYCHIC: 1},
|
||||
effect=unimplemented,
|
||||
effect=horoscope,
|
||||
),
|
||||
Attack(
|
||||
title="Teleportation Burst",
|
||||
game_text="Switch this Pok\u00e9mon with 1 of your Benched Pok\u00e9mon.",
|
||||
cost={PokemonTypes.PSYCHIC: 1, PokemonTypes.COLORLESS: 2},
|
||||
damage=80,
|
||||
effect=unimplemented,
|
||||
effect=switch_self_attack(damage=80, optional=False),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import recoil_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="889fffbc-c90f-5f38-8e62-a2c1a40e0268",
|
||||
@@ -29,7 +30,7 @@ card = PokemonCardDef(
|
||||
game_text="This Pok\u00e9mon also does 50 damage to itself.",
|
||||
cost={PokemonTypes.LIGHTNING: 1, PokemonTypes.COLORLESS: 2},
|
||||
damage=150,
|
||||
effect=unimplemented,
|
||||
effect=recoil_attack(50),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,6 +1,13 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
|
||||
|
||||
async def assault_gate(ctx):
|
||||
"""If this Pokemon didn't move Bench->Active this turn, this attack does nothing; damage ignores Weakness."""
|
||||
if not ctx.entered_active_this_turn(ctx.attacker):
|
||||
return
|
||||
await ctx.deal_damage(ignore_weakness=True)
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="27413188-f69d-55ba-ab2b-4f72c7337aa1",
|
||||
key="CZ",
|
||||
@@ -20,10 +27,10 @@ card = PokemonCardDef(
|
||||
abilities=[
|
||||
Attack(
|
||||
title="Assault Gate",
|
||||
game_text="If this Pok\u00e9mon didn't move from the Bench to the Active Spot this turn, this attack does nothing. This attack's damage isn't affected by Weakness.",
|
||||
game_text="If this Pokémon didn't move from the Bench to the Active Spot this turn, this attack does nothing. This attack's damage isn't affected by Weakness.",
|
||||
cost={PokemonTypes.DARKNESS: 1},
|
||||
damage=90,
|
||||
effect=unimplemented,
|
||||
effect=assault_gate,
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.card_effects.trainers import hop
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
|
||||
card = SupporterCardDef(
|
||||
@@ -11,5 +12,5 @@ card = SupporterCardDef(
|
||||
collector_number=133,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.RareHolo,
|
||||
effect=unimplemented
|
||||
effect=hop
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, SpecialConditions
|
||||
from spirit.game.card_effects.attacks_common import condition_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="cd07c0d1-fd80-5ebe-bbea-12232fa13f95",
|
||||
@@ -23,7 +24,7 @@ card = PokemonCardDef(
|
||||
game_text="Your opponent's Active Pok\u00e9mon is now Poisoned.",
|
||||
cost={PokemonTypes.DARKNESS: 1, PokemonTypes.COLORLESS: 1},
|
||||
damage=20,
|
||||
effect=unimplemented,
|
||||
effect=condition_attack(SpecialConditions.POISONED),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_bonus
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="134d56d1-fa37-5ec6-a7bf-441abd394007",
|
||||
@@ -24,7 +25,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.GRASS: 1},
|
||||
damage=10,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=flip_bonus(20),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import mill_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="335d48e9-4d6e-52be-aaa4-19ca779b2fbd",
|
||||
@@ -28,7 +29,7 @@ card = PokemonCardDef(
|
||||
title="Dredge Up",
|
||||
game_text="Discard the top 3 cards of your opponent's deck.",
|
||||
cost={PokemonTypes.COLORLESS: 3},
|
||||
effect=unimplemented,
|
||||
effect=mill_attack(3),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import snipe_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="4403b192-7c0c-5597-a32d-56a4686d0b6b",
|
||||
@@ -22,14 +23,14 @@ card = PokemonCardDef(
|
||||
title="Dual Splash",
|
||||
game_text="This attack does 50 damage to 2 of your opponent's Pok\u00e9mon. (Don't apply Weakness and Resistance for Benched Pok\u00e9mon.)",
|
||||
cost={PokemonTypes.WATER: 1, PokemonTypes.COLORLESS: 2},
|
||||
effect=unimplemented,
|
||||
effect=snipe_attack(50, pool="any", count=2, side="opponent"),
|
||||
),
|
||||
Attack(
|
||||
title="Aqua Typhoon",
|
||||
game_text="During your next turn, this Pok\u00e9mon can't use Aqua Typhoon.",
|
||||
cost={PokemonTypes.WATER: 1, PokemonTypes.COLORLESS: 3},
|
||||
damage=210,
|
||||
effect=unimplemented,
|
||||
locks_next_turn=True,
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,28 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.pokemon import energy_provides_type
|
||||
from spirit.game.card_effects.support_common import search_attach_energy
|
||||
|
||||
|
||||
def _is_water_energy(card):
|
||||
return energy_provides_type(card, PokemonTypes.WATER.value)
|
||||
|
||||
|
||||
async def dynamic_wave(ctx):
|
||||
"""Put 3 Energy attached to this Pokemon into hand; 180 to 1 of opponent's Pokemon."""
|
||||
attached = ctx.attached_energies(ctx.attacker)
|
||||
if attached:
|
||||
picks = await ctx.choose_cards(
|
||||
attached, 3,
|
||||
prompt="Choose 3 Energy attached to this Pokémon to put into your hand",
|
||||
)
|
||||
await ctx.put_in_hand(picks, reveal=False)
|
||||
target = await ctx.choose_pokemon(
|
||||
ctx.opponent_pokemon_in_play(), "Choose 1 of your opponent's Pokémon"
|
||||
)
|
||||
if target is not None:
|
||||
await ctx.deal_damage(180, target=target)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="32672775-3b7e-5d18-a914-d5eaced8cdc9",
|
||||
@@ -22,13 +45,13 @@ card = PokemonCardDef(
|
||||
title="Wave Summoning",
|
||||
game_text="Search your deck for a Water Energy card and attach it to this Pok\u00e9mon. Then, shuffle your deck.",
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
effect=unimplemented,
|
||||
effect=search_attach_energy(predicate=_is_water_energy, count=1, to_self=True),
|
||||
),
|
||||
Attack(
|
||||
title="Dynamic Wave",
|
||||
game_text="Put 3 Energy attached to this Pok\u00e9mon into your hand. This attack does 180 damage to 1 of your opponent's Pok\u00e9mon. (Don't apply Weakness and Resistance for Benched Pok\u00e9mon.)",
|
||||
cost={PokemonTypes.WATER: 3, PokemonTypes.COLORLESS: 1},
|
||||
effect=unimplemented,
|
||||
effect=dynamic_wave,
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,6 +1,15 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
|
||||
|
||||
async def wreak_havoc(ctx):
|
||||
"""80. Flip a coin until tails; discard opponent's top deck card per heads."""
|
||||
await ctx.deal_damage()
|
||||
heads = await ctx.flip_until_tails(ctx.ability.title)
|
||||
if heads:
|
||||
await ctx.discard_cards(ctx.deck_top(heads, player_id=ctx.opponent_id))
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="76a0f9a8-6eea-5977-87ed-453818144afb",
|
||||
key="CZ",
|
||||
@@ -30,7 +39,7 @@ card = PokemonCardDef(
|
||||
game_text="Flip a coin until you get tails. For each heads, discard the top card of your opponent's deck.",
|
||||
cost={PokemonTypes.METAL: 2, PokemonTypes.COLORLESS: 2},
|
||||
damage=80,
|
||||
effect=unimplemented,
|
||||
effect=wreak_havoc,
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,38 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.passives_common import TakesLessPassive
|
||||
|
||||
|
||||
def _ivy_star_condition(board, player_id, pokemon):
|
||||
opponent_id = next(p for p in board.player_ids if p != player_id)
|
||||
bench = board.find_player_area(opponent_id, "bench")
|
||||
return bool(board.active_pokemon(opponent_id)) and bool(bench and bench.children)
|
||||
|
||||
|
||||
async def ivy_star(ctx):
|
||||
"""You may switch 1 of your opponent's Benched Pokémon with their Active
|
||||
Pokémon."""
|
||||
opp_active = ctx.opponent_active()
|
||||
opp_bench = ctx.opponent_bench()
|
||||
if opp_active is None or not opp_bench or ctx.effects_blocked(opp_active):
|
||||
return
|
||||
if not await ctx.ask_yes_no(
|
||||
"Switch 1 of your opponent's Benched Pokémon with their Active Pokémon?"
|
||||
):
|
||||
return
|
||||
target = await ctx.choose_pokemon(
|
||||
opp_bench, "Choose the opponent's new Active Pokémon"
|
||||
)
|
||||
if target is not None:
|
||||
await ctx.switch_active(ctx.opponent_id, target)
|
||||
|
||||
|
||||
async def leaf_guard(ctx):
|
||||
"""180. During your opponent's next turn, this Pokémon takes 30 less
|
||||
damage from attacks (after applying Weakness and Resistance)."""
|
||||
await ctx.deal_damage()
|
||||
ctx.add_passive_through_opponents_turn(ctx.attacker, TakesLessPassive(30))
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="1c418037-55c4-561c-b98b-acb0a20099c0",
|
||||
@@ -22,14 +55,16 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Ivy Star",
|
||||
game_text="During your turn, you may switch 1 of your opponent's Benched Pok\u00e9mon with their Active Pok\u00e9mon. (You can't use more than 1 VSTAR Power in a game.)",
|
||||
effect=unimplemented,
|
||||
vstar=True,
|
||||
condition=_ivy_star_condition,
|
||||
effect=ivy_star,
|
||||
),
|
||||
Attack(
|
||||
title="Leaf Guard",
|
||||
game_text="During your opponent's next turn, this Pok\u00e9mon takes 30 less damage from attacks (after applying Weakness and Resistance).",
|
||||
cost={PokemonTypes.GRASS: 2, PokemonTypes.COLORLESS: 1},
|
||||
damage=180,
|
||||
effect=unimplemented,
|
||||
effect=leaf_guard,
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,14 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.passives_common import TakesLessPassive
|
||||
|
||||
|
||||
async def leaf_guard(ctx):
|
||||
"""30. During your opponent's next turn, this Pokémon takes 30 less
|
||||
damage from attacks (after applying Weakness and Resistance)."""
|
||||
await ctx.deal_damage()
|
||||
ctx.add_passive_through_opponents_turn(ctx.attacker, TakesLessPassive(30))
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="af49d502-c4b6-5599-bde4-b5c95992105a",
|
||||
@@ -23,14 +32,14 @@ card = PokemonCardDef(
|
||||
game_text="During your opponent's next turn, this Pok\u00e9mon takes 30 less damage from attacks (after applying Weakness and Resistance).",
|
||||
cost={PokemonTypes.GRASS: 1},
|
||||
damage=30,
|
||||
effect=unimplemented,
|
||||
effect=leaf_guard,
|
||||
),
|
||||
Attack(
|
||||
title="Slashing Strike",
|
||||
game_text="During your next turn, this Pok\u00e9mon can't use Slashing Strike.",
|
||||
cost={PokemonTypes.GRASS: 2, PokemonTypes.COLORLESS: 1},
|
||||
damage=180,
|
||||
effect=unimplemented,
|
||||
locks_next_turn=True,
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,16 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.session.passives import TurnDamageModifier
|
||||
|
||||
|
||||
async def leon_effect(ctx):
|
||||
"""This turn, your Pokemon's attacks do 30 more damage to the opponent's Active (before W/R)."""
|
||||
ctx.add_turn_damage_modifier(TurnDamageModifier(30, ctx.player_id))
|
||||
for pokemon in ctx.my_pokemon_in_play():
|
||||
await ctx.add_stat_visualization(
|
||||
pokemon, "Positive", "DamageDealtIncreased", card_text="+30 damage"
|
||||
)
|
||||
|
||||
|
||||
card = SupporterCardDef(
|
||||
guid="f8fa0778-c5f3-5966-a0f2-e8aa20803a1e",
|
||||
@@ -11,5 +22,5 @@ card = SupporterCardDef(
|
||||
collector_number=134,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.RareHolo,
|
||||
effect=unimplemented
|
||||
effect=leon_effect
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_damage
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="2e9bf2ed-ca51-5c17-8f91-a9057b71cedb",
|
||||
@@ -25,7 +26,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.COLORLESS: 2},
|
||||
damage=40,
|
||||
damage_operator="x",
|
||||
effect=unimplemented,
|
||||
effect=flip_damage(coins=3, per_heads=40),
|
||||
),
|
||||
Attack(
|
||||
title="Claw Slash",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from spirit.game.data_utils import ItemCardDef, unimplemented
|
||||
from spirit.game.card_effects.trainers import lost_vacuum, lost_vacuum_playable
|
||||
from spirit.game.data_utils import ItemCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
|
||||
card = ItemCardDef(
|
||||
@@ -11,5 +12,6 @@ card = ItemCardDef(
|
||||
collector_number=135,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Uncommon,
|
||||
effect=unimplemented
|
||||
effect=lost_vacuum,
|
||||
condition=lost_vacuum_playable
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.pokemon import read_the_wind
|
||||
from spirit.game.card_effects.attacks_common import damage_per, count_energy
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="2629a956-6b0c-58b5-a372-91927fa03c96",
|
||||
@@ -23,7 +25,7 @@ card = PokemonCardDef(
|
||||
title="Cycle Draw",
|
||||
game_text="Discard a card from your hand. If you do, draw 3 cards.",
|
||||
cost={PokemonTypes.PSYCHIC: 1},
|
||||
effect=unimplemented,
|
||||
effect=read_the_wind,
|
||||
),
|
||||
Attack(
|
||||
title="Moon Kinesis",
|
||||
@@ -31,7 +33,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.COLORLESS: 3},
|
||||
damage=30,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=damage_per(count_energy("self", energy_type=PokemonTypes.PSYCHIC.value), 30),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,6 +1,13 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
|
||||
|
||||
async def emotional_draw(ctx):
|
||||
"""Shuffle your hand into your deck. Then, draw 5 cards."""
|
||||
await ctx.shuffle_into_deck(ctx.hand(), ctx.player_id)
|
||||
await ctx.draw_cards(5)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="0367b96d-ec56-5b5f-96f8-e5ee7689be85",
|
||||
key="CZ",
|
||||
@@ -22,7 +29,7 @@ card = PokemonCardDef(
|
||||
title="Emotional Draw",
|
||||
game_text="Shuffle your hand into your deck. Then, draw 5 cards.",
|
||||
cost={PokemonTypes.WATER: 1},
|
||||
effect=unimplemented,
|
||||
effect=emotional_draw,
|
||||
),
|
||||
Attack(
|
||||
title="Tackle",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import snipe_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="affeecef-93e0-5191-bdf3-abec1ff30a6e",
|
||||
@@ -23,7 +24,7 @@ card = PokemonCardDef(
|
||||
title="Jumping Kick",
|
||||
game_text="This attack does 30 damage to 1 of your opponent's Pok\u00e9mon. (Don't apply Weakness and Resistance for Benched Pok\u00e9mon.)",
|
||||
cost={PokemonTypes.LIGHTNING: 1},
|
||||
effect=unimplemented,
|
||||
effect=snipe_attack(30, pool="any", count=1),
|
||||
),
|
||||
Attack(
|
||||
title="Head Bolt",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import has_tool
|
||||
|
||||
|
||||
async def shorting_spark(ctx):
|
||||
"""90 to each opponent Pokemon with a Pokemon Tool attached (Bench takes no W/R)."""
|
||||
active = ctx.opponent_active()
|
||||
for target in ctx.opponent_pokemon_in_play():
|
||||
if has_tool(target):
|
||||
await ctx.deal_damage(90, target=target, apply_modifiers=target is active)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="323885a3-01bb-580d-98ad-49079cb9379f",
|
||||
@@ -23,7 +33,7 @@ card = PokemonCardDef(
|
||||
title="Shorting Spark",
|
||||
game_text="This attack does 90 damage to each of your opponent's Pok\u00e9mon that has a Pok\u00e9mon Tool attached. (Don't apply Weakness and Resistance for Benched Pok\u00e9mon.)",
|
||||
cost={PokemonTypes.LIGHTNING: 1},
|
||||
effect=unimplemented,
|
||||
effect=shorting_spark,
|
||||
),
|
||||
Attack(
|
||||
title="Bite",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import snipe_attack, bonus_if, has_damage
|
||||
|
||||
|
||||
async def _switch_self(ctx):
|
||||
bench = ctx.my_bench()
|
||||
if not bench:
|
||||
return
|
||||
target = await ctx.choose_pokemon(bench, "Choose your new Active Pokémon")
|
||||
if target is not None:
|
||||
await ctx.switch_active(ctx.player_id, target)
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="8b0a6d3e-8365-5861-85de-47ec0ed75b5f",
|
||||
@@ -21,17 +31,17 @@ card = PokemonCardDef(
|
||||
abilities=[
|
||||
Attack(
|
||||
title="Electrostep",
|
||||
game_text="This attack does 40 damage to 1 of your opponent's Pok\u00e9mon. (Don't apply Weakness and Resistance for Benched Pok\u00e9mon.) Switch this Pok\u00e9mon with 1 of your Benched Pok\u00e9mon.",
|
||||
game_text="This attack does 40 damage to 1 of your opponent's Pokémon. (Don't apply Weakness and Resistance for Benched Pokémon.) Switch this Pokémon with 1 of your Benched Pokémon.",
|
||||
cost={PokemonTypes.LIGHTNING: 1},
|
||||
effect=unimplemented,
|
||||
effect=snipe_attack(40, pool="any", count=1, also=_switch_self),
|
||||
),
|
||||
Attack(
|
||||
title="Scar Strikes",
|
||||
game_text="If your opponent's Active Pok\u00e9mon already has any damage counters on it, this attack does 100 more damage.",
|
||||
game_text="If your opponent's Active Pokémon already has any damage counters on it, this attack does 100 more damage.",
|
||||
cost={PokemonTypes.LIGHTNING: 1, PokemonTypes.COLORLESS: 1},
|
||||
damage=100,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=bonus_if(has_damage("defender"), 100),
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.support_common import search_to_hand
|
||||
from spirit.game.session.effects import is_trainer_card
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="ef8ca3ef-7c49-55f9-8a3b-0bf871f8e524",
|
||||
@@ -18,18 +20,21 @@ card = PokemonCardDef(
|
||||
weakness_type=PokemonTypes.FIGHTING,
|
||||
evolves_from="com.direwolfdigital.cake.data.archetypes.pokemon.Luxio.Name",
|
||||
family_id=403,
|
||||
setup_as_active=True,
|
||||
abilities=[
|
||||
Ability(
|
||||
title="Explosiveness",
|
||||
game_text="If this Pok\u00e9mon is in your hand when you are setting up to play, you may put it face down as your Active Pok\u00e9mon.",
|
||||
effect=unimplemented,
|
||||
),
|
||||
Attack(
|
||||
title="Seeking Fang",
|
||||
game_text="Search your deck for up to 2 Trainer cards, reveal them, and put them into your hand. Then, shuffle your deck.",
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
damage=50,
|
||||
effect=unimplemented,
|
||||
effect=search_to_hand(
|
||||
is_trainer_card, count=2, minimum=0,
|
||||
prompt="Choose up to 2 Trainer cards to put into your hand.",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import damage_per, count_energy
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="e9a82ef0-4501-5963-a606-5cbc18edaff7",
|
||||
@@ -25,7 +26,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.FIGHTING: 1, PokemonTypes.COLORLESS: 1},
|
||||
damage=240,
|
||||
damage_operator="-",
|
||||
effect=unimplemented,
|
||||
effect=damage_per(count_energy(scope="defender"), per=-80, base=240),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_damage
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="dab72893-000a-5cf9-ae14-fe1a2ce534ff",
|
||||
@@ -26,7 +27,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.METAL: 1, PokemonTypes.COLORLESS: 1},
|
||||
damage=30,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=flip_damage(coins=2, bonus_per_heads=30),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,4 +1,5 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.card_effects.pokemon import energy_mix, psychic_leap
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
|
||||
card = PokemonCardDef(
|
||||
@@ -23,14 +24,14 @@ card = PokemonCardDef(
|
||||
title="Energy Mix",
|
||||
game_text="Search your deck for an Energy card and attach it to 1 of your Fusion Strike Pok\u00e9mon. Then, shuffle your deck.",
|
||||
cost={PokemonTypes.PSYCHIC: 1},
|
||||
effect=unimplemented,
|
||||
effect=energy_mix,
|
||||
),
|
||||
Attack(
|
||||
title="Psychic Leap",
|
||||
game_text="You may shuffle this Pok\u00e9mon and all attached cards into your deck.",
|
||||
cost={PokemonTypes.PSYCHIC: 1, PokemonTypes.COLORLESS: 1},
|
||||
damage=70,
|
||||
effect=unimplemented,
|
||||
effect=psychic_leap,
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,12 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import bonus_if, opponent_prizes_taken_at_least
|
||||
from spirit.game.card_effects.pokemon import energy_provides_type
|
||||
from spirit.game.card_effects.support_common import attach_from_discard
|
||||
|
||||
|
||||
def _is_psychic_energy(card):
|
||||
return energy_provides_type(card, PokemonTypes.PSYCHIC.value)
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="2577cc87-9e1b-5938-89f6-4dc23574caf9",
|
||||
@@ -23,7 +30,10 @@ card = PokemonCardDef(
|
||||
title="Psypump",
|
||||
game_text="Attach up to 2 Psychic Energy cards from your discard pile to 1 of your Pok\u00e9mon.",
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
effect=unimplemented,
|
||||
effect=attach_from_discard(
|
||||
predicate=_is_psychic_energy, count=2, target="choice", minimum=0,
|
||||
prompt="Choose up to 2 Psychic Energy cards from your discard pile to attach.",
|
||||
),
|
||||
),
|
||||
Attack(
|
||||
title="Limit Break",
|
||||
@@ -31,7 +41,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.PSYCHIC: 2, PokemonTypes.COLORLESS: 1},
|
||||
damage=90,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=bonus_if(opponent_prizes_taken_at_least(3), 90),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,17 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import PokemonTypes, Rarities, AttrID
|
||||
from spirit.game.card_effects.support_common import recover_from_discard, requires_discard, is_energy
|
||||
from spirit.game.session.effects import is_water_pokemon
|
||||
|
||||
|
||||
def is_water_energy_card(card) -> bool:
|
||||
types = card.get_attribute(AttrID.POKEMON_TYPES) or []
|
||||
return is_energy(card) and PokemonTypes.WATER.value in types
|
||||
|
||||
|
||||
def _nessa_predicate(card) -> bool:
|
||||
return is_water_pokemon(card) or is_water_energy_card(card)
|
||||
|
||||
|
||||
card = SupporterCardDef(
|
||||
guid="910d43ac-a842-55d1-81b5-f09de43ee5d8",
|
||||
@@ -11,5 +23,9 @@ card = SupporterCardDef(
|
||||
collector_number=136,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.RareHolo,
|
||||
effect=unimplemented
|
||||
effect=recover_from_discard(
|
||||
_nessa_predicate, count=4, minimum=1, reveal=False, to="hand",
|
||||
prompt="Choose up to 4 Water Pokémon and Water Energy cards",
|
||||
),
|
||||
condition=requires_discard(_nessa_predicate),
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_damage
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="fdac5939-1fcb-51c2-844a-581984efe448",
|
||||
@@ -24,7 +25,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
damage=10,
|
||||
damage_operator="x",
|
||||
effect=unimplemented,
|
||||
effect=flip_damage(coins=2, per_heads=10),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,36 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, TRAINER_EFFECTS_BY_GUID, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.session.effects import is_supporter_card
|
||||
|
||||
|
||||
def _runnable_supporter(card):
|
||||
if not is_supporter_card(card):
|
||||
return False
|
||||
effect = TRAINER_EFFECTS_BY_GUID.get((card.archetype_id or "").lower())
|
||||
return effect is not None and effect is not unimplemented
|
||||
|
||||
|
||||
def _primate_acting_condition(board, player_id, pokemon):
|
||||
opponent_id = next(p for p in board.player_ids if p != player_id)
|
||||
discard = board.find_player_area(opponent_id, "discard")
|
||||
return bool(discard) and any(_runnable_supporter(c) for c in discard.children)
|
||||
|
||||
|
||||
async def primate_acting(ctx):
|
||||
"""Choose a Supporter card from the opponent's discard pile and use its
|
||||
effect as the effect of this attack."""
|
||||
candidates = [c for c in ctx.discard_pile(ctx.opponent_id) if _runnable_supporter(c)]
|
||||
if not candidates:
|
||||
return
|
||||
picked = await ctx.choose_cards(
|
||||
candidates, 1, minimum=1,
|
||||
prompt="Choose a Supporter card from your opponent's discard pile",
|
||||
)
|
||||
if not picked:
|
||||
return
|
||||
effect = TRAINER_EFFECTS_BY_GUID[(picked[0].archetype_id or "").lower()]
|
||||
await effect(ctx)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="eafa4d0e-eb5e-5eea-a370-7b74de785952",
|
||||
@@ -22,7 +53,8 @@ card = PokemonCardDef(
|
||||
title="Primate Acting",
|
||||
game_text="Choose a Supporter card from your opponent's discard pile and use the effect of that card as the effect of this attack.",
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
effect=unimplemented,
|
||||
condition=_primate_acting_condition,
|
||||
effect=primate_acting,
|
||||
),
|
||||
Attack(
|
||||
title="Hammer In",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import recoil_attack
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="4ceae16b-44a9-5072-adaa-0b1ed27fef8a",
|
||||
@@ -29,7 +30,7 @@ card = PokemonCardDef(
|
||||
game_text="This Pok\u00e9mon also does 30 damage to itself.",
|
||||
cost={PokemonTypes.DARKNESS: 2, PokemonTypes.COLORLESS: 1},
|
||||
damage=160,
|
||||
effect=unimplemented,
|
||||
effect=recoil_attack(30),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,4 +1,5 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.card_effects.attacks_common import recoil_attack
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
|
||||
card = PokemonCardDef(
|
||||
@@ -21,10 +22,10 @@ card = PokemonCardDef(
|
||||
abilities=[
|
||||
Attack(
|
||||
title="Reckless Charge",
|
||||
game_text="This Pok\u00e9mon also does 10 damage to itself.",
|
||||
game_text="This Pokémon also does 10 damage to itself.",
|
||||
cost={PokemonTypes.METAL: 1},
|
||||
damage=30,
|
||||
effect=unimplemented,
|
||||
effect=recoil_attack(10),
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.card_effects.attacks_common import recoil_attack
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
|
||||
card = PokemonCardDef(
|
||||
@@ -20,10 +21,10 @@ card = PokemonCardDef(
|
||||
abilities=[
|
||||
Attack(
|
||||
title="Wild Charge",
|
||||
game_text="This Pok\u00e9mon also does 30 damage to itself.",
|
||||
game_text="This Pokémon also does 30 damage to itself.",
|
||||
cost={PokemonTypes.LIGHTNING: 2, PokemonTypes.COLORLESS: 1},
|
||||
damage=90,
|
||||
effect=unimplemented,
|
||||
effect=recoil_attack(30),
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_damage
|
||||
from spirit.game.card_effects.support_common import search_to_bench
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="715f3cd8-7b81-5d2b-9884-283de7d5c1a3",
|
||||
@@ -22,7 +24,7 @@ card = PokemonCardDef(
|
||||
title="Call for Family",
|
||||
game_text="Search your deck for up to 2 Basic Pok\u00e9mon and put them onto your Bench. Then, shuffle your deck.",
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
effect=unimplemented,
|
||||
effect=search_to_bench(count=2),
|
||||
),
|
||||
Attack(
|
||||
title="Continuous Tumble",
|
||||
@@ -30,7 +32,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.LIGHTNING: 1, PokemonTypes.COLORLESS: 1},
|
||||
damage=30,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=flip_damage(until_tails=True, bonus_per_heads=30),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,15 +1,29 @@
|
||||
from spirit.game.data_utils import ItemCardDef, unimplemented
|
||||
from spirit.game.data_utils import ItemCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.session.effects import is_pokemon_card
|
||||
|
||||
|
||||
async def poke_ball(ctx):
|
||||
"""Flip a coin. If heads, search the deck for a Pokemon, reveal it, and
|
||||
put it into your hand. Then, shuffle your deck."""
|
||||
if (await ctx.flip_coins(1, "Poké Ball"))[0]:
|
||||
picks = await ctx.search_deck(
|
||||
is_pokemon_card, count=1, minimum=0,
|
||||
prompt="Choose a Pokémon to put into your hand.",
|
||||
)
|
||||
await ctx.put_in_hand(picks, reveal=True)
|
||||
await ctx.shuffle_deck()
|
||||
|
||||
|
||||
card = ItemCardDef(
|
||||
guid="d4644be3-57c5-546d-aeec-4cb076dd48ed",
|
||||
key="CZ",
|
||||
name="com.direwolfdigital.cake.data.archetypes.trainer.PokBall.Name",
|
||||
display_name="Poké Ball",
|
||||
searchable_by=["Pok\u00c3\u00a9 Ball", "Item"],
|
||||
searchable_by=["Poké Ball", "Item"],
|
||||
subtypes=["Item"],
|
||||
collector_number=137,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Common,
|
||||
effect=unimplemented
|
||||
effect=poke_ball
|
||||
)
|
||||
|
||||
@@ -1,15 +1,33 @@
|
||||
from spirit.game.data_utils import ItemCardDef, unimplemented
|
||||
from spirit.game.data_utils import ItemCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.card_effects.trainers import opponent_has_bench
|
||||
|
||||
|
||||
async def pokemon_catcher(ctx):
|
||||
"""Flip a coin. If heads, switch 1 of the opponent's Benched Pokemon
|
||||
with their Active Pokemon."""
|
||||
if not (await ctx.flip_coins(1, "Pokémon Catcher"))[0]:
|
||||
return
|
||||
bench = ctx.opponent_bench()
|
||||
if not bench:
|
||||
return
|
||||
target = await ctx.choose_pokemon(
|
||||
bench, "Choose your opponent's new Active Pokémon"
|
||||
)
|
||||
if target is not None:
|
||||
await ctx.switch_active(ctx.opponent_id, target)
|
||||
|
||||
|
||||
card = ItemCardDef(
|
||||
guid="14cbcefb-fac6-56ca-8a73-9d93e81c7699",
|
||||
key="CZ",
|
||||
name="com.direwolfdigital.cake.data.archetypes.trainer.PokmonCatcher.Name",
|
||||
display_name="Pokémon Catcher",
|
||||
searchable_by=["Pok\u00c3\u00a9mon Catcher", "Item"],
|
||||
searchable_by=["Pokémon Catcher", "Item"],
|
||||
subtypes=["Item"],
|
||||
collector_number=138,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Uncommon,
|
||||
effect=unimplemented
|
||||
effect=pokemon_catcher,
|
||||
condition=opponent_has_bench
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import ItemCardDef, unimplemented
|
||||
from spirit.game.data_utils import ItemCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.card_effects.support_common import heal_item, requires_damaged_pokemon
|
||||
|
||||
card = ItemCardDef(
|
||||
guid="0673acf4-d7f4-52c1-87cd-67e9eda9f4e1",
|
||||
@@ -11,5 +12,6 @@ card = ItemCardDef(
|
||||
collector_number=139,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Common,
|
||||
effect=unimplemented
|
||||
condition=requires_damaged_pokemon(),
|
||||
effect=heal_item(30)
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.card_effects.trainers import professors_research
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
|
||||
card = SupporterCardDef(
|
||||
@@ -11,5 +12,5 @@ card = SupporterCardDef(
|
||||
collector_number=150,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.RareUltra,
|
||||
effect=unimplemented
|
||||
effect=professors_research
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import flip_damage
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="5b63994a-3cb9-56f4-85d5-cb399a8373b6",
|
||||
@@ -24,7 +25,7 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
damage=10,
|
||||
damage_operator="x",
|
||||
effect=unimplemented,
|
||||
effect=flip_damage(coins=3, per_heads=10),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,4 +1,5 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.card_effects.pokemon import ExcitedHeartPassive
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
|
||||
card = PokemonCardDef(
|
||||
@@ -20,15 +21,15 @@ card = PokemonCardDef(
|
||||
abilities=[
|
||||
Ability(
|
||||
title="Excited Heart",
|
||||
game_text="This Pok\u00e9mon's attacks cost Colorless less for each Prize card your opponent has taken.",
|
||||
effect=unimplemented,
|
||||
game_text="This Pokémon's attacks cost Colorless less for each Prize card your opponent has taken.",
|
||||
passive=ExcitedHeartPassive(),
|
||||
),
|
||||
Attack(
|
||||
title="Combustion Blast",
|
||||
game_text="During your next turn, this Pok\u00e9mon can't use Combustion Blast.",
|
||||
game_text="During your next turn, this Pokémon can't use Combustion Blast.",
|
||||
cost={PokemonTypes.FIRE: 1, PokemonTypes.COLORLESS: 4},
|
||||
damage=250,
|
||||
effect=unimplemented,
|
||||
locks_next_turn=True,
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, Triggers, is_pokemon_v
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import snipe_attack
|
||||
|
||||
|
||||
async def shocking_block(ctx):
|
||||
"""Whenever any player attaches an Energy from hand to their Pokemon V, put 2 damage counters on it."""
|
||||
receiver = ctx.energy_receiver
|
||||
if receiver is None or not is_pokemon_v(receiver.archetype_id):
|
||||
return
|
||||
await ctx.deal_damage(20, target=receiver, apply_modifiers=False, as_counters=True)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="b6f25036-ac03-5190-ba5e-f4f448c4528c",
|
||||
@@ -21,13 +31,14 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Shocking Block",
|
||||
game_text="Whenever any player attaches an Energy card from their hand to 1 of their Pok\u00e9mon V, put 2 damage counters on that Pok\u00e9mon.",
|
||||
effect=unimplemented,
|
||||
trigger=Triggers.ON_ENERGY_ATTACHED,
|
||||
effect=shocking_block,
|
||||
),
|
||||
Attack(
|
||||
title="Linear Attack",
|
||||
game_text="This attack does 30 damage to 1 of your opponent's Pok\u00e9mon. (Don't apply Weakness and Resistance for Benched Pok\u00e9mon.)",
|
||||
cost={PokemonTypes.LIGHTNING: 1},
|
||||
effect=unimplemented,
|
||||
effect=snipe_attack(30, pool="any", count=1, side="opponent"),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,24 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, Triggers
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.support_common import search_to_bench
|
||||
from spirit.game.card_effects.trainers import is_pokemon_vmax
|
||||
from spirit.game.session.effects import is_pokemon_card
|
||||
|
||||
|
||||
def _is_vmax(card):
|
||||
return is_pokemon_card(card) and is_pokemon_vmax(card.archetype_id)
|
||||
|
||||
|
||||
async def climactic_gate(ctx):
|
||||
"""You may search up to 2 Pokemon VMAX to the Bench; using it ends the turn."""
|
||||
if not await ctx.ask_yes_no(
|
||||
"Search your deck for up to 2 Pokémon VMAX and put them onto "
|
||||
"your Bench? If you do, your turn ends."
|
||||
):
|
||||
return
|
||||
await search_to_bench(predicate=_is_vmax, count=2)(ctx)
|
||||
ctx.ends_turn = True
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="d799e888-b9fa-5bb8-b022-acc672128675",
|
||||
@@ -20,7 +39,8 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Climactic Gate",
|
||||
game_text="When you play this Pok\u00e9mon from your hand onto your Bench during your turn, you may search your deck for up to 2 Pok\u00e9mon VMAX and put them onto your Bench. Then, shuffle your deck. If you use this Ability, your turn ends.",
|
||||
effect=unimplemented,
|
||||
trigger=Triggers.ON_PLAY,
|
||||
effect=climactic_gate,
|
||||
),
|
||||
Attack(
|
||||
title="Power Beam",
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
from spirit.game.data_utils import SupporterCardDef, unimplemented
|
||||
from spirit.game.data_utils import SupporterCardDef
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.card_effects.support_common import attach_from_discard
|
||||
from spirit.game.card_effects.trainers import is_basic_energy_card
|
||||
|
||||
|
||||
async def _raihan_search(ctx, picks):
|
||||
found = await ctx.search_deck(
|
||||
count=1, minimum=0,
|
||||
prompt="Search your deck for a card and put it into your hand.",
|
||||
)
|
||||
await ctx.put_in_hand(found, reveal=False)
|
||||
await ctx.shuffle_deck()
|
||||
|
||||
|
||||
def _raihan_condition(board, player_id):
|
||||
return bool(board.turn_state.kos_by_attack_last_turn.get(player_id))
|
||||
|
||||
|
||||
card = SupporterCardDef(
|
||||
guid="cc0d13f8-938c-5a84-96d8-e9cc96b22bb1",
|
||||
@@ -11,5 +27,10 @@ card = SupporterCardDef(
|
||||
collector_number=140,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.RareHolo,
|
||||
effect=unimplemented
|
||||
condition=_raihan_condition,
|
||||
effect=attach_from_discard(
|
||||
predicate=is_basic_energy_card, count=1, target="choice",
|
||||
prompt="Attach a basic Energy card from your discard pile to 1 of your Pokémon.",
|
||||
then=_raihan_search,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1,5 +1,50 @@
|
||||
from spirit.game.data_utils import ItemCardDef, unimplemented
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.data_utils import ItemCardDef, evolves_from
|
||||
from spirit.game.attributes import Rarities, AttrID, PokemonStage
|
||||
from spirit.game.session.effects import is_basic_pokemon, is_pokemon_card
|
||||
|
||||
|
||||
def _stage2_matches(hand_cards, logic_name):
|
||||
return [
|
||||
c for c in hand_cards
|
||||
if is_pokemon_card(c)
|
||||
and c.get_attribute(AttrID.STAGE) == PokemonStage.STAGE2.value
|
||||
and evolves_from(c.archetype_id, logic_name)
|
||||
]
|
||||
|
||||
|
||||
def _turn_eligible_basics(board, player_id):
|
||||
turn_state = getattr(board, "turn_state", None)
|
||||
if turn_state is None:
|
||||
return []
|
||||
return [
|
||||
p for p in board.pokemon_in_play(player_id)
|
||||
if is_basic_pokemon(p) and turn_state.may_evolve_target(p.entity_id)
|
||||
]
|
||||
|
||||
|
||||
def _rare_candy_condition(board, player_id):
|
||||
return bool(_turn_eligible_basics(board, player_id))
|
||||
|
||||
|
||||
async def _rare_candy(ctx):
|
||||
"""Choose a Basic Pokemon in play; if you have a Stage 2 in hand that evolves from it, put that card onto it, skipping the Stage 1."""
|
||||
candidates = _turn_eligible_basics(ctx.board, ctx.player_id)
|
||||
if not candidates:
|
||||
return
|
||||
target = await ctx.choose_pokemon(candidates, "Choose a Basic Pokémon in play")
|
||||
if target is None:
|
||||
return
|
||||
logic_name = target.get_attribute(AttrID.EVOLUTION_LOGIC_NAME)
|
||||
stage2_hand = _stage2_matches(ctx.hand(), logic_name) if logic_name else []
|
||||
if not stage2_hand:
|
||||
return
|
||||
picks = await ctx.choose_cards(
|
||||
stage2_hand, 1, prompt="Choose a Stage 2 Pokémon to evolve into",
|
||||
)
|
||||
if not picks:
|
||||
return
|
||||
await ctx.evolve_pokemon(target, picks[0])
|
||||
|
||||
|
||||
card = ItemCardDef(
|
||||
guid="963902d0-48a5-507a-ae11-816234a0cd76",
|
||||
@@ -11,5 +56,6 @@ card = ItemCardDef(
|
||||
collector_number=141,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Uncommon,
|
||||
effect=unimplemented
|
||||
effect=_rare_candy,
|
||||
condition=_rare_candy_condition,
|
||||
)
|
||||
|
||||
@@ -1,5 +1,39 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, Activations
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, AttrID
|
||||
from spirit.game.card_effects.trainers import is_basic_energy_card
|
||||
|
||||
|
||||
async def azure_pulse(ctx):
|
||||
"""Once per turn: you may discard your hand and draw 3 cards."""
|
||||
if not await ctx.ask_yes_no("Discard your hand and draw 3 cards?"):
|
||||
return
|
||||
await ctx.discard_cards(ctx.hand())
|
||||
await ctx.draw_cards(3)
|
||||
|
||||
|
||||
def _is_basic_type(card, type_value):
|
||||
types = card.get_attribute(AttrID.POKEMON_TYPES) or []
|
||||
return is_basic_energy_card(card) and type_value in types
|
||||
|
||||
|
||||
async def max_burst(ctx):
|
||||
"""You may discard any amount of basic Fire or Lightning Energy from
|
||||
this Pokemon; +80 damage for each card discarded this way."""
|
||||
attached = [
|
||||
e for e in ctx.attached_energies(ctx.attacker)
|
||||
if _is_basic_type(e, PokemonTypes.FIRE.value)
|
||||
or _is_basic_type(e, PokemonTypes.LIGHTNING.value)
|
||||
]
|
||||
picks = []
|
||||
if attached:
|
||||
picks = await ctx.choose_cards(
|
||||
attached, len(attached), minimum=0,
|
||||
prompt="Discard any amount of basic Fire or Lightning Energy from this Pokémon.",
|
||||
)
|
||||
if picks:
|
||||
await ctx.discard_cards(picks)
|
||||
await ctx.deal_damage(20 + 80 * len(picks))
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="c902b0f4-1b29-5b8a-a6f5-80d8b80e4639",
|
||||
@@ -21,15 +55,16 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Azure Pulse",
|
||||
game_text="Once during your turn, you may discard your hand and draw 3 cards.",
|
||||
effect=unimplemented,
|
||||
activation=Activations.ONCE_PER_TURN,
|
||||
effect=azure_pulse,
|
||||
),
|
||||
Attack(
|
||||
title="Max Burst",
|
||||
game_text="You may discard any amount of basic Fire Energy or any amount of basic Lightning Energy from this Pok\u00e9mon. This attack does 80 more damage for each card you discarded in this way.",
|
||||
game_text="You may discard any amount of basic Fire Energy or any amount of basic Lightning Energy from this Pokémon. This attack does 80 more damage for each card you discarded in this way.",
|
||||
cost={PokemonTypes.FIRE: 1, PokemonTypes.LIGHTNING: 1},
|
||||
damage=20,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=max_burst,
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,39 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, Activations
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, AttrID
|
||||
from spirit.game.card_effects.trainers import is_basic_energy_card
|
||||
|
||||
|
||||
async def azure_pulse(ctx):
|
||||
"""Once per turn: you may discard your hand and draw 3 cards."""
|
||||
if not await ctx.ask_yes_no("Discard your hand and draw 3 cards?"):
|
||||
return
|
||||
await ctx.discard_cards(ctx.hand())
|
||||
await ctx.draw_cards(3)
|
||||
|
||||
|
||||
def _is_basic_type(card, type_value):
|
||||
types = card.get_attribute(AttrID.POKEMON_TYPES) or []
|
||||
return is_basic_energy_card(card) and type_value in types
|
||||
|
||||
|
||||
async def max_burst(ctx):
|
||||
"""You may discard any amount of basic Fire or Lightning Energy from
|
||||
this Pokemon; +80 damage for each card discarded this way."""
|
||||
attached = [
|
||||
e for e in ctx.attached_energies(ctx.attacker)
|
||||
if _is_basic_type(e, PokemonTypes.FIRE.value)
|
||||
or _is_basic_type(e, PokemonTypes.LIGHTNING.value)
|
||||
]
|
||||
picks = []
|
||||
if attached:
|
||||
picks = await ctx.choose_cards(
|
||||
attached, len(attached), minimum=0,
|
||||
prompt="Discard any amount of basic Fire or Lightning Energy from this Pokémon.",
|
||||
)
|
||||
if picks:
|
||||
await ctx.discard_cards(picks)
|
||||
await ctx.deal_damage(20 + 80 * len(picks))
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="42d2e5b0-e92a-5d96-9e6b-429164987df7",
|
||||
@@ -21,15 +55,16 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Azure Pulse",
|
||||
game_text="Once during your turn, you may discard your hand and draw 3 cards.",
|
||||
effect=unimplemented,
|
||||
activation=Activations.ONCE_PER_TURN,
|
||||
effect=azure_pulse,
|
||||
),
|
||||
Attack(
|
||||
title="Max Burst",
|
||||
game_text="You may discard any amount of basic Fire Energy or any amount of basic Lightning Energy from this Pok\u00e9mon. This attack does 80 more damage for each card you discarded in this way.",
|
||||
game_text="You may discard any amount of basic Fire Energy or any amount of basic Lightning Energy from this Pokémon. This attack does 80 more damage for each card you discarded in this way.",
|
||||
cost={PokemonTypes.FIRE: 1, PokemonTypes.LIGHTNING: 1},
|
||||
damage=20,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=max_burst,
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,40 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import mill_attack
|
||||
from spirit.game.card_effects.trainers import is_basic_energy_card
|
||||
from spirit.game.card_effects.pokemon import energy_provides_type
|
||||
|
||||
|
||||
async def spiral_burst(ctx):
|
||||
"""20, +80 for each basic Fire or basic Lightning Energy discarded from
|
||||
this Pokémon (up to 2 of one type)."""
|
||||
attacker = ctx.attacker
|
||||
attached = ctx.attached_energies(attacker)
|
||||
fire = [c for c in attached if is_basic_energy_card(c)
|
||||
and energy_provides_type(c, PokemonTypes.FIRE.value)]
|
||||
lightning = [c for c in attached if is_basic_energy_card(c)
|
||||
and energy_provides_type(c, PokemonTypes.LIGHTNING.value)]
|
||||
discarded = []
|
||||
if fire and lightning:
|
||||
choice = await ctx.choose(
|
||||
"Choose up to 2 Energy to discard from this Pokémon:",
|
||||
["Basic Fire Energy", "Basic Lightning Energy"],
|
||||
)
|
||||
pool = fire if choice == 0 else lightning
|
||||
discarded = await ctx.choose_cards(
|
||||
pool, min(2, len(pool)), minimum=0,
|
||||
prompt="Choose up to 2 Energy to discard",
|
||||
)
|
||||
elif fire or lightning:
|
||||
pool = fire or lightning
|
||||
discarded = await ctx.choose_cards(
|
||||
pool, min(2, len(pool)), minimum=0,
|
||||
prompt="Choose up to 2 Energy to discard",
|
||||
)
|
||||
if discarded:
|
||||
await ctx.discard_cards(discarded)
|
||||
await ctx.deal_damage(20 + 80 * len(discarded))
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="cab0d1d1-5756-59e7-8693-34e498b89845",
|
||||
@@ -22,15 +57,15 @@ card = PokemonCardDef(
|
||||
game_text="Discard the top 2 cards of your deck.",
|
||||
cost={PokemonTypes.LIGHTNING: 1},
|
||||
damage=40,
|
||||
effect=unimplemented,
|
||||
effect=mill_attack(2, opponent=False),
|
||||
),
|
||||
Attack(
|
||||
title="Spiral Burst",
|
||||
game_text="You may discard up to 2 basic Fire Energy or up to 2 basic Lightning Energy from this Pok\u00e9mon. This attack does 80 more damage for each card you discarded in this way.",
|
||||
game_text="You may discard up to 2 basic Fire Energy or up to 2 basic Lightning Energy from this Pokémon. This attack does 80 more damage for each card you discarded in this way.",
|
||||
cost={PokemonTypes.FIRE: 1, PokemonTypes.LIGHTNING: 1},
|
||||
damage=20,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=spiral_burst,
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,37 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.card_effects.attacks_common import lock_all_attacks
|
||||
from spirit.game.session.effects import full_stack
|
||||
|
||||
|
||||
def _star_guardian_condition(board, player_id, pokemon):
|
||||
opponent_id = next(p for p in board.player_ids if p != player_id)
|
||||
prizes = board.find_player_area(opponent_id, "prizePile")
|
||||
bench = board.find_player_area(opponent_id, "bench")
|
||||
return bool(prizes) and len(prizes.children) == 1 and bool(bench and bench.children)
|
||||
|
||||
|
||||
async def star_guardian(ctx):
|
||||
"""VSTAR Power: if the opponent has exactly 1 Prize left, you may make
|
||||
them discard 1 of their Benched Pokemon and all attached cards."""
|
||||
if not await ctx.ask_yes_no(
|
||||
"Choose 1 of your opponent's Benched Pokémon? They discard that "
|
||||
"Pokémon and all attached cards."
|
||||
):
|
||||
return
|
||||
target = await ctx.choose_pokemon(
|
||||
ctx.opponent_bench(), "Choose 1 of your opponent's Benched Pokémon"
|
||||
)
|
||||
if target is None:
|
||||
return
|
||||
await ctx.discard_cards(full_stack(target))
|
||||
|
||||
|
||||
async def giga_impact(ctx):
|
||||
"""230. During your next turn, this Pokemon can't attack."""
|
||||
await ctx.deal_damage()
|
||||
lock_all_attacks(ctx, ctx.attacker)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="0e4aa482-8295-5b75-b012-daf58cb96397",
|
||||
@@ -22,14 +54,16 @@ card = PokemonCardDef(
|
||||
Ability(
|
||||
title="Star Guardian",
|
||||
game_text="During your turn, if your opponent has exactly 1 Prize card remaining, you may choose 1 of your opponent's Benched Pok\u00e9mon. They discard that Pok\u00e9mon and all attached cards. (You can't use more than 1 VSTAR Power in a game.)",
|
||||
effect=unimplemented,
|
||||
vstar=True,
|
||||
condition=_star_guardian_condition,
|
||||
effect=star_guardian,
|
||||
),
|
||||
Attack(
|
||||
title="Giga Impact",
|
||||
game_text="During your next turn, this Pok\u00e9mon can't attack.",
|
||||
cost={PokemonTypes.COLORLESS: 3},
|
||||
damage=230,
|
||||
effect=unimplemented,
|
||||
effect=giga_impact,
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,11 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities, SpecialConditions
|
||||
from spirit.game.card_effects.attacks_common import damage_per, damage_counters_on
|
||||
|
||||
|
||||
async def _confuse_self(ctx):
|
||||
await ctx.apply_special_condition(ctx.attacker, SpecialConditions.CONFUSED)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="1da3abc5-6669-50ab-bbe9-e80900566bdc",
|
||||
@@ -29,7 +35,8 @@ card = PokemonCardDef(
|
||||
cost={PokemonTypes.COLORLESS: 3},
|
||||
damage=100,
|
||||
damage_operator="+",
|
||||
effect=unimplemented,
|
||||
effect=damage_per(damage_counters_on("self"), 10, base=100,
|
||||
also=_confuse_self),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1,5 +1,12 @@
|
||||
from spirit.game.data_utils import ItemCardDef, unimplemented
|
||||
from spirit.game.attributes import Rarities
|
||||
from spirit.game.data_utils import ItemCardDef
|
||||
from spirit.game.attributes import Rarities, AttrID
|
||||
from spirit.game.session.effects import is_pokemon_card
|
||||
from spirit.game.card_effects.support_common import recover_from_discard, requires_discard
|
||||
|
||||
|
||||
def _low_hp_pokemon(card):
|
||||
return is_pokemon_card(card) and (card.get_attribute(AttrID.HP, 999) or 0) <= 90
|
||||
|
||||
|
||||
card = ItemCardDef(
|
||||
guid="0205ee20-a659-547a-9f16-f0eb96fe47d6",
|
||||
@@ -11,5 +18,9 @@ card = ItemCardDef(
|
||||
collector_number=142,
|
||||
set_code="CZ",
|
||||
rarity=Rarities.Uncommon,
|
||||
effect=unimplemented
|
||||
effect=recover_from_discard(
|
||||
_low_hp_pokemon, count=2, reveal=False,
|
||||
prompt="Put up to 2 Pokémon with 90 HP or less from your discard pile into your hand",
|
||||
),
|
||||
condition=requires_discard(_low_hp_pokemon),
|
||||
)
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability, unimplemented
|
||||
from spirit.game.data_utils import PokemonCardDef, Attack, Ability
|
||||
from spirit.game.attributes import PokemonTypes, PokemonStage, Rarities
|
||||
|
||||
|
||||
async def invite_out(ctx):
|
||||
"""Flip a coin. If heads, switch 1 of your opponent's Benched Pokémon
|
||||
with their Active Pokémon."""
|
||||
heads = (await ctx.flip_coins(1, "Invite Out"))[0]
|
||||
if not heads:
|
||||
return
|
||||
active = ctx.opponent_active()
|
||||
bench = ctx.opponent_bench()
|
||||
if active is None or not bench or ctx.effects_blocked(active):
|
||||
return
|
||||
target = await ctx.choose_pokemon(
|
||||
bench, "Choose the opponent's new Active Pokémon"
|
||||
) or bench[0]
|
||||
await ctx.switch_active(ctx.opponent_id, target)
|
||||
|
||||
|
||||
card = PokemonCardDef(
|
||||
guid="498a4795-0542-573f-96e5-54f951ec5e36",
|
||||
key="CZ",
|
||||
@@ -22,7 +39,7 @@ card = PokemonCardDef(
|
||||
title="Invite Out",
|
||||
game_text="Flip a coin. If heads, switch 1 of your opponent's Benched Pok\u00e9mon with their Active Pok\u00e9mon.",
|
||||
cost={PokemonTypes.COLORLESS: 1},
|
||||
effect=unimplemented,
|
||||
effect=invite_out,
|
||||
),
|
||||
Attack(
|
||||
title="Smash Kick",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user