mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
[REX] Implement Ian Malcolm, Chaotician (#12117)
* Start on Ian Malcolm, Chaotician, missing key effects * fox ANY clause in DrawNthCardTriggeredAbility * Get exile effect working * Start using Evelyn, the Covetous code * align exile effect * align player clause * align card type clause * align counter check clause * align mana clause * add ownership clause * remove redundant comments * fix redundant mana clause description * fix counter clause in mana cost effect * fix active clause in mana effect * use MageObjectReference to associate exiled cards with an Ian Malcolm instance * optimize imports * Start tests, failing currently * fix test and add blink test * fix signature of constructor * fix order of super() call in checkTrigger * clarify hash maps in watcher * use correct AsThoughEffect * document header of checkExile * generalize modal and double faced cards for LKI fetch * remove land played event for watcher * Use custom MageIdentifier to filter usedMap
This commit is contained in:
parent
f8f9b0caa0
commit
40143c648f
5 changed files with 398 additions and 1 deletions
282
Mage.Sets/src/mage/cards/i/IanMalcolmChaotician.java
Normal file
282
Mage.Sets/src/mage/cards/i/IanMalcolmChaotician.java
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
package mage.cards.i;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import mage.MageIdentifier;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.DrawNthCardTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.AsThoughManaEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.*;
|
||||
import mage.constants.*;
|
||||
import mage.game.CardState;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.ManaPoolItem;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
import mage.watchers.Watcher;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimga150
|
||||
*/
|
||||
public final class IanMalcolmChaotician extends CardImpl {
|
||||
|
||||
public IanMalcolmChaotician(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}");
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.SCIENTIST);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// Whenever a player draws their second card each turn, that player exiles the top card of their library.
|
||||
this.addAbility(new IanMalcolmChaoticianDrawTriggerAbility(), new IanMalcolmChaoticianWatcher());
|
||||
|
||||
// During each player's turn, that player may cast a spell from among the cards they don't own exiled with
|
||||
// Ian Malcolm, Chaotician, and mana of any type can be spent to cast it.
|
||||
Ability ability = new SimpleStaticAbility(new IanMalcolmChaoticianCastEffect())
|
||||
.setIdentifier(MageIdentifier.IanMalcolmChaoticianWatcher);
|
||||
ability.addEffect(new IanMalcolmChaoticianManaEffect());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private IanMalcolmChaotician(final IanMalcolmChaotician card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IanMalcolmChaotician copy() {
|
||||
return new IanMalcolmChaotician(this);
|
||||
}
|
||||
}
|
||||
|
||||
class IanMalcolmChaoticianDrawTriggerAbility extends DrawNthCardTriggeredAbility {
|
||||
|
||||
IanMalcolmChaoticianDrawTriggerAbility() {
|
||||
super(new IanMalcolmChaoticianExileEffect(), false, TargetController.ANY, 2);
|
||||
}
|
||||
|
||||
private IanMalcolmChaoticianDrawTriggerAbility(final IanMalcolmChaoticianDrawTriggerAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (super.checkTrigger(event, game)){
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getPlayerId()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IanMalcolmChaoticianDrawTriggerAbility copy() {
|
||||
return new IanMalcolmChaoticianDrawTriggerAbility(this);
|
||||
}
|
||||
}
|
||||
|
||||
class IanMalcolmChaoticianExileEffect extends OneShotEffect {
|
||||
|
||||
IanMalcolmChaoticianExileEffect() {
|
||||
super(Outcome.Exile);
|
||||
staticText = "that player exiles the top card of their library";
|
||||
}
|
||||
|
||||
private IanMalcolmChaoticianExileEffect(final IanMalcolmChaoticianExileEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IanMalcolmChaoticianExileEffect copy() {
|
||||
return new IanMalcolmChaoticianExileEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
UUID targetPlayerID = getTargetPointer().getFirst(game, source);
|
||||
Player targetPlayer = game.getPlayer(targetPlayerID);
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (targetPlayer == null || sourceObject == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Card card = targetPlayer.getLibrary().getFromTop(game);
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UUID exileZoneId = CardUtil.getExileZoneId(game, sourceObject.getId(), sourceObject.getZoneChangeCounter(game));
|
||||
targetPlayer.moveCardsToExile(card, source, game, true, exileZoneId, sourceObject.getIdName());
|
||||
MageObjectReference sourceMOR = new MageObjectReference(source.getSourceId(), game);
|
||||
IanMalcolmChaoticianWatcher.addCard(sourceMOR, card, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class IanMalcolmChaoticianCastEffect extends AsThoughEffectImpl {
|
||||
|
||||
IanMalcolmChaoticianCastEffect() {
|
||||
super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.PlayForFree);
|
||||
staticText = "During each player's turn, that player may cast a spell from among the cards they don't own " +
|
||||
"exiled with {this}";
|
||||
}
|
||||
|
||||
private IanMalcolmChaoticianCastEffect(final IanMalcolmChaoticianCastEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IanMalcolmChaoticianCastEffect copy() {
|
||||
return new IanMalcolmChaoticianCastEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
|
||||
if (!game.isActivePlayer(affectedControllerId) || IanMalcolmChaoticianWatcher.checkUsed(source, game)) {
|
||||
return false;
|
||||
}
|
||||
Card card = game.getCard(CardUtil.getMainCardId(game, sourceId));
|
||||
if (card == null || card.isLand(game)){
|
||||
return false;
|
||||
}
|
||||
MageObjectReference sourceMOR = new MageObjectReference(source.getSourceId(), game);
|
||||
return !card.getOwnerId().equals(affectedControllerId)
|
||||
&& IanMalcolmChaoticianWatcher.checkExile(sourceMOR, card, game, 0);
|
||||
}
|
||||
}
|
||||
|
||||
class IanMalcolmChaoticianManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect {
|
||||
|
||||
IanMalcolmChaoticianManaEffect() {
|
||||
super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||
staticText = ", and mana of any type can be spent to cast it";
|
||||
}
|
||||
|
||||
private IanMalcolmChaoticianManaEffect(final IanMalcolmChaoticianManaEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IanMalcolmChaoticianManaEffect copy() {
|
||||
return new IanMalcolmChaoticianManaEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
|
||||
if (!game.isActivePlayer(affectedControllerId) || IanMalcolmChaoticianWatcher.checkUsed(source, game)) {
|
||||
return false;
|
||||
}
|
||||
MageObjectReference sourceMOR = new MageObjectReference(source.getSourceId(), game);
|
||||
Card card = game.getCard(CardUtil.getMainCardId(game, sourceId));
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
if (game.getState().getZone(card.getId()) == Zone.EXILED) {
|
||||
return IanMalcolmChaoticianWatcher.checkExile(sourceMOR, card, game, 0);
|
||||
}
|
||||
// not exiled, must be on the stack--get LKI
|
||||
CardState cardState = game.getLastKnownInformationCard(card.getMainCard().getId(), Zone.EXILED);;
|
||||
return cardState != null && IanMalcolmChaoticianWatcher.checkExile(sourceMOR, card, game, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) {
|
||||
return mana.getFirstAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
class IanMalcolmChaoticianWatcher extends Watcher {
|
||||
|
||||
// Maps MOR representing the specific instance of Ian Malcolm (changes when it changes zones, i.e. blinked)
|
||||
// to many exiled cards exiled with Ian Malcolm
|
||||
private final Map<MageObjectReference, Set<MageObjectReference>> exiledMap = new HashMap<>();
|
||||
|
||||
// Maps instances of approving MORs (some of which might be instances of Ian Malcolm, if his ability was used to
|
||||
// cast that spell) to UUIDs of players that have used that approving object this turn
|
||||
private final Map<MageObjectReference, Set<UUID>> usedMap = new HashMap<>();
|
||||
|
||||
IanMalcolmChaoticianWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.SPELL_CAST &&
|
||||
event.hasApprovingIdentifier(MageIdentifier.IanMalcolmChaoticianWatcher)) {
|
||||
usedMap.computeIfAbsent(
|
||||
event.getAdditionalReference()
|
||||
.getApprovingMageObjectReference(),
|
||||
x -> new HashSet<>()
|
||||
).add(event.getPlayerId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
usedMap.clear();
|
||||
}
|
||||
|
||||
static void addCard(MageObjectReference sourceObj, Card card, Game game) {
|
||||
Set<MageObjectReference> set = game
|
||||
.getState()
|
||||
.getWatcher(IanMalcolmChaoticianWatcher.class)
|
||||
.exiledMap
|
||||
.computeIfAbsent(sourceObj, x -> new HashSet<>());
|
||||
MageObjectReference mor = new MageObjectReference(card, game);
|
||||
set.add(mor);
|
||||
}
|
||||
|
||||
static boolean checkUsed(Ability source, Game game) {
|
||||
Permanent sourceObject = game.getPermanent(source.getSourceId());
|
||||
if (sourceObject == null) {
|
||||
return true;
|
||||
}
|
||||
return game
|
||||
.getState()
|
||||
.getWatcher(IanMalcolmChaoticianWatcher.class)
|
||||
.usedMap
|
||||
.getOrDefault(
|
||||
new MageObjectReference(sourceObject, game),
|
||||
Collections.emptySet()
|
||||
).contains(source.getControllerId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if card was added to the tracked exiled cards under sourceObj
|
||||
*
|
||||
* @param sourceObj exiling card
|
||||
* @param card exiled card to check
|
||||
* @param game
|
||||
* @param offset zone change counter offset: 0 = in exile, 1 = on the stack waiting to be cast
|
||||
*/
|
||||
static boolean checkExile(MageObjectReference sourceObj, Card card, Game game, int offset) {
|
||||
return game
|
||||
.getState()
|
||||
.getWatcher(IanMalcolmChaoticianWatcher.class)
|
||||
.exiledMap
|
||||
.getOrDefault(sourceObj, Collections.emptySet())
|
||||
.stream()
|
||||
.anyMatch(mor -> mor.refersTo(card, game, offset));
|
||||
}
|
||||
}
|
||||
|
|
@ -33,6 +33,7 @@ public final class JurassicWorldCollection extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Grim Giganotosaurus", 11, Rarity.RARE, mage.cards.g.GrimGiganotosaurus.class));
|
||||
cards.add(new SetCardInfo("Henry Wu, InGen Geneticist", 12, Rarity.RARE, mage.cards.h.HenryWuInGenGeneticist.class));
|
||||
cards.add(new SetCardInfo("Hunting Velociraptor", 4, Rarity.RARE, mage.cards.h.HuntingVelociraptor.class));
|
||||
cards.add(new SetCardInfo("Ian Malcolm, Chaotician", 13, Rarity.RARE, mage.cards.i.IanMalcolmChaotician.class));
|
||||
cards.add(new SetCardInfo("Indoraptor, the Perfect Hybrid", 15, Rarity.RARE, mage.cards.i.IndoraptorThePerfectHybrid.class));
|
||||
cards.add(new SetCardInfo("Island", 22, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
|
||||
cards.add(new SetCardInfo("Island", "22b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
package org.mage.test.cards.watchers;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestCommander4Players;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimga150
|
||||
*/
|
||||
public class IanMalcolmChaoticianTests extends CardTestCommander4Players {
|
||||
|
||||
@Test
|
||||
public void testManaCostsandWatcher() {
|
||||
|
||||
skipInitShuffling();
|
||||
|
||||
// Whenever a player draws their second card each turn, that player exiles the top card of their library.
|
||||
// During each player's turn, that player may cast a spell from among the cards they don't own exiled with
|
||||
// Ian Malcolm, Chaotician, and mana of any type can be spent to cast it.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Ian Malcolm, Chaotician");
|
||||
|
||||
// Flying
|
||||
// At the beginning of your draw step, draw an additional card.
|
||||
// At the beginning of your end step, discard your hand.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Avaricious Dragon");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Avaricious Dragon");
|
||||
addCard(Zone.BATTLEFIELD, playerC, "Avaricious Dragon");
|
||||
addCard(Zone.BATTLEFIELD, playerD, "Avaricious Dragon");
|
||||
|
||||
addCard(Zone.LIBRARY, playerA, "Horde of Notions", 3);
|
||||
addCard(Zone.LIBRARY, playerB, "Fusion Elemental", 10);
|
||||
addCard(Zone.LIBRARY, playerC, "Chromanticore", 10);
|
||||
addCard(Zone.LIBRARY, playerD, "Garth One-Eye", 10);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 15);
|
||||
|
||||
// Should be able to cast all cards exiled from other players' decks
|
||||
checkPlayableAbility("Can't cast card exiled with this Ian Malcolm", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Fusion Elemental", true);
|
||||
checkPlayableAbility("Can't cast card exiled with this Ian Malcolm", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Chromanticore", true);
|
||||
checkPlayableAbility("Can't cast card exiled with this Ian Malcolm", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Garth One-Eye", true);
|
||||
|
||||
// Should NOT be able to cast own card exiled in same way
|
||||
checkPlayableAbility("Able to cast Horde of Notions, but should not be.", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Horde of Notions", false);
|
||||
|
||||
// Cast a card exiled with Ian Malcolm, preventing any future casts from this zone on this turn.
|
||||
castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, "Fusion Elemental", true);
|
||||
|
||||
checkPlayableAbility("Able to cast Chromanticore, but should not be due to watcher.", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Chromanticore", false);
|
||||
checkPlayableAbility("Able to cast Garth One-Eye, but should not be due to watcher.", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Garth One-Eye", false);
|
||||
|
||||
setStopAt(5, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlink() {
|
||||
|
||||
skipInitShuffling();
|
||||
|
||||
// Whenever a player draws their second card each turn, that player exiles the top card of their library.
|
||||
// During each player's turn, that player may cast a spell from among the cards they don't own exiled with
|
||||
// Ian Malcolm, Chaotician, and mana of any type can be spent to cast it.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Ian Malcolm, Chaotician");
|
||||
|
||||
// Flying
|
||||
// At the beginning of your draw step, draw an additional card.
|
||||
// At the beginning of your end step, discard your hand.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Heightened Awareness");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Heightened Awareness");
|
||||
addCard(Zone.BATTLEFIELD, playerC, "Heightened Awareness");
|
||||
addCard(Zone.BATTLEFIELD, playerD, "Heightened Awareness");
|
||||
|
||||
addCard(Zone.LIBRARY, playerA, "Horde of Notions", 3);
|
||||
addCard(Zone.LIBRARY, playerA, "Ephemerate", 1);
|
||||
addCard(Zone.LIBRARY, playerB, "Fusion Elemental", 10);
|
||||
addCard(Zone.LIBRARY, playerC, "Chromanticore", 10);
|
||||
addCard(Zone.LIBRARY, playerD, "Garth One-Eye", 10);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 15);
|
||||
|
||||
// Should be able to cast all cards exiled from other players' decks
|
||||
checkPlayableAbility("Can't cast card exiled with this Ian Malcolm", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Fusion Elemental", true);
|
||||
checkPlayableAbility("Can't cast card exiled with this Ian Malcolm", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Chromanticore", true);
|
||||
checkPlayableAbility("Can't cast card exiled with this Ian Malcolm", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Garth One-Eye", true);
|
||||
|
||||
// Should NOT be able to cast own card exiled in same way
|
||||
checkPlayableAbility("Able to cast Horde of Notions, but should not be.", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Horde of Notions", false);
|
||||
|
||||
// Blink Ian Malcolm, causing all cards in his current exile zone to become uncastable
|
||||
castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, "Ephemerate", true);
|
||||
addTarget(playerA, "Ian Malcolm, Chaotician");
|
||||
|
||||
// Should no longer be able to cast all cards exiled from other players' decks
|
||||
checkPlayableAbility("Can't cast card exiled with this Ian Malcolm", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Fusion Elemental", false);
|
||||
checkPlayableAbility("Can't cast card exiled with this Ian Malcolm", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Chromanticore", false);
|
||||
checkPlayableAbility("Can't cast card exiled with this Ian Malcolm", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Garth One-Eye", false);
|
||||
|
||||
setStopAt(5, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ public enum MageIdentifier {
|
|||
HaukensInsightWatcher,
|
||||
IntrepidPaleontologistWatcher,
|
||||
KessDissidentMageWatcher,
|
||||
IanMalcolmChaoticianWatcher,
|
||||
MuldrothaTheGravetideWatcher,
|
||||
ShareTheSpoilsWatcher,
|
||||
WishWatcher,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public class DrawNthCardTriggeredAbility extends TriggeredAbilityImpl {
|
|||
setTriggerPhrase(generateTriggerPhrase());
|
||||
}
|
||||
|
||||
private DrawNthCardTriggeredAbility(final DrawNthCardTriggeredAbility ability) {
|
||||
protected DrawNthCardTriggeredAbility(final DrawNthCardTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.targetController = ability.targetController;
|
||||
this.cardNumber = ability.cardNumber;
|
||||
|
|
@ -72,6 +72,9 @@ public class DrawNthCardTriggeredAbility extends TriggeredAbilityImpl {
|
|||
return false;
|
||||
}
|
||||
break;
|
||||
case ANY:
|
||||
// Doesn't matter who
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("TargetController " + targetController + " not supported");
|
||||
}
|
||||
|
|
@ -87,6 +90,8 @@ public class DrawNthCardTriggeredAbility extends TriggeredAbilityImpl {
|
|||
return "Whenever a player draws their " + CardUtil.numberToOrdinalText(cardNumber) + " card during their turn, ";
|
||||
case OPPONENT:
|
||||
return "Whenever an opponent draws their " + CardUtil.numberToOrdinalText(cardNumber) + " card each turn, ";
|
||||
case ANY:
|
||||
return "Whenever a player draws their " + CardUtil.numberToOrdinalText(cardNumber) + " card each turn, ";
|
||||
default:
|
||||
throw new IllegalArgumentException("TargetController " + targetController + " not supported");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue