master #13

Merged
Failure merged 17 commits from External/mage:master into master 2025-01-18 14:08:11 -08:00
48 changed files with 1853 additions and 211 deletions

View file

@ -565,6 +565,7 @@ public class ScryfallImageSupportCards {
add("DSC"); // Duskmourn: House of Horror Commander
add("FDN"); // Foundations
add("J25"); // Foundations Jumpstart
add("INR"); // Innistrad Remastered
add("DFT"); // Aetherdrift
// Custom sets using Scryfall images - must provide a direct link for each card in directDownloadLinks

View file

@ -2455,7 +2455,41 @@ public class ScryfallImageSupportTokens {
put("BLB/Wall", "https://api.scryfall.com/cards/tblb/4/en?format=image");
// BLC
put("BLC/Beast/1", "https://api.scryfall.com/cards/tblc/24/en?format=image");
put("BLC/Beast/2", "https://api.scryfall.com/cards/tblc/25/en?format=image");
put("BLC/Bird/1", "https://api.scryfall.com/cards/tblc/11/en?format=image");
put("BLC/Bird/2", "https://api.scryfall.com/cards/tblc/3/en?format=image");
put("BLC/Blood", "https://api.scryfall.com/cards/tblc/36/en?format=image");
put("BLC/Cat", "https://api.scryfall.com/cards/tblc/26/en?format=image");
put("BLC/Citizen", "https://api.scryfall.com/cards/tblc/33/en?format=image");
put("BLC/Clue", "https://api.scryfall.com/cards/tblc/37/en?format=image");
put("BLC/Eldrazi", "https://api.scryfall.com/cards/tblc/2/en?format=image");
put("BLC/Elemental", "https://api.scryfall.com/cards/tblc/4/en?format=image");
put("BLC/Elephant", "https://api.scryfall.com/cards/tblc/27/en?format=image");
put("BLC/Faerie", "https://api.scryfall.com/cards/tblc/12/en?format=image");
put("BLC/Frog Lizard", "https://api.scryfall.com/cards/tblc/28/en?format=image");
put("BLC/Goat", "https://api.scryfall.com/cards/tblc/5/en?format=image");
put("BLC/Goblin", "https://api.scryfall.com/cards/tblc/21/en?format=image");
put("BLC/Hamster", "https://api.scryfall.com/cards/tblc/22/en?format=image");
put("BLC/Human", "https://api.scryfall.com/cards/tblc/6/en?format=image");
put("BLC/Human Soldier", "https://api.scryfall.com/cards/tblc/7/en?format=image");
put("BLC/Illusion", "https://api.scryfall.com/cards/tblc/13/en?format=image");
put("BLC/Octopus", "https://api.scryfall.com/cards/tblc/14/en?format=image");
put("BLC/Pest", "https://api.scryfall.com/cards/tblc/34/en?format=image");
put("BLC/Phyrexian Golem", "https://api.scryfall.com/cards/tblc/38/en?format=image");
put("BLC/Raccoon", "https://api.scryfall.com/cards/tblc/29/en?format=image");
put("BLC/Rat", "https://api.scryfall.com/cards/tblc/19/en?format=image");
put("BLC/Saproling", "https://api.scryfall.com/cards/tblc/30/en?format=image");
put("BLC/Shapeshifter", "https://api.scryfall.com/cards/tblc/15/en?format=image");
put("BLC/Shark", "https://api.scryfall.com/cards/tblc/16/en?format=image");
put("BLC/Soldier", "https://api.scryfall.com/cards/tblc/8/en?format=image");
put("BLC/Spider", "https://api.scryfall.com/cards/tblc/31/en?format=image");
put("BLC/Spirit", "https://api.scryfall.com/cards/tblc/9/en?format=image");
put("BLC/Squid", "https://api.scryfall.com/cards/tblc/17/en?format=image");
put("BLC/Storm Crow", "https://api.scryfall.com/cards/tblc/18/en?format=image");
put("BLC/Thopter", "https://api.scryfall.com/cards/tblc/39/en?format=image");
put("BLC/Wolf/1", "https://api.scryfall.com/cards/tblc/35/en?format=image");
put("BLC/Wolf/2", "https://api.scryfall.com/cards/tblc/32/en?format=image");
// DSK
put("DSK/Emblem Kaito", "https://api.scryfall.com/cards/tdsk/17/en?format=image");

View file

@ -1,8 +1,6 @@
package mage.utils;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
@ -26,6 +24,7 @@ import mage.game.permanent.token.Token;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPlayer;
import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
import mage.util.MultiAmountMessage;
import mage.util.RandomUtil;
@ -68,15 +67,14 @@ public final class SystemUtil {
// [@mana add] -> MANA ADD
private static final String COMMAND_CARDS_ADD_TO_HAND = "@card add to hand";
private static final String COMMAND_LANDS_ADD_TO_BATTLEFIELD = "@lands add";
private static final String COMMAND_OPPONENT_UNDER_CONTROL_START = "@opponent under control start";
private static final String COMMAND_OPPONENT_UNDER_CONTROL_END = "@opponent under control end";
private static final String COMMAND_UNDER_CONTROL_TAKE = "@under control take";
private static final String COMMAND_UNDER_CONTROL_GIVE = "@under control give";
private static final String COMMAND_MANA_ADD = "@mana add"; // TODO: not implemented
private static final String COMMAND_RUN_CUSTOM_CODE = "@run custom code"; // TODO: not implemented
private static final String COMMAND_SHOW_OPPONENT_HAND = "@show opponent hand";
private static final String COMMAND_SHOW_OPPONENT_LIBRARY = "@show opponent library";
private static final String COMMAND_SHOW_MY_HAND = "@show my hand";
private static final String COMMAND_SHOW_MY_LIBRARY = "@show my library";
private static final String COMMAND_ACTIVATE_OPPONENT_ABILITY = "@activate opponent ability";
private static final Map<String, String> supportedCommands = new HashMap<>();
static {
@ -84,14 +82,13 @@ public final class SystemUtil {
supportedCommands.put(COMMAND_CARDS_ADD_TO_HAND, "CARDS: ADD TO HAND");
supportedCommands.put(COMMAND_MANA_ADD, "MANA ADD");
supportedCommands.put(COMMAND_LANDS_ADD_TO_BATTLEFIELD, "LANDS: ADD TO BATTLEFIELD");
supportedCommands.put(COMMAND_OPPONENT_UNDER_CONTROL_START, "OPPONENT CONTROL: ENABLE");
supportedCommands.put(COMMAND_OPPONENT_UNDER_CONTROL_END, "OPPONENT CONTROL: DISABLE");
supportedCommands.put(COMMAND_UNDER_CONTROL_TAKE, "UNDER CONTROL: TAKE");
supportedCommands.put(COMMAND_UNDER_CONTROL_GIVE, "UNDER CONTROL: GIVE");
supportedCommands.put(COMMAND_RUN_CUSTOM_CODE, "RUN CUSTOM CODE");
supportedCommands.put(COMMAND_SHOW_OPPONENT_HAND, "SHOW OPPONENT HAND");
supportedCommands.put(COMMAND_SHOW_OPPONENT_LIBRARY, "SHOW OPPONENT LIBRARY");
supportedCommands.put(COMMAND_SHOW_MY_HAND, "SHOW MY HAND");
supportedCommands.put(COMMAND_SHOW_MY_LIBRARY, "SHOW MY LIBRARY");
supportedCommands.put(COMMAND_ACTIVATE_OPPONENT_ABILITY, "ACTIVATE OPPONENT ABILITY");
}
private static final Pattern patternGroup = Pattern.compile("\\[(.+)\\]"); // [test new card]
@ -307,8 +304,8 @@ public final class SystemUtil {
// add default commands
initLines.add(0, String.format("[%s]", COMMAND_LANDS_ADD_TO_BATTLEFIELD));
initLines.add(1, String.format("[%s]", COMMAND_CARDS_ADD_TO_HAND));
initLines.add(2, String.format("[%s]", COMMAND_OPPONENT_UNDER_CONTROL_START));
initLines.add(3, String.format("[%s]", COMMAND_OPPONENT_UNDER_CONTROL_END));
initLines.add(2, String.format("[%s]", COMMAND_UNDER_CONTROL_TAKE));
initLines.add(3, String.format("[%s]", COMMAND_UNDER_CONTROL_GIVE));
// collect all commands
CommandGroup currentGroup = null;
@ -427,53 +424,6 @@ public final class SystemUtil {
break;
}
case COMMAND_ACTIVATE_OPPONENT_ABILITY: {
// WARNING, maybe very bugged if called in wrong priority
// uses choose triggered ability dialog to select it
UUID savedPriorityPlayer = null;
if (game.getActivePlayerId() != opponent.getId()) {
savedPriorityPlayer = game.getActivePlayerId();
}
// change active player to find and play selected abilities (it's danger and buggy code)
if (savedPriorityPlayer != null) {
game.getState().setPriorityPlayerId(opponent.getId());
game.firePriorityEvent(opponent.getId());
}
List<ActivatedAbility> abilities = opponent.getPlayable(game, true);
Map<String, String> choices = new HashMap<>();
abilities.forEach(ability -> {
MageObject object = ability.getSourceObject(game);
choices.put(ability.getId().toString(), object.getName() + ": " + ability.toString());
});
// TODO: set priority for us?
Choice choice = new ChoiceImpl(false);
choice.setMessage("Choose playable ability to activate by opponent " + opponent.getName());
choice.setKeyChoices(choices);
if (feedbackPlayer.choose(Outcome.Detriment, choice, game) && choice.getChoiceKey() != null) {
String needId = choice.getChoiceKey();
Optional<ActivatedAbility> ability = abilities.stream().filter(a -> a.getId().toString().equals(needId)).findFirst();
if (ability.isPresent()) {
// TODO: set priority for player?
ActivatedAbility activatedAbility = ability.get();
game.informPlayers(feedbackPlayer.getLogName() + " as another player " + opponent.getLogName()
+ " trying to force an activate ability: " + activatedAbility.getGameLogMessage(game));
if (opponent.activateAbility(activatedAbility, game)) {
game.informPlayers("Force to activate ability: DONE");
} else {
game.informPlayers("Force to activate ability: FAIL");
}
}
}
// restore original priority player
if (savedPriorityPlayer != null) {
game.getState().setPriorityPlayerId(savedPriorityPlayer);
game.firePriorityEvent(savedPriorityPlayer);
}
break;
}
case COMMAND_CARDS_ADD_TO_HAND: {
// card
@ -552,12 +502,12 @@ public final class SystemUtil {
break;
}
case COMMAND_OPPONENT_UNDER_CONTROL_START: {
Target target = new TargetPlayer().withNotTarget(true).withChooseHint("to take under your control");
case COMMAND_UNDER_CONTROL_TAKE: {
Target target = new TargetOpponent().withNotTarget(true).withChooseHint("to take under your control");
Ability fakeSourceAbility = fakeSourceAbilityTemplate.copy();
if (feedbackPlayer.chooseTarget(Outcome.GainControl, target, fakeSourceAbility, game)) {
Player targetPlayer = game.getPlayer(target.getFirstTarget());
if (targetPlayer != null && targetPlayer != feedbackPlayer) {
if (!targetPlayer.getId().equals(feedbackPlayer.getId())) {
CardUtil.takeControlUnderPlayerStart(game, fakeSourceAbility, feedbackPlayer, targetPlayer, false);
// allow priority play again in same step (for better cheat UX)
targetPlayer.resetPassed();
@ -568,13 +518,19 @@ public final class SystemUtil {
break;
}
case COMMAND_OPPONENT_UNDER_CONTROL_END: {
Target target = new TargetPlayer().withNotTarget(true).withChooseHint("to free from your control");
case COMMAND_UNDER_CONTROL_GIVE: {
Target target = new TargetPlayer().withNotTarget(true).withChooseHint("to give control of your player");
Ability fakeSourceAbility = fakeSourceAbilityTemplate.copy();
if (feedbackPlayer.chooseTarget(Outcome.GainControl, target, fakeSourceAbility, game)) {
Player targetPlayer = game.getPlayer(target.getFirstTarget());
if (targetPlayer != null && targetPlayer != feedbackPlayer && !targetPlayer.isGameUnderControl()) {
CardUtil.takeControlUnderPlayerEnd(game, fakeSourceAbility, feedbackPlayer, targetPlayer);
if (targetPlayer != null) {
if (!targetPlayer.getId().equals(feedbackPlayer.getId())) {
// give control to another player
CardUtil.takeControlUnderPlayerStart(game, fakeSourceAbility, targetPlayer, feedbackPlayer, false);
} else {
// return control to itself
CardUtil.takeControlUnderPlayerEnd(game, fakeSourceAbility, feedbackPlayer, targetPlayer);
}
}
// workaround for refresh priority dialog like avatar click (cheats called from priority in 99%)
game.firePriorityEvent(feedbackPlayer.getId());

View file

@ -204,7 +204,9 @@ public class ComputerPlayer extends PlayerImpl {
for (Permanent permanent : targets) {
if (origTarget.canTarget(abilityControllerId, permanent.getId(), source, game, false) && !target.getTargets().contains(permanent.getId())) {
target.add(permanent.getId(), game);
return true;
if (target.isChosen(game)) {
return true;
}
}
}
return false;

View file

@ -360,9 +360,14 @@ public class HumanPlayer extends PlayerImpl {
// async command: cheat by current player
if (response.getAsyncWantCheat()) {
// execute cheats and continue
// run cheats
SystemUtil.executeCheatCommands(game, null, this);
game.fireUpdatePlayersEvent(); // need force to game update for new possible data
// force to game update for new possible data
game.fireUpdatePlayersEvent();
// must stop current dialog on changed control, so game can give priority to actual player
if (this.isGameUnderControl() != game.getPlayer(this.getId()).isGameUnderControl()) {
return;
}
// wait another answer
if (canRespond()) {
loop = true;

View file

@ -0,0 +1,43 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.TriggeredAbility;
import mage.abilities.abilityword.SurvivalAbility;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.counters.CounterType;
import java.util.UUID;
/**
* @author markort147
*/
public final class AcrobaticCheerleader extends CardImpl {
public AcrobaticCheerleader(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SURVIVOR);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Survival -- At the beginning of your second main phase, if Acrobatic Cheerleader is tapped, put a flying counter on it. This ability triggers only once.
TriggeredAbility ability = new SurvivalAbility(new AddCountersSourceEffect(CounterType.FLYING.createInstance()))
.setTriggersLimitEachGame(1)
.withRuleTextReplacement(true);
this.addAbility(ability);
}
private AcrobaticCheerleader(final AcrobaticCheerleader card) {
super(card);
}
@Override
public AcrobaticCheerleader copy() {
return new AcrobaticCheerleader(this);
}
}

View file

@ -35,7 +35,7 @@ public final class AwakenedSkyclave extends CardImpl {
this.addAbility(HasteAbility.getInstance());
// As long as Awakened Skyclave is on the battlefield, it's a land in addition to its other types.
this.addAbility(new SimpleStaticAbility(new AddCardTypeSourceEffect(Duration.WhileOnBattlefield)
this.addAbility(new SimpleStaticAbility(new AddCardTypeSourceEffect(Duration.WhileOnBattlefield, CardType.LAND)
.setText("as long as {this} is on the battlefield, it's a land in addition to its other types")));
// {T}: Add one mana of any color.

View file

@ -3,6 +3,8 @@ package mage.cards.b;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.hint.ConditionHint;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.GenericManaCost;
@ -35,6 +37,7 @@ public final class BrassGnat extends CardImpl {
// At the beginning of your upkeep, you may pay {1}. If you do, untap Brass Gnat.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new DoIfCostPaid(new UntapSourceEffect(), new GenericManaCost(1))
.withChooseHint(new ConditionHint(SourceTappedCondition.UNTAPPED))
));
}

View file

@ -3,6 +3,8 @@ package mage.cards.b;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.hint.ConditionHint;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.GenericManaCost;
@ -33,6 +35,7 @@ public final class BrassMan extends CardImpl {
// At the beginning of your upkeep, you may pay {1}. If you do, untap Brass Man.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new DoIfCostPaid(new UntapSourceEffect(), new GenericManaCost(1))
.withChooseHint(new ConditionHint(SourceTappedCondition.UNTAPPED))
));
}

View file

@ -0,0 +1,211 @@
package mage.cards.f;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.continuous.GainClassAbilitySourceEffect;
import mage.abilities.keyword.ClassLevelAbility;
import mage.abilities.keyword.ClassReminderAbility;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.events.CreateTokenEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.token.FishNoAbilityToken;
import mage.game.permanent.token.OctopusToken;
import mage.game.permanent.token.Shark33Token;
import mage.game.permanent.token.Token;
import mage.players.Player;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
/**
* Note to future reader: this card's replacement effects do NOT affect tokens with Changeling such as those of Birthing Boughs. This is not a bug, see 701.6b
* @author PurpleCrowbar
*/
public final class FishersTalent extends CardImpl {
public FishersTalent(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{U}");
this.subtype.add(SubType.CLASS);
// (Gain the next level as a sorcery to add its ability.)
this.addAbility(new ClassReminderAbility());
// At the beginning of your upkeep, look at the top card of your library. You may reveal it if it's a land card. Create a 1/1 blue Fish creature token if you revealed it this way. Then draw a card.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new FishersTalentLevel1Effect()));
// {G}{U}: Level 2
this.addAbility(new ClassLevelAbility(2, "{G}{U}"));
// If you would create a Fish token, create a 3/3 blue Shark creature token instead.
this.addAbility(new SimpleStaticAbility(new GainClassAbilitySourceEffect(new SimpleStaticAbility(new FishersTalentLevel2Effect()), 2)));
// {2}{G}{U}: Level 3
this.addAbility(new ClassLevelAbility(3, "{2}{G}{U}"));
// If you would create a Shark token, create an 8/8 blue Octopus creature token instead.
this.addAbility(new SimpleStaticAbility(new GainClassAbilitySourceEffect(new SimpleStaticAbility(new FishersTalentLevel3Effect()), 3)));
}
private FishersTalent(final FishersTalent card) {
super(card);
}
@Override
public FishersTalent copy() {
return new FishersTalent(this);
}
}
class FishersTalentLevel1Effect extends OneShotEffect {
FishersTalentLevel1Effect() {
super(Outcome.Benefit);
this.staticText = "look at the top card of your library. You may reveal it if it's a land card. " +
"Create a 1/1 blue Fish creature token if you revealed it this way. Then draw a card.";
}
private FishersTalentLevel1Effect(final FishersTalentLevel1Effect effect) {
super(effect);
}
@Override
public FishersTalentLevel1Effect copy() {
return new FishersTalentLevel1Effect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Card topCard = controller.getLibrary().getFromTop(game);
if (topCard != null) {
controller.lookAtCards("Top card of library", topCard, game);
if (topCard.isLand(game)) {
if (controller.chooseUse(Outcome.PutCreatureInPlay, "Reveal " + topCard.getLogName() + " to create a 1/1 blue Fish creature token?", source, game)) {
controller.revealCards(source, new CardsImpl(topCard), game);
new FishNoAbilityToken().putOntoBattlefield(1, game, source);
}
}
}
controller.drawCards(1, source, game);
return true;
}
}
class FishersTalentLevel2Effect extends ReplacementEffectImpl {
FishersTalentLevel2Effect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
this.staticText = "If you would create a Fish token, create a 3/3 blue Shark creature token instead";
}
private FishersTalentLevel2Effect(final FishersTalentLevel2Effect effect) {
super(effect);
}
@Override
public FishersTalentLevel2Effect copy() {
return new FishersTalentLevel2Effect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CREATE_TOKEN;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (!(event instanceof CreateTokenEvent) || !event.getPlayerId().equals(source.getControllerId())) {
return false;
}
for (Token token : ((CreateTokenEvent) event).getTokens().keySet()) {
if (token.hasSubtype(SubType.FISH, game)) {
return true;
}
}
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
int amount = 0;
Map<Token, Integer> tokens = ((CreateTokenEvent) event).getTokens();
for (Iterator<Map.Entry<Token, Integer>> iter = tokens.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry<Token, Integer> entry = iter.next();
Token token = entry.getKey();
if (token.hasSubtype(SubType.FISH, game)) {
amount += entry.getValue();
iter.remove();
}
}
tokens.put(new Shark33Token(), amount);
return false;
}
}
class FishersTalentLevel3Effect extends ReplacementEffectImpl {
FishersTalentLevel3Effect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
this.staticText = "If you would create a Shark token, create an 8/8 blue Octopus creature token instead";
}
private FishersTalentLevel3Effect(final FishersTalentLevel3Effect effect) {
super(effect);
}
@Override
public FishersTalentLevel3Effect copy() {
return new FishersTalentLevel3Effect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CREATE_TOKEN;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (!(event instanceof CreateTokenEvent) || !event.getPlayerId().equals(source.getControllerId())) {
return false;
}
for (Token token : ((CreateTokenEvent) event).getTokens().keySet()) {
if (token.hasSubtype(SubType.SHARK, game)) {
return true;
}
}
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
int amount = 0;
Map<Token, Integer> tokens = ((CreateTokenEvent) event).getTokens();
for (Iterator<Map.Entry<Token, Integer>> iter = tokens.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry<Token, Integer> entry = iter.next();
Token token = entry.getKey();
if (token.hasSubtype(SubType.SHARK, game)) {
amount += entry.getValue();
iter.remove();
}
}
tokens.put(new OctopusToken(), amount);
return false;
}
}

View file

@ -3,6 +3,8 @@ package mage.cards.g;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.hint.ConditionHint;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
@ -34,7 +36,9 @@ public final class GoblinDirigible extends CardImpl {
this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepSourceEffect()));
// At the beginning of your upkeep, you may pay {4}. If you do, untap Goblin Dirigible.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid(
new UntapSourceEffect(), new ManaCostsImpl<>("{4}"))));
new UntapSourceEffect(), new ManaCostsImpl<>("{4}"))
.withChooseHint(new ConditionHint(SourceTappedCondition.UNTAPPED))
));
}
private GoblinDirigible(final GoblinDirigible card) {

View file

@ -3,6 +3,8 @@ package mage.cards.g;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.hint.ConditionHint;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
@ -31,7 +33,8 @@ public final class GoblinWarWagon extends CardImpl {
this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepSourceEffect()));
// At the beginning of your upkeep, you may pay {2}. If you do, untap Goblin War Wagon.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid(
new UntapSourceEffect(), new ManaCostsImpl<>("{2}"))));
new UntapSourceEffect(), new ManaCostsImpl<>("{2}"))
.withChooseHint(new ConditionHint(SourceTappedCondition.UNTAPPED))));
}
private GoblinWarWagon(final GoblinWarWagon card) {

View file

@ -3,6 +3,8 @@ package mage.cards.i;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.hint.ConditionHint;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.ControlsPermanentsControllerTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
@ -35,6 +37,7 @@ public final class IslandFishJasconius extends CardImpl {
// At the beginning of your upkeep, you may pay {U}{U}{U}. If you do, untap Island Fish Jasconius.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new DoIfCostPaid(new UntapSourceEffect(), new ManaCostsImpl<>("{U}{U}{U}"))
.withChooseHint(new ConditionHint(SourceTappedCondition.UNTAPPED))
));
// Island Fish Jasconius can't attack unless defending player controls an Island.

View file

@ -24,7 +24,7 @@ public final class LeylineOfResonance extends CardImpl {
);
static {
filter.add(new HasOnlySingleTargetPermanentPredicate(StaticFilters.FILTER_PERMANENT_CREATURE));
filter.add(new HasOnlySingleTargetPermanentPredicate(StaticFilters.FILTER_CONTROLLED_CREATURE));
}
public LeylineOfResonance(UUID ownerId, CardSetInfo setInfo) {

View file

@ -1,6 +1,9 @@
package mage.cards.m;
import mage.Mana;
import mage.abilities.hint.ConditionHint;
import mage.abilities.hint.ConditionTrueHint;
import mage.abilities.hint.ValueConditionHint;
import mage.abilities.triggers.BeginningOfDrawTriggeredAbility;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
@ -33,13 +36,14 @@ public final class ManaVault extends CardImpl {
// At the beginning of your upkeep, you may pay {4}. If you do, untap Mana Vault.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new DoIfCostPaid(new UntapSourceEffect(), new GenericManaCost(4), "Pay {4} to untap {this}?")
.withChooseHint(new ConditionHint(SourceTappedCondition.UNTAPPED))
));
// At the beginning of your draw step, if Mana Vault is tapped, it deals 1 damage to you.
this.addAbility(new BeginningOfDrawTriggeredAbility(new DamageControllerEffect(1, "it"),
false).withInterveningIf(SourceTappedCondition.TAPPED));
// {tap}: Add {C}{C}{C}.
// {T}: Add {C}{C}{C}.
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana(3), new TapSourceCost()));
}

View file

@ -42,7 +42,7 @@ public final class MimicVat extends CardImpl {
// Imprint - Whenever a nontoken creature dies, you may exile that card. If you do, return each other card exiled with Mimic Vat to its owner's graveyard.
this.addAbility(new MimicVatTriggeredAbility());
// {3}, {tap}: Create a token that's a copy of the exiled card. It gains haste. Exile it at the beginning of the next end step.
// {3}, {T}: Create a token that's a copy of the exiled card. It gains haste. Exile it at the beginning of the next end step.
Ability ability = new SimpleActivatedAbility(new MimicVatCreateTokenEffect(), new GenericManaCost(3));
ability.addCost(new TapSourceCost());
this.addAbility(ability);

View file

@ -73,11 +73,11 @@ class MysticSubdualEffect extends ContinuousEffectImpl {
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent == null) {
return true;
return false;
}
Permanent creature = game.getPermanent(permanent.getAttachedTo());
if (creature == null) {
return true;
return false;
}
creature.removeAllAbilities(source.getSourceId(), game);
return true;

View file

@ -0,0 +1,132 @@
package mage.cards.r;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.combat.GoadTargetEffect;
import mage.abilities.keyword.MenaceAbility;
import mage.abilities.keyword.ReachAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.token.Black22BirdToken;
import mage.game.permanent.token.Token;
import mage.game.stack.Spell;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
* @author PurpleCrowbar
*/
public final class RendmawCreakingNest extends CardImpl {
public RendmawCreakingNest(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{B}{G}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SCARECROW);
this.power = new MageInt(5);
this.toughness = new MageInt(5);
// Menace
this.addAbility(new MenaceAbility(false));
// Reach
this.addAbility(ReachAbility.getInstance());
// When Rendmaw, Creaking Nest enters and whenever you play a card with two or more card types, each player creates a tapped 2/2 black Bird creature token with flying. The tokens are goaded for the rest of the game.
this.addAbility(new RendmawCreakingNestTriggeredAbility());
}
private RendmawCreakingNest(final RendmawCreakingNest card) {
super(card);
}
@Override
public RendmawCreakingNest copy() {
return new RendmawCreakingNest(this);
}
}
class RendmawCreakingNestTriggeredAbility extends TriggeredAbilityImpl {
RendmawCreakingNestTriggeredAbility() {
super(Zone.BATTLEFIELD, new RendmawCreakingNestEffect());
setTriggerPhrase("When {this} enters and whenever you play a card with two or more card types, ");
}
private RendmawCreakingNestTriggeredAbility(final RendmawCreakingNestTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD
|| event.getType() == GameEvent.EventType.SPELL_CAST
|| event.getType() == GameEvent.EventType.LAND_PLAYED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
switch (event.getType()) {
case ENTERS_THE_BATTLEFIELD:
return event.getTargetId().equals(getSourceId());
case SPELL_CAST:
if (!event.getPlayerId().equals(this.getControllerId())) {
return false;
}
Spell spell = game.getSpellOrLKIStack(event.getTargetId());
return spell != null && spell.getCardType(game).size() >= 2;
case LAND_PLAYED:
if (!event.getPlayerId().equals(this.getControllerId())) {
return false;
}
Card card = game.getCard(event.getTargetId());
return card != null && card.getCardType(game).size() >= 2;
default:
return false;
}
}
@Override
public RendmawCreakingNestTriggeredAbility copy() {
return new RendmawCreakingNestTriggeredAbility(this);
}
}
class RendmawCreakingNestEffect extends OneShotEffect {
RendmawCreakingNestEffect() {
super(Outcome.Benefit);
staticText = "each player creates a tapped 2/2 black Bird creature token with flying. " +
"The tokens are goaded for the rest of the game";
}
private RendmawCreakingNestEffect(final RendmawCreakingNestEffect effect) {
super(effect);
}
@Override
public RendmawCreakingNestEffect copy() {
return new RendmawCreakingNestEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) {
if (!game.getPlayer(playerId).isInGame()) {
continue;
}
Token token = new Black22BirdToken();
token.putOntoBattlefield(1, game, source, playerId, true, false);
token.getLastAddedTokenIds().forEach(id -> game.addEffect(
new GoadTargetEffect().setDuration(Duration.EndOfGame).setTargetPointer(new FixedTarget(id, game)), source
));
}
return true;
}
}

View file

@ -35,6 +35,7 @@ public final class SlinzaTheSpikedStampede extends CardImpl {
private static final FilterPermanent filter3 = new FilterCreaturePermanent("creature with power 4 or greater");
static {
filter.add(SubType.BEAST.getPredicate());
filter3.add(new PowerPredicate(ComparisonType.MORE_THAN, 3));
}

View file

@ -104,6 +104,7 @@ public final class BloomburrowCommander extends ExpansionSet {
cards.add(new SetCardInfo("Farseek", 119, Rarity.UNCOMMON, mage.cards.f.Farseek.class));
cards.add(new SetCardInfo("Fellwar Stone", 269, Rarity.UNCOMMON, mage.cards.f.FellwarStone.class));
cards.add(new SetCardInfo("Ferrous Lake", 303, Rarity.RARE, mage.cards.f.FerrousLake.class));
cards.add(new SetCardInfo("Fisher's Talent", 36, Rarity.RARE, mage.cards.f.FishersTalent.class));
cards.add(new SetCardInfo("Flooded Grove", 304, Rarity.RARE, mage.cards.f.FloodedGrove.class));
cards.add(new SetCardInfo("Flubs, the Fool", 356, Rarity.MYTHIC, mage.cards.f.FlubsTheFool.class));
cards.add(new SetCardInfo("Forgotten Ancient", 217, Rarity.RARE, mage.cards.f.ForgottenAncient.class));

View file

@ -23,6 +23,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet {
cards.add(new SetCardInfo("Abandoned Campground", 255, Rarity.COMMON, mage.cards.a.AbandonedCampground.class));
cards.add(new SetCardInfo("Abhorrent Oculus", 42, Rarity.MYTHIC, mage.cards.a.AbhorrentOculus.class));
cards.add(new SetCardInfo("Acrobatic Cheerleader", 1, Rarity.COMMON, mage.cards.a.AcrobaticCheerleader.class));
cards.add(new SetCardInfo("Altanak, the Thrice-Called", 166, Rarity.UNCOMMON, mage.cards.a.AltanakTheThriceCalled.class));
cards.add(new SetCardInfo("Anthropede", 167, Rarity.COMMON, mage.cards.a.Anthropede.class));
cards.add(new SetCardInfo("Appendage Amalgam", 83, Rarity.COMMON, mage.cards.a.AppendageAmalgam.class));

View file

@ -105,7 +105,7 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet {
cards.add(new SetCardInfo("Explosive Vegetation", 177, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class));
cards.add(new SetCardInfo("Extravagant Replication", 117, Rarity.RARE, mage.cards.e.ExtravagantReplication.class));
cards.add(new SetCardInfo("Ezuri's Predation", 178, Rarity.RARE, mage.cards.e.EzurisPredation.class));
cards.add(new SetCardInfo("Falkenrath Noble", 140, Rarity.UNCOMMON, mage.cards.f.FalkenrathNoble.class));
cards.add(new SetCardInfo("Falkenrath Noble", 140, Rarity.COMMON, mage.cards.f.FalkenrathNoble.class));
cards.add(new SetCardInfo("Fate Unraveler", 141, Rarity.RARE, mage.cards.f.FateUnraveler.class));
cards.add(new SetCardInfo("Fear of Sleep Paralysis", 12, Rarity.RARE, mage.cards.f.FearOfSleepParalysis.class));
cards.add(new SetCardInfo("Feed the Swarm", 78, Rarity.COMMON, mage.cards.f.FeedTheSwarm.class));
@ -213,6 +213,7 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet {
cards.add(new SetCardInfo("Reanimate", 155, Rarity.RARE, mage.cards.r.Reanimate.class));
cards.add(new SetCardInfo("Redress Fate", 9, Rarity.RARE, mage.cards.r.RedressFate.class));
cards.add(new SetCardInfo("Reliquary Tower", 295, Rarity.UNCOMMON, mage.cards.r.ReliquaryTower.class));
cards.add(new SetCardInfo("Rendmaw, Creaking Nest", 5, Rarity.MYTHIC, mage.cards.r.RendmawCreakingNest.class));
cards.add(new SetCardInfo("Retreat to Coralhelm", 126, Rarity.UNCOMMON, mage.cards.r.RetreatToCoralhelm.class));
cards.add(new SetCardInfo("Return to Dust", 102, Rarity.UNCOMMON, mage.cards.r.ReturnToDust.class));
cards.add(new SetCardInfo("Sakura-Tribe Elder", 194, Rarity.COMMON, mage.cards.s.SakuraTribeElder.class));

View file

@ -0,0 +1,604 @@
package mage.sets;
import mage.cards.CardGraphicInfo;
import mage.cards.ExpansionSet;
import mage.cards.FrameStyle;
import mage.constants.Rarity;
import mage.constants.SetType;
/**
* https://scryfall.com/sets/inr
*
* @author JayDi85
*/
public class InnistradRemastered extends ExpansionSet {
private static final InnistradRemastered instance = new InnistradRemastered();
public static InnistradRemastered getInstance() {
return instance;
}
private InnistradRemastered() {
super("Innistrad Remastered", "INR", ExpansionSet.buildDate(2025, 1, 24), SetType.SUPPLEMENTAL);
this.hasBoosters = true; // TODO: after set release - improve rarity distribution or implement collation
this.hasBasicLands = true;
this.numBoosterLands = 1;
this.numBoosterCommon = 7 + 1; // +1 instead the list
this.numBoosterUncommon = 3 + 1; // +1 instead 1 of 2 wildcards
this.numBoosterRare = 1 + 1; // +1 instead 2 of 2 wildcards
this.ratioBoosterMythic = 8;
this.numBoosterDoubleFaced = -1;
this.maxCardNumberInBooster = 480; // play boosters #1480, collector boosters #1491
final CardGraphicInfo FULL_ART = new CardGraphicInfo(FrameStyle.MPOP_FULL_ART_BASIC, true);
cards.add(new SetCardInfo("Aberrant Researcher", 454, Rarity.UNCOMMON, mage.cards.a.AberrantResearcher.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aberrant Researcher", 52, Rarity.UNCOMMON, mage.cards.a.AberrantResearcher.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Abrade", 139, Rarity.COMMON, mage.cards.a.Abrade.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Abrade", 311, Rarity.COMMON, mage.cards.a.Abrade.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Abundant Growth", 184, Rarity.COMMON, mage.cards.a.AbundantGrowth.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Abundant Growth", 315, Rarity.COMMON, mage.cards.a.AbundantGrowth.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Abundant Growth", 406, Rarity.COMMON, mage.cards.a.AbundantGrowth.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Abundant Maw", 1, Rarity.COMMON, mage.cards.a.AbundantMaw.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Abundant Maw", 329, Rarity.COMMON, mage.cards.a.AbundantMaw.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aim High", 185, Rarity.COMMON, mage.cards.a.AimHigh.class));
cards.add(new SetCardInfo("Alchemist's Greeting", 140, Rarity.COMMON, mage.cards.a.AlchemistsGreeting.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Alchemist's Greeting", 393, Rarity.COMMON, mage.cards.a.AlchemistsGreeting.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Altered Ego", 228, Rarity.RARE, mage.cards.a.AlteredEgo.class));
cards.add(new SetCardInfo("Ambitious Farmhand", 448, Rarity.UNCOMMON, mage.cards.a.AmbitiousFarmhand.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ambitious Farmhand", 8, Rarity.UNCOMMON, mage.cards.a.AmbitiousFarmhand.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ambush Viper", 186, Rarity.COMMON, mage.cards.a.AmbushViper.class));
cards.add(new SetCardInfo("Ancestral Anger", 141, Rarity.COMMON, mage.cards.a.AncestralAnger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ancestral Anger", 394, Rarity.COMMON, mage.cards.a.AncestralAnger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Angel's Tomb", 253, Rarity.UNCOMMON, mage.cards.a.AngelsTomb.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Angel's Tomb", 438, Rarity.UNCOMMON, mage.cards.a.AngelsTomb.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Angelfire Ignition", 229, Rarity.RARE, mage.cards.a.AngelfireIgnition.class));
cards.add(new SetCardInfo("Angelic Purge", 333, Rarity.COMMON, mage.cards.a.AngelicPurge.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Angelic Purge", 9, Rarity.COMMON, mage.cards.a.AngelicPurge.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Apothecary Geist", 10, Rarity.COMMON, mage.cards.a.ApothecaryGeist.class));
cards.add(new SetCardInfo("Archangel Avacyn", 11, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Archangel Avacyn", 449, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Archghoul of Thraben", 370, Rarity.UNCOMMON, mage.cards.a.ArchghoulOfThraben.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Archghoul of Thraben", 95, Rarity.UNCOMMON, mage.cards.a.ArchghoulOfThraben.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Arlinn Kord", 230, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Arlinn Kord", 324, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 230, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 324, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ashmouth Blade", 269, Rarity.UNCOMMON, mage.cards.a.AshmouthBlade.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ashmouth Blade", 473, Rarity.UNCOMMON, mage.cards.a.AshmouthBlade.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Asylum Visitor", 371, Rarity.UNCOMMON, mage.cards.a.AsylumVisitor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Asylum Visitor", 96, Rarity.UNCOMMON, mage.cards.a.AsylumVisitor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aurora of Emrakul", 260, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aurora of Emrakul", 472, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Avacyn, Angel of Hope", 477, Rarity.MYTHIC, mage.cards.a.AvacynAngelOfHope.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Avacyn, Angel of Hope", 482, Rarity.MYTHIC, mage.cards.a.AvacynAngelOfHope.class, FULL_ART));
cards.add(new SetCardInfo("Avacyn, the Purifier", 11, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Avacyn, the Purifier", 449, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Avacynian Priest", 12, Rarity.COMMON, mage.cards.a.AvacynianPriest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Avacynian Priest", 334, Rarity.COMMON, mage.cards.a.AvacynianPriest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Awoken Demon", 107, Rarity.COMMON, mage.cards.a.AwokenDemon.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Awoken Demon", 462, Rarity.COMMON, mage.cards.a.AwokenDemon.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Awoken Horror", 460, Rarity.RARE, mage.cards.a.AwokenHorror.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Awoken Horror", 91, Rarity.RARE, mage.cards.a.AwokenHorror.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Balefire Dragon", 479, Rarity.MYTHIC, mage.cards.b.BalefireDragon.class));
cards.add(new SetCardInfo("Bane of Hanweir", 158, Rarity.COMMON, mage.cards.b.BaneOfHanweir.class));
cards.add(new SetCardInfo("Battleground Geist", 53, Rarity.COMMON, mage.cards.b.BattlegroundGeist.class));
cards.add(new SetCardInfo("Bedlam Reveler", 142, Rarity.RARE, mage.cards.b.BedlamReveler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bedlam Reveler", 312, Rarity.RARE, mage.cards.b.BedlamReveler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Biolume Egg", 455, Rarity.UNCOMMON, mage.cards.b.BiolumeEgg.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Biolume Egg", 54, Rarity.UNCOMMON, mage.cards.b.BiolumeEgg.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Biolume Serpent", 455, Rarity.UNCOMMON, mage.cards.b.BiolumeSerpent.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Biolume Serpent", 54, Rarity.UNCOMMON, mage.cards.b.BiolumeSerpent.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bladestitched Skaab", 231, Rarity.UNCOMMON, mage.cards.b.BladestitchedSkaab.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bladestitched Skaab", 426, Rarity.UNCOMMON, mage.cards.b.BladestitchedSkaab.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blazing Torch", 254, Rarity.COMMON, mage.cards.b.BlazingTorch.class));
cards.add(new SetCardInfo("Blood Artist", 326, Rarity.UNCOMMON, mage.cards.b.BloodArtist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blood Artist", 372, Rarity.UNCOMMON, mage.cards.b.BloodArtist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blood Artist", 97, Rarity.UNCOMMON, mage.cards.b.BloodArtist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blood Mist", 143, Rarity.UNCOMMON, mage.cards.b.BloodMist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blood Mist", 395, Rarity.UNCOMMON, mage.cards.b.BloodMist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blood Petal Celebrant", 144, Rarity.COMMON, mage.cards.b.BloodPetalCelebrant.class));
cards.add(new SetCardInfo("Bloodbat Summoner", 138, Rarity.RARE, mage.cards.b.BloodbatSummoner.class));
cards.add(new SetCardInfo("Bloodhall Priest", 232, Rarity.RARE, mage.cards.b.BloodhallPriest.class));
cards.add(new SetCardInfo("Bloodline Keeper", 327, Rarity.MYTHIC, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bloodline Keeper", 461, Rarity.MYTHIC, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bloodline Keeper", 98, Rarity.MYTHIC, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bloodmad Vampire", 145, Rarity.COMMON, mage.cards.b.BloodmadVampire.class));
cards.add(new SetCardInfo("Bloodsoaked Reveler", 128, Rarity.UNCOMMON, mage.cards.b.BloodsoakedReveler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bloodsoaked Reveler", 463, Rarity.UNCOMMON, mage.cards.b.BloodsoakedReveler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bloodtithe Harvester", 233, Rarity.UNCOMMON, mage.cards.b.BloodtitheHarvester.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bloodtithe Harvester", 427, Rarity.UNCOMMON, mage.cards.b.BloodtitheHarvester.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Boarded Window", 255, Rarity.UNCOMMON, mage.cards.b.BoardedWindow.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Boarded Window", 439, Rarity.UNCOMMON, mage.cards.b.BoardedWindow.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Borrowed Hostility", 146, Rarity.COMMON, mage.cards.b.BorrowedHostility.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Borrowed Hostility", 396, Rarity.COMMON, mage.cards.b.BorrowedHostility.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bound by Moonsilver", 13, Rarity.COMMON, mage.cards.b.BoundByMoonsilver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bound by Moonsilver", 335, Rarity.COMMON, mage.cards.b.BoundByMoonsilver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bramble Wurm", 187, Rarity.COMMON, mage.cards.b.BrambleWurm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bramble Wurm", 407, Rarity.COMMON, mage.cards.b.BrambleWurm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Brisela, Voice of Nightmares", "14b", Rarity.MYTHIC, mage.cards.b.BriselaVoiceOfNightmares.class));
cards.add(new SetCardInfo("Bruna, the Fading Light", "14a", Rarity.RARE, mage.cards.b.BrunaTheFadingLight.class));
cards.add(new SetCardInfo("Burning Vengeance", 147, Rarity.UNCOMMON, mage.cards.b.BurningVengeance.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Burning Vengeance", 397, Rarity.UNCOMMON, mage.cards.b.BurningVengeance.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Butcher Ghoul", 373, Rarity.COMMON, mage.cards.b.ButcherGhoul.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Butcher Ghoul", 99, Rarity.COMMON, mage.cards.b.ButcherGhoul.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Butcher's Cleaver", 256, Rarity.UNCOMMON, mage.cards.b.ButchersCleaver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Butcher's Cleaver", 440, Rarity.UNCOMMON, mage.cards.b.ButchersCleaver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cackling Counterpart", 353, Rarity.UNCOMMON, mage.cards.c.CacklingCounterpart.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cackling Counterpart", 55, Rarity.UNCOMMON, mage.cards.c.CacklingCounterpart.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Captivating Vampire", 100, Rarity.RARE, mage.cards.c.CaptivatingVampire.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Captivating Vampire", 374, Rarity.RARE, mage.cards.c.CaptivatingVampire.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Captivating Vampire", 484, Rarity.RARE, mage.cards.c.CaptivatingVampire.class, FULL_ART));
cards.add(new SetCardInfo("Cathar Commando", 15, Rarity.COMMON, mage.cards.c.CatharCommando.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cathar Commando", 336, Rarity.COMMON, mage.cards.c.CatharCommando.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cathar's Call", 16, Rarity.UNCOMMON, mage.cards.c.CatharsCall.class));
cards.add(new SetCardInfo("Cathars' Crusade", 17, Rarity.RARE, mage.cards.c.CatharsCrusade.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cathars' Crusade", 337, Rarity.RARE, mage.cards.c.CatharsCrusade.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cathars' Crusade", 483, Rarity.RARE, mage.cards.c.CatharsCrusade.class, FULL_ART));
cards.add(new SetCardInfo("Chalice of Death", 257, Rarity.UNCOMMON, mage.cards.c.ChaliceOfDeath.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Chalice of Death", 471, Rarity.UNCOMMON, mage.cards.c.ChaliceOfDeath.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Chalice of Life", 257, Rarity.UNCOMMON, mage.cards.c.ChaliceOfLife.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Chalice of Life", 471, Rarity.UNCOMMON, mage.cards.c.ChaliceOfLife.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Chandra, Dressed to Kill", 148, Rarity.MYTHIC, mage.cards.c.ChandraDressedToKill.class));
cards.add(new SetCardInfo("Chittering Host", "123b", Rarity.COMMON, mage.cards.c.ChitteringHost.class));
cards.add(new SetCardInfo("Cipherbound Spirit", 459, Rarity.UNCOMMON, mage.cards.c.CipherboundSpirit.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cipherbound Spirit", 85, Rarity.UNCOMMON, mage.cards.c.CipherboundSpirit.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Clear Shot", 188, Rarity.UNCOMMON, mage.cards.c.ClearShot.class));
cards.add(new SetCardInfo("Cobbled Lancer", 56, Rarity.UNCOMMON, mage.cards.c.CobbledLancer.class));
cards.add(new SetCardInfo("Cobbled Wings", 258, Rarity.COMMON, mage.cards.c.CobbledWings.class));
cards.add(new SetCardInfo("Collective Brutality", 101, Rarity.RARE, mage.cards.c.CollectiveBrutality.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Collective Brutality", 308, Rarity.RARE, mage.cards.c.CollectiveBrutality.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Collective Brutality", 375, Rarity.RARE, mage.cards.c.CollectiveBrutality.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Collective Defiance", 149, Rarity.RARE, mage.cards.c.CollectiveDefiance.class));
cards.add(new SetCardInfo("Compelling Deterrence", 57, Rarity.UNCOMMON, mage.cards.c.CompellingDeterrence.class));
cards.add(new SetCardInfo("Conduit of Emrakul", 150, Rarity.COMMON, mage.cards.c.ConduitOfEmrakul.class));
cards.add(new SetCardInfo("Conduit of Storms", 150, Rarity.COMMON, mage.cards.c.ConduitOfStorms.class));
cards.add(new SetCardInfo("Conjurer's Closet", 259, Rarity.RARE, mage.cards.c.ConjurersCloset.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Conjurer's Closet", 321, Rarity.RARE, mage.cards.c.ConjurersCloset.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Conjurer's Closet", 441, Rarity.RARE, mage.cards.c.ConjurersCloset.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Covetous Castaway", 456, Rarity.UNCOMMON, mage.cards.c.CovetousCastaway.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Covetous Castaway", 58, Rarity.UNCOMMON, mage.cards.c.CovetousCastaway.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Craterhoof Behemoth", 480, Rarity.MYTHIC, mage.cards.c.CraterhoofBehemoth.class));
cards.add(new SetCardInfo("Crawl from the Cellar", 102, Rarity.COMMON, mage.cards.c.CrawlFromTheCellar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Crawl from the Cellar", 376, Rarity.COMMON, mage.cards.c.CrawlFromTheCellar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Crusader of Odric", 18, Rarity.COMMON, mage.cards.c.CrusaderOfOdric.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Crusader of Odric", 338, Rarity.COMMON, mage.cards.c.CrusaderOfOdric.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cryptolith Fragment", 260, Rarity.UNCOMMON, mage.cards.c.CryptolithFragment.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cryptolith Fragment", 472, Rarity.UNCOMMON, mage.cards.c.CryptolithFragment.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cryptolith Rite", 189, Rarity.RARE, mage.cards.c.CryptolithRite.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cryptolith Rite", 316, Rarity.RARE, mage.cards.c.CryptolithRite.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cryptolith Rite", 408, Rarity.RARE, mage.cards.c.CryptolithRite.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cultivator Colossus", 190, Rarity.MYTHIC, mage.cards.c.CultivatorColossus.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cultivator Colossus", 317, Rarity.MYTHIC, mage.cards.c.CultivatorColossus.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cultivator Colossus", 409, Rarity.MYTHIC, mage.cards.c.CultivatorColossus.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dauntless Cathar", 19, Rarity.COMMON, mage.cards.d.DauntlessCathar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dauntless Cathar", 339, Rarity.COMMON, mage.cards.d.DauntlessCathar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dawnhart Disciple", 191, Rarity.COMMON, mage.cards.d.DawnhartDisciple.class));
cards.add(new SetCardInfo("Deadeye Navigator", 492, Rarity.RARE, mage.cards.d.DeadeyeNavigator.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Deadeye Navigator", 59, Rarity.RARE, mage.cards.d.DeadeyeNavigator.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Deadly Allure", 103, Rarity.UNCOMMON, mage.cards.d.DeadlyAllure.class));
cards.add(new SetCardInfo("Deathcap Glade", 275, Rarity.RARE, mage.cards.d.DeathcapGlade.class));
cards.add(new SetCardInfo("Decimator of the Provinces", 2, Rarity.RARE, mage.cards.d.DecimatorOfTheProvinces.class));
cards.add(new SetCardInfo("Deluge of the Dead", 120, Rarity.RARE, mage.cards.d.DelugeOfTheDead.class));
cards.add(new SetCardInfo("Delver of Secrets", 457, Rarity.COMMON, mage.cards.d.DelverOfSecrets.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Delver of Secrets", 60, Rarity.COMMON, mage.cards.d.DelverOfSecrets.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Demonic Taskmaster", 104, Rarity.UNCOMMON, mage.cards.d.DemonicTaskmaster.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Demonic Taskmaster", 377, Rarity.UNCOMMON, mage.cards.d.DemonicTaskmaster.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Demonmail Hauberk", 261, Rarity.UNCOMMON, mage.cards.d.DemonmailHauberk.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Demonmail Hauberk", 442, Rarity.UNCOMMON, mage.cards.d.DemonmailHauberk.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Depraved Harvester", 105, Rarity.COMMON, mage.cards.d.DepravedHarvester.class));
cards.add(new SetCardInfo("Deranged Assistant", 61, Rarity.COMMON, mage.cards.d.DerangedAssistant.class));
cards.add(new SetCardInfo("Deserted Beach", 276, Rarity.RARE, mage.cards.d.DesertedBeach.class));
cards.add(new SetCardInfo("Desperate Farmer", 105, Rarity.COMMON, mage.cards.d.DesperateFarmer.class));
cards.add(new SetCardInfo("Distended Mindbender", 3, Rarity.RARE, mage.cards.d.DistendedMindbender.class));
cards.add(new SetCardInfo("Docent of Perfection", 62, Rarity.RARE, mage.cards.d.DocentOfPerfection.class));
cards.add(new SetCardInfo("Dreamroot Cascade", 277, Rarity.RARE, mage.cards.d.DreamrootCascade.class));
cards.add(new SetCardInfo("Drogskol Shieldmate", 20, Rarity.COMMON, mage.cards.d.DrogskolShieldmate.class));
cards.add(new SetCardInfo("Drunau Corpse Trawler", 63, Rarity.UNCOMMON, mage.cards.d.DrunauCorpseTrawler.class));
cards.add(new SetCardInfo("Duel for Dominance", 192, Rarity.COMMON, mage.cards.d.DuelForDominance.class));
cards.add(new SetCardInfo("Duskwatch Recruiter", 193, Rarity.UNCOMMON, mage.cards.d.DuskwatchRecruiter.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Duskwatch Recruiter", 323, Rarity.UNCOMMON, mage.cards.d.DuskwatchRecruiter.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Duskwatch Recruiter", 467, Rarity.UNCOMMON, mage.cards.d.DuskwatchRecruiter.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eaten Alive", 106, Rarity.COMMON, mage.cards.e.EatenAlive.class));
cards.add(new SetCardInfo("Eccentric Farmer", 194, Rarity.COMMON, mage.cards.e.EccentricFarmer.class));
cards.add(new SetCardInfo("Ecstatic Awakener", 107, Rarity.COMMON, mage.cards.e.EcstaticAwakener.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ecstatic Awakener", 462, Rarity.COMMON, mage.cards.e.EcstaticAwakener.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Edgar Markov", 234, Rarity.MYTHIC, mage.cards.e.EdgarMarkov.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Edgar Markov", 328, Rarity.MYTHIC, mage.cards.e.EdgarMarkov.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Edgar Markov", 428, Rarity.MYTHIC, mage.cards.e.EdgarMarkov.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Edgar Markov", 491, Rarity.MYTHIC, mage.cards.e.EdgarMarkov.class, FULL_ART));
cards.add(new SetCardInfo("Edgar's Awakening", 108, Rarity.UNCOMMON, mage.cards.e.EdgarsAwakening.class));
cards.add(new SetCardInfo("Elder Deep-Fiend", 4, Rarity.RARE, mage.cards.e.ElderDeepFiend.class));
cards.add(new SetCardInfo("Eldritch Evolution", 195, Rarity.RARE, mage.cards.e.EldritchEvolution.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eldritch Evolution", 410, Rarity.RARE, mage.cards.e.EldritchEvolution.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Emrakul, the Promised End", 330, Rarity.MYTHIC, mage.cards.e.EmrakulThePromisedEnd.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Emrakul, the Promised End", 481, Rarity.MYTHIC, mage.cards.e.EmrakulThePromisedEnd.class, FULL_ART));
cards.add(new SetCardInfo("Emrakul, the Promised End", 5, Rarity.MYTHIC, mage.cards.e.EmrakulThePromisedEnd.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Epitaph Golem", 262, Rarity.COMMON, mage.cards.e.EpitaphGolem.class));
cards.add(new SetCardInfo("Erupting Dreadwolf", 171, Rarity.UNCOMMON, mage.cards.e.EruptingDreadwolf.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Erupting Dreadwolf", 465, Rarity.UNCOMMON, mage.cards.e.EruptingDreadwolf.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Essence Flux", 354, Rarity.COMMON, mage.cards.e.EssenceFlux.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Essence Flux", 64, Rarity.COMMON, mage.cards.e.EssenceFlux.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Evolving Wilds", 278, Rarity.COMMON, mage.cards.e.EvolvingWilds.class));
cards.add(new SetCardInfo("Faith Unbroken", 21, Rarity.UNCOMMON, mage.cards.f.FaithUnbroken.class));
cards.add(new SetCardInfo("Faithless Looting", 151, Rarity.COMMON, mage.cards.f.FaithlessLooting.class));
cards.add(new SetCardInfo("Falkenrath Gorger", 152, Rarity.RARE, mage.cards.f.FalkenrathGorger.class));
cards.add(new SetCardInfo("Falkenrath Torturer", 109, Rarity.COMMON, mage.cards.f.FalkenrathTorturer.class));
cards.add(new SetCardInfo("Festerhide Boar", 196, Rarity.COMMON, mage.cards.f.FesterhideBoar.class));
cards.add(new SetCardInfo("Festival Crasher", 153, Rarity.COMMON, mage.cards.f.FestivalCrasher.class));
cards.add(new SetCardInfo("Fiend Hunter", 22, Rarity.UNCOMMON, mage.cards.f.FiendHunter.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fiend Hunter", 340, Rarity.UNCOMMON, mage.cards.f.FiendHunter.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fiery Temper", 154, Rarity.UNCOMMON, mage.cards.f.FieryTemper.class));
cards.add(new SetCardInfo("Final Iteration", 62, Rarity.RARE, mage.cards.f.FinalIteration.class));
cards.add(new SetCardInfo("Fleshtaker", 235, Rarity.UNCOMMON, mage.cards.f.Fleshtaker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fleshtaker", 429, Rarity.UNCOMMON, mage.cards.f.Fleshtaker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forbidden Alchemy", 355, Rarity.UNCOMMON, mage.cards.f.ForbiddenAlchemy.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forbidden Alchemy", 65, Rarity.UNCOMMON, mage.cards.f.ForbiddenAlchemy.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", 296, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", 297, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Furyblade Vampire", 155, Rarity.UNCOMMON, mage.cards.f.FurybladeVampire.class));
cards.add(new SetCardInfo("Galvanic Iteration", 236, Rarity.RARE, mage.cards.g.GalvanicIteration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Galvanic Iteration", 430, Rarity.RARE, mage.cards.g.GalvanicIteration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Galvanic Juggernaut", 263, Rarity.UNCOMMON, mage.cards.g.GalvanicJuggernaut.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Galvanic Juggernaut", 443, Rarity.UNCOMMON, mage.cards.g.GalvanicJuggernaut.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Garruk Relentless", 197, Rarity.MYTHIC, mage.cards.g.GarrukRelentless.class));
cards.add(new SetCardInfo("Garruk, the Veil-Cursed", 197, Rarity.MYTHIC, mage.cards.g.GarrukTheVeilCursed.class));
cards.add(new SetCardInfo("Gather the Townsfolk", 23, Rarity.COMMON, mage.cards.g.GatherTheTownsfolk.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Gather the Townsfolk", 341, Rarity.COMMON, mage.cards.g.GatherTheTownsfolk.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Geier Reach Bandit", 156, Rarity.UNCOMMON, mage.cards.g.GeierReachBandit.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Geier Reach Bandit", 464, Rarity.UNCOMMON, mage.cards.g.GeierReachBandit.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Geistcatcher's Rig", 264, Rarity.UNCOMMON, mage.cards.g.GeistcatchersRig.class));
cards.add(new SetCardInfo("Geistlight Snare", 356, Rarity.UNCOMMON, mage.cards.g.GeistlightSnare.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Geistlight Snare", 66, Rarity.UNCOMMON, mage.cards.g.GeistlightSnare.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ghostly Castigator", 456, Rarity.UNCOMMON, mage.cards.g.GhostlyCastigator.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ghostly Castigator", 58, Rarity.UNCOMMON, mage.cards.g.GhostlyCastigator.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ghoulish Procession", 110, Rarity.UNCOMMON, mage.cards.g.GhoulishProcession.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ghoulish Procession", 378, Rarity.UNCOMMON, mage.cards.g.GhoulishProcession.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ghoultree", 198, Rarity.UNCOMMON, mage.cards.g.Ghoultree.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ghoultree", 411, Rarity.UNCOMMON, mage.cards.g.Ghoultree.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Gisa and Geralf", 237, Rarity.RARE, mage.cards.g.GisaAndGeralf.class));
cards.add(new SetCardInfo("Gisa's Bidding", 111, Rarity.COMMON, mage.cards.g.GisasBidding.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Gisa's Bidding", 379, Rarity.COMMON, mage.cards.g.GisasBidding.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Gisela, the Broken Blade", 24, Rarity.MYTHIC, mage.cards.g.GiselaTheBrokenBlade.class));
cards.add(new SetCardInfo("Gluttonous Guest", 112, Rarity.COMMON, mage.cards.g.GluttonousGuest.class));
cards.add(new SetCardInfo("Graf Rats", 113, Rarity.UNCOMMON, mage.cards.g.GrafRats.class));
cards.add(new SetCardInfo("Grapple with the Past", 199, Rarity.COMMON, mage.cards.g.GrappleWithThePast.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Grapple with the Past", 412, Rarity.COMMON, mage.cards.g.GrappleWithThePast.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Gravecrawler", 114, Rarity.RARE, mage.cards.g.Gravecrawler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Gravecrawler", 380, Rarity.RARE, mage.cards.g.Gravecrawler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Grimgrin, Corpse-Born", 239, Rarity.MYTHIC, mage.cards.g.GrimgrinCorpseBorn.class));
cards.add(new SetCardInfo("Griselbrand", 115, Rarity.MYTHIC, mage.cards.g.Griselbrand.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Griselbrand", 381, Rarity.MYTHIC, mage.cards.g.Griselbrand.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Griselbrand", 485, Rarity.MYTHIC, mage.cards.g.Griselbrand.class, FULL_ART));
cards.add(new SetCardInfo("Grisly Anglerfish", 458, Rarity.UNCOMMON, mage.cards.g.GrislyAnglerfish.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Grisly Anglerfish", 67, Rarity.UNCOMMON, mage.cards.g.GrislyAnglerfish.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Grizzled Angler", 458, Rarity.UNCOMMON, mage.cards.g.GrizzledAngler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Grizzled Angler", 67, Rarity.UNCOMMON, mage.cards.g.GrizzledAngler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Grizzly Ghoul", 240, Rarity.UNCOMMON, mage.cards.g.GrizzlyGhoul.class));
cards.add(new SetCardInfo("Groundskeeper", 200, Rarity.UNCOMMON, mage.cards.g.Groundskeeper.class));
cards.add(new SetCardInfo("Gryff's Boon", 25, Rarity.UNCOMMON, mage.cards.g.GryffsBoon.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Gryff's Boon", 342, Rarity.UNCOMMON, mage.cards.g.GryffsBoon.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Guardian of Pilgrims", 26, Rarity.COMMON, mage.cards.g.GuardianOfPilgrims.class));
cards.add(new SetCardInfo("Hamlet Captain", 201, Rarity.UNCOMMON, mage.cards.h.HamletCaptain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hamlet Captain", 413, Rarity.UNCOMMON, mage.cards.h.HamletCaptain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hanweir Battlements", 279, Rarity.RARE, mage.cards.h.HanweirBattlements.class));
cards.add(new SetCardInfo("Hanweir Garrison", "157a", Rarity.RARE, mage.cards.h.HanweirGarrison.class));
cards.add(new SetCardInfo("Hanweir Watchkeep", 158, Rarity.COMMON, mage.cards.h.HanweirWatchkeep.class));
cards.add(new SetCardInfo("Hanweir, the Writhing Township", "157b", Rarity.RARE, mage.cards.h.HanweirTheWrithingTownship.class));
cards.add(new SetCardInfo("Harvest Hand", 265, Rarity.COMMON, mage.cards.h.HarvestHand.class));
cards.add(new SetCardInfo("Haunted Dead", 116, Rarity.UNCOMMON, mage.cards.h.HauntedDead.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Haunted Dead", 382, Rarity.UNCOMMON, mage.cards.h.HauntedDead.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Haunted Ridge", 280, Rarity.RARE, mage.cards.h.HauntedRidge.class));
cards.add(new SetCardInfo("Heartless Summoning", 117, Rarity.RARE, mage.cards.h.HeartlessSummoning.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Heartless Summoning", 309, Rarity.RARE, mage.cards.h.HeartlessSummoning.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Heartless Summoning", 383, Rarity.RARE, mage.cards.h.HeartlessSummoning.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Helvault", 266, Rarity.RARE, mage.cards.h.Helvault.class));
cards.add(new SetCardInfo("Hermit Druid", 202, Rarity.RARE, mage.cards.h.HermitDruid.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hermit Druid", 488, Rarity.RARE, mage.cards.h.HermitDruid.class, FULL_ART));
cards.add(new SetCardInfo("Hinterland Logger", 203, Rarity.COMMON, mage.cards.h.HinterlandLogger.class));
cards.add(new SetCardInfo("Honeymoon Hearse", 159, Rarity.UNCOMMON, mage.cards.h.HoneymoonHearse.class));
cards.add(new SetCardInfo("Hopeful Initiate", 27, Rarity.RARE, mage.cards.h.HopefulInitiate.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hopeful Initiate", 343, Rarity.RARE, mage.cards.h.HopefulInitiate.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Howling Chorus", 214, Rarity.UNCOMMON, mage.cards.h.HowlingChorus.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Howling Chorus", 469, Rarity.UNCOMMON, mage.cards.h.HowlingChorus.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Howlpack Alpha", 207, Rarity.RARE, mage.cards.h.HowlpackAlpha.class));
cards.add(new SetCardInfo("Howlpack of Estwald", 224, Rarity.COMMON, mage.cards.h.HowlpackOfEstwald.class));
cards.add(new SetCardInfo("Howlpack Resurgence", 204, Rarity.UNCOMMON, mage.cards.h.HowlpackResurgence.class));
cards.add(new SetCardInfo("Hullbreaker Horror", 303, Rarity.RARE, mage.cards.h.HullbreakerHorror.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hullbreaker Horror", 357, Rarity.RARE, mage.cards.h.HullbreakerHorror.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hullbreaker Horror", 68, Rarity.RARE, mage.cards.h.HullbreakerHorror.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hungry Ridgewolf", 160, Rarity.COMMON, mage.cards.h.HungryRidgewolf.class));
cards.add(new SetCardInfo("Huntmaster of the Fells", 241, Rarity.RARE, mage.cards.h.HuntmasterOfTheFells.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Huntmaster of the Fells", 325, Rarity.RARE, mage.cards.h.HuntmasterOfTheFells.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Huntmaster of the Fells", 470, Rarity.RARE, mage.cards.h.HuntmasterOfTheFells.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Imprisoned in the Moon", 358, Rarity.COMMON, mage.cards.i.ImprisonedInTheMoon.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Imprisoned in the Moon", 69, Rarity.COMMON, mage.cards.i.ImprisonedInTheMoon.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Incited Rabble", 451, Rarity.UNCOMMON, mage.cards.i.IncitedRabble.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Incited Rabble", 46, Rarity.UNCOMMON, mage.cards.i.IncitedRabble.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Indulgent Aristocrat", 118, Rarity.UNCOMMON, mage.cards.i.IndulgentAristocrat.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Indulgent Aristocrat", 384, Rarity.UNCOMMON, mage.cards.i.IndulgentAristocrat.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Infernal Grasp", 119, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Infernal Grasp", 310, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Infernal Grasp", 385, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Insectile Aberration", 457, Rarity.COMMON, mage.cards.i.InsectileAberration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Insectile Aberration", 60, Rarity.COMMON, mage.cards.i.InsectileAberration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Inspiring Captain", 28, Rarity.COMMON, mage.cards.i.InspiringCaptain.class));
cards.add(new SetCardInfo("Intangible Virtue", 29, Rarity.UNCOMMON, mage.cards.i.IntangibleVirtue.class));
cards.add(new SetCardInfo("Intrepid Provisioner", 205, Rarity.COMMON, mage.cards.i.IntrepidProvisioner.class));
cards.add(new SetCardInfo("Invasion of Innistrad", 120, Rarity.RARE, mage.cards.i.InvasionOfInnistrad.class));
cards.add(new SetCardInfo("Island", 290, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", 291, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("It of the Horrid Swarm", 331, Rarity.COMMON, mage.cards.i.ItOfTheHorridSwarm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("It of the Horrid Swarm", 6, Rarity.COMMON, mage.cards.i.ItOfTheHorridSwarm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jace, Unraveler of Secrets", 70, Rarity.MYTHIC, mage.cards.j.JaceUnravelerOfSecrets.class));
cards.add(new SetCardInfo("Join the Dance", 242, Rarity.UNCOMMON, mage.cards.j.JoinTheDance.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Join the Dance", 432, Rarity.UNCOMMON, mage.cards.j.JoinTheDance.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Killing Wave", 121, Rarity.UNCOMMON, mage.cards.k.KillingWave.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Killing Wave", 386, Rarity.UNCOMMON, mage.cards.k.KillingWave.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Krallenhorde Howler", 193, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Krallenhorde Howler", 323, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Krallenhorde Howler", 467, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kruin Outlaw", 161, Rarity.RARE, mage.cards.k.KruinOutlaw.class));
cards.add(new SetCardInfo("Laboratory Maniac", 304, Rarity.UNCOMMON, mage.cards.l.LaboratoryManiac.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Laboratory Maniac", 359, Rarity.UNCOMMON, mage.cards.l.LaboratoryManiac.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Laboratory Maniac", 71, Rarity.UNCOMMON, mage.cards.l.LaboratoryManiac.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lantern Bearer", 72, Rarity.COMMON, mage.cards.l.LanternBearer.class));
cards.add(new SetCardInfo("Lanterns' Lift", 72, Rarity.COMMON, mage.cards.l.LanternsLift.class));
cards.add(new SetCardInfo("Liesa, Forgotten Archangel", 243, Rarity.RARE, mage.cards.l.LiesaForgottenArchangel.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Liesa, Forgotten Archangel", 433, Rarity.RARE, mage.cards.l.LiesaForgottenArchangel.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lightning Axe", 162, Rarity.UNCOMMON, mage.cards.l.LightningAxe.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lightning Axe", 398, Rarity.UNCOMMON, mage.cards.l.LightningAxe.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lightning Mauler", 163, Rarity.UNCOMMON, mage.cards.l.LightningMauler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lightning Mauler", 399, Rarity.UNCOMMON, mage.cards.l.LightningMauler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Liliana of the Veil", 475, Rarity.MYTHIC, mage.cards.l.LilianaOfTheVeil.class));
cards.add(new SetCardInfo("Lingering Souls", 30, Rarity.UNCOMMON, mage.cards.l.LingeringSouls.class));
cards.add(new SetCardInfo("Lord of Lineage", 327, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lord of Lineage", 461, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lord of Lineage", 98, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lumberknot", 206, Rarity.UNCOMMON, mage.cards.l.Lumberknot.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lumberknot", 414, Rarity.UNCOMMON, mage.cards.l.Lumberknot.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Luminous Phantom", 32, Rarity.COMMON, mage.cards.l.LuminousPhantom.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Luminous Phantom", 450, Rarity.COMMON, mage.cards.l.LuminousPhantom.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lunarch Mantle", 31, Rarity.COMMON, mage.cards.l.LunarchMantle.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lunarch Mantle", 344, Rarity.COMMON, mage.cards.l.LunarchMantle.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lunarch Veteran", 32, Rarity.COMMON, mage.cards.l.LunarchVeteran.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lunarch Veteran", 450, Rarity.COMMON, mage.cards.l.LunarchVeteran.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lupine Prototype", 267, Rarity.UNCOMMON, mage.cards.l.LupinePrototype.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lupine Prototype", 444, Rarity.UNCOMMON, mage.cards.l.LupinePrototype.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Maelstrom Pulse", 244, Rarity.RARE, mage.cards.m.MaelstromPulse.class));
cards.add(new SetCardInfo("Makeshift Mauler", 73, Rarity.COMMON, mage.cards.m.MakeshiftMauler.class));
cards.add(new SetCardInfo("Markov Waltzer", 245, Rarity.UNCOMMON, mage.cards.m.MarkovWaltzer.class));
cards.add(new SetCardInfo("Mass Hysteria", 164, Rarity.RARE, mage.cards.m.MassHysteria.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mass Hysteria", 400, Rarity.RARE, mage.cards.m.MassHysteria.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mausoleum Guard", 33, Rarity.UNCOMMON, mage.cards.m.MausoleumGuard.class));
cards.add(new SetCardInfo("Mausoleum Wanderer", 305, Rarity.RARE, mage.cards.m.MausoleumWanderer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mausoleum Wanderer", 360, Rarity.RARE, mage.cards.m.MausoleumWanderer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mausoleum Wanderer", 74, Rarity.RARE, mage.cards.m.MausoleumWanderer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mayor of Avabruck", 207, Rarity.RARE, mage.cards.m.MayorOfAvabruck.class));
cards.add(new SetCardInfo("Memory Deluge", 361, Rarity.RARE, mage.cards.m.MemoryDeluge.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Memory Deluge", 75, Rarity.RARE, mage.cards.m.MemoryDeluge.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mentor of the Meek", 34, Rarity.UNCOMMON, mage.cards.m.MentorOfTheMeek.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mentor of the Meek", 345, Rarity.UNCOMMON, mage.cards.m.MentorOfTheMeek.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Metallic Mimic", 268, Rarity.RARE, mage.cards.m.MetallicMimic.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Metallic Mimic", 445, Rarity.RARE, mage.cards.m.MetallicMimic.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Midnight Scavengers", 123, Rarity.COMMON, mage.cards.m.MidnightScavengers.class));
cards.add(new SetCardInfo("Mirrorwing Dragon", 165, Rarity.MYTHIC, mage.cards.m.MirrorwingDragon.class));
cards.add(new SetCardInfo("Mist Raven", 362, Rarity.UNCOMMON, mage.cards.m.MistRaven.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mist Raven", 76, Rarity.UNCOMMON, mage.cards.m.MistRaven.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Moldgraf Millipede", 208, Rarity.COMMON, mage.cards.m.MoldgrafMillipede.class));
cards.add(new SetCardInfo("Moonlight Hunt", 209, Rarity.UNCOMMON, mage.cards.m.MoonlightHunt.class));
cards.add(new SetCardInfo("Moonrise Intruder", 179, Rarity.COMMON, mage.cards.m.MoonriseIntruder.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Moonrise Intruder", 466, Rarity.COMMON, mage.cards.m.MoonriseIntruder.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Moonscarred Werewolf", 212, Rarity.COMMON, mage.cards.m.MoonscarredWerewolf.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Moonscarred Werewolf", 468, Rarity.COMMON, mage.cards.m.MoonscarredWerewolf.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Morbid Opportunist", 124, Rarity.UNCOMMON, mage.cards.m.MorbidOpportunist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Morbid Opportunist", 388, Rarity.UNCOMMON, mage.cards.m.MorbidOpportunist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Morkrut Banshee", 125, Rarity.UNCOMMON, mage.cards.m.MorkrutBanshee.class));
cards.add(new SetCardInfo("Mountain", 294, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 295, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Murderous Compulsion", 126, Rarity.COMMON, mage.cards.m.MurderousCompulsion.class));
cards.add(new SetCardInfo("Mystic Retrieval", 363, Rarity.UNCOMMON, mage.cards.m.MysticRetrieval.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mystic Retrieval", 77, Rarity.UNCOMMON, mage.cards.m.MysticRetrieval.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nebelgast Herald", 364, Rarity.UNCOMMON, mage.cards.n.NebelgastHerald.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nebelgast Herald", 78, Rarity.UNCOMMON, mage.cards.n.NebelgastHerald.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Necroduality", 365, Rarity.MYTHIC, mage.cards.n.Necroduality.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Necroduality", 79, Rarity.MYTHIC, mage.cards.n.Necroduality.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Neglected Heirloom", 269, Rarity.UNCOMMON, mage.cards.n.NeglectedHeirloom.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Neglected Heirloom", 473, Rarity.UNCOMMON, mage.cards.n.NeglectedHeirloom.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Neonate's Rush", 166, Rarity.COMMON, mage.cards.n.NeonatesRush.class));
cards.add(new SetCardInfo("Niblis of the Urn", 346, Rarity.UNCOMMON, mage.cards.n.NiblisOfTheUrn.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Niblis of the Urn", 35, Rarity.UNCOMMON, mage.cards.n.NiblisOfTheUrn.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Noose Constrictor", 210, Rarity.UNCOMMON, mage.cards.n.NooseConstrictor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Noose Constrictor", 415, Rarity.UNCOMMON, mage.cards.n.NooseConstrictor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Odric, Lunarch Marshal", 298, Rarity.RARE, mage.cards.o.OdricLunarchMarshal.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Odric, Lunarch Marshal", 36, Rarity.RARE, mage.cards.o.OdricLunarchMarshal.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Olivia Voldaren", 246, Rarity.MYTHIC, mage.cards.o.OliviaVoldaren.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Olivia Voldaren", 490, Rarity.MYTHIC, mage.cards.o.OliviaVoldaren.class, FULL_ART));
cards.add(new SetCardInfo("Olivia's Dragoon", 127, Rarity.COMMON, mage.cards.o.OliviasDragoon.class));
cards.add(new SetCardInfo("Ormendahl, Profane Prince", 287, Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ormendahl, Profane Prince", 474, Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Overcharged Amalgam", 80, Rarity.RARE, mage.cards.o.OverchargedAmalgam.class));
cards.add(new SetCardInfo("Overgrown Farmland", 281, Rarity.RARE, mage.cards.o.OvergrownFarmland.class));
cards.add(new SetCardInfo("Pack Guardian", 211, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Pack Guardian", 416, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Perfected Form", 454, Rarity.UNCOMMON, mage.cards.p.PerfectedForm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Perfected Form", 52, Rarity.UNCOMMON, mage.cards.p.PerfectedForm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 288, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 289, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Rally the Peasants", 347, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Rally the Peasants", 37, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ravager of the Fells", 241, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ravager of the Fells", 325, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ravager of the Fells", 470, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Reckless Scholar", 81, Rarity.COMMON, mage.cards.r.RecklessScholar.class));
cards.add(new SetCardInfo("Reforge the Soul", 167, Rarity.RARE, mage.cards.r.ReforgeTheSoul.class));
cards.add(new SetCardInfo("Restless Bloodseeker", 128, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Restless Bloodseeker", 463, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Restoration Angel", 299, Rarity.RARE, mage.cards.r.RestorationAngel.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Restoration Angel", 38, Rarity.RARE, mage.cards.r.RestorationAngel.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Rise from the Tides", 366, Rarity.UNCOMMON, mage.cards.r.RiseFromTheTides.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Rise from the Tides", 82, Rarity.UNCOMMON, mage.cards.r.RiseFromTheTides.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Rockfall Vale", 282, Rarity.RARE, mage.cards.r.RockfallVale.class));
cards.add(new SetCardInfo("Rooftop Storm", 306, Rarity.RARE, mage.cards.r.RooftopStorm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Rooftop Storm", 83, Rarity.RARE, mage.cards.r.RooftopStorm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Runebound Wolf", 168, Rarity.UNCOMMON, mage.cards.r.RuneboundWolf.class));
cards.add(new SetCardInfo("Sanitarium Skeleton", 129, Rarity.COMMON, mage.cards.s.SanitariumSkeleton.class));
cards.add(new SetCardInfo("Savage Alliance", 169, Rarity.UNCOMMON, mage.cards.s.SavageAlliance.class));
cards.add(new SetCardInfo("Scorned Villager", 212, Rarity.COMMON, mage.cards.s.ScornedVillager.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Scorned Villager", 468, Rarity.COMMON, mage.cards.s.ScornedVillager.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Scrounged Scythe", 265, Rarity.COMMON, mage.cards.s.ScroungedScythe.class));
cards.add(new SetCardInfo("Seasoned Cathar", 448, Rarity.UNCOMMON, mage.cards.s.SeasonedCathar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Seasoned Cathar", 8, Rarity.UNCOMMON, mage.cards.s.SeasonedCathar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Second Harvest", 213, Rarity.RARE, mage.cards.s.SecondHarvest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Second Harvest", 417, Rarity.RARE, mage.cards.s.SecondHarvest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Seize the Storm", 170, Rarity.COMMON, mage.cards.s.SeizeTheStorm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Seize the Storm", 401, Rarity.COMMON, mage.cards.s.SeizeTheStorm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sever the Bloodline", 130, Rarity.UNCOMMON, mage.cards.s.SeverTheBloodline.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sever the Bloodline", 389, Rarity.UNCOMMON, mage.cards.s.SeverTheBloodline.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shattered Sanctum", 283, Rarity.RARE, mage.cards.s.ShatteredSanctum.class));
cards.add(new SetCardInfo("Shipwreck Marsh", 284, Rarity.RARE, mage.cards.s.ShipwreckMarsh.class));
cards.add(new SetCardInfo("Shrill Howler", 214, Rarity.UNCOMMON, mage.cards.s.ShrillHowler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shrill Howler", 469, Rarity.UNCOMMON, mage.cards.s.ShrillHowler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Siege Zombie", 131, Rarity.COMMON, mage.cards.s.SiegeZombie.class));
cards.add(new SetCardInfo("Sigarda, Host of Herons", 247, Rarity.MYTHIC, mage.cards.s.SigardaHostOfHerons.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sigarda, Host of Herons", 434, Rarity.MYTHIC, mage.cards.s.SigardaHostOfHerons.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Silent Departure", 367, Rarity.COMMON, mage.cards.s.SilentDeparture.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Silent Departure", 84, Rarity.COMMON, mage.cards.s.SilentDeparture.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Skirsdag High Priest", 132, Rarity.RARE, mage.cards.s.SkirsdagHighPriest.class));
cards.add(new SetCardInfo("Slayer of the Wicked", 348, Rarity.UNCOMMON, mage.cards.s.SlayerOfTheWicked.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Slayer of the Wicked", 39, Rarity.UNCOMMON, mage.cards.s.SlayerOfTheWicked.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Smoldering Werewolf", 171, Rarity.UNCOMMON, mage.cards.s.SmolderingWerewolf.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Smoldering Werewolf", 465, Rarity.UNCOMMON, mage.cards.s.SmolderingWerewolf.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Snapcaster Mage", 478, Rarity.MYTHIC, mage.cards.s.SnapcasterMage.class));
cards.add(new SetCardInfo("Somberwald Sage", 215, Rarity.UNCOMMON, mage.cards.s.SomberwaldSage.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Somberwald Sage", 418, Rarity.UNCOMMON, mage.cards.s.SomberwaldSage.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sorin, Imperious Bloodlord", 133, Rarity.MYTHIC, mage.cards.s.SorinImperiousBloodlord.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sorin, Imperious Bloodlord", 322, Rarity.MYTHIC, mage.cards.s.SorinImperiousBloodlord.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sorin, Imperious Bloodlord", 476, Rarity.MYTHIC, mage.cards.s.SorinImperiousBloodlord.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Soul Separator", 270, Rarity.UNCOMMON, mage.cards.s.SoulSeparator.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Soul Separator", 446, Rarity.UNCOMMON, mage.cards.s.SoulSeparator.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Soul-Guide Gryff", 40, Rarity.COMMON, mage.cards.s.SoulGuideGryff.class));
cards.add(new SetCardInfo("Soulcipher Board", 459, Rarity.UNCOMMON, mage.cards.s.SoulcipherBoard.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Soulcipher Board", 85, Rarity.UNCOMMON, mage.cards.s.SoulcipherBoard.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spectral Shepherd", 349, Rarity.UNCOMMON, mage.cards.s.SpectralShepherd.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spectral Shepherd", 41, Rarity.UNCOMMON, mage.cards.s.SpectralShepherd.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spell Queller", 248, Rarity.RARE, mage.cards.s.SpellQueller.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spell Queller", 320, Rarity.RARE, mage.cards.s.SpellQueller.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spell Queller", 435, Rarity.RARE, mage.cards.s.SpellQueller.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider Spawning", 216, Rarity.UNCOMMON, mage.cards.s.SpiderSpawning.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider Spawning", 419, Rarity.UNCOMMON, mage.cards.s.SpiderSpawning.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Splinterfright", 217, Rarity.UNCOMMON, mage.cards.s.Splinterfright.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Splinterfright", 420, Rarity.UNCOMMON, mage.cards.s.Splinterfright.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spontaneous Mutation", 86, Rarity.COMMON, mage.cards.s.SpontaneousMutation.class));
cards.add(new SetCardInfo("Spore Crawler", 218, Rarity.COMMON, mage.cards.s.SporeCrawler.class));
cards.add(new SetCardInfo("Stensia Masquerade", 172, Rarity.UNCOMMON, mage.cards.s.StensiaMasquerade.class));
cards.add(new SetCardInfo("Stitched Mangler", 87, Rarity.COMMON, mage.cards.s.StitchedMangler.class));
cards.add(new SetCardInfo("Stitcher's Graft", 271, Rarity.RARE, mage.cards.s.StitchersGraft.class));
cards.add(new SetCardInfo("Stormcarved Coast", 285, Rarity.RARE, mage.cards.s.StormcarvedCoast.class));
cards.add(new SetCardInfo("Strength of Arms", 42, Rarity.COMMON, mage.cards.s.StrengthOfArms.class));
cards.add(new SetCardInfo("Stromkirk Occultist", 173, Rarity.UNCOMMON, mage.cards.s.StromkirkOccultist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Stromkirk Occultist", 402, Rarity.UNCOMMON, mage.cards.s.StromkirkOccultist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Subjugator Angel", 350, Rarity.UNCOMMON, mage.cards.s.SubjugatorAngel.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Subjugator Angel", 43, Rarity.UNCOMMON, mage.cards.s.SubjugatorAngel.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Summary Dismissal", 368, Rarity.UNCOMMON, mage.cards.s.SummaryDismissal.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Summary Dismissal", 88, Rarity.UNCOMMON, mage.cards.s.SummaryDismissal.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sundown Pass", 286, Rarity.RARE, mage.cards.s.SundownPass.class));
cards.add(new SetCardInfo("Swamp", 292, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", 293, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Syncopate", 89, Rarity.COMMON, mage.cards.s.Syncopate.class));
cards.add(new SetCardInfo("Tamiyo's Journal", 272, Rarity.RARE, mage.cards.t.TamiyosJournal.class));
cards.add(new SetCardInfo("Tamiyo, Field Researcher", 249, Rarity.MYTHIC, mage.cards.t.TamiyoFieldResearcher.class));
cards.add(new SetCardInfo("Temporal Mastery", 307, Rarity.MYTHIC, mage.cards.t.TemporalMastery.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Temporal Mastery", 90, Rarity.MYTHIC, mage.cards.t.TemporalMastery.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Terror of Kruin Pass", 161, Rarity.RARE, mage.cards.t.TerrorOfKruinPass.class));
cards.add(new SetCardInfo("Thalia, Heretic Cathar", 300, Rarity.RARE, mage.cards.t.ThaliaHereticCathar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thalia, Heretic Cathar", 351, Rarity.RARE, mage.cards.t.ThaliaHereticCathar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thalia, Heretic Cathar", 44, Rarity.RARE, mage.cards.t.ThaliaHereticCathar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Gitrog Monster", 238, Rarity.MYTHIC, mage.cards.t.TheGitrogMonster.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Gitrog Monster", 431, Rarity.MYTHIC, mage.cards.t.TheGitrogMonster.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Gitrog Monster", 489, Rarity.MYTHIC, mage.cards.t.TheGitrogMonster.class, FULL_ART));
cards.add(new SetCardInfo("The Meathook Massacre", 122, Rarity.MYTHIC, mage.cards.t.TheMeathookMassacre.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Meathook Massacre", 387, Rarity.MYTHIC, mage.cards.t.TheMeathookMassacre.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Meathook Massacre", 486, Rarity.MYTHIC, mage.cards.t.TheMeathookMassacre.class, FULL_ART));
cards.add(new SetCardInfo("Thermo-Alchemist", 174, Rarity.UNCOMMON, mage.cards.t.ThermoAlchemist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thermo-Alchemist", 403, Rarity.UNCOMMON, mage.cards.t.ThermoAlchemist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thing in the Ice", 460, Rarity.RARE, mage.cards.t.ThingInTheIce.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thing in the Ice", 91, Rarity.RARE, mage.cards.t.ThingInTheIce.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Think Twice", 369, Rarity.COMMON, mage.cards.t.ThinkTwice.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Think Twice", 92, Rarity.COMMON, mage.cards.t.ThinkTwice.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thraben Inspector", 301, Rarity.COMMON, mage.cards.t.ThrabenInspector.class, FULL_ART));
cards.add(new SetCardInfo("Thraben Inspector", 45, Rarity.COMMON, mage.cards.t.ThrabenInspector.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Through the Breach", 175, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Through the Breach", 404, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Through the Breach", 487, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, FULL_ART));
cards.add(new SetCardInfo("Timber Shredder", 203, Rarity.COMMON, mage.cards.t.TimberShredder.class));
cards.add(new SetCardInfo("Tireless Tracker", 219, Rarity.RARE, mage.cards.t.TirelessTracker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tireless Tracker", 318, Rarity.RARE, mage.cards.t.TirelessTracker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Torens, Fist of the Angels", 250, Rarity.RARE, mage.cards.t.TorensFistOfTheAngels.class));
cards.add(new SetCardInfo("Tower Geist", 93, Rarity.COMMON, mage.cards.t.TowerGeist.class));
cards.add(new SetCardInfo("Town Gossipmonger", 451, Rarity.UNCOMMON, mage.cards.t.TownGossipmonger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Town Gossipmonger", 46, Rarity.UNCOMMON, mage.cards.t.TownGossipmonger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tragic Slip", 134, Rarity.COMMON, mage.cards.t.TragicSlip.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tragic Slip", 390, Rarity.COMMON, mage.cards.t.TragicSlip.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Travel Preparations", 220, Rarity.UNCOMMON, mage.cards.t.TravelPreparations.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Travel Preparations", 421, Rarity.UNCOMMON, mage.cards.t.TravelPreparations.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Traveler's Amulet", 273, Rarity.COMMON, mage.cards.t.TravelersAmulet.class));
cards.add(new SetCardInfo("Traverse the Ulvenwald", 221, Rarity.RARE, mage.cards.t.TraverseTheUlvenwald.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Traverse the Ulvenwald", 422, Rarity.RARE, mage.cards.t.TraverseTheUlvenwald.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tree of Perdition", 135, Rarity.RARE, mage.cards.t.TreeOfPerdition.class));
cards.add(new SetCardInfo("Triskaidekaphobia", 136, Rarity.UNCOMMON, mage.cards.t.Triskaidekaphobia.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Triskaidekaphobia", 391, Rarity.UNCOMMON, mage.cards.t.Triskaidekaphobia.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Twinblade Geist", 452, Rarity.UNCOMMON, mage.cards.t.TwinbladeGeist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Twinblade Geist", 47, Rarity.UNCOMMON, mage.cards.t.TwinbladeGeist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Twinblade Invocation", 452, Rarity.UNCOMMON, mage.cards.t.TwinbladeInvocation.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Twinblade Invocation", 47, Rarity.UNCOMMON, mage.cards.t.TwinbladeInvocation.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ulrich's Kindred", 176, Rarity.UNCOMMON, mage.cards.u.UlrichsKindred.class));
cards.add(new SetCardInfo("Ulvenwald Mysteries", 222, Rarity.UNCOMMON, mage.cards.u.UlvenwaldMysteries.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ulvenwald Mysteries", 423, Rarity.UNCOMMON, mage.cards.u.UlvenwaldMysteries.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Uncaged Fury", 177, Rarity.UNCOMMON, mage.cards.u.UncagedFury.class));
cards.add(new SetCardInfo("Unnatural Growth", 223, Rarity.RARE, mage.cards.u.UnnaturalGrowth.class));
cards.add(new SetCardInfo("Valorous Stance", 352, Rarity.UNCOMMON, mage.cards.v.ValorousStance.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Valorous Stance", 48, Rarity.UNCOMMON, mage.cards.v.ValorousStance.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vanquish the Horde", 302, Rarity.RARE, mage.cards.v.VanquishTheHorde.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vanquish the Horde", 49, Rarity.RARE, mage.cards.v.VanquishTheHorde.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vexing Devil", 178, Rarity.RARE, mage.cards.v.VexingDevil.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vexing Devil", 313, Rarity.RARE, mage.cards.v.VexingDevil.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vildin-Pack Alpha", 156, Rarity.UNCOMMON, mage.cards.v.VildinPackAlpha.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vildin-Pack Alpha", 464, Rarity.UNCOMMON, mage.cards.v.VildinPackAlpha.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vilespawn Spider", 251, Rarity.UNCOMMON, mage.cards.v.VilespawnSpider.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vilespawn Spider", 436, Rarity.UNCOMMON, mage.cards.v.VilespawnSpider.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Village Messenger", 179, Rarity.COMMON, mage.cards.v.VillageMessenger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Village Messenger", 466, Rarity.COMMON, mage.cards.v.VillageMessenger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Village Rites", 137, Rarity.COMMON, mage.cards.v.VillageRites.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Village Rites", 392, Rarity.COMMON, mage.cards.v.VillageRites.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Villagers of Estwald", 224, Rarity.COMMON, mage.cards.v.VillagersOfEstwald.class));
cards.add(new SetCardInfo("Voice of the Blessed", 50, Rarity.RARE, mage.cards.v.VoiceOfTheBlessed.class));
cards.add(new SetCardInfo("Voldaren Ambusher", 180, Rarity.UNCOMMON, mage.cards.v.VoldarenAmbusher.class));
cards.add(new SetCardInfo("Voldaren Bloodcaster", 138, Rarity.RARE, mage.cards.v.VoldarenBloodcaster.class));
cards.add(new SetCardInfo("Voldaren Duelist", 181, Rarity.COMMON, mage.cards.v.VoldarenDuelist.class));
cards.add(new SetCardInfo("Voldaren Epicure", 182, Rarity.COMMON, mage.cards.v.VoldarenEpicure.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Voldaren Epicure", 405, Rarity.COMMON, mage.cards.v.VoldarenEpicure.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wandering Mind", 252, Rarity.UNCOMMON, mage.cards.w.WanderingMind.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wandering Mind", 437, Rarity.UNCOMMON, mage.cards.w.WanderingMind.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wedding Announcement", 453, Rarity.RARE, mage.cards.w.WeddingAnnouncement.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wedding Announcement", 51, Rarity.RARE, mage.cards.w.WeddingAnnouncement.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wedding Festivity", 453, Rarity.RARE, mage.cards.w.WeddingFestivity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wedding Festivity", 51, Rarity.RARE, mage.cards.w.WeddingFestivity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Westvale Abbey", 287, Rarity.RARE, mage.cards.w.WestvaleAbbey.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Westvale Abbey", 474, Rarity.RARE, mage.cards.w.WestvaleAbbey.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wild Hunger", 225, Rarity.UNCOMMON, mage.cards.w.WildHunger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wild Hunger", 424, Rarity.UNCOMMON, mage.cards.w.WildHunger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wild-Field Scarecrow", 274, Rarity.COMMON, mage.cards.w.WildFieldScarecrow.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wild-Field Scarecrow", 447, Rarity.COMMON, mage.cards.w.WildFieldScarecrow.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wrenn and Seven", 226, Rarity.MYTHIC, mage.cards.w.WrennAndSeven.class));
cards.add(new SetCardInfo("Wretched Gryff", 332, Rarity.COMMON, mage.cards.w.WretchedGryff.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wretched Gryff", 7, Rarity.COMMON, mage.cards.w.WretchedGryff.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wretched Throng", 94, Rarity.COMMON, mage.cards.w.WretchedThrong.class));
cards.add(new SetCardInfo("Young Wolf", 227, Rarity.COMMON, mage.cards.y.YoungWolf.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Young Wolf", 319, Rarity.COMMON, mage.cards.y.YoungWolf.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Young Wolf", 425, Rarity.COMMON, mage.cards.y.YoungWolf.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Zealous Conscripts", 183, Rarity.RARE, mage.cards.z.ZealousConscripts.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Zealous Conscripts", 314, Rarity.RARE, mage.cards.z.ZealousConscripts.class, NON_FULL_USE_VARIOUS));
}
}

View file

@ -47,6 +47,7 @@ public class ConspireTest extends CardTestPlayerBase {
setChoice(playerA, "Goblin Roughrider^Raging Goblin"); // tap for conspire
setChoice(playerA, false); // don't change target
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
@ -54,7 +55,6 @@ public class ConspireTest extends CardTestPlayerBase {
assertGraveyardCount(playerA, "Burn Trail", 1);
assertTapped("Goblin Roughrider", true);
assertTapped("Raging Goblin", true);
}
@Test
@ -67,6 +67,7 @@ public class ConspireTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Burn Trail", playerB);
setChoice(playerA, false);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
@ -103,7 +104,6 @@ public class ConspireTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "Wort, the Raidmother", 1);
assertGraveyardCount(playerA, "Lightning Bolt", 1);
assertLife(playerB, 20 - 3 - 3);
}
@Test
@ -137,7 +137,6 @@ public class ConspireTest extends CardTestPlayerBase {
assertGraveyardCount(playerA, "Lightning Bolt", 1);
assertTapped("Raging Goblin", false);
assertLife(playerB, 20 - 3 - 3 - 2);
}
@Test
@ -158,8 +157,10 @@ public class ConspireTest extends CardTestPlayerBase {
setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire
setChoice(playerA, false); // keep targets
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Wort, the Raidmother", 1);
assertLife(playerB, 20 - 3 - 3);
assertLife(playerA, 20);
@ -181,22 +182,20 @@ public class ConspireTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Burn Trail", playerB);
setChoice(playerA, true); // use Conspire from Burn Trail itself
setChoice(playerA, true); // use Conspire gained from Wort, the Raidmother
setChoice(playerA, "When you pay the conspire"); // order triggers
setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire
setChoice(playerA, false); // keep targets
setChoice(playerA, "Raging Goblin", 2); // tap for conspire
setChoice(playerA, "When you pay the conspire"); // order triggers
setChoice(playerA, false); // keep targets
setChoice(playerA, false); // keep targets
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Wort, the Raidmother", 1);
assertLife(playerB, 20 - 3 - 3 - 3);
assertLife(playerA, 20);
assertGraveyardCount(playerA, "Burn Trail", 1);
}
@Test
@ -221,8 +220,10 @@ public class ConspireTest extends CardTestPlayerBase {
setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire
setChoice(playerA, false); // keep targets
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Wort, the Raidmother", 1);
assertPermanentCount(playerA, "Sakashima the Impostor", 1);
assertLife(playerB, 20 - 3 - 3);
@ -248,15 +249,16 @@ public class ConspireTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
setChoice(playerA, true); // use Conspire gained from Wort, the Raidmother
setChoice(playerA, true); // use Conspire gained from Sakashima the Imposter
setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire
setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire
setChoice(playerA, "When you pay the conspire"); // order triggers
setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire
setChoice(playerA, false); // keep targets
setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire
setChoice(playerA, false); // keep targets
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Wort, the Raidmother", 1);
assertPermanentCount(playerA, "Sakashima the Impostor", 1);
assertLife(playerB, 20 - 3 - 3 - 3);

View file

@ -6,13 +6,12 @@ import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author Quercitron
* @author Quercitron, JayDi85
*/
public class DoIfCostPaidTest extends CardTestPlayerBase {
@Test
public void testPayIsNotOptional() {
public void test_NonOptional() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
// Shock deals 2 damage to any target.
addCard(Zone.HAND, playerA, "Shock", 1);
@ -22,6 +21,8 @@ public class DoIfCostPaidTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerB, "Awaken the Sky Tyrant");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", playerB);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
@ -29,4 +30,72 @@ public class DoIfCostPaidTest extends CardTestPlayerBase {
assertPermanentCount(playerB, "Dragon Token", 1);
}
@Test
public void test_Optional_ManaVault_1() {
// Mana Vault doesn't untap during your untap step.
// At the beginning of your upkeep, you may pay {4}. If you do, untap Mana Vault.
// At the beginning of your draw step, if Mana Vault is tapped, it deals 1 damage to you.
// {T}: Add {C}{C}{C}.
addCard(Zone.BATTLEFIELD, playerA, "Mana Vault", 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
// turn 1 - untapped and ask about untap
setChoice(playerA, false); // do not pay
checkPermanentTapped("must be untapped on start", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mana Vault", false, 1);
checkLife("no damage on untapped", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 20);
// turn 2 - tap
activateManaAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {C}");
checkPermanentTapped("must be tapped after usage", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Mana Vault", true, 1);
// turn 3 - tapped and ask about untap (do not pay)
setChoice(playerA, false);
checkPermanentTapped("must be tapped after dialog", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Mana Vault", true, 1);
checkLife("must do damage on tapped", 3, PhaseStep.PRECOMBAT_MAIN, playerA, 20 - 1);
// turn 4 - nothing
// turn 5 - tapped and ask about untap (do pay)
setChoice(playerA, true);
checkPermanentTapped("must be untapped after dialog", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Mana Vault", false, 1);
checkLife("no damage on untapped", 5, PhaseStep.PRECOMBAT_MAIN, playerA, 20 - 1); // -1 from old damage
setStrictChooseMode(true);
setStopAt(5, PhaseStep.END_TURN);
execute();
}
@Test
public void test_Optional_ManaVault_2() {
// Make sure it allow to pay untap cost anyway, so some combos can be used, see https://github.com/magefree/mage/issues/2656
// Example:
// When Mana Vault is untapped you can respond to the trigger pay four to untap is to tap it and then pay 4
// to untap it. That would not be possible if the trigger is skipped.
// That's legal according to the rules and would net mana if Mana Reflection was in play, would allow
// self milling with Mesmeric Orb in play, and I'm sure many other interactions that change the game state.
// Mana Vault doesn't untap during your untap step.
// At the beginning of your upkeep, you may pay {4}. If you do, untap Mana Vault.
// At the beginning of your draw step, if Mana Vault is tapped, it deals 1 damage to you.
// {T}: Add {C}{C}{C}.
addCard(Zone.BATTLEFIELD, playerA, "Mana Vault", 1);
//
// If you tap a permanent for mana, it produces twice as much of that mana instead.
addCard(Zone.BATTLEFIELD, playerA, "Mana Reflection", 1);
//
// Whenever a permanent becomes untapped, that permanent's controller puts the top card of
// their library into their graveyard.
addCard(Zone.BATTLEFIELD, playerA, "Mesmeric Orb", 1);
setChoice(playerA, true); // pay by itself
checkPermanentTapped("must be untapped", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mana Vault", false, 1);
checkLife("no damage on untapped", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 20);
checkGraveyardCount("must mill", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain", 1);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
}
}

View file

@ -10,10 +10,10 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
* {3}
* Artifact
* Imprint Whenever a nontoken creature dies, you may exile that card.
* If you do, return each other card exiled with Mimic Vat to its owners graveyard.
* If you do, return each other card exiled with Mimic Vat to its owners graveyard.
* {3}, {T}: Create a token thats a copy of a card exiled with Mimic Vat.
* It gains haste.
* Exile it at the beginning of the next end step.
* It gains haste.
* Exile it at the beginning of the next end step.
*
* @author LevelX2
*/
@ -77,17 +77,23 @@ public class MimicVatTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
// prepare copy
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Metamorph", true);
setChoice(playerA, true);
setChoice(playerA, "Silvercoat Lion");
setChoice(playerA, true); // pay 2 life
setChoice(playerA, true); // copy on etb
setChoice(playerA, "Silvercoat Lion"); // copy
// sacrifice and exile a copy
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}, {T}, Sacrifice a creature");
setChoice(playerA, true);
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Create a token that's a copy of a card exiled with ");
setChoice(playerA, true);
setChoice(playerA, "Silvercoat Lion");
setChoice(playerA, true);
// create copy of exiled Metamorph
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Create a token that's a copy of a card exiled with ");
setChoice(playerA, true); // copy on etb
setChoice(playerA, "Silvercoat Lion"); // copy
setStrictChooseMode(true);
setStopAt(3, PhaseStep.BEGIN_COMBAT);
execute();
@ -125,6 +131,7 @@ public class MimicVatTest extends CardTestPlayerBase {
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Create a token that's a copy of a card exiled with ");
setStrictChooseMode(true);
setStopAt(3, PhaseStep.BEGIN_COMBAT);
execute();

View file

@ -9,12 +9,13 @@ import mage.constants.Zone;
import mage.game.permanent.Permanent;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.player.TestPlayer;
import org.mage.test.serverside.base.CardTestPlayerBase;
import static org.junit.Assert.*;
/**
* @author noxx
* @author noxx, JayDi85
* <p>
* Card: You may have {this} enter the battlefield as a copy of any creature on
* the battlefield, except it's an Illusion in addition to its other types and
@ -30,7 +31,10 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerB, "Craw Wurm");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image");
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Craw Wurm"); // copy
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
@ -51,7 +55,10 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerB, "Howling Banshee");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image");
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Howling Banshee"); // copy
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
@ -79,7 +86,10 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
}
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image");
setChoice(playerB, true); // use copy on etb
setChoice(playerB, "Transcendent Master"); // copy
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
@ -112,10 +122,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Illusionary Servant");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image", true);
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Illusionary Servant");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image");
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Illusionary Servant-M10");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
@ -147,16 +161,28 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
// Enchantment - Creatures you control have hexproof.
addCard(Zone.HAND, playerA, "Asceticism");
// Huntmaster of the Fells:
// Whenever this creature enters the battlefield or transforms into
// Huntmaster of the Fells, put a 2/2 green Wolf creature token onto
// the battlefield and you gain 2 life.
// At the beginning of each upkeep, if no spells were cast last turn, transform Huntmaster of the Fells. ==> Ravager of the Fells
// Ravager of the Fells:
// Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls.
addCard(Zone.BATTLEFIELD, playerA, "Huntmaster of the Fells");
// transform on upkeep to Ravager of the Fells
addTarget(playerA, playerB); // x2 damage on transform (player)
addTarget(playerA, TestPlayer.TARGET_SKIP); // x2 damage on transform (creature)
// copy transformed
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // copy target: Ravergers of the Fells
setChoice(playerB, true); // use copy on etb
setChoice(playerB, "Ravager of the Fells"); // copy
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Asceticism");
castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerB, "Titanic Growth", "Ravager of the Fells");
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
execute();
@ -167,7 +193,6 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
// check playerB's creature was sacrificed
assertGraveyardCount(playerB, "Phantasmal Image", 1);
assertPermanentCount(playerB, "Ravager of the Fells", 0);
}
/**
@ -175,7 +200,7 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
* Messenger: Geralf's Messenger enters the battlefield tapped
*/
@Test
public void testCopyEntersTapped() {
public void testCopyEntersTappedAndEtb() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
// You may have Phantasmal Image enter the battlefield as a copy of any creature
// on the battlefield, except it's an Illusion in addition to its other types and
@ -184,7 +209,11 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerB, "Geralf's Messenger");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image");
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Geralf's Messenger"); // copy
addTarget(playerA, playerB); // x2 damage from etb of copied
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
@ -211,11 +240,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
// When you control no permanents of the chosen color, sacrifice Lurebound Scarecrow.
addCard(Zone.HAND, playerA, "Lurebound Scarecrow");
setChoice(playerA, "Green");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lurebound Scarecrow");
setChoice(playerA, "Red");
setChoice(playerA, "Green");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Phantasmal Image");
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Lurebound Scarecrow"); // copy
setChoice(playerA, "Red");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
@ -235,11 +267,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
addCard(Zone.HAND, playerA, "Phantasmal Image");
addCard(Zone.HAND, playerA, "Lurebound Scarecrow");
setChoice(playerA, "Green");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lurebound Scarecrow");
setChoice(playerA, "Red");
setChoice(playerA, "Green");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Phantasmal Image");
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Lurebound Scarecrow"); // copy
setChoice(playerA, "Red");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
@ -257,12 +292,16 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerB, "Llanowar Elves");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image");
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Azure Drake"); // copy
attack(1, playerA, "Azure Drake");
block(1, playerB, "Llanowar Elves", "Azure Drake");
attack(2, playerB, "Azure Drake");
block(2, playerA, "Elite Vanguard", "Azure Drake");
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
@ -288,13 +327,15 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
setChoice(playerA, "X=0");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image");
setChoice(playerB, "Steel Hellkite");
setChoice(playerB, true); // use copy on etb
setChoice(playerB, "Steel Hellkite"); // copy
attack(4, playerB, "Steel Hellkite");
activateAbility(4, PhaseStep.POSTCOMBAT_MAIN, playerB, "{X}:");
setChoice(playerB, "X=0");
setStrictChooseMode(true);
setStopAt(4, PhaseStep.END_TURN);
execute();
@ -306,7 +347,6 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "Chalice of the Void", 0);
assertGraveyardCount(playerA, "Chalice of the Void", 1);
}
/**
@ -317,38 +357,59 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
*/
@Test
public void testCopiedFrostTitan() {
// Whenever Frost Titan becomes the target of a spell or ability an opponent controls, counter that spell or ability unless its controller pays {2}.
// Whenever Frost Titan enters the battlefield or attacks, tap target permanent. It doesn't untap during its controller's next untap step.
// Whenever Frost Titan becomes the target of a spell or ability an opponent controls,
// counter that spell or ability unless its controller pays 2.
// Whenever Frost Titan enters the battlefield or attacks, tap target permanent. It doesn't
// untap during its controller's next untap step.
addCard(Zone.BATTLEFIELD, playerA, "Frost Titan");
addCard(Zone.HAND, playerA, "Terror");
addCard(Zone.BATTLEFIELD, playerA, "Island", 2); // for counter pay
addCard(Zone.BATTLEFIELD, playerB, "Island", 2); // for counter pay
//
// {1}{U} - Target creature gains shroud until end of turn and can't be blocked this turn.
addCard(Zone.HAND, playerA, "Veil of Secrecy");
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
addCard(Zone.HAND, playerA, "Veil of Secrecy", 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
addCard(Zone.HAND, playerB, "Veil of Secrecy", 1);
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
//
addCard(Zone.HAND, playerB, "Phantasmal Image"); // {1}{U}
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
addCard(Zone.HAND, playerB, "Phantasmal Image");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Veil of Secrecy", "Frost Titan"); // so it's no longer targetable
setChoice(playerB, "Frost Titan");
// prepare copy
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image");
setChoice(playerB, true); // use copy on etb
setChoice(playerB, "Frost Titan"); // copy
addTarget(playerB, "Island"); // tap on etb
waitStackResolved(2, PhaseStep.PRECOMBAT_MAIN);
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Terror", "Frost Titan"); // of player Bs Phantasmal Image copying Frost Titan
// should be countered if not paying {2}
// make sure both has titan permanent
checkPermanentCount("after prepare", 2, PhaseStep.PRECOMBAT_MAIN, playerB, playerA, "Frost Titan", 1);
checkPermanentCount("after prepare", 2, PhaseStep.PRECOMBAT_MAIN, playerB, playerB, "Frost Titan", 1);
// try original target trigger (B cast into A's titan and ask to anti-counter pay)
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Veil of Secrecy");
addTarget(playerB, "Frost Titan[no copy]");
setChoice(playerB, true); // pay to stop counter
waitStackResolved(2, PhaseStep.POSTCOMBAT_MAIN);
// try copied target trigger (A cast into B's titan and ask to anti-counter pay)
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Veil of Secrecy");
addTarget(playerA, "Frost Titan[only copy]");
setChoice(playerB, "When {this} becomes the target of a spell or ability, sacrifice it."); // x2 triggers (make sure illusion's will go first)
setChoice(playerA, true); // pay to stop counter (it's useless here, but will sure trigger works fine)
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerA, "Veil of Secrecy", 1);
assertGraveyardCount(playerA, "Terror", 1);
assertLife(playerB, 20);
assertLife(playerA, 20);
assertPermanentCount(playerA, "Frost Titan", 1);
assertPermanentCount(playerB, "Frost Titan", 0);
assertGraveyardCount(playerB, "Phantasmal Image", 1);
assertGraveyardCount(playerB, "Phantasmal Image", 1); // if triggered ability did not work, the Titan would be in the graveyard instaed
// 2 from cast Phantasmal + 4 from cast Veil + 4 from counter pay
assertTappedCount("Island", true, 2 + 2 * 2 + 2 * 2);
}
// I've casted a Phantasmal Image targeting opponent's Wurmcoil Engine
@ -365,12 +426,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
addCard(Zone.HAND, playerB, "Phantasmal Image");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted
setChoice(playerB, "Wurmcoil Engine");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image");
setChoice(playerB, true); // use copy on etb
setChoice(playerB, "Wurmcoil Engine"); // copy
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Wurmcoil Engine"); // of player Bs Phantasmal Image copying Frost Titan
// should be countered if not paying {2}
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution");
addTarget(playerA, "Wurmcoil Engine[only copy]");
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
@ -403,11 +466,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
addCard(Zone.HAND, playerB, "Phantasmal Image");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted
setChoice(playerB, "Thalakos Seer");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image");
setChoice(playerB, true); // use copy on etb
setChoice(playerB, "Thalakos Seer"); // copy
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Thalakos Seer");
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution");
addTarget(playerA, "Thalakos Seer[only copy]");
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
@ -474,11 +540,16 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitchen Finks");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted
setChoice(playerB, true); // use copy on etb
setChoice(playerB, "Kitchen Finks"); // copy
// destroy and return to battlefield by persist
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution");
addTarget(playerA, "Kitchen Finks[only copy]");
setChoice(playerB, true); // use copy on etb
setChoice(playerB, "Kitchen Finks");
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Kitchen Finks");
setChoice(playerB, "Kitchen Finks");
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
@ -515,11 +586,16 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Butcher Ghoul");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted
setChoice(playerB, "Butcher Ghoul");
setChoice(playerB, true); // use copy on etb
setChoice(playerB, "Butcher Ghoul"); // copy
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Butcher Ghoul");
setChoice(playerB, "Butcher Ghoul");
// destroy and return to battlefield by undying
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution");
addTarget(playerA, "Butcher Ghoul[only copy]");
setChoice(playerB, true); // use copy on etb
setChoice(playerB, "Butcher Ghoul"); // copy
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
@ -559,10 +635,13 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
addCard(Zone.HAND, playerA, "Phantasmal Image");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); // not targeted
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Wurmcoil Engine");
attack(2, playerB, "Wurmcoil Engine");
block(2, playerA, "Wurmcoil Engine", "Wurmcoil Engine");
setStrictChooseMode(true);
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
@ -591,10 +670,13 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
addCard(Zone.HAND, playerA, "Phantasmal Image");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); // not targeted
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Voice of Resurgence");
attack(2, playerB, "Voice of Resurgence");
block(2, playerA, "Voice of Resurgence", "Voice of Resurgence");
setStrictChooseMode(true);
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
@ -615,12 +697,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
addCard(Zone.HAND, playerA, "Phantasmal Image");
setChoice(playerB, "X=1");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{X}");
setChoice(playerB, "X=1");
setChoice(playerA, "Chimeric Staff");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Phantasmal Image");
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Chimeric Staff"); // copy
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
@ -646,9 +730,11 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karn's Touch", "Cloak and Dagger");
setChoice(playerA, "Cloak and Dagger");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Phantasmal Image");
setChoice(playerA, true); // use copy on etb
setChoice(playerA, "Cloak and Dagger"); // copy
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();

View file

@ -1,4 +1,3 @@
package org.mage.test.cards.cost.additional;
import mage.constants.PhaseStep;
@ -7,7 +6,6 @@ import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
@ -15,16 +13,18 @@ public class RemoveCounterCostTest extends CardTestPlayerBase {
@Test
public void testNovijenSages() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 7);
// Graft 4
// {1}, Remove two +1/+1 counters from among creatures you control: Draw a card.
addCard(Zone.HAND, playerA, "Novijen Sages");
addCard(Zone.BATTLEFIELD, playerA, "Island", 7);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Novijen Sages", true);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, Remove two +1/+1 counters");
setChoice(playerA, "X=2");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, Remove two +1/+1 counters");
setChoice(playerA, "Novijen Sages"); // counters to remove
setChoice(playerA, "X=2"); // counters to remove
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
@ -32,9 +32,8 @@ public class RemoveCounterCostTest extends CardTestPlayerBase {
assertPowerToughness(playerA, "Novijen Sages", 2, 2);
assertHandCount(playerA, 1);
assertLife(playerA, 20);
assertLife(playerB, 20);
}
}

View file

@ -1,4 +1,3 @@
package org.mage.test.cards.cost.modification;
import mage.constants.PhaseStep;
@ -7,7 +6,6 @@ import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class HeartstoneTest extends CardTestPlayerBase {
@ -29,8 +27,12 @@ public class HeartstoneTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerA);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{U}", "Lightning Bolt", "Lightning Bolt");
setChoice(playerA, true);
addTarget(playerA, playerB);
setChoice(playerA, "Fugitive Wizard"); // tap cost 1 of 2
setChoice(playerA, "Sigil Tracer"); // tap cost 2 of 2
setChoice(playerA, true); // change target
addTarget(playerA, playerB); // new target
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
@ -41,7 +43,6 @@ public class HeartstoneTest extends CardTestPlayerBase {
assertLife(playerB, 17);
assertTappedCount("Island", true, 1);
}
}

View file

@ -4,16 +4,14 @@ import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.util.RandomUtil;
import org.junit.Test;
import org.mage.test.sba.PlaneswalkerRuleTest;
import org.mage.test.serverside.base.CardTestPlayerBase;
import java.util.Random;
/**
* Reported bugs: https://github.com/magefree/mage/issues/8980
* Cards like Soldevi Excavations, Heart of Yavimaya, and Lake of the Dead
* will sometimes immediately go to the graveyard without asking the controller if they wish to sacrifice a land
* even though they had one available
* Cards like Soldevi Excavations, Heart of Yavimaya, and Lake of the Dead
* will sometimes immediately go to the graveyard without asking the controller if they wish to sacrifice a land
* even though they had one available
*
* @author Alex-Vasile
*/
public class SacrificeLandTest extends CardTestPlayerBase {
@ -35,14 +33,21 @@ public class SacrificeLandTest extends CardTestPlayerBase {
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, soldeviExcavations);
setChoice(playerA, sacFirstLand);
if (sacFirstLand) {
setChoice(playerA, "Island");
}
rollbackTurns(1, PhaseStep.PRECOMBAT_MAIN, playerA, 0);
rollbackAfterActionsStart();
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, soldeviExcavations);
setChoice(playerA, sacSecondLand);
if (sacSecondLand) {
setChoice(playerA, "Island");
}
rollbackAfterActionsEnd();
setStrictChooseMode(true);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
@ -73,14 +78,18 @@ public class SacrificeLandTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Swamp");
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, soldeviExcavations);
setChoice(playerA, "Yes");
setChoice(playerA, "Yes"); // use sacrifice to keep soldevi
setChoice(playerA, "Island"); // sacrifice
playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, heartofYavimaya);
setChoice(playerA, "Yes");
setChoice(playerA, "Yes"); // use sacrifice to keep heart
setChoice(playerA, "Forest"); // sacrifice
playLand(5, PhaseStep.PRECOMBAT_MAIN, playerA, lakeOfTheDead);
setChoice(playerA, "Yes");
setChoice(playerA, "Yes"); // use sacrifice to keep lake
setChoice(playerA, "Swamp"); // sacrifice
setStrictChooseMode(true);
setStopAt(5, PhaseStep.PRECOMBAT_MAIN);
execute();

View file

@ -181,8 +181,8 @@ public class PrimalClayTest extends CardTestPlayerBase {
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, clone);
setChoice(playerB, true); // whether to copy
setFlipCoinResult(playerB, false);
setChoice(playerB, sentry); // what to copy
setFlipCoinResult(playerB, false);
setStrictChooseMode(true);
setStopAt(2, PhaseStep.BEGIN_COMBAT);
@ -218,7 +218,7 @@ public class PrimalClayTest extends CardTestPlayerBase {
// Target creature you control gets +2/+2 until end of turn if its power is 2. Then it fights target creature you dont control.
addCard(Zone.BATTLEFIELD, playerB, "Siege Mastodon", 1); // 3/5 creature for fighting
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aquamorph+" using Morph");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aquamorph + " using Morph");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Savage Swipe");
addTarget(playerA, EmptyNames.FACE_DOWN_CREATURE.getTestCommand()); // morph

View file

@ -0,0 +1,108 @@
package org.mage.test.cards.rules;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author markort147
*/
public class TriggerAbilityOnlyLimitedTimesTest extends CardTestPlayerBase {
/**
* Enduring Innocence {1}{W}{W}
* Enchantment Creature - Sheep Glimmer
* 2/1
* Lifelink
* Whenever one or more other creatures you control with power 2 or less enter, draw a card. This ability triggers only once each turn.
* When Enduring Innocence dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment. (It's not a creature.)
*/
@Test
public void testTriggerOnceEachTurn() {
addCard(Zone.HAND, playerA, "Llanowar Elves", 2);
addCard(Zone.BATTLEFIELD, playerA, "Enduring Innocence", 1);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Llanowar Elves", true); // Draw a card
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Llanowar Elves", true); // Do not draw a card
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertHandCount(playerA, 1);
}
/**
* Momentary Blink {1}{W}
* Instant
* Exile target creature you control, then return it to the battlefield under its owner's control.
* Flashback (You may cast this card from your graveyard for its flashback cost. Then exile it.)
*/
@Test
public void testTriggerTwiceSameTurnIfBlinked() {
addCard(Zone.HAND, playerA, "Llanowar Elves", 2);
addCard(Zone.HAND, playerA, "Momentary Blink");
addCard(Zone.BATTLEFIELD, playerA, "Enduring Innocence", 1);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Llanowar Elves", true); // Draw a card
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Momentary Blink", "Enduring Innocence", true); // Blink
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Llanowar Elves", true); // Draw a card again
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertHandCount(playerA, 2);
assertPermanentCount(playerA, "Enduring Innocence", 1);
}
/**
* Acrobatic Cheerleader {1}{W}
* Creature - Human Survivor
* 2/2
* Survival At the beginning of your second main phase, if Acrobatic Cheerleader is tapped, put a flying counter on it. This ability triggers only once.
*/
@Test
public void testTriggerOnceEachGame() {
addCard(Zone.BATTLEFIELD, playerA, "Acrobatic Cheerleader", 1);
attack(3, playerA, "Acrobatic Cheerleader", playerB); // Put a flying counter
attack(5, playerA, "Acrobatic Cheerleader", playerB); // Do not put another flying counter
setStopAt(5, PhaseStep.END_TURN);
execute();
assertCounterCount(playerA, "Acrobatic Cheerleader", CounterType.FLYING, 1);
}
/**
* Momentary Blink {1}{W}
* Instant
* Exile target creature you control, then return it to the battlefield under its owner's control.
* Flashback (You may cast this card from your graveyard for its flashback cost. Then exile it.)
*/
@Test
public void testTriggerTwiceSameGameIfBlinked() {
addCard(Zone.BATTLEFIELD, playerA, "Acrobatic Cheerleader", 1);
addCard(Zone.HAND, playerA, "Momentary Blink");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
attack(3, playerA, "Acrobatic Cheerleader", playerB); // Put a flying counter
castSpell(3, PhaseStep.END_TURN, playerA, "Momentary Blink", "Acrobatic Cheerleader"); // Blinks and loses the counter
attack(5, playerA, "Acrobatic Cheerleader", playerB); // Put a flying counter
setStopAt(5, PhaseStep.END_TURN);
execute();
assertCounterCount(playerA, "Acrobatic Cheerleader", CounterType.FLYING, 1);
}
}

View file

@ -10,6 +10,9 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
*/
public class CadricSoulKindlerTest extends CardTestPlayerBase {
// The "legend rule" doesn't apply to tokens you control.
// Whenever another nontoken legendary permanent you control enters, you may pay {1}. If you do, create a token
// that's a copy of it. That token gains haste. Sacrifice it at the beginning of the next end step.
private static final String cadric = "Cadric, Soul Kindler";
private static final String isamaru = "Isamaru, Hound of Konda";
@ -20,7 +23,7 @@ public class CadricSoulKindlerTest extends CardTestPlayerBase {
addCard(Zone.HAND, playerA, isamaru);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, isamaru);
setChoice(playerA, true);
setChoice(playerA, true); // create copy
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
setStrictChooseMode(true);
@ -36,12 +39,14 @@ public class CadricSoulKindlerTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
addCard(Zone.HAND, playerA, isamaru, 2);
// first isamaru and copy of it
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, isamaru);
setChoice(playerA, true);
setChoice(playerA, true); // create copy
// second isamaru and copy of it
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, isamaru);
setChoice(playerA, true);
setChoice(playerA, isamaru);
setChoice(playerA, isamaru); // keep 1 perm due legendary rule
setChoice(playerA, true); // create copy
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
setStrictChooseMode(true);

View file

@ -0,0 +1,96 @@
package org.mage.test.cards.single.rix;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
/**
* @author JayDi85
*/
public class VonasHungerTest extends CardTestPlayerBaseWithAIHelps {
@Test
public void test_NoAscend_Normal() {
// Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)
// Each opponent sacrifices a creature.
// If you have the city's blessing, instead each opponent sacrifices half the creatures they control rounded up.
addCard(Zone.HAND, playerA, "Vona's Hunger"); // {2}{B}
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
//
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 5);
// opponent must sacrifice 1
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vona's Hunger");
setChoice(playerB, "Grizzly Bears"); // to sacrifice
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerB, 5 - 1);
}
@Test
public void test_NoAscend_AI() {
// Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)
// Each opponent sacrifices a creature.
// If you have the city's blessing, instead each opponent sacrifices half the creatures they control rounded up.
addCard(Zone.HAND, playerA, "Vona's Hunger"); // {2}{B}
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
//
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 5);
// AI must sacrifice 1
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vona's Hunger");
aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerB);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerB, 5 - 1);
}
@Test
public void test_Ascend_Normal() {
// Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)
// Each opponent sacrifices a creature.
// If you have the city's blessing, instead each opponent sacrifices half the creatures they control rounded up.
addCard(Zone.HAND, playerA, "Vona's Hunger"); // {2}{B}
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 10);
//
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 5);
// opponent must sacrifice 3
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vona's Hunger");
setChoice(playerB, "Grizzly Bears^Grizzly Bears^Grizzly Bears"); // to sacrifice
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerB, 5 - 3);
}
@Test
public void test_Ascend_AI() {
// Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)
// Each opponent sacrifices a creature.
// If you have the city's blessing, instead each opponent sacrifices half the creatures they control rounded up.
addCard(Zone.HAND, playerA, "Vona's Hunger"); // {2}{B}
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 10);
//
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 5);
// AI must sacrifice 3
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vona's Hunger");
aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerB);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerB, 5 - 3);
}
}

View file

@ -2293,7 +2293,8 @@ public class TestPlayer implements Player {
} else {
filterPermanent = ((TargetPermanent) target.getOriginalTarget()).getFilter();
}
for (String choiceRecord : choices) {
while (!choices.isEmpty()) {
String choiceRecord = choices.get(0);
String[] targetList = choiceRecord.split("\\^");
boolean targetFound = false;
for (String targetName : targetList) {
@ -2332,24 +2333,46 @@ public class TestPlayer implements Player {
}
}
}
if (targetFound) {
choices.remove(choiceRecord);
return true;
try {
if (target.isChosen(game)) {
return true;
} else {
if (!targetFound) {
failOnLastBadChoice(game, source, target, choiceRecord, "unknown or can't target");
}
}
} finally {
choices.remove(0);
}
}
}
if (target instanceof TargetPlayer) {
for (Player player : game.getPlayers().values()) {
for (String choose2 : choices) {
if (player.getName().equals(choose2)) {
while (!choices.isEmpty()) {
String choiceRecord = choices.get(0);
boolean targetFound = false;
for (Player player : game.getPlayers().values()) {
if (player.getName().equals(choiceRecord)) {
if (target.canTarget(abilityControllerId, player.getId(), null, game) && !target.getTargets().contains(player.getId())) {
target.add(player.getId(), game);
choices.remove(choose2);
return true;
targetFound = true;
} else {
failOnLastBadChoice(game, source, target, choiceRecord, "can't target");
}
}
}
try {
if (target.isChosen(game)) {
return true;
}
if (!targetFound) {
failOnLastBadChoice(game, source, target, choiceRecord, "unknown target");
}
} finally {
choices.remove(0);
}
}
}
@ -3080,8 +3103,8 @@ public class TestPlayer implements Player {
}
@Override
public void controlPlayersTurn(Game game, UUID playerUnderControlId, String info) {
computerPlayer.controlPlayersTurn(game, playerUnderControlId, info);
public boolean controlPlayersTurn(Game game, UUID playerUnderControlId, String info) {
return computerPlayer.controlPlayersTurn(game, playerUnderControlId, info);
}
@Override
@ -4684,6 +4707,15 @@ public class TestPlayer implements Player {
return !this.strictChooseMode;
}
private void failOnLastBadChoice(Game game, Ability source, Target target, String lastChoice, String reason) {
Assert.fail(String.format("Found wrong choice command (%s):\n%s\n%s\n%s",
reason,
lastChoice,
getInfo(target, game),
getInfo(source, game)
));
}
private void assertWrongChoiceUsage(String choice) {
// TODO: enable fail checks and fix tests, it's a part of setStrictChooseMode's implementation to all tests
//Assert.fail("Wrong choice command: " + choice);

View file

@ -244,7 +244,8 @@ public class TriggeredAbilities extends LinkedHashMap<String, TriggeredAbility>
NumberOfTriggersEvent numberOfTriggersEvent = new NumberOfTriggersEvent(ability, event);
// event == null - state based triggers like StateTriggeredAbility, must be ignored for number event
if (event == null || !game.replaceEvent(numberOfTriggersEvent, ability)) {
int numTriggers = Integer.min(ability.getRemainingTriggersLimitEachTurn(game), numberOfTriggersEvent.getAmount());
int limit = Integer.min(ability.getRemainingTriggersLimitEachGame(game), ability.getRemainingTriggersLimitEachTurn(game));
int numTriggers = Integer.min(limit, numberOfTriggersEvent.getAmount());
for (int i = 0; i < numTriggers; i++) {
if (this.enableIntegrityLogs) {
logger.info("trigger will be USED: " + ability);

View file

@ -40,6 +40,11 @@ public interface TriggeredAbility extends Ability {
*/
TriggeredAbility setTriggersLimitEachTurn(int limit);
/**
* limit the number of triggers each game
*/
TriggeredAbility setTriggersLimitEachGame(int limit);
/**
* Get the number of times the trigger may trigger this turn.
* e.g. 0, 1 or 2 for a trigger that is limited to trigger twice each turn.
@ -47,6 +52,13 @@ public interface TriggeredAbility extends Ability {
*/
int getRemainingTriggersLimitEachTurn(Game game);
/**
* Get the number of times the trigger may trigger this game.
* e.g. 0, 1 or 2 for a trigger that is limited to trigger twice each game.
* Integer.MAX_VALUE when no limit.
*/
int getRemainingTriggersLimitEachGame(Game game);
TriggeredAbility setDoOnlyOnceEachTurn(boolean doOnlyOnce);
/**

View file

@ -10,9 +10,7 @@ import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.BatchEvent;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeBatchEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentToken;
import mage.players.Player;
import mage.util.CardUtil;
@ -31,6 +29,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
private Condition interveningIfCondition;
private boolean leavesTheBattlefieldTrigger;
private int triggerLimitEachTurn = Integer.MAX_VALUE; // for "triggers only once|twice each turn"
private int triggerLimitEachGame = Integer.MAX_VALUE; // for "triggers only once|twice"
private boolean doOnlyOnceEachTurn = false;
private boolean replaceRuleText = false; // if true, replace "{this}" with "it" in effect text
private GameEvent triggerEvent = null;
@ -60,6 +59,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
this.interveningIfCondition = ability.interveningIfCondition;
this.leavesTheBattlefieldTrigger = ability.leavesTheBattlefieldTrigger;
this.triggerLimitEachTurn = ability.triggerLimitEachTurn;
this.triggerLimitEachGame = ability.triggerLimitEachGame;
this.doOnlyOnceEachTurn = ability.doOnlyOnceEachTurn;
this.replaceRuleText = ability.replaceRuleText;
this.triggerEvent = ability.triggerEvent;
@ -70,7 +70,8 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
public void trigger(Game game, UUID controllerId, GameEvent triggeringEvent) {
//20091005 - 603.4
if (checkInterveningIfClause(game)) {
setLastTrigger(game);
updateTurnCount(game);
updateGameCount(game);
game.addTriggeredAbility(this, triggeringEvent);
}
}
@ -89,7 +90,14 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
);
}
private void setLastTrigger(Game game) {
// Used for triggers with a per-game limit.
private String getKeyGameTriggeredCount(Game game) {
return CardUtil.getCardZoneString(
"gameTriggeredCount|" + getOriginalId(), getSourceId(), game
);
}
private void updateTurnCount(Game game) {
if (triggerLimitEachTurn == Integer.MAX_VALUE) {
return;
}
@ -108,6 +116,16 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
}
}
private void updateGameCount(Game game) {
if (triggerLimitEachGame == Integer.MAX_VALUE) {
return;
}
String keyGameTriggeredCount = getKeyGameTriggeredCount(game);
int lastCount = Optional.ofNullable((Integer) game.getState().getValue(keyGameTriggeredCount)).orElse(0);
// Incrementing the count.
game.getState().setValue(keyGameTriggeredCount, lastCount + 1);
}
@Override
public TriggeredAbilityImpl setTriggerPhrase(String triggerPhrase) {
this.triggerPhrase = triggerPhrase;
@ -126,7 +144,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
@Override
public boolean checkTriggeredLimit(Game game) {
return getRemainingTriggersLimitEachTurn(game) > 0;
return getRemainingTriggersLimitEachGame(game) > 0 && getRemainingTriggersLimitEachTurn(game) > 0;
}
@Override
@ -146,6 +164,12 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
return this;
}
@Override
public TriggeredAbility setTriggersLimitEachGame(int limit) {
this.triggerLimitEachGame = limit;
return this;
}
@Override
public int getRemainingTriggersLimitEachTurn(Game game) {
if (triggerLimitEachTurn == Integer.MAX_VALUE) {
@ -165,6 +189,16 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
}
}
@Override
public int getRemainingTriggersLimitEachGame(Game game) {
if (triggerLimitEachGame == Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
String keyGameTriggeredCount = getKeyGameTriggeredCount(game);
int count = Optional.ofNullable((Integer) game.getState().getValue(keyGameTriggeredCount)).orElse(0);
return Math.max(0, triggerLimitEachGame - count);
}
@Override
public TriggeredAbility setDoOnlyOnceEachTurn(boolean doOnlyOnce) {
this.doOnlyOnceEachTurn = doOnlyOnce;
@ -300,6 +334,21 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
}
sb.append(" each turn.");
}
if (triggerLimitEachGame != Integer.MAX_VALUE) {
sb.append(" This ability triggers only ");
switch (triggerLimitEachGame) {
case 1:
sb.append("once.");
break;
case 2:
// No card with that behavior yet, so feel free to change the text once one exist
sb.append("twice.");
break;
default:
// No card with that behavior yet, so feel free to change the text once one exist
sb.append(CardUtil.numberToText(triggerLimitEachGame)).append(" times.");
}
}
if (doOnlyOnceEachTurn) {
sb.append(" Do this only once each turn.");
}

View file

@ -78,8 +78,9 @@ public class RemoveCounterCost extends CostImpl {
Outcome outcome;
if (target instanceof TargetPermanent) {
outcome = Outcome.UnboostCreature;
} else if (target instanceof TargetCard) { // For Mari, the Killing Quill
outcome = Outcome.AIDontUseIt;
} else if (target instanceof TargetCard) {
// Mari, the Killing Quill - AI can safely use it all the time
outcome = Outcome.Neutral;
} else {
throw new IllegalArgumentException(
@ -123,7 +124,7 @@ public class RemoveCounterCost extends CostImpl {
}
choice.setChoices(choices);
choice.setMessage("Choose a counter to remove from " + targetObject.getLogName());
if (!controller.choose(Outcome.UnboostCreature, choice, game)) {
if (!controller.choose(outcome, choice, game)) {
return false;
}
counterName = choice.getChoice();
@ -135,7 +136,7 @@ public class RemoveCounterCost extends CostImpl {
int numberOfCountersSelected = 1;
if (countersLeft > 1 && countersOnPermanent > 1) {
numberOfCountersSelected = controller.getAmount(1, Math.min(countersLeft, countersOnPermanent),
"Remove how many counters from " + targetObject.getIdName(), game);
"Choose how many counters (" + counterName + ") to remove from " + targetObject.getLogName() + " as payment", game);
}
targetObject.removeCounters(counterName, numberOfCountersSelected, source, game);
countersRemoved += numberOfCountersSelected;

View file

@ -8,6 +8,7 @@ import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.hint.Hint;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
@ -20,6 +21,7 @@ public class DoIfCostPaid extends OneShotEffect {
protected final Cost cost;
private final String chooseUseText;
private final boolean optional;
private Hint chooseHint = null;
public DoIfCostPaid(Effect effectOnPaid, Cost cost) {
this(effectOnPaid, cost, null);
@ -63,6 +65,7 @@ public class DoIfCostPaid extends OneShotEffect {
this.cost = effect.cost.copy();
this.chooseUseText = effect.chooseUseText;
this.optional = effect.optional;
this.chooseHint = effect.chooseHint;
}
public DoIfCostPaid addEffect(Effect effect) {
@ -75,6 +78,19 @@ public class DoIfCostPaid extends OneShotEffect {
return this;
}
/**
* Allow to add additional info in pay dialog, so user can split it in diff use cases to remember by right click
* Example: ignore untap payment for already untapped permanent like Mana Vault
*/
public DoIfCostPaid withChooseHint(Hint chooseHint) {
if (!this.optional) {
throw new IllegalArgumentException("Wrong code usage: chooseHint can be used for optional dialogs only");
}
this.chooseHint = chooseHint;
return this;
}
@Override
public boolean apply(Game game, Ability source) {
Player player = getPayingPlayer(game, source);
@ -82,11 +98,16 @@ public class DoIfCostPaid extends OneShotEffect {
if (player == null || mageObject == null) {
return false;
}
String message = CardUtil.replaceSourceName(makeChooseText(source), mageObject.getName());
// nothing to pay (do not support mana cost - it's true all the time)
if (!this.cost.canPay(source, source, player.getId(), game)) {
return false;
}
String message = CardUtil.replaceSourceName(makeChooseText(game, source), mageObject.getName());
Outcome payOutcome = executingEffects.getOutcome(source, this.outcome);
boolean canPay = cost.canPay(source, source, player.getId(), game);
boolean didPay = false;
if (canPay && (!optional || player.chooseUse(payOutcome, message, source, game))) {
if (!optional || player.chooseUse(payOutcome, message, source, game)) {
cost.clearPaid();
int bookmark = game.bookmarkState();
if (cost.pay(source, game, source, player.getId(), false)) {
@ -121,18 +142,26 @@ public class DoIfCostPaid extends OneShotEffect {
}
}
private String makeChooseText(Ability source) {
if (chooseUseText != null && !chooseUseText.isEmpty()) {
return chooseUseText;
private String makeChooseText(Game game, Ability source) {
// static
String res = chooseUseText;
// dynamic
if (res == null || res.isEmpty()) {
String effectText = executingEffects.getText(source.getModes().getMode());
if (!effectText.isEmpty() && effectText.charAt(effectText.length() - 1) == '.') {
effectText = effectText.substring(0, effectText.length() - 1);
}
res = CardUtil.addCostVerb(cost.getText()) + (effectText.isEmpty() ? "" : " and " + effectText) + "?";
res = Character.toUpperCase(res.charAt(0)) + res.substring(1);
}
String message;
String effectText = executingEffects.getText(source.getModes().getMode());
if (!effectText.isEmpty() && effectText.charAt(effectText.length() - 1) == '.') {
effectText = effectText.substring(0, effectText.length() - 1);
// additional hint, so user can remember it
if (this.chooseHint != null) {
res += String.format(" (%s)", this.chooseHint.getText(game, source));
}
message = CardUtil.addCostVerb(cost.getText()) + (effectText.isEmpty() ? "" : " and " + effectText) + "?";
message = Character.toUpperCase(message.charAt(0)) + message.substring(1);
return message;
return res;
}
protected Player getPayingPlayer(Game game, Ability source) {

View file

@ -21,12 +21,17 @@ public class AddCardTypeSourceEffect extends ContinuousEffectImpl {
public AddCardTypeSourceEffect(Duration duration, CardType... addedCardType) {
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
if (addedCardType.length == 0) {
throw new IllegalArgumentException("AddCardTypeSourceEffect should be called with at least one card type.");
}
for (CardType cardType : addedCardType) {
this.addedCardTypes.add(cardType);
if (cardType == CardType.ENCHANTMENT) {
dependencyTypes.add(DependencyType.EnchantmentAddingRemoving);
} else if (cardType == CardType.ARTIFACT) {
dependencyTypes.add(DependencyType.ArtifactAddingRemoving);
} else if (cardType == CardType.LAND) {
dependencyTypes.add(DependencyType.BecomeNonbasicLand);
}
}
}
@ -45,7 +50,10 @@ public class AddCardTypeSourceEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && affectedObjectList.contains(new MageObjectReference(permanent, game))) {
if (permanent != null
&& (affectedObjectList.contains(new MageObjectReference(permanent, game))
// Workaround to support abilities like "As long as __, this permanent is a __ in addition to its other types."
|| !duration.isOnlyValidIfNoZoneChange())) {
for (CardType cardType : addedCardTypes) {
permanent.addCardType(game, cardType);
}

View file

@ -21,12 +21,17 @@ public class AddCardTypeTargetEffect extends ContinuousEffectImpl {
public AddCardTypeTargetEffect(Duration duration, CardType... addedCardType) {
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
if (addedCardType.length == 0) {
throw new IllegalArgumentException("AddCardTypeTargetEffect should be called with at least one card type.");
}
for (CardType cardType : addedCardType) {
this.addedCardTypes.add(cardType);
if (cardType == CardType.ENCHANTMENT) {
dependencyTypes.add(DependencyType.EnchantmentAddingRemoving);
} else if (cardType == CardType.ARTIFACT) {
dependencyTypes.add(DependencyType.ArtifactAddingRemoving);
} else if (cardType == CardType.LAND) {
dependencyTypes.add(DependencyType.BecomeNonbasicLand);
}
}

View file

@ -0,0 +1,32 @@
package mage.game.permanent.token;
import mage.MageInt;
import mage.abilities.keyword.FlyingAbility;
import mage.constants.CardType;
import mage.constants.SubType;
/**
* @author PurpleCrowbar
*/
public final class Black22BirdToken extends TokenImpl {
public Black22BirdToken() {
super("Bird Token", "2/2 black Bird creature token with flying");
cardType.add(CardType.CREATURE);
color.setBlack(true);
subtype.add(SubType.BIRD);
power = new MageInt(2);
toughness = new MageInt(2);
addAbility(FlyingAbility.getInstance());
}
private Black22BirdToken(final Black22BirdToken token) {
super(token);
}
@Override
public Black22BirdToken copy() {
return new Black22BirdToken(this);
}
}

View file

@ -0,0 +1,29 @@
package mage.game.permanent.token;
import mage.MageInt;
import mage.constants.CardType;
import mage.constants.SubType;
/**
* @author PurpleCrowbar
*/
public final class Shark33Token extends TokenImpl {
public Shark33Token() {
super("Shark Token", "3/3 blue Shark creature token");
cardType.add(CardType.CREATURE);
color.setBlue(true);
subtype.add(SubType.SHARK);
power = new MageInt(3);
toughness = new MageInt(3);
}
private Shark33Token(final Shark33Token token) {
super(token);
}
public Shark33Token copy() {
return new Shark33Token(this);
}
}

View file

@ -341,8 +341,9 @@ public interface Player extends MageItem, Copyable<Player> {
* @param game
* @param playerUnderControlId
* @param info additional info to show in game logs like source
* @return false on failed taken control, e.g. on unsupported player type
*/
void controlPlayersTurn(Game game, UUID playerUnderControlId, String info);
boolean controlPlayersTurn(Game game, UUID playerUnderControlId, String info);
/**
* Sets player {@link UUID} who controls this player's turn.

View file

@ -598,8 +598,17 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void controlPlayersTurn(Game game, UUID playerUnderControlId, String info) {
public boolean controlPlayersTurn(Game game, UUID playerUnderControlId, String info) {
Player playerUnderControl = game.getPlayer(playerUnderControlId);
// TODO: add support computer over computer
// TODO: add support computer over human
if (this.isComputer()) {
// not supported yet
game.informPlayers(getLogName() + " is AI and can't take control over " + playerUnderControl.getLogName() + info);
return false;
}
playerUnderControl.setTurnControlledBy(this.getId());
game.informPlayers(getLogName() + " taken turn control of " + playerUnderControl.getLogName() + info);
if (!playerUnderControlId.equals(this.getId())) {
@ -609,6 +618,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
// control will reset on start of the turn
}
return true;
}
@Override
@ -777,10 +788,10 @@ public abstract class PlayerImpl implements Player, Serializable {
}
// if this method was called from a replacement event, pass the number of cards back through
// (uncomment conditions if correct ruling is to only count cards drawn by the same player)
if (event instanceof DrawCardEvent /* && event.getPlayerId().equals(getId()) */ ) {
if (event instanceof DrawCardEvent /* && event.getPlayerId().equals(getId()) */) {
((DrawCardEvent) event).incrementCardsDrawn(numDrawn);
}
if (event instanceof DrawTwoOrMoreCardsEvent /* && event.getPlayerId().equals(getId()) */ ) {
if (event instanceof DrawTwoOrMoreCardsEvent /* && event.getPlayerId().equals(getId()) */) {
((DrawTwoOrMoreCardsEvent) event).incrementCardsDrawn(numDrawn);
}
return numDrawn;

View file

@ -1358,7 +1358,11 @@ public final class CardUtil {
*/
public static void takeControlUnderPlayerStart(Game game, Ability source, Player controller, Player playerUnderControl, boolean givePauseForResponse) {
// game logs added in child's call
controller.controlPlayersTurn(game, playerUnderControl.getId(), CardUtil.getSourceLogName(game, source));
if (!controller.controlPlayersTurn(game, playerUnderControl.getId(), CardUtil.getSourceLogName(game, source))) {
return;
}
// give pause, so new controller can look around battlefield and hands before finish controlling choose dialog
if (givePauseForResponse) {
while (controller.canRespond()) {
if (controller.chooseUse(Outcome.Benefit, "You got control of " + playerUnderControl.getLogName()

View file

@ -2330,7 +2330,41 @@
|Generate|TOK:BLB|Wall|||WallWhiteToken|
# BLC
|Generate|TOK:BLC|Racoon|||RaccoonToken|
|Generate|TOK:BLC|Beast|1||BeastToken|
|Generate|TOK:BLC|Beast|2||BeastToken2|
|Generate|TOK:BLC|Bird|1||SwanSongBirdToken|
|Generate|TOK:BLC|Bird|2||BirdToken|
|Generate|TOK:BLC|Blood|||BloodToken|
|Generate|TOK:BLC|Cat|||GreenCat2Token|
|Generate|TOK:BLC|Citizen|||CitizenGreenWhiteToken|
|Generate|TOK:BLC|Clue|||ClueArtifactToken|
|Generate|TOK:BLC|Eldrazi|||EldraziToken|
|Generate|TOK:BLC|Elemental|||WhiteElementalToken|
|Generate|TOK:BLC|Elephant|||ElephantToken|
|Generate|TOK:BLC|Faerie|||FaerieToken|
|Generate|TOK:BLC|Frog Lizard|||FrogLizardToken|
|Generate|TOK:BLC|Goat|||GoatToken|
|Generate|TOK:BLC|Goblin|||GoblinToken|
|Generate|TOK:BLC|Hamster|||HamsterToken|
|Generate|TOK:BLC|Human|||HumanToken|
|Generate|TOK:BLC|Human Soldier|||HumanSoldierToken|
|Generate|TOK:BLC|Illusion|||CustomIllusionToken|
|Generate|TOK:BLC|Octopus|||OctopusToken|
|Generate|TOK:BLC|Pest|||Pest11GainLifeToken|
|Generate|TOK:BLC|Phyrexian Golem|||PhyrexianGolemToken|
|Generate|TOK:BLC|Raccoon|||RaccoonToken|
|Generate|TOK:BLC|Rat|||RatToken|
|Generate|TOK:BLC|Saproling|||SaprolingToken|
|Generate|TOK:BLC|Shapeshifter|||ShapeshifterBlueToken|
|Generate|TOK:BLC|Shark|||Shark33Token|
|Generate|TOK:BLC|Soldier|||SoldierToken|
|Generate|TOK:BLC|Spider|||SpiderToken|
|Generate|TOK:BLC|Spirit|||SpiritWhiteToken|
|Generate|TOK:BLC|Squid|||SquidToken|
|Generate|TOK:BLC|Storm Crow|||StormCrowToken|
|Generate|TOK:BLC|Thopter|||ThopterColorlessToken|
|Generate|TOK:BLC|Wolf|1||GarrukCursedHuntsmanToken|
|Generate|TOK:BLC|Wolf|2||WolfToken|
# FDN
|Generate|TOK:FDN|Beast|1||BeastToken|