Reworking effects which allow casting spells from a selection of cards (ready for review) (#8136)

* added function for casting spells with specific attributes from a selection of cards

* updated cascade to use new method

* refactored various cards to use new methods

* added TestPlayer method

* fixed a small error

* text fix

* broke out some repeated code

* added missing notTarget setting

* add additional retain zone check

* some more cards refactored

* more refactoring

* added interface for split/modal cards

* reworked spell casting methods

* reworked multiple cast to prevent unnecessary dialogs

* fixed test failures due to change in functionality

* add AI code

* small nonfunctional change

* reworked Kaya, the Inexorable

* added currently failing test

* added more tests

* updated Geode Golem implementation

* fixed adventure/cascade interaction, added/updated tests

* some nonfunctional refactoring

* added interface for subcards

* [AFC] Implemented Fevered Suspicion

* [AFC] Implemented Extract Brain

* [AFC] updated Arcane Endeavor implementation

* [C17] reworked implementation of Izzet Chemister

* [ZEN] reworked implemented of Chandra Ablaze

* additional merge fix

* [SLD] updated Eleven, the Mage

* [NEO] Implemented Discover the Impossible

* [NEO] Implemented The Dragon-Kami Reborn / Dragon-Kami's Egg

* [NEO] Implemented Invoke Calamity

* [AFR] Implemented Rod of Absorption

* [VOC] Implemented Spectral Arcanist

* [VOC] added additional printings

* [NEO] added all variants

* [SLD] updated implementation of Ken, Burning Brawler
This commit is contained in:
Evan Kranzler 2022-03-09 08:03:54 -05:00 committed by GitHub
parent 7fb089db48
commit bbb9382150
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
83 changed files with 2551 additions and 2059 deletions

View file

@ -2986,7 +2986,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
@Override
public SpellAbility chooseAbilityForCast(Card card, Game game, boolean noMana) {
Map<UUID, ActivatedAbility> useable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), card, game.getState().getZone(card.getId()), noMana);
Map<UUID, SpellAbility> useable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), card, game.getState().getZone(card.getId()), noMana);
return (SpellAbility) useable.values().stream().findFirst().orElse(null);
}

View file

@ -2185,10 +2185,10 @@ public class HumanPlayer extends PlayerImpl {
MageObject object = game.getObject(card.getId()); // must be object to find real abilities (example: commander)
if (object != null) {
String message = "Choose ability to cast" + (noMana ? " for FREE" : "") + "<br>" + object.getLogName();
LinkedHashMap<UUID, ActivatedAbility> useableAbilities = PlayerImpl.getCastableSpellAbilities(game, playerId, object, game.getState().getZone(object.getId()), noMana);
LinkedHashMap<UUID, SpellAbility> useableAbilities = PlayerImpl.getCastableSpellAbilities(game, playerId, object, game.getState().getZone(object.getId()), noMana);
if (useableAbilities != null
&& useableAbilities.size() == 1) {
return (SpellAbility) useableAbilities.values().iterator().next();
return useableAbilities.values().iterator().next();
} else if (useableAbilities != null
&& !useableAbilities.isEmpty()) {
@ -2202,7 +2202,7 @@ public class HumanPlayer extends PlayerImpl {
UUID responseId = getFixedResponseUUID(game);
if (responseId != null) {
if (useableAbilities.containsKey(responseId)) {
return (SpellAbility) useableAbilities.get(responseId);
return useableAbilities.get(responseId);
}
}
}

View file

@ -1,8 +1,5 @@
package mage.cards.a;
import java.util.Set;
import java.util.UUID;
import mage.ApprovingObject;
import mage.abilities.Ability;
import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
@ -10,20 +7,22 @@ import mage.abilities.costs.common.PayEnergyCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterNonlandCard;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author emerald000
*/
public final class AetherworksMarvel extends CardImpl {
@ -35,13 +34,13 @@ public final class AetherworksMarvel extends CardImpl {
// Whenever a permanent you control is put into a graveyard, you get {E}.
this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility(
new GetEnergyCountersControllerEffect(1), false,
new FilterControlledPermanent("a permanent you control"), false));
StaticFilters.FILTER_CONTROLLED_A_PERMANENT, false
));
// {T}, Pay {E}{E}{E}{E}{E}{E}: Look at the top six cards of your library.
// You may cast a card from among them without paying its mana cost.
// Put the rest on the bottom of your library in a random order.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new AetherworksMarvelEffect(), new TapSourceCost());
Ability ability = new SimpleActivatedAbility(new AetherworksMarvelEffect(), new TapSourceCost());
ability.addCost(new PayEnergyCost(6));
this.addAbility(ability);
}
@ -78,26 +77,13 @@ class AetherworksMarvelEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Set<Card> cardsSet = controller.getLibrary().getTopCards(game, 6);
Cards cards = new CardsImpl(cardsSet);
TargetCard target = new TargetCardInLibrary(0, 1,
new FilterNonlandCard("card to cast without paying its mana cost"));
if (controller.choose(Outcome.PlayForFree, cards, target, game)) {
Card card = controller.getLibrary().getCard(target.getFirstTarget(), game);
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
if (cardWasCast) {
cards.remove(card);
}
}
}
controller.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
if (controller == null) {
return false;
}
return false;
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 6));
CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, StaticFilters.FILTER_CARD);
cards.retainZone(Zone.LIBRARY, game);
controller.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
}
}

View file

@ -1,17 +1,19 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.filter.FilterCard;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.List;
import java.util.UUID;
@ -40,10 +42,6 @@ public final class ArcaneEndeavor extends CardImpl {
class ArcaneEndeavorEffect extends OneShotEffect {
private static final FilterCard filter = new FilterInstantOrSorceryCard(
"instant or sorcery card with mana value %mv or less from your hand"
);
ArcaneEndeavorEffect() {
super(Outcome.Benefit);
staticText = "roll two d8 and choose one result. Draw cards equal to that result. " +
@ -82,7 +80,9 @@ class ArcaneEndeavorEffect extends OneShotEffect {
second = firstResult;
}
player.drawCards(first, source, game);
new CastWithoutPayingManaCostEffect(StaticValue.get(second), filter).apply(game, source);
FilterCard filter = new FilterInstantOrSorceryCard();
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, second + 1));
CardUtil.castSpellWithAttributesForFree(player, source, game, new CardsImpl(player.getHand()), filter);
return true;
}
}

View file

@ -1,23 +1,26 @@
package mage.cards.a;
import java.util.UUID;
import mage.ApprovingObject;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.card.FaceDownPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.AshiokNightmareMuseToken;
import mage.players.Player;
import mage.target.common.TargetCardInExile;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetNonlandPermanent;
import mage.util.CardUtil;
import java.util.UUID;
/**
* @author TheElk801
@ -95,6 +98,7 @@ class AshiokNightmareMuseCastEffect extends OneShotEffect {
static {
filter.add(TargetController.OPPONENT.getOwnerPredicate());
filter.add(Predicates.not(FaceDownPredicate.instance));
}
AshiokNightmareMuseCastEffect() {
@ -117,25 +121,10 @@ class AshiokNightmareMuseCastEffect extends OneShotEffect {
if (controller == null) {
return false;
}
TargetCardInExile target = new TargetCardInExile(0, 3, filter, null);
target.setNotTarget(true);
if (!controller.chooseTarget(outcome, target, source, game)) { // method is fine, controller is still choosing the card
return false;
}
for (UUID targetId : target.getTargets()) {
if (targetId != null) {
Card chosenCard = game.getCard(targetId);
if (chosenCard != null
&& game.getState().getZone(chosenCard.getId()) == Zone.EXILED // must be exiled
&& game.getOpponents(controller.getId()).contains(chosenCard.getOwnerId()) // must be owned by an opponent
&& controller.chooseUse(outcome, "Cast " + chosenCard.getName() + " without paying its mana cost?", source, game)) {
game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(chosenCard, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), null);
}
}
}
CardUtil.castMultipleWithAttributeForFree(
controller, source, game, new CardsImpl(game.getExile().getCards(filter, game)),
StaticFilters.FILTER_CARD, 3
);
return true;
}
}

View file

@ -1,27 +1,34 @@
package mage.cards.b;
import java.util.UUID;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class BaralsExpertise extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("artifacts and/or creatures");
private static final FilterCard filter2 = new FilterCard("a spell with mana value 4 or less");
static {
filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(),
CardType.CREATURE.getPredicate()));
filter.add(Predicates.or(
CardType.ARTIFACT.getPredicate(),
CardType.CREATURE.getPredicate()
));
filter2.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 5));
}
public BaralsExpertise(UUID ownerId, CardSetInfo setInfo) {
@ -32,7 +39,7 @@ public final class BaralsExpertise extends CardImpl {
getSpellAbility().addTarget(new TargetPermanent(0, 3, filter, false));
// You may cast a card with converted mana cost 4 or less from your hand without paying its mana cost.
getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(4).concatBy("<br>"));
getSpellAbility().addEffect(new CastFromHandForFreeEffect(filter2).concatBy("<br>"));
}
private BaralsExpertise(final BaralsExpertise card) {

View file

@ -1,7 +1,5 @@
package mage.cards.b;
import java.util.UUID;
import mage.ApprovingObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.RemoveVariableCountersSourceCost;
@ -10,13 +8,11 @@ import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.dynamicvalue.common.RemovedCountersForCostValue;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterCard;
import mage.filter.common.FilterInstantOrSorceryCard;
@ -24,10 +20,11 @@ import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInHand;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class BrainInAJar extends CardImpl {
@ -39,20 +36,17 @@ public final class BrainInAJar extends CardImpl {
// cast an instant or sorcery card with converted mana costs equal
// to the number of charge counters on Brain in a Jar from your
// hand without paying its mana cost.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new AddCountersSourceEffect(CounterType.CHARGE.createInstance()),
new GenericManaCost(1));
Ability ability = new SimpleActivatedAbility(
new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), new GenericManaCost(1)
);
ability.addEffect(new BrainInAJarCastEffect());
ability.addCost(new TapSourceCost());
this.addAbility(ability);
// {3}, {T}, Remove X charge counters from Brain in a Jar: Scry X.
ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new BrainInAJarScryEffect(),
new GenericManaCost(3));
ability = new SimpleActivatedAbility(new BrainInAJarScryEffect(), new GenericManaCost(3));
ability.addCost(new TapSourceCost());
ability.addCost(new RemoveVariableCountersSourceCost(
CounterType.CHARGE.createInstance()));
ability.addCost(new RemoveVariableCountersSourceCost(CounterType.CHARGE.createInstance()));
this.addAbility(ability);
}
@ -87,32 +81,14 @@ class BrainInAJarCastEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (controller != null
&& sourceObject != null) {
int counters = sourceObject.getCounters(game).getCount(CounterType.CHARGE);
FilterCard filter = new FilterInstantOrSorceryCard();
filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, counters));
int cardsToCast = controller.getHand().count(filter, source.getControllerId(),
source.getSourceId(), game);
if (cardsToCast > 0
&& controller.chooseUse(Outcome.PlayForFree,
"Cast an instant or sorcery card with mana values of "
+ counters + " from your hand without paying its mana cost?",
source, game)) {
TargetCardInHand target = new TargetCardInHand(filter);
controller.chooseTarget(outcome, target, source, game);
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
}
}
return true;
Permanent sourceObject = source.getSourcePermanentOrLKI(game);
if (controller == null || sourceObject == null) {
return false;
}
return false;
int counters = sourceObject.getCounters(game).getCount(CounterType.CHARGE);
FilterCard filter = new FilterInstantOrSorceryCard();
filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, counters));
return CardUtil.castSpellWithAttributesForFree(controller, source, game, controller.getHand(), filter);
}
}

View file

@ -1,24 +1,19 @@
package mage.cards.c;
import mage.ApprovingObject;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect;
import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect;
import mage.abilities.keyword.FriendsForeverAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetCardInHand;
import org.apache.log4j.Logger;
import mage.util.CardUtil;
import java.util.UUID;
@ -83,45 +78,10 @@ class CecilyHauntedMageEffect extends OneShotEffect {
}
player.drawCards(1, source, game);
player.loseLife(1, game, source, false);
if (player.getHand().size() < 11) {
return true;
}
// TODO: change this to fit with changes made in https://github.com/magefree/mage/pull/8136 when merged
Target target = new TargetCardInHand(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY);
if (!target.canChoose(
source.getSourceId(), player.getId(), game
) || !player.chooseUse(
Outcome.PlayForFree, "Cast an instant or sorcery spell " +
"from your hand without paying its mana cost?", source, game
)) {
return true;
}
Card cardToCast = null;
boolean cancel = false;
while (player.canRespond()
&& !cancel) {
if (player.chooseTarget(Outcome.PlayForFree, target, source, game)) {
cardToCast = game.getCard(target.getFirstTarget());
if (cardToCast != null) {
if (cardToCast.getSpellAbility() == null) {
Logger.getLogger(CastWithoutPayingManaCostEffect.class).fatal("Card: "
+ cardToCast.getName() + " is no land and has no spell ability!");
cancel = true;
}
if (cardToCast.getSpellAbility().canChooseTarget(game, player.getId())) {
cancel = true;
}
}
} else {
cancel = true;
}
}
if (cardToCast != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE);
player.cast(player.chooseAbilityForCast(cardToCast, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null);
}
return true;
return player.getHand().size() < 11
|| CardUtil.castSpellWithAttributesForFree(
player, source, game, player.getHand().copy(),
StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY
);
}
}

View file

@ -10,23 +10,20 @@ import mage.abilities.effects.common.discard.DiscardHandAllEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicates;
import mage.filter.StaticFilters;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetAnyTarget;
import mage.target.common.TargetCardInGraveyard;
import mage.target.common.TargetDiscard;
import mage.util.CardUtil;
import java.util.Set;
import java.util.UUID;
import mage.ApprovingObject;
/**
* @author North
@ -138,6 +135,12 @@ class ChandraAblazeEffect2 extends OneShotEffect {
class ChandraAblazeEffect5 extends OneShotEffect {
private static final FilterCard filter = new FilterInstantOrSorceryCard();
static {
filter.add(new ColorPredicate(ObjectColor.RED));
}
public ChandraAblazeEffect5() {
super(Outcome.PlayForFree);
this.staticText = "Cast any number of red instant and/or sorcery cards from your graveyard without paying their mana costs";
@ -154,33 +157,17 @@ class ChandraAblazeEffect5 extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
// Under this card's current oracle wording, it only casts red instant or sorcery cards
// This may have been a mistake which could change in the future
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
FilterCard filter = new FilterCard("red instant or sorcery card from your graveyard to play");
filter.add(new ColorPredicate(ObjectColor.RED));
filter.add(Predicates.or(
CardType.INSTANT.getPredicate(),
CardType.SORCERY.getPredicate()));
String message = "Play red instant or sorcery card from your graveyard without paying its mana cost?";
Set<Card> cards = player.getGraveyard().getCards(filter, game);
TargetCardInGraveyard target = new TargetCardInGraveyard(filter);
while (!cards.isEmpty() && player.chooseUse(outcome, message, source, game)) {
target.clearChosen();
if (player.choose(outcome, target, source.getSourceId(), game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
player.cast(player.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
cards.remove(card);
}
}
}
return true;
if (player == null) {
return false;
}
return false;
CardUtil.castMultipleWithAttributeForFree(
player, source, game,
new CardsImpl(player.getGraveyard().getCards(filter, game)),
StaticFilters.FILTER_CARD
);
return true;
}
}

View file

@ -1,10 +1,11 @@
package mage.cards.c;
import mage.ApprovingObject;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
@ -13,7 +14,7 @@ import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.util.CardUtil;
import java.util.UUID;
@ -51,12 +52,6 @@ class CollectedConjuringEffect extends OneShotEffect {
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4));
}
private static final FilterCard filter2 = filter.copy();
static {
filter2.setMessage("sorcery card with mana value 3 or less");
}
CollectedConjuringEffect() {
super(Outcome.PlayForFree);
this.staticText = "exile the top six cards of your library. You may cast up to two sorcery spells " +
@ -76,42 +71,12 @@ class CollectedConjuringEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller == null
|| sourceObject == null) {
if (controller == null) {
return false;
}
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 6));
Cards cardsToChoose = new CardsImpl(cards);
controller.moveCards(cards, Zone.EXILED, source, game);
int cardsCast = 0;
while (!cardsToChoose.getCards(filter, source.getSourceId(), source.getControllerId(), game).isEmpty()
&& cardsCast < 2) {
if (!controller.chooseUse(Outcome.PlayForFree, "Cast a card exiled with "
+ sourceObject.getLogName() + " without paying its mana cost?", source, game)) {
break;
}
TargetCard targetCard = new TargetCard(1, Zone.EXILED, filter2);
if (!controller.choose(Outcome.PlayForFree, cardsToChoose, targetCard, game)) {
continue;
}
Card card = game.getCard(targetCard.getFirstTarget());
if (card == null) {
continue;
}
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
cardsToChoose.remove(card); // remove on non cast too (infinite freeze fix)
if (cardWasCast) {
cards.remove(card);
cardsCast++;
} else {
game.informPlayer(controller, "You're not able to cast "
+ card.getIdName() + " or you canceled the casting.");
}
}
CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter, 2);
controller.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
}

View file

@ -1,15 +1,11 @@
package mage.cards.c;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.FilterCard;
@ -19,10 +15,13 @@ import mage.game.Game;
import mage.game.stack.StackObject;
import mage.players.Player;
import mage.target.TargetSpell;
import mage.target.common.TargetCardInHand;
import mage.util.CardUtil;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
*
* @author BetaSteward
*/
public final class Counterlash extends CardImpl {
@ -50,9 +49,9 @@ class CounterlashEffect extends OneShotEffect {
public CounterlashEffect() {
super(Outcome.Detriment);
this.staticText = "Counter target spell. You may cast a nonland "
+ "card in your hand that shares a card type with that "
+ "spell without paying its mana cost";
this.staticText = "Counter target spell. You may cast a spell "
+ "that shares a card type with it from your hand "
+ "without paying its mana cost";
}
public CounterlashEffect(final CounterlashEffect effect) {
@ -68,32 +67,21 @@ class CounterlashEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget());
Player controller = game.getPlayer(source.getControllerId());
if (stackObject != null
&& controller != null) {
game.getStack().counter(source.getFirstTarget(), source, game);
if (controller.chooseUse(Outcome.PlayForFree, "Cast a nonland card in your hand that "
+ "shares a card type with that spell without paying its mana cost?", source, game)) {
FilterCard filter = new FilterCard();
List<Predicate<MageObject>> types = new ArrayList<>();
for (CardType type : stackObject.getCardType(game)) {
if (type != CardType.LAND) {
types.add(type.getPredicate());
}
}
filter.add(Predicates.or(types));
TargetCardInHand target = new TargetCardInHand(filter);
if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) {
Card card = controller.getHand().get(target.getFirstTarget(), game);
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
}
}
}
if (stackObject == null || controller == null) {
return false;
}
Set<Predicate<MageObject>> predicates = stackObject
.getCardType(game)
.stream()
.map(CardType::getPredicate)
.collect(Collectors.toSet());
game.getStack().counter(source.getFirstTarget(), source, game);
if (predicates.isEmpty()) {
return true;
}
return false;
FilterCard filter = new FilterCard();
filter.add(Predicates.or(predicates));
CardUtil.castSpellWithAttributesForFree(controller, source, game, new CardsImpl(controller.getHand()), filter);
return true;
}
}

View file

@ -4,14 +4,17 @@ import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.FullPartyCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.dynamicvalue.common.PartyCount;
import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.abilities.hint.common.PartyCountHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
@ -21,6 +24,12 @@ import java.util.UUID;
*/
public final class CovetedPrize extends CardImpl {
private static final FilterCard filter = new FilterCard("a spell with mana value 4 or less");
static {
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 5));
}
public CovetedPrize(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}");
@ -32,7 +41,7 @@ public final class CovetedPrize extends CardImpl {
// Search your library for a card, put it into your hand, then shuffle your library. If you have a full party, you may cast a spell with converted mana cost 4 or less from your hand without paying its mana cost.
this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary()));
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new CastWithoutPayingManaCostEffect(4),
new CastFromHandForFreeEffect(filter),
FullPartyCondition.instance, "If you have a full party, " +
"you may cast a spell with mana value 4 or less from your hand without paying its mana cost."
));

View file

@ -0,0 +1,91 @@
package mage.cards.d;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary;
import mage.util.CardUtil;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class DiscoverTheImpossible extends CardImpl {
public DiscoverTheImpossible(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}");
// Look at the top five cards of your library. Exile one of them face down and put the rest on the bottom of your library in a random order. You may cast the exiled card without paying its mana cost if it's an instant spell with mana value 2 or less. If you don't, put that card into your hand.
this.getSpellAbility().addEffect(new DiscoverTheImpossibleEffect());
}
private DiscoverTheImpossible(final DiscoverTheImpossible card) {
super(card);
}
@Override
public DiscoverTheImpossible copy() {
return new DiscoverTheImpossible(this);
}
}
class DiscoverTheImpossibleEffect extends OneShotEffect {
private static final FilterCard filter = new FilterCard();
static {
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3));
}
DiscoverTheImpossibleEffect() {
super(Outcome.PlayForFree);
staticText = "look at the top five cards of your library. Exile one of them face down " +
"and put the rest on the bottom of your library in a random order. " +
"You may cast the exiled card without paying its mana cost if it's an instant spell " +
"with mana value 2 or less. If you don't, put that card into your hand";
}
private DiscoverTheImpossibleEffect(final DiscoverTheImpossibleEffect effect) {
super(effect);
}
@Override
public DiscoverTheImpossibleEffect copy() {
return new DiscoverTheImpossibleEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 5));
if (cards.isEmpty()) {
return false;
}
TargetCard target = new TargetCardInLibrary();
player.choose(outcome, cards, target, game);
Card card = game.getCard(target.getFirstTarget());
if (card == null) {
player.putCardsOnBottomOfLibrary(card, game, source, false);
return true;
}
player.moveCards(card, Zone.EXILED, source, game);
card.setFaceDown(true, game);
cards.retainZone(Zone.LIBRARY, game);
player.putCardsOnBottomOfLibrary(cards, game, source, false);
return CardUtil.castSpellWithAttributesForFree(player, source, game, new CardsImpl(card), filter)
|| player.moveCards(card, Zone.HAND, source, game);
}
}

View file

@ -0,0 +1,91 @@
package mage.cards.d;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DiesThisOrAnotherCreatureTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.Objects;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class DragonKamisEgg extends CardImpl {
private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DRAGON);
public DragonKamisEgg(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "");
this.subtype.add(SubType.EGG);
this.power = new MageInt(0);
this.toughness = new MageInt(1);
this.color.setGreen(true);
this.nightCard = true;
// Whenever Dragon-Kami's Egg or a Dragon you control dies, you may cast a creature spell from among cards you own in exile with hatching counters on them without paying its mana cost.
this.addAbility(new DiesThisOrAnotherCreatureTriggeredAbility(
new DragonKamisEggEffect(), false, filter
).setTriggerPhrase("Whenever {this} or a Dragon you control dies, "));
}
private DragonKamisEgg(final DragonKamisEgg card) {
super(card);
}
@Override
public DragonKamisEgg copy() {
return new DragonKamisEgg(this);
}
}
class DragonKamisEggEffect extends OneShotEffect {
DragonKamisEggEffect() {
super(Outcome.Benefit);
staticText = "you may cast a creature spell from among cards you own in exile " +
"with hatching counters on them without paying its mana cost";
}
private DragonKamisEggEffect(final DragonKamisEggEffect effect) {
super(effect);
}
@Override
public DragonKamisEggEffect copy() {
return new DragonKamisEggEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Cards cards = new CardsImpl();
game.getExile()
.getAllCards(game, player.getId())
.stream()
.filter(Objects::nonNull)
.filter(card -> card.getCounters(game).containsKey(CounterType.HATCHLING))
.forEach(cards::add);
return !cards.isEmpty() && CardUtil.castSpellWithAttributesForFree(
player, source, game, cards, StaticFilters.FILTER_CARD_CREATURE
);
}
}

View file

@ -1,12 +1,20 @@
package mage.cards.e;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetAnyTarget;
import mage.util.CardUtil;
import java.util.UUID;
@ -21,7 +29,7 @@ public final class Electrodominance extends CardImpl {
// Electrodominance deals X damage to any target. You may cast a card with converted mana cost X or less from your hand without paying its mana cost.
this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.REGULAR));
this.getSpellAbility().addTarget(new TargetAnyTarget());
this.getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(ManacostVariableValue.REGULAR));
this.getSpellAbility().addEffect(new ElectrodominanceEffect());
}
private Electrodominance(final Electrodominance card) {
@ -33,3 +41,34 @@ public final class Electrodominance extends CardImpl {
return new Electrodominance(this);
}
}
class ElectrodominanceEffect extends OneShotEffect {
ElectrodominanceEffect() {
super(Outcome.Benefit);
staticText = "You may cast a spell with mana value X " +
"or less from your hand without paying its mana cost";
}
private ElectrodominanceEffect(final ElectrodominanceEffect effect) {
super(effect);
}
@Override
public ElectrodominanceEffect copy() {
return new ElectrodominanceEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
FilterCard filter = new FilterCard();
filter.add(new ManaValuePredicate(
ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1
));
return CardUtil.castSpellWithAttributesForFree(controller, source, game, controller.getHand(), filter);
}
}

View file

@ -3,7 +3,10 @@ package mage.cards.e;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
@ -11,13 +14,11 @@ import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.ExileZone;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.util.CardUtil;
import java.util.UUID;
import mage.ApprovingObject;
/**
* @author LevelX2
@ -61,59 +62,16 @@ class EpicExperimentEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller != null && sourceObject != null) {
// move cards from library to exile
controller.moveCardsToExile(controller.getLibrary().getTopCards(game,
source.getManaCostsToPay().getX()), source, game, true,
source.getSourceId(), sourceObject.getIdName());
// cast the possible cards without paying the mana
ExileZone epicExperimentExileZone = game.getExile().getExileZone(source.getSourceId());
FilterCard filter = new FilterInstantOrSorceryCard();
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN,
source.getManaCostsToPay().getX() + 1));
filter.setMessage("instant and sorcery cards with mana value "
+ source.getManaCostsToPay().getX() + " or less");
Cards cardsToCast = new CardsImpl();
if (epicExperimentExileZone == null) {
return true;
}
cardsToCast.addAll(epicExperimentExileZone.getCards(filter, source.getSourceId(),
source.getControllerId(), game));
while (controller.canRespond() && !cardsToCast.isEmpty()) {
if (!controller.chooseUse(Outcome.PlayForFree, "Cast (another) a card exiled with "
+ sourceObject.getLogName() + " without paying its mana cost?", source, game)) {
break;
}
TargetCard targetCard = new TargetCard(1, Zone.EXILED, new FilterCard(
"instant or sorcery card to cast for free"));
if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) {
Card card = game.getCard(targetCard.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
if (!cardWasCast) {
game.informPlayer(controller, "You're not able to cast "
+ card.getIdName() + " or you canceled the casting.");
}
cardsToCast.remove(card);
} else {
break;
}
} else {
break;
}
}
// move cards not cast to graveyard
ExileZone exileZone = game.getExile().getExileZone(source.getSourceId());
if (exileZone != null) {
controller.moveCards(exileZone.getCards(game), Zone.GRAVEYARD, source, game);
}
return true;
if (controller == null || sourceObject == null) {
return false;
}
return false;
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, source.getManaCostsToPay().getX()));
controller.moveCards(cards, Zone.EXILED, source, game);
FilterCard filter = new FilterInstantOrSorceryCard();
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1));
CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter);
controller.moveCards(cards, Zone.GRAVEYARD, source, game);
return true;
}
@Override

View file

@ -1,22 +1,20 @@
package mage.cards.e;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.common.FilterNonlandCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.util.CardUtil;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.ApprovingObject;
/**
* @author ciaccona007 & L_J
@ -34,7 +32,6 @@ public final class EtaliPrimalStorm extends CardImpl {
// Whenever Etali, Primal Storm attacks, exile the top card of each player's library,
// then you may cast any number of nonland cards exiled this way without paying their mana costs.
this.addAbility(new AttacksTriggeredAbility(new EtaliPrimalStormEffect(), false));
}
private EtaliPrimalStorm(final EtaliPrimalStorm card) {
@ -69,58 +66,19 @@ class EtaliPrimalStormEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller != null
&& sourceObject != null) {
// move cards from library to exile
Set<Card> currentExiledCards = new HashSet<>();
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
if (!player.getLibrary().getTopCards(game, 1).isEmpty()) {
Card topCard = player.getLibrary().getFromTop(game);
if (topCard != null) {
if (filter.match(topCard, source.getSourceId(), source.getControllerId(), game)) {
currentExiledCards.add(topCard);
}
controller.moveCardsToExile(topCard, source, game, true, source.getSourceId(), sourceObject.getIdName());
}
}
}
}
// cast the possible cards without paying the mana
Cards cardsToCast = new CardsImpl();
cardsToCast.addAll(currentExiledCards);
boolean alreadyCast = false;
while (controller.canRespond() && !cardsToCast.isEmpty()) {
if (!controller.chooseUse(Outcome.PlayForFree, "Cast a"
+ (alreadyCast ? "nother" : "") + " card exiled with "
+ sourceObject.getLogName() + " without paying its mana cost?", source, game)) {
break;
}
TargetCard targetCard = new TargetCard(1, Zone.EXILED, new FilterCard("nonland card to cast for free"));
if (!controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) {
break;
}
alreadyCast = true;
Card card = game.getCard(targetCard.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
if (!cardWasCast) {
game.informPlayer(controller, "You're not able to cast "
+ card.getIdName() + " or you canceled the casting.");
}
cardsToCast.remove(card);
}
}
return true;
if (controller == null) {
return false;
}
return false;
// move cards from library to exile
Cards cards = new CardsImpl();
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
cards.add(player.getLibrary().getFromTop(game));
}
}
controller.moveCards(cards, Zone.EXILED, source, game);
CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter);
return true;
}
}

View file

@ -0,0 +1,77 @@
package mage.cards.e;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ExtractBrain extends CardImpl {
public ExtractBrain(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{B}");
// Target opponent chooses X cards from their hand. Look at those cards. You may cast a spell from among them without paying its mana cost.
this.getSpellAbility().addEffect(new ExtractBrainEffect());
this.getSpellAbility().addTarget(new TargetOpponent());
}
private ExtractBrain(final ExtractBrain card) {
super(card);
}
@Override
public ExtractBrain copy() {
return new ExtractBrain(this);
}
}
class ExtractBrainEffect extends OneShotEffect {
ExtractBrainEffect() {
super(Outcome.Benefit);
staticText = "target opponent chooses X cards from their hand. Look at those cards. " +
"You may cast a spell from among them without paying its mana cost";
}
private ExtractBrainEffect(final ExtractBrainEffect effect) {
super(effect);
}
@Override
public ExtractBrainEffect copy() {
return new ExtractBrainEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Player opponent = game.getPlayer(source.getFirstTarget());
int xValue = source.getManaCostsToPay().getX();
if (controller == null || opponent == null || opponent.getHand().isEmpty() || xValue < 1) {
return false;
}
TargetCardInHand target = new TargetCardInHand(
Math.min(opponent.getHand().size(), xValue), StaticFilters.FILTER_CARD
);
opponent.choose(Outcome.Detriment, opponent.getHand(), target, game);
Cards cards = new CardsImpl(target.getTargets());
controller.lookAtCards(source, null, cards, game);
CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, StaticFilters.FILTER_CARD);
return true;
}
}

View file

@ -79,14 +79,10 @@ class FeatherTheRedeemedTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (!event.getPlayerId().equals(this.getControllerId())) {
if (!isControlledBy(event.getPlayerId())) {
return false;
}
Spell spell = game.getStack().getSpell(event.getTargetId());
return checkSpell(spell, game);
}
private boolean checkSpell(Spell spell, Game game) {
if (spell == null) {
return false;
}
@ -166,15 +162,15 @@ class FeatherTheRedeemedEffect extends ReplacementEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
ZoneChangeEvent zEvent = ((ZoneChangeEvent) event);
if (zEvent.getFromZone() == Zone.STACK
&& zEvent.getToZone() == Zone.GRAVEYARD
&& event.getSourceId() != null) {
if (event.getSourceId().equals(event.getTargetId()) && mor.getZoneChangeCounter() == game.getState().getZoneChangeCounter(event.getSourceId())) {
Spell spell = game.getStack().getSpell(mor.getSourceId());
return spell != null && spell.isInstantOrSorcery(game);
}
if (zEvent.getFromZone() != Zone.STACK
|| zEvent.getToZone() != Zone.GRAVEYARD
|| event.getSourceId() == null
|| !event.getSourceId().equals(event.getTargetId())
|| mor.getZoneChangeCounter() != game.getState().getZoneChangeCounter(event.getSourceId())) {
return false;
}
return false;
Spell spell = game.getStack().getSpell(mor.getSourceId());
return spell != null && spell.isInstantOrSorcery(game);
}
@Override

View file

@ -0,0 +1,88 @@
package mage.cards.f;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.ReboundAbility;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class FeveredSuspicion extends CardImpl {
public FeveredSuspicion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{B}{R}");
// Each opponent exiles cards from the top of their library until they exile a nonland card. You may cast any number of spells from among those nonland cards without paying their mana costs.
this.getSpellAbility().addEffect(new FeveredSuspicionEffect());
// Rebound
this.addAbility(new ReboundAbility());
}
private FeveredSuspicion(final FeveredSuspicion card) {
super(card);
}
@Override
public FeveredSuspicion copy() {
return new FeveredSuspicion(this);
}
}
class FeveredSuspicionEffect extends OneShotEffect {
FeveredSuspicionEffect() {
super(Outcome.Benefit);
staticText = "each opponent exiles cards from the top of their library until they exile a nonland card. " +
"You may cast any number of spells from among those nonland cards without paying their mana costs";
}
private FeveredSuspicionEffect(final FeveredSuspicionEffect effect) {
super(effect);
}
@Override
public FeveredSuspicionEffect copy() {
return new FeveredSuspicionEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Cards cards = new CardsImpl();
Cards nonlands = new CardsImpl();
for (UUID opponentId : game.getOpponents(source.getControllerId())) {
Player opponent = game.getPlayer(opponentId);
if (opponent == null) {
continue;
}
for (Card card : opponent.getLibrary().getCards(game)) {
cards.add(card);
if (!card.isLand(game)) {
nonlands.add(card);
break;
}
}
}
controller.moveCards(cards, Zone.EXILED, source, game);
nonlands.retainZone(Zone.EXILED, game);
CardUtil.castMultipleWithAttributeForFree(
controller, source, game, nonlands,
StaticFilters.FILTER_CARD
);
return true;
}
}

View file

@ -1,22 +1,23 @@
package mage.cards.g;
import mage.ApprovingObject;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.constants.CardType;
import mage.constants.CommanderCardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.util.CardUtil;
import java.util.Set;
import java.util.UUID;
/**
@ -35,7 +36,7 @@ public final class GeodeGolem extends CardImpl {
this.addAbility(TrampleAbility.getInstance());
// Whenever Geode Golem deals combat damage to a player, you may cast your commander from the command zone without paying its mana cost.
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new GeodeGolemEffect(), true));
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new GeodeGolemEffect(), false));
}
private GeodeGolem(final GeodeGolem card) {
@ -63,48 +64,13 @@ class GeodeGolemEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Card selectedCommander = null;
Set<Card> commandersInCommandZone = game.getCommanderCardsFromCommandZone(controller, CommanderCardType.COMMANDER_OR_OATHBREAKER);
if (commandersInCommandZone.isEmpty()) {
return false;
}
// select from commanders
if (commandersInCommandZone.size() == 1) {
selectedCommander = commandersInCommandZone.stream().findFirst().get();
} else {
TargetCard target = new TargetCard(Zone.COMMAND, new FilterCard("commander to cast without mana cost"));
target.setNotTarget(true);
if (controller.canRespond()
&& controller.choose(Outcome.PlayForFree, new CardsImpl(commandersInCommandZone), target, game)) {
selectedCommander = commandersInCommandZone.stream()
.filter(c -> c.getId().equals(target.getFirstTarget()))
.findFirst()
.orElse(null);
}
}
if (selectedCommander == null) {
return false;
}
// commander tax applies as additional cost
if (selectedCommander.getSpellAbility() != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + selectedCommander.getId(), Boolean.TRUE);
Boolean commanderWasCast = controller.cast(controller.chooseAbilityForCast(selectedCommander, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + selectedCommander.getId(), null);
return commanderWasCast;
} else {
// play commander as land is xmage feature, but mtg rules for text "cast commander" doesn't allow that
// TODO: improve lands support for "cast your commander" (allow land play from mdf cards)?
return controller.playLand(selectedCommander, game, true);
}
if (controller == null) {
return false;
}
return false;
Cards cards = new CardsImpl(game.getCommanderCardsFromCommandZone(
controller, CommanderCardType.COMMANDER_OR_OATHBREAKER
));
return CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, StaticFilters.FILTER_CARD);
}
@Override

View file

@ -1,41 +1,44 @@
package mage.cards.h;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledLandPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.ExileZone;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.util.CardUtil;
import java.util.UUID;
import mage.ApprovingObject;
/**
* @author ciaccona007
*/
public final class HazoretsUndyingFury extends CardImpl {
private static final FilterPermanent filter = new FilterControlledLandPermanent("Lands you control");
public HazoretsUndyingFury(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}");
//Shuffle your library, then exile the top four cards.
//You may cast any number of nonland cards with converted mana
//cost 5 or less from among them without paying their mana costs.
getSpellAbility().addEffect(new HazoretsUndyingFuryEffect());
this.getSpellAbility().addEffect(new HazoretsUndyingFuryEffect());
//Land you control don't untap during your next untap step.
this.getSpellAbility().addEffect(new DontUntapInControllersUntapStepAllEffect(
Duration.UntilYourNextTurn, TargetController.YOU,
new FilterControlledLandPermanent("Lands you control"))
.setText("Lands you control don't untap during your next untap phase"));
StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND
).setText("Lands you control don't untap during your next untap phase"));
}
private HazoretsUndyingFury(final HazoretsUndyingFury card) {
@ -50,19 +53,17 @@ public final class HazoretsUndyingFury extends CardImpl {
class HazoretsUndyingFuryEffect extends OneShotEffect {
private static final FilterCard filter = new FilterCard(
"nonland cards with mana value 5 or less");
private static final FilterCard filter = new FilterCard();
static {
filter.add(Predicates.not(CardType.LAND.getPredicate()));
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 6));
}
public HazoretsUndyingFuryEffect() {
super(Outcome.PlayForFree);
this.staticText = "Shuffle your library, then exile the top four cards. "
+ "You may cast any number of nonland cards with mana value "
+ "5 or less from among them without paying their mana costs";
this.staticText = "Shuffle your library, then exile the top four cards. " +
"You may cast any number of spells with mana value " +
"5 or less from among them without paying their mana costs";
}
public HazoretsUndyingFuryEffect(final HazoretsUndyingFuryEffect effect) {
@ -77,46 +78,15 @@ class HazoretsUndyingFuryEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller != null
&& sourceObject != null) {
controller.shuffleLibrary(source, game);
// move cards from library to exile
controller.moveCardsToExile(controller.getLibrary().getTopCards(game, 4),
source, game, true, source.getSourceId(), sourceObject.getIdName());
// cast the possible cards without paying the mana
ExileZone hazoretsUndyingFuryExileZone = game.getExile().getExileZone(source.getSourceId());
Cards cardsToCast = new CardsImpl();
if (hazoretsUndyingFuryExileZone == null) {
return true;
}
cardsToCast.addAll(hazoretsUndyingFuryExileZone.getCards(filter,
source.getSourceId(), source.getControllerId(), game));
while (controller.canRespond() && !cardsToCast.isEmpty()) {
if (!controller.chooseUse(Outcome.PlayForFree,
"Cast (another) a card exiled with "
+ sourceObject.getLogName() + " without paying its mana cost?", source, game)) {
break;
}
TargetCard targetCard = new TargetCard(1, Zone.EXILED,
new FilterCard("nonland card to cast for free"));
if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) {
Card card = game.getCard(targetCard.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
cardsToCast.remove(card);
if (!cardWasCast) {
game.informPlayer(controller, "You're not able to cast "
+ card.getIdName() + " or you canceled the casting.");
}
}
}
}
return true;
if (controller == null) {
return false;
}
return false;
controller.shuffleLibrary(source, game);
// move cards from library to exile
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4));
controller.moveCards(cards, Zone.EXILED, source, game);
// cast the possible cards without paying the mana
CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter);
return true;
}
}

View file

@ -1,26 +1,24 @@
package mage.cards.h;
import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterNonlandCard;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetCard;
import mage.util.CardUtil;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import mage.ApprovingObject;
/**
* @author jeffwadsworth & L_J
@ -58,7 +56,7 @@ class HellcarverDemonEffect extends OneShotEffect {
super(Outcome.PlayForFree);
staticText = "sacrifice all other permanents you control and discard your hand. "
+ "Exile the top six cards of your library. You may cast any number of "
+ "nonland cards exiled this way without paying their mana costs.";
+ "spells from among cards exiled this way without paying their mana costs";
}
public HellcarverDemonEffect(final HellcarverDemonEffect effect) {
@ -68,54 +66,25 @@ class HellcarverDemonEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (controller != null && sourceObject != null) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) {
if (!Objects.equals(permanent, sourceObject)) {
permanent.sacrifice(source, game);
}
}
if (!controller.getHand().isEmpty()) {
int cardsInHand = controller.getHand().size();
controller.discard(cardsInHand, false, false, source, game);
}
// move cards from library to exile
Set<Card> currentExiledCards = new HashSet<>();
currentExiledCards.addAll(controller.getLibrary().getTopCards(game, 6));
controller.moveCardsToExile(currentExiledCards, source, game, true,
source.getSourceId(), sourceObject.getIdName());
// cast the possible cards without paying the mana
Cards cardsToCast = new CardsImpl();
cardsToCast.addAll(currentExiledCards);
boolean alreadyCast = false;
while (controller.canRespond() && !cardsToCast.isEmpty()) {
if (!controller.chooseUse(outcome, "Cast a" + (alreadyCast ? "another" : "")
+ " card exiled with " + sourceObject.getLogName()
+ " without paying its mana cost?", source, game)) {
break;
}
TargetCard targetCard = new TargetCard(1, Zone.EXILED,
new FilterNonlandCard("nonland card to cast for free"));
if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) {
alreadyCast = true;
Card card = game.getCard(targetCard.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
cardsToCast.remove(card);
if (!cardWasCast) {
game.informPlayer(controller, "You're not able to cast "
+ card.getIdName() + " or you canceled the casting.");
}
}
}
}
return true;
if (controller == null) {
return false;
}
return false;
MageObjectReference sourceMor = new MageObjectReference(source);
for (Permanent permanent : game.getBattlefield().getActivePermanents(
StaticFilters.FILTER_CONTROLLED_PERMANENT,
source.getControllerId(), source.getSourceId(), game
)) {
if (!sourceMor.refersTo(permanent, game)) {
permanent.sacrifice(source, game);
}
}
controller.discard(controller.getHand(), false, source, game);
CardUtil.castMultipleWithAttributeForFree(
controller, source, game, new CardsImpl(
controller.getLibrary().getTopCards(game, 6)
), StaticFilters.FILTER_CARD
);
return true;
}
@Override

View file

@ -1,25 +1,28 @@
package mage.cards.i;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.common.FilterPermanentCard;
import mage.filter.predicate.Predicates;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInHand;
import mage.util.CardUtil;
import java.util.Objects;
import java.util.UUID;
/**
*
* @author weirddan455
*/
public final class InSearchOfGreatness extends CardImpl {
@ -30,8 +33,8 @@ public final class InSearchOfGreatness extends CardImpl {
// At the beginning of your upkeep, you may cast a permanent spell from your hand with converted mana cost
// equal to 1 plus the highest converted mana cost among other permanents you control
// without paying its mana cost. If you don't, scry 1.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new InSearchOfGreatnessEffect(),
TargetController.YOU, false, false
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new InSearchOfGreatnessEffect(), TargetController.YOU, false
));
}
@ -69,35 +72,19 @@ class InSearchOfGreatnessEffect extends OneShotEffect {
if (controller == null) {
return false;
}
int cmc = 0;
UUID permId = source.getSourceId();
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(controller.getId())) {
if (permanent != null && !permanent.getId().equals(permId)) {
int permCmc = permanent.getManaValue();
if (permCmc > cmc) {
cmc = permCmc;
}
}
}
if (controller.chooseUse(outcome, "Cast a permanent spell from your hand with CMC equal to "
+ ++cmc + "?", source, game)) {
FilterPermanentCard filter = new FilterPermanentCard("permanent spell from your hand");
filter.add(Predicates.not(CardType.LAND.getPredicate()));
filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, cmc));
TargetCardInHand target = new TargetCardInHand(filter);
if (controller.chooseTarget(outcome, target, source, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
if (cardWasCast) {
return true;
}
}
}
}
return controller.scry(1, source, game);
MageObjectReference sourceRef = new MageObjectReference(source);
int manaValue = game
.getBattlefield()
.getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT, controller.getId(), game)
.stream()
.filter(Objects::nonNull)
.filter(permanent -> !sourceRef.refersTo(permanent, game))
.mapToInt(MageObject::getManaValue)
.sum();
FilterCard filter = new FilterCard();
filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, manaValue + 1));
return CardUtil.castSpellWithAttributesForFree(
controller, source, game, new CardsImpl(controller.getHand()), filter
) || controller.scry(1, source, game);
}
}

View file

@ -0,0 +1,135 @@
package mage.cards.i;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.ExileSpellEffect;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class InvokeCalamity extends CardImpl {
public InvokeCalamity(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}{R}{R}{R}");
// You may cast up to two instant and/or sorcery spells with total mana value 6 or less from your graveyard and/or hand without paying their mana costs. If those spells would be put into your graveyard, exile them instead. Exile Invoke Calamity.
this.getSpellAbility().addEffect(new InvokeCalamityEffect());
this.getSpellAbility().addEffect(new ExileSpellEffect());
}
private InvokeCalamity(final InvokeCalamity card) {
super(card);
}
@Override
public InvokeCalamity copy() {
return new InvokeCalamity(this);
}
}
class InvokeCalamityEffect extends OneShotEffect {
InvokeCalamityEffect() {
super(Outcome.Benefit);
staticText = "you may cast up to two instant and/or sorcery spells " +
"with total mana value 6 or less from your graveyard and/or hand without paying their mana costs. " +
"If those spells would be put into your graveyard, exile them instead";
}
private InvokeCalamityEffect(final InvokeCalamityEffect effect) {
super(effect);
}
@Override
public InvokeCalamityEffect copy() {
return new InvokeCalamityEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Cards cards = new CardsImpl(player.getHand());
cards.addAll(player.getGraveyard());
CardUtil.castMultipleWithAttributeForFree(
player, source, game, cards,
StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY,
2, new InvokeCalamityTracker()
);
return true;
}
}
class InvokeCalamityTracker implements CardUtil.SpellCastTracker {
private int totalManaValue = 0;
@Override
public boolean checkCard(Card card, Game game) {
return card.getManaValue() + totalManaValue <= 6;
}
@Override
public void addCard(Card card, Ability source, Game game) {
totalManaValue += card.getManaValue();
game.addEffect(new InvokeCalamityReplacementEffect(card, game), source);
}
}
class InvokeCalamityReplacementEffect extends ReplacementEffectImpl {
private final MageObjectReference mor;
InvokeCalamityReplacementEffect(Card card, Game game) {
super(Duration.EndOfTurn, Outcome.Exile);
this.mor = new MageObjectReference(card.getMainCard(), game);
}
private InvokeCalamityReplacementEffect(final InvokeCalamityReplacementEffect effect) {
super(effect);
this.mor = effect.mor;
}
@Override
public InvokeCalamityReplacementEffect copy() {
return new InvokeCalamityReplacementEffect(this);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
Card card = mor.getCard(game);
return controller != null
&& card != null
&& controller.moveCards(card, Zone.EXILED, source, game);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
return zEvent.getToZone() == Zone.GRAVEYARD
&& zEvent.getTargetId().equals(mor.getSourceId());
}
}

View file

@ -9,37 +9,26 @@ import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.keyword.HasteAbility;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterOwnedCard;
import mage.filter.predicate.Predicates;
import mage.filter.StaticFilters;
import mage.game.ExileZone;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInExile;
import mage.target.common.TargetCardInGraveyard;
import mage.util.CardUtil;
import java.util.UUID;
import mage.ApprovingObject;
/**
* @author TheElk801
*/
public final class IzzetChemister extends CardImpl {
private static final FilterCard filter = new FilterOwnedCard("instant or sorcery card from your graveyard");
static {
filter.add(Predicates.or(
CardType.INSTANT.getPredicate(),
CardType.SORCERY.getPredicate())
);
}
public IzzetChemister(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}");
@ -51,15 +40,16 @@ public final class IzzetChemister extends CardImpl {
// Haste
this.addAbility(HasteAbility.getInstance());
// R, T: Exile target instant or sorcery card from your graveyard.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(this.getId(), this.getIdName()), new ManaCostsImpl("{R}"));
// {R}, {T}: Exile target instant or sorcery card from your graveyard.
Ability ability = new SimpleActivatedAbility(
new ExileTargetEffect().setToSourceExileZone(true), new ManaCostsImpl<>("{R}")
);
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetCard(Zone.GRAVEYARD, filter));
ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD));
this.addAbility(ability);
// 1R, T: Sacrifice Izzet Chemister: Cast any number of cards exiled with Izzet Chemister without paying their mana costs.
IzzetChemisterCastFromExileEffect returnFromExileEffect = new IzzetChemisterCastFromExileEffect(this.getId(), "Cast any number of cards exiled with {this} without paying their mana costs.");
ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, returnFromExileEffect, new ManaCostsImpl("{1}{R}"));
// {1}{R}, {T}: Sacrifice Izzet Chemister: Cast any number of cards exiled with Izzet Chemister without paying their mana costs.
ability = new SimpleActivatedAbility(new IzzetChemisterCastFromExileEffect(), new ManaCostsImpl<>("{1}{R}"));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
@ -77,17 +67,13 @@ public final class IzzetChemister extends CardImpl {
class IzzetChemisterCastFromExileEffect extends OneShotEffect {
private final UUID exileId;
public IzzetChemisterCastFromExileEffect(UUID exileId, String description) {
public IzzetChemisterCastFromExileEffect() {
super(Outcome.PlayForFree);
this.exileId = exileId;
this.setText(description);
staticText = "cast any number of cards exiled with {this} without paying their mana costs";
}
public IzzetChemisterCastFromExileEffect(final IzzetChemisterCastFromExileEffect effect) {
super(effect);
this.exileId = effect.exileId;
}
@Override
@ -97,38 +83,15 @@ class IzzetChemisterCastFromExileEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
ExileZone exile = game.getExile().getExileZone(exileId);
Player controller = game.getPlayer(source.getControllerId());
FilterCard filter = new FilterCard();
if (controller != null
&& exile != null) {
Cards cardsToExile = new CardsImpl();
cardsToExile.addAll(exile.getCards(game));
OuterLoop:
while (cardsToExile.count(filter, game) > 0) {
if (!controller.canRespond()) {
return false;
}
TargetCardInExile target = new TargetCardInExile(0, 1, filter, exileId, false);
target.setNotTarget(true);
while (controller.canRespond()
&& cardsToExile.count(filter, game) > 0
&& controller.choose(Outcome.PlayForFree, cardsToExile, target, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(card, game, true), game, true,
new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
cardsToExile.remove(card);
} else {
break OuterLoop;
}
target.clearChosen();
}
}
return true;
ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source));
if (controller == null || exile == null || exile.isEmpty()) {
return false;
}
return false;
CardUtil.castMultipleWithAttributeForFree(
controller, source, game, new CardsImpl(exile),
StaticFilters.FILTER_CARD
);
return true;
}
}

View file

@ -5,21 +5,20 @@ import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
import java.util.Set;
import java.util.UUID;
import mage.ApprovingObject;
/**
* @author LevelX2
@ -75,44 +74,15 @@ class JaceMindseekerEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Cards cardsToCast = new CardsImpl();
Player targetOpponent = game.getPlayer(targetPointer.getFirst(game, source));
if (targetOpponent != null) {
Set<Card> allCards = targetOpponent.millCards(5, source, game).getCards(game);
for (Card card : allCards) {
if (filter.match(card, game)) {
Zone zone = game.getState().getZone(card.getId());
// If the five cards are put into a public zone such as exile instead
// of a graveyard (perhaps due to the ability of Rest in Peace),
// you can cast one of those instant or sorcery cards from that zone.
if (zone == Zone.GRAVEYARD
|| zone == Zone.EXILED) {
cardsToCast.add(card);
}
}
}
// cast an instant or sorcery for free
if (!cardsToCast.isEmpty()) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
TargetCard target = new TargetCard(Zone.GRAVEYARD, filter); // zone should be ignored here
target.setNotTarget(true);
if (controller.chooseUse(outcome, "Cast an instant or sorcery card from among them for free?", source, game)
&& controller.choose(Outcome.PlayForFree, cardsToCast, target, game)) {
Card card = cardsToCast.get(target.getFirstTarget(), game);
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
}
}
}
}
return true;
Player controller = game.getPlayer(source.getControllerId());
Player opponent = game.getPlayer(source.getFirstTarget());
if (controller == null || opponent == null) {
return false;
}
return false;
return CardUtil.castSpellWithAttributesForFree(
controller, source, game,
opponent.millCards(5, source, game),
StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY
);
}
}

View file

@ -1,9 +1,5 @@
package mage.cards.j;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
@ -11,27 +7,25 @@ import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.WatcherScope;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.game.ExileZone;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.players.Player;
import mage.target.common.TargetCardInExile;
import mage.util.CardUtil;
import mage.watchers.Watcher;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class JelevaNephaliasScourge extends CardImpl {
@ -112,8 +106,8 @@ class JelevaNephaliasCastEffect extends OneShotEffect {
public JelevaNephaliasCastEffect() {
super(Outcome.PlayForFree);
this.staticText = "you may cast an instant or sorcery card "
+ "exiled with it without paying its mana cost";
this.staticText = "you may cast an instant or sorcery spell " +
"from among cards exiled with {this} without paying its mana cost";
}
public JelevaNephaliasCastEffect(final JelevaNephaliasCastEffect effect) {
@ -128,29 +122,14 @@ class JelevaNephaliasCastEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
if (exileZone != null
&& exileZone.count(new FilterInstantOrSorceryCard(), game) > 0) {
if (controller.chooseUse(outcome, "Cast an instant or sorcery card from "
+ "exile without paying its mana cost?", source, game)) {
TargetCardInExile target = new TargetCardInExile(
new FilterInstantOrSorceryCard(), CardUtil.getCardExileZoneId(game, source));
if (controller.choose(Outcome.PlayForFree, exileZone, target, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
return cardWasCast;
}
}
}
}
return true;
if (controller == null) {
return false;
}
return false;
Cards cards = new CardsImpl(game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)));
return CardUtil.castSpellWithAttributesForFree(
controller, source, game, cards,
StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY
);
}
}
@ -170,8 +149,8 @@ class JelevaNephaliasWatcher extends Watcher {
for (StackObject stackObject : game.getStack()) {
if (stackObject instanceof Spell) {
Spell spell = (Spell) stackObject;
manaSpendToCast.putIfAbsent(spell.getSourceId().toString()
+ spell.getCard().getZoneChangeCounter(game),
manaSpendToCast.putIfAbsent(spell.getSourceId().toString()
+ spell.getCard().getZoneChangeCounter(game),
spell.getSpellAbility().getManaCostsToPay().manaValue());
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.k;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
@ -11,23 +9,21 @@ import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.SearchEffect;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInExile;
import mage.target.common.TargetCardInLibrary;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class KahoMinamoHistorian extends CardImpl {
@ -109,8 +105,8 @@ class KahoMinamoHistorianCastEffect extends OneShotEffect {
public KahoMinamoHistorianCastEffect() {
super(Outcome.PlayForFree);
this.staticText = "you may cast a card with mana value X "
+ "exiled with {this} without paying its mana cost";
this.staticText = "you may cast a spell with mana value X " +
"from among cards exiled with {this} without paying its mana cost";
}
public KahoMinamoHistorianCastEffect(final KahoMinamoHistorianCastEffect effect) {
@ -125,24 +121,12 @@ class KahoMinamoHistorianCastEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
FilterCard filter = new FilterCard();
filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, source.getManaCostsToPay().getX()));
TargetCardInExile target = new TargetCardInExile(filter, CardUtil.getCardExileZoneId(game, source));
Cards cards = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
if (cards != null
&& !cards.isEmpty()
&& controller.choose(Outcome.PlayForFree, cards, target, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
}
}
return true;
Cards cards = new CardsImpl(game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)));
if (controller == null || cards.isEmpty()) {
return false;
}
return false;
FilterCard filter = new FilterCard();
filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, source.getManaCostsToPay().getX()));
return CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, filter);
}
}

View file

@ -1,32 +1,39 @@
package mage.cards.k;
import java.util.UUID;
import mage.abilities.effects.common.UntapTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class KariZevsExpertise extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("creature or Vehicle");
private static final FilterCard filter2 = new FilterCard("a spell with mana value 2 or less");
static {
filter.add(Predicates.or(CardType.CREATURE.getPredicate(),
SubType.VEHICLE.getPredicate()));
filter.add(Predicates.or(
CardType.CREATURE.getPredicate(),
SubType.VEHICLE.getPredicate()
));
filter2.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3));
}
public KariZevsExpertise(UUID ownerId, CardSetInfo setInfo) {
@ -36,10 +43,12 @@ public final class KariZevsExpertise extends CardImpl {
this.getSpellAbility().addTarget(new TargetPermanent(filter));
this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn));
this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap it"));
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("It gains haste until end of turn"));
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(
HasteAbility.getInstance(), Duration.EndOfTurn
).setText("It gains haste until end of turn"));
// You may cast a card with converted mana cost 2 or less from your hand without paying its mana cost.
this.getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(2).concatBy("<br>"));
this.getSpellAbility().addEffect(new CastFromHandForFreeEffect(filter2).concatBy("<br>"));
}
private KariZevsExpertise(final KariZevsExpertise card) {

View file

@ -5,17 +5,19 @@ import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.ProwessAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.UUID;
@ -59,12 +61,6 @@ public final class KenBurningBrawler extends CardImpl {
class KenBurningBrawlerEffect extends OneShotEffect {
private static final FilterCard filter = new FilterCard("sorcery spell");
static {
filter.add(CardType.SORCERY.getPredicate());
}
KenBurningBrawlerEffect() {
super(Outcome.Benefit);
staticText = "you may cast a sorcery spell from your hand with mana value " +
@ -82,8 +78,13 @@ class KenBurningBrawlerEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
return new CastWithoutPayingManaCostEffect(
StaticValue.get((Integer) getValue("damage")), filter
).apply(game, source);
Player player = game.getPlayer(source.getControllerId());
if (player == null || player.getHand().isEmpty()) {
return false;
}
FilterCard filter = new FilterCard();
filter.add(CardType.SORCERY.getPredicate());
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 1 + (Integer) getValue("damage")));
return CardUtil.castSpellWithAttributesForFree(player, source, game, new CardsImpl(player.getHand()), filter);
}
}

View file

@ -1,31 +1,24 @@
package mage.cards.m;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.common.FilterNonlandCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetCardInHand;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class MaelstromArchangel extends CardImpl {
private static final FilterCard filter = new FilterCard("a spell");
public MaelstromArchangel(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}");
this.subtype.add(SubType.ANGEL);
@ -37,8 +30,7 @@ public final class MaelstromArchangel extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever Maelstrom Archangel deals combat damage to a player, you may cast a nonland card from your hand without paying its mana cost.
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new MaelstromArchangelCastEffect(), false));
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new CastFromHandForFreeEffect(filter), false));
}
private MaelstromArchangel(final MaelstromArchangel card) {
@ -50,53 +42,3 @@ public final class MaelstromArchangel extends CardImpl {
return new MaelstromArchangel(this);
}
}
class MaelstromArchangelCastEffect extends OneShotEffect {
private static final FilterCard filter = new FilterNonlandCard("spell from your hand");
public MaelstromArchangelCastEffect() {
super(Outcome.PlayForFree);
this.staticText = "you may cast a spell from your hand without paying its mana cost";
}
public MaelstromArchangelCastEffect(final MaelstromArchangelCastEffect effect) {
super(effect);
}
@Override
public MaelstromArchangelCastEffect copy() {
return new MaelstromArchangelCastEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Target target = new TargetCardInHand(filter);
if (target.canChoose(source.getSourceId(), controller.getId(), game)
&& controller.chooseUse(outcome, "Cast a spell from your hand without paying its mana cost?", source, game)) {
Card cardToCast = null;
boolean cancel = false;
while (controller.canRespond() && !cancel) {
if (controller.chooseTarget(outcome, target, source, game)) {
cardToCast = game.getCard(target.getFirstTarget());
if (cardToCast != null && cardToCast.getSpellAbility().canChooseTarget(game, controller.getId())) {
cancel = true;
}
} else {
cancel = true;
}
}
if (cardToCast != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(cardToCast, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null);
}
}
return true;
}
return false;
}
}

View file

@ -1,29 +1,25 @@
package mage.cards.m;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicates;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class MindclawShaman extends CardImpl {
@ -55,14 +51,6 @@ public final class MindclawShaman extends CardImpl {
class MindclawShamanEffect extends OneShotEffect {
private static final FilterCard filter = new FilterCard("instant or sorcery card");
static {
filter.add(Predicates.or(
CardType.INSTANT.getPredicate(),
CardType.SORCERY.getPredicate()));
}
public MindclawShamanEffect() {
super(Outcome.PlayForFree);
this.staticText = "target opponent reveals their hand. You may cast "
@ -80,34 +68,15 @@ class MindclawShamanEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player targetOpponent = game.getPlayer(source.getFirstTarget());
MageObject sourceObject = source.getSourceObject(game);
if (targetOpponent != null && sourceObject != null) {
if (!targetOpponent.getHand().isEmpty()) {
targetOpponent.revealCards(sourceObject.getName(), targetOpponent.getHand(), game);
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
TargetCard target = new TargetCard(Zone.HAND, filter);
target.setNotTarget(true);
if (controller.choose(Outcome.PlayForFree, targetOpponent.getHand(), target, game)) {
Card chosenCard = targetOpponent.getHand().get(target.getFirstTarget(), game);
if (chosenCard != null) {
if (controller.chooseUse(Outcome.PlayForFree, "Cast the chosen card without "
+ "paying its mana cost?", source, game)) {
game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(chosenCard, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), null);
} else {
game.informPlayers(sourceObject.getLogName() + ": "
+ controller.getLogName() + " canceled casting the card.");
}
}
}
return true;
}
}
Player controller = game.getPlayer(source.getControllerId());
Player opponent = game.getPlayer(source.getFirstTarget());
if (controller == null || opponent == null) {
return false;
}
return false;
opponent.revealCards(source, opponent.getHand(), game);
return CardUtil.castSpellWithAttributesForFree(
controller, source, game, new CardsImpl(opponent.getHand()),
StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY
);
}
}

View file

@ -1,28 +1,24 @@
package mage.cards.m;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterNonlandCard;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class MindleechMass extends CardImpl {
@ -39,7 +35,9 @@ public final class MindleechMass extends CardImpl {
// Whenever Mindleech Mass deals combat damage to a player, you may look at that
// player's hand. If you do, you may cast a nonland card in it without paying that card's mana cost.
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new MindleechMassEffect(), true, true));
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(
new MindleechMassEffect(), true, true
));
}
private MindleechMass(final MindleechMass card) {
@ -56,8 +54,8 @@ class MindleechMassEffect extends OneShotEffect {
public MindleechMassEffect() {
super(Outcome.PlayForFree);
this.staticText = "you may look at that player's hand. If you do, "
+ "you may cast a nonland card in it without paying that card's mana cost";
this.staticText = "look at that player's hand. If you do, you " +
"may cast a spell from among those cards without paying its mana cost";
}
public MindleechMassEffect(final MindleechMassEffect effect) {
@ -71,27 +69,15 @@ class MindleechMassEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source));
Player controller = game.getPlayer(source.getControllerId());
if (opponent != null && controller != null) {
Cards cardsInHand = new CardsImpl();
cardsInHand.addAll(opponent.getHand());
opponent.revealCards("Opponents hand", cardsInHand, game);
if (!cardsInHand.isEmpty()
&& !cardsInHand.getCards(new FilterNonlandCard(), game).isEmpty()) {
TargetCard target = new TargetCard(1, Zone.HAND, new FilterNonlandCard());
if (controller.chooseTarget(Outcome.PlayForFree, cardsInHand, target, source, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
}
}
}
return true;
Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source));
if (controller == null || opponent == null) {
return false;
}
return false;
controller.lookAtCards(opponent.getName(), opponent.getHand(), game);
return CardUtil.castSpellWithAttributesForFree(
controller, source, game, new CardsImpl(opponent.getHand()),
StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY
);
}
}

View file

@ -1,19 +1,22 @@
package mage.cards.m;
import mage.ApprovingObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInExile;
import mage.util.CardUtil;
import java.util.UUID;
@ -60,36 +63,21 @@ class MuseVortexEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
Player player = game.getPlayer(source.getControllerId());
int xValue = source.getManaCostsToPay().getX();
if (player == null || xValue < 1) {
return false;
}
int xValue = source.getManaCostsToPay().getX();
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, xValue));
controller.moveCards(cards, Zone.EXILED, source, game);
Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, xValue));
player.moveCards(cards, Zone.EXILED, source, game);
cards.retainZone(Zone.EXILED, game);
FilterCard filter = new FilterInstantOrSorceryCard("an instant or sorcery card with mana value " + xValue + " or less");
FilterCard filter = new FilterInstantOrSorceryCard();
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1));
TargetCardInExile target = new TargetCardInExile(filter);
target.setNotTarget(true);
if (controller.choose(Outcome.Benefit, cards, target, game)) {
Card card = cards.get(target.getFirstTarget(), game);
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
cards.remove(card);
if (cardWasCast) {
cards.remove(card);
} else {
game.informPlayer(controller, "You're not able to cast "
+ card.getIdName() + " or you canceled the casting.");
}
controller.putCardsOnTopOfLibrary(cards, game, source, true);
return true;
}
}
return false;
CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter);
cards.retainZone(Zone.EXILED, game);
player.moveCards(cards.getCards(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game), Zone.HAND, source, game);
cards.retainZone(Zone.EXILED, game);
player.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
}
}

View file

@ -5,30 +5,23 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardIdPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetCardInHand;
import java.util.UUID;
import mage.ApprovingObject;
/**
* @author TheElk801
*/
public final class OmnispellAdept extends CardImpl {
private static final FilterCard filter = new FilterInstantOrSorceryCard("an instant or sorcery spell");
public OmnispellAdept(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}");
@ -40,7 +33,7 @@ public final class OmnispellAdept extends CardImpl {
// {2}{U}, {T}: You may cast an instant or sorcery card from your hand
// without paying its mana cost.
Ability ability = new SimpleActivatedAbility(
new OmnispellAdeptEffect(), new ManaCostsImpl("{2}{U}")
new CastFromHandForFreeEffect(filter), new ManaCostsImpl<>("{2}{U}")
);
ability.addCost(new TapSourceCost());
this.addAbility(ability);
@ -55,65 +48,3 @@ public final class OmnispellAdept extends CardImpl {
return new OmnispellAdept(this);
}
}
class OmnispellAdeptEffect extends OneShotEffect {
private static final FilterCard filter = new FilterInstantOrSorceryCard(
"instant or sorcery card from your hand");
public OmnispellAdeptEffect() {
super(Outcome.PlayForFree);
this.staticText = "you may cast an instant or sorcery card from your hand "
+ "without paying its mana cost";
}
public OmnispellAdeptEffect(final OmnispellAdeptEffect effect) {
super(effect);
}
@Override
public OmnispellAdeptEffect copy() {
return new OmnispellAdeptEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
FilterCard realFilter = filter.copy();
Target target = new TargetCardInHand(realFilter);
// choose one card until it possible to cast
if (target.canChoose(source.getSourceId(), controller.getId(), game)
&& controller.chooseUse(Outcome.PlayForFree, "Cast an instant or sorcery "
+ "card from your hand without paying its mana cost?", source, game)) {
Card cardToCast;
while (controller.canRespond()
&& controller.chooseTarget(Outcome.PlayForFree, target, source, game)) {
cardToCast = game.getCard(target.getFirstTarget());
if (cardToCast == null) {
break;
}
realFilter.add(Predicates.not(new CardIdPredicate(cardToCast.getId()))); // remove card from choose dialog (infinite fix)
if (!cardToCast.getSpellAbility().canChooseTarget(game, controller.getId())) {
continue;
}
game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(cardToCast, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null);
if (cardWasCast) {
break;
} else {
game.informPlayer(controller, "You're not able to cast "
+ cardToCast.getIdName() + " or you canceled the casting.");
}
}
}
return true;
}
}

View file

@ -1,31 +1,21 @@
package mage.cards.o;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.TributeNotPaidCondition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.abilities.keyword.HasteAbility;
import mage.abilities.keyword.TributeAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetCardInHand;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class OracleOfBones extends CardImpl {
@ -44,10 +34,14 @@ public final class OracleOfBones extends CardImpl {
this.addAbility(new TributeAbility(2));
// When Oracle of Bones enters the battlefield, if tribute wasn't paid,
// you may cast an instant or sorcery card from your hand without paying its mana cost.
TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new OracleOfBonesCastEffect(), false);
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, TributeNotPaidCondition.instance,
"When {this} enters the battlefield, if its tribute wasn't paid, "
+ "you may cast an instant or sorcery card from your hand without paying its mana cost."));
this.addAbility(new ConditionalInterveningIfTriggeredAbility(
new EntersBattlefieldTriggeredAbility(new CastFromHandForFreeEffect(
StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY
), false),
TributeNotPaidCondition.instance, "When {this} enters the battlefield, " +
"if its tribute wasn't paid, you may cast an instant or " +
"sorcery spell from your hand without paying its mana cost."
));
}
private OracleOfBones(final OracleOfBones card) {
@ -59,58 +53,3 @@ public final class OracleOfBones extends CardImpl {
return new OracleOfBones(this);
}
}
class OracleOfBonesCastEffect extends OneShotEffect {
private static final FilterCard filter = new FilterInstantOrSorceryCard(
"instant or sorcery card from your hand");
public OracleOfBonesCastEffect() {
super(Outcome.PlayForFree);
this.staticText = "you may cast an instant or sorcery card "
+ "from your hand without paying its mana cost";
}
public OracleOfBonesCastEffect(final OracleOfBonesCastEffect effect) {
super(effect);
}
@Override
public OracleOfBonesCastEffect copy() {
return new OracleOfBonesCastEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Target target = new TargetCardInHand(filter);
if (target.canChoose(source.getSourceId(), controller.getId(), game)
&& controller.chooseUse(outcome, "Cast an instant or sorcery "
+ "card from your hand without paying its mana cost?", source, game)) {
Card cardToCast = null;
boolean cancel = false;
while (controller.canRespond()
&& !cancel) {
if (controller.chooseTarget(outcome, target, source, game)) {
cardToCast = game.getCard(target.getFirstTarget());
if (cardToCast != null
&& cardToCast.getSpellAbility().canChooseTarget(game, controller.getId())) {
cancel = true;
}
} else {
cancel = true;
}
}
if (cardToCast != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(cardToCast, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null);
}
}
return true;
}
return false;
}
}

View file

@ -2,14 +2,18 @@ package mage.cards.r;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetSpell;
import mage.util.CardUtil;
import java.util.UUID;
@ -56,12 +60,17 @@ class ReinterpretEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Spell spell = game.getSpell(source.getFirstTarget());
if (spell == null) {
Player controller = game.getPlayer(source.getControllerId());
if (spell == null || controller == null) {
return false;
}
int manaValue = spell.getManaValue();
game.getStack().counter(spell.getId(), source, game);
new CastWithoutPayingManaCostEffect(manaValue).apply(game, source);
spell.counter(source, game);
FilterCard filter = new FilterCard();
filter.add(new ManaValuePredicate(
ComparisonType.FEWER_THAN, manaValue + 1
));
CardUtil.castSpellWithAttributesForFree(controller, source, game, controller.getHand(), filter);
return true;
}
}

View file

@ -1,20 +1,29 @@
package mage.cards.r;
import java.util.UUID;
import mage.abilities.dynamicvalue.common.GreatestPowerAmongControlledCreaturesValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import java.util.UUID;
/**
* @author fireshoes
*/
public final class RishkarsExpertise extends CardImpl {
private static final FilterCard filter = new FilterCard("a spell with mana value 5 or less");
static {
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 6));
}
public RishkarsExpertise(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}");
@ -24,7 +33,7 @@ public final class RishkarsExpertise extends CardImpl {
this.getSpellAbility().addEffect(effect);
// You may cast a card with converted mana cost 5 or less from your hand without paying its mana cost.
this.getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(5).concatBy("<br>"));
this.getSpellAbility().addEffect(new CastFromHandForFreeEffect(filter).concatBy("<br>"));
}
private RishkarsExpertise(final RishkarsExpertise card) {

View file

@ -0,0 +1,200 @@
package mage.cards.r;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class RodOfAbsorption extends CardImpl {
public RodOfAbsorption(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}");
// Whenever a player casts an instant or sorcery spell, exile it instead of putting it into a graveyard as it resolves.
this.addAbility(new RodOfAbsorptionTriggeredAbility());
// {X}, {T}, Sacrifice Rod of Absorption: You may cast any number of spells from among cards exiled with Rod of Absorption with total mana value X or less without paying their mana costs.
Ability ability = new SimpleActivatedAbility(new RodOfAbsorptionCastEffect(), new ManaCostsImpl<>("{X}"));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
}
private RodOfAbsorption(final RodOfAbsorption card) {
super(card);
}
@Override
public RodOfAbsorption copy() {
return new RodOfAbsorption(this);
}
}
class RodOfAbsorptionTriggeredAbility extends TriggeredAbilityImpl {
RodOfAbsorptionTriggeredAbility() {
super(Zone.BATTLEFIELD, null, false);
}
private RodOfAbsorptionTriggeredAbility(final RodOfAbsorptionTriggeredAbility ability) {
super(ability);
}
@Override
public RodOfAbsorptionTriggeredAbility copy() {
return new RodOfAbsorptionTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.SPELL_CAST;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell == null || !spell.isInstantOrSorcery(game)) {
return false;
}
this.getEffects().clear();
this.addEffect(new RodOfAbsorptionExileEffect(spell, game));
return true;
}
@Override
public String getRule() {
return "Whenever a player casts an instant or sorcery spell, " +
"exile it instead of putting it into a graveyard as it resolves.";
}
}
class RodOfAbsorptionExileEffect extends ReplacementEffectImpl {
private final MageObjectReference mor;
RodOfAbsorptionExileEffect(Spell spell, Game game) {
super(Duration.WhileOnStack, Outcome.Benefit);
this.mor = new MageObjectReference(spell, game);
}
private RodOfAbsorptionExileEffect(final RodOfAbsorptionExileEffect effect) {
super(effect);
this.mor = effect.mor;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Spell sourceSpell = game.getStack().getSpell(event.getTargetId());
if (sourceSpell == null || sourceSpell.isCopy()) {
return false;
}
Player player = game.getPlayer(sourceSpell.getOwnerId());
if (player == null) {
return false;
}
player.moveCardsToExile(
sourceSpell, source, game, false,
CardUtil.getExileZoneId(game, source),
CardUtil.getSourceName(game, source)
);
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
ZoneChangeEvent zEvent = ((ZoneChangeEvent) event);
if (zEvent.getFromZone() != Zone.STACK
|| zEvent.getToZone() != Zone.GRAVEYARD
|| event.getSourceId() == null
|| !event.getSourceId().equals(event.getTargetId())
|| mor.getZoneChangeCounter() != game.getState().getZoneChangeCounter(event.getSourceId())) {
return false;
}
Spell spell = game.getStack().getSpell(mor.getSourceId());
return spell != null && spell.isInstantOrSorcery(game);
}
@Override
public RodOfAbsorptionExileEffect copy() {
return new RodOfAbsorptionExileEffect(this);
}
}
class RodOfAbsorptionCastEffect extends OneShotEffect {
RodOfAbsorptionCastEffect() {
super(Outcome.Benefit);
staticText = "you may cast any number of spells from among cards exiled with " +
"{this} with total mana value X or less without paying their mana costs";
}
private RodOfAbsorptionCastEffect(final RodOfAbsorptionCastEffect effect) {
super(effect);
}
@Override
public RodOfAbsorptionCastEffect copy() {
return new RodOfAbsorptionCastEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Cards cards = new CardsImpl(game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)));
if (player == null || cards.isEmpty()) {
return false;
}
CardUtil.castMultipleWithAttributeForFree(
player, source, game, cards, StaticFilters.FILTER_CARD, Integer.MAX_VALUE,
new RodOfAbsorptionTracker(source.getManaCostsToPay().getX())
);
return true;
}
}
class RodOfAbsorptionTracker implements CardUtil.SpellCastTracker {
private final int xValue;
private int totalManaValue = 0;
RodOfAbsorptionTracker(int xValue) {
this.xValue = xValue;
}
@Override
public boolean checkCard(Card card, Game game) {
return card.getManaValue() + totalManaValue <= xValue;
}
@Override
public void addCard(Card card, Ability source, Game game) {
totalManaValue += card.getManaValue();
}
}

View file

@ -1,22 +1,18 @@
package mage.cards.s;
import java.util.UUID;
import mage.ApprovingObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.FilterSpell;
import mage.filter.StaticFilters;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.filter.predicate.Predicates;
@ -27,11 +23,11 @@ import mage.game.stack.StackObject;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetSpell;
import mage.target.common.TargetCardInExile;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class ShellOfTheLastKappa extends CardImpl {
@ -50,16 +46,18 @@ public final class ShellOfTheLastKappa extends CardImpl {
addSuperType(SuperType.LEGENDARY);
// {3}, {tap}: Exile target instant or sorcery spell that targets you.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new ShellOfTheLastKappaEffect(), new ManaCostsImpl("{3}"));
Ability ability = new SimpleActivatedAbility(
new ShellOfTheLastKappaEffect(), new GenericManaCost(3)
);
ability.addCost(new TapSourceCost());
Target target = new TargetSpell(filter);
ability.addTarget(target);
this.addAbility(ability);
// {3}, {tap}, Sacrifice Shell of the Last Kappa: You may cast a card
// exiled with Shell of the Last Kappa without paying its mana cost.
ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new ShellOfTheLastKappaCastEffect(), new ManaCostsImpl("{3}"));
ability = new SimpleActivatedAbility(
new ShellOfTheLastKappaCastEffect(), new GenericManaCost(3)
);
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
@ -118,7 +116,7 @@ class ShellOfTheLastKappaCastEffect extends OneShotEffect {
public ShellOfTheLastKappaCastEffect() {
super(Outcome.PlayForFree);
this.staticText = "You may cast a card exiled with {this} without paying its mana cost";
this.staticText = "You may cast a spell from among cards exiled with {this} without paying its mana cost";
}
public ShellOfTheLastKappaCastEffect(final ShellOfTheLastKappaCastEffect effect) {
@ -134,25 +132,11 @@ class ShellOfTheLastKappaCastEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (controller != null
&& sourcePermanent != null) {
TargetCardInExile target = new TargetCardInExile(new FilterCard(),
CardUtil.getExileZoneId(game, source.getSourceId(), sourcePermanent.getZoneChangeCounter(game)));
if (controller.choose(Outcome.PlayForFree, game.getExile()
.getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(),
sourcePermanent.getZoneChangeCounter(game))), target, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null
&& controller.chooseUse(outcome, "Cast " + card.getLogName() + " without paying its mana cost?", source, game)) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
return cardWasCast;
}
}
if (controller == null || sourcePermanent == null) {
return false;
}
return false;
Cards cards = new CardsImpl(game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)));
return CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, StaticFilters.FILTER_CARD);
}
}

View file

@ -3,21 +3,20 @@ package mage.cards.s;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.NinjutsuAbility;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.util.CardUtil;
import java.util.UUID;
import mage.ApprovingObject;
/**
* @author LevelX2
@ -56,8 +55,8 @@ class SilentBladeOniEffect extends OneShotEffect {
SilentBladeOniEffect() {
super(Outcome.PlayForFree);
this.staticText = "look at that player's hand. "
+ "You may cast a nonland card in it without paying that card's mana cost";
this.staticText = "look at that player's hand. You may cast a spell " +
"from among those cards without paying its mana cost";
}
private SilentBladeOniEffect(final SilentBladeOniEffect effect) {
@ -71,32 +70,15 @@ class SilentBladeOniEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source));
Player controller = game.getPlayer(source.getControllerId());
if (opponent == null
|| controller == null) {
Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source));
if (controller == null || opponent == null) {
return false;
}
Cards cardsInHand = new CardsImpl();
cardsInHand.addAll(opponent.getHand());
if (cardsInHand.isEmpty()) {
return true;
}
TargetCard target = new TargetCard(
0, 1, Zone.HAND, StaticFilters.FILTER_CARD_A_NON_LAND
controller.lookAtCards(opponent.getName(), opponent.getHand(), game);
return CardUtil.castSpellWithAttributesForFree(
controller, source, game, new CardsImpl(opponent.getHand()),
StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY
);
if (!controller.chooseUse(outcome, "Cast a card from " + opponent.getName() + "'s hand?", source, game)
|| !controller.chooseTarget(outcome, cardsInHand, target, source, game)) {
return true;
}
Card card = game.getCard(target.getFirstTarget());
if (card == null) {
return false;
}
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
return cardWasCast;
}
}

View file

@ -0,0 +1,164 @@
package mage.cards.s;
import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.*;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.Objects;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class SpectralArcanist extends CardImpl {
public SpectralArcanist(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}");
this.subtype.add(SubType.SPIRIT);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(3);
this.toughness = new MageInt(2);
// Flying
this.addAbility(FlyingAbility.getInstance());
// When Spectral Arcanist enters the battlefield, you may cast an instant or sorcery spell with mana value less than or equal to the number of Spirits you control from a graveyard without paying its mana cost. If that spell would be put into a graveyard, exile it instead.
this.addAbility(new EntersBattlefieldTriggeredAbility(new SpectralArcanistCastEffect())
.addHint(SpectralArcanistCastEffect.getHint()));
}
private SpectralArcanist(final SpectralArcanist card) {
super(card);
}
@Override
public SpectralArcanist copy() {
return new SpectralArcanist(this);
}
}
class SpectralArcanistCastEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SPIRIT);
private static final Hint hint = new ValueHint("Spirits you control", new PermanentsOnBattlefieldCount(filter));
SpectralArcanistCastEffect() {
super(Outcome.Benefit);
staticText = "you may cast an instant or sorcery spell with mana value less than or equal to " +
"the number of Spirits you control from a graveyard without paying its mana cost. " +
"If that spell would be put into a graveyard, exile it instead";
}
private SpectralArcanistCastEffect(final SpectralArcanistCastEffect effect) {
super(effect);
}
@Override
public SpectralArcanistCastEffect copy() {
return new SpectralArcanistCastEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
FilterCard filterCard = new FilterInstantOrSorceryCard();
filterCard.add(new ManaValuePredicate(
ComparisonType.FEWER_THAN,
game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game)
));
Cards cards = new CardsImpl();
game.getState()
.getPlayersInRange(source.getControllerId(), game)
.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.map(Player::getGraveyard)
.forEach(cards::addAll);
return CardUtil.castSpellWithAttributesForFree(
player, source, game, cards, filterCard,
SpectralArcanistTracker.instance
);
}
public static Hint getHint() {
return hint;
}
}
enum SpectralArcanistTracker implements CardUtil.SpellCastTracker {
instance;
@Override
public boolean checkCard(Card card, Game game) {
return true;
}
@Override
public void addCard(Card card, Ability source, Game game) {
game.addEffect(new SpectralArcanistReplacementEffect(card, game), source);
}
}
class SpectralArcanistReplacementEffect extends ReplacementEffectImpl {
private final MageObjectReference mor;
SpectralArcanistReplacementEffect(Card card, Game game) {
super(Duration.EndOfTurn, Outcome.Exile);
this.mor = new MageObjectReference(card.getMainCard(), game);
}
private SpectralArcanistReplacementEffect(final SpectralArcanistReplacementEffect effect) {
super(effect);
this.mor = effect.mor;
}
@Override
public SpectralArcanistReplacementEffect copy() {
return new SpectralArcanistReplacementEffect(this);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
Card card = mor.getCard(game);
return controller != null
&& card != null
&& controller.moveCards(card, Zone.EXILED, source, game);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
return zEvent.getToZone() == Zone.GRAVEYARD
&& zEvent.getTargetId().equals(mor.getSourceId());
}
}

View file

@ -1,29 +1,36 @@
package mage.cards.s;
import java.util.UUID;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.permanent.token.ServoToken;
import java.util.UUID;
/**
* @author fireshoes
*/
public final class SramsExpertise extends CardImpl {
private static final FilterCard filter = new FilterCard("a spell with mana value 3 or less");
static {
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4));
}
public SramsExpertise(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}");
// Create three 1/1 colorless Servo artifact creature tokens.
this.getSpellAbility().addEffect(new CreateTokenEffect(new ServoToken(), 3));
// You may cast a card with converted mana cost 3 or less from your hand without paying its mana cost.
this.getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(3).concatBy("<br>"));
this.getSpellAbility().addEffect(new CastFromHandForFreeEffect(filter).concatBy("<br>"));
}
private SramsExpertise(final SramsExpertise card) {

View file

@ -1,13 +1,9 @@
package mage.cards.s;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
@ -17,17 +13,17 @@ import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterNonlandCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author spjspj
*/
public final class SunbirdsInvocation extends CardImpl {
@ -54,11 +50,11 @@ public final class SunbirdsInvocation extends CardImpl {
class SunbirdsInvocationTriggeredAbility extends SpellCastControllerTriggeredAbility {
public SunbirdsInvocationTriggeredAbility() {
SunbirdsInvocationTriggeredAbility() {
super(new SunbirdsInvocationEffect(), false);
}
public SunbirdsInvocationTriggeredAbility(SunbirdsInvocationTriggeredAbility ability) {
private SunbirdsInvocationTriggeredAbility(SunbirdsInvocationTriggeredAbility ability) {
super(ability);
}
@ -87,12 +83,10 @@ class SunbirdsInvocationTriggeredAbility extends SpellCastControllerTriggeredAbi
@Override
public String getRule() {
return "Whenever you cast a spell from your hand, "
+ "reveal the top X cards of your library, "
+ "where X is that spell's mana value. "
+ "You may cast a card revealed this way with "
+ "mana value X or less without paying its mana cost."
+ " Put the rest on the bottom of your library in a random order.";
return "Whenever you cast a spell from your hand, reveal the top X cards of your library, " +
"where X is that spell's mana value. You may cast a spell with mana value X or less " +
"from among cards revealed this way without paying its mana cost. " +
"Put the rest on the bottom of your library in a random order.";
}
}
@ -100,10 +94,6 @@ class SunbirdsInvocationEffect extends OneShotEffect {
public SunbirdsInvocationEffect() {
super(Outcome.PutCardInPlay);
staticText = "reveal the top X cards of your library, where X is that "
+ "spell's mana value. You may cast a card revealed this "
+ "way with mana value X or less without paying its mana cost. "
+ "Put the rest on the bottom of your library in a random order";
}
public SunbirdsInvocationEffect(final SunbirdsInvocationEffect effect) {
@ -113,9 +103,7 @@ class SunbirdsInvocationEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId());
if (controller == null
|| sourceObject == null) {
if (controller == null) {
return false;
}
Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source));
@ -124,29 +112,15 @@ class SunbirdsInvocationEffect extends OneShotEffect {
}
int xValue = spell.getManaValue();
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, xValue));
if (!cards.isEmpty()) {
controller.revealCards(sourceObject.getIdName(), cards, game);
FilterCard filter = new FilterNonlandCard("card revealed this way with mana value " + xValue + " or less");
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1));
TargetCard target = new TargetCard(1, Zone.LIBRARY, filter);
if (controller.chooseTarget(Outcome.PlayForFree, cards, target, source, game)) {
Card card = cards.get(target.getFirstTarget(), game);
if (card != null) {
if (controller.chooseUse(Outcome.Benefit, "Cast " + card.getLogName() + " without paying its mana cost?", source, game)) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
if (cardWasCast) {
cards.remove(card);
}
}
}
}
controller.putCardsOnBottomOfLibrary(cards, game, source, false);
if (cards.isEmpty()) {
return true;
}
controller.revealCards(source, cards, game);
FilterCard filter = new FilterCard();
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1));
CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, filter);
cards.retainZone(Zone.LIBRARY, game);
controller.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
}

View file

@ -1,34 +1,29 @@
package mage.cards.s;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.costs.OrCost;
import mage.abilities.costs.common.RevealTargetFromHandCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.target.common.TargetCardInHand;
import java.util.UUID;
/**
*
* @author weirddan455
*/
public final class SurtlandElementalist extends CardImpl {
private static final FilterCard filter = new FilterCard("a Giant card from your hand");
private static final FilterCard filter2 = new FilterInstantOrSorceryCard("an instant or sorcery spell");
static {
filter.add(SubType.GIANT.getPredicate());
}
@ -48,7 +43,7 @@ public final class SurtlandElementalist extends CardImpl {
"reveal a Giant card from your hand or pay {2}"));
// Whenever Surtland Elementalist attacks, you may cast an instant or sorcery spell from your hand without paying its mana cost.
this.addAbility(new AttacksTriggeredAbility(new SurtlandElementalistEffect(), true));
this.addAbility(new AttacksTriggeredAbility(new CastFromHandForFreeEffect(filter2), true));
}
private SurtlandElementalist(final SurtlandElementalist card) {
@ -60,39 +55,3 @@ public final class SurtlandElementalist extends CardImpl {
return new SurtlandElementalist(this);
}
}
class SurtlandElementalistEffect extends OneShotEffect {
public SurtlandElementalistEffect () {
super(Outcome.PlayForFree);
this.staticText = "cast an instant or sorcery spell from your hand without paying its mana cost";
}
private SurtlandElementalistEffect(final SurtlandElementalistEffect effect) {
super(effect);
}
@Override
public SurtlandElementalistEffect copy() {
return new SurtlandElementalistEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
TargetCardInHand target = new TargetCardInHand(0, 1, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY);
if (player.chooseTarget(Outcome.PlayForFree, target, source, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
boolean cardWasCast = player.cast(player.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
return cardWasCast;
}
}
}
return false;
}
}

View file

@ -1,6 +1,5 @@
package mage.cards.s;
import mage.ApprovingObject;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@ -9,19 +8,17 @@ import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.common.FilterNonlandCard;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.token.IcyManalithToken;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary;
import mage.util.CardUtil;
import java.util.Set;
import java.util.UUID;
/**
@ -47,7 +44,7 @@ public final class SvellaIceShaper extends CardImpl {
this.addAbility(ability);
// {6}{R}{G}, {T}: Look at the top four cards of your library. You may cast a spell from among them without paying its mana cost. Put the rest on the bottom of your library in a random order.
ability = new SimpleActivatedAbility(new SvellaIceShaperEffect(), new ManaCostsImpl("{6}{R}{G}"));
ability = new SimpleActivatedAbility(new SvellaIceShaperEffect(), new ManaCostsImpl<>("{6}{R}{G}"));
ability.addCost(new TapSourceCost());
this.addAbility(ability);
}
@ -86,23 +83,9 @@ class SvellaIceShaperEffect extends OneShotEffect {
if (controller == null) {
return false;
}
Set<Card> cardsSet = controller.getLibrary().getTopCards(game, 4);
Cards cards = new CardsImpl(cardsSet);
TargetCard target = new TargetCardInLibrary(0, 1,
new FilterNonlandCard("card to cast without paying its mana cost"));
controller.choose(Outcome.PlayForFree, cards, target, game);
Card card = controller.getLibrary().getCard(target.getFirstTarget(), game);
if (card == null) {
controller.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
}
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
if (cardWasCast) {
cards.remove(card);
}
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4));
CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, StaticFilters.FILTER_CARD);
cards.retainZone(Zone.LIBRARY, game);
controller.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
}

View file

@ -1,23 +1,24 @@
package mage.cards.t;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.condition.common.SpellMasteryCondition;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
import java.util.Set;
import java.util.UUID;
import mage.ApprovingObject;
/**
* @author LevelX2
@ -33,9 +34,8 @@ public final class TalentOfTheTelepath extends CardImpl {
// <i>Spell mastery</i> &mdash; If there are two or more instant and/or
// sorcery cards in your graveyard, you may cast up to two revealed instant
// and/or sorcery cards instead of one.
getSpellAbility().addEffect(new TalentOfTheTelepathEffect());
getSpellAbility().addTarget(new TargetOpponent());
this.getSpellAbility().addEffect(new TalentOfTheTelepathEffect());
this.getSpellAbility().addTarget(new TargetOpponent());
}
private TalentOfTheTelepath(final TalentOfTheTelepath card) {
@ -54,12 +54,12 @@ class TalentOfTheTelepathEffect extends OneShotEffect {
public TalentOfTheTelepathEffect() {
super(Outcome.PlayForFree);
this.staticText = "Target opponent reveals the top seven cards of their "
+ "library. You may cast an instant or sorcery card from among them "
+ "without paying its mana cost. Then that player puts the rest into their graveyard. "
+ "<BR><i>Spell mastery</i> &mdash; If there are two or more instant "
+ "and/or sorcery cards in your graveyard, you may cast up to two "
+ "revealed instant and/or sorcery cards instead of one.";
this.staticText = "Target opponent reveals the top seven cards of their " +
"library. You may cast an instant or sorcery spell from among them " +
"without paying its mana cost. Then that player puts the rest into their graveyard. "
+ "<br><i>Spell mastery</i> &mdash; If there are two or more instant " +
"and/or sorcery cards in your graveyard, you may cast up to two " +
"instant and/or sorcery spells from among the revealed cards instead of one.";
}
public TalentOfTheTelepathEffect(final TalentOfTheTelepathEffect effect) {
@ -73,60 +73,19 @@ class TalentOfTheTelepathEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Cards cardsToCast = new CardsImpl();
Player targetOpponent = game.getPlayer(targetPointer.getFirst(game, source));
MageObject sourceObject = source.getSourceObject(game);
if (targetOpponent != null && sourceObject != null) {
Set<Card> allCards = targetOpponent.getLibrary().getTopCards(game, 7);
Cards cards = new CardsImpl(allCards);
targetOpponent.revealCards(sourceObject.getIdName() + " - "
+ targetOpponent.getName() + "'s top library cards", cards, game);
for (Card card : allCards) {
if (filter.match(card, game)) {
cardsToCast.add(card);
}
}
// cast an instant or sorcery for free
if (!cardsToCast.isEmpty()) {
int numberOfSpells = 1;
if (SpellMasteryCondition.instance.apply(game, source)) {
numberOfSpells++;
}
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
TargetCard target = new TargetCard(Zone.LIBRARY, filter); // zone should be ignored here
target.setNotTarget(true);
while (controller.canRespond()
&& numberOfSpells > 0
&& !cardsToCast.isEmpty()
&& controller.chooseUse(outcome, "Cast an instant or sorcery card "
+ "from among them for free?", source, game)
&& controller.choose(Outcome.PlayForFree, cardsToCast, target, game)) {
Card card = cardsToCast.get(target.getFirstTarget(), game);
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
cardsToCast.remove(card);
if (cardWasCast) {
numberOfSpells--;
allCards.remove(card);
}
} else {
break;
}
if (!controller.canRespond()) {
return false;
}
target.clearChosen();
}
}
}
targetOpponent.moveCards(allCards, Zone.GRAVEYARD, source, game);
return true;
Player controller = game.getPlayer(source.getControllerId());
Player opponent = game.getPlayer(targetPointer.getFirst(game, source));
if (controller == null || opponent == null) {
return false;
}
return false;
Cards cards = new CardsImpl(opponent.getLibrary().getTopCards(game, 7));
opponent.revealCards(source, cards, game);
CardUtil.castMultipleWithAttributeForFree(
controller, source, game, cards, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY,
SpellMasteryCondition.instance.apply(game, source) ? 2 : 1
);
cards.retainZone(Zone.LIBRARY, game);
opponent.moveCards(cards, Zone.GRAVEYARD, source, game);
return true;
}
}

View file

@ -0,0 +1,96 @@
package mage.cards.t;
import mage.abilities.Ability;
import mage.abilities.common.SagaAbility;
import mage.abilities.effects.Effects;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.keyword.TransformAbility;
import mage.cards.*;
import mage.constants.*;
import mage.counters.CounterType;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class TheDragonKamiReborn extends CardImpl {
public TheDragonKamiReborn(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}");
this.subtype.add(SubType.SAGA);
this.secondSideCardClazz = mage.cards.d.DragonKamisEgg.class;
// (As this Saga enters and after your draw step, add a lore counter.)
SagaAbility sagaAbility = new SagaAbility(this);
// I, II You gain 2 life. Look at the top three cards of your library. Exile one of them face down with a hatching counter on it, then put the rest on the bottom of your library in any order.
sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II,
new Effects(new GainLifeEffect(2), new TheDragonKamiRebornEffect())
);
// III Exile this Saga, then return it to the battlefield transformed under your control.
this.addAbility(new TransformAbility());
sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect());
this.addAbility(sagaAbility);
}
private TheDragonKamiReborn(final TheDragonKamiReborn card) {
super(card);
}
@Override
public TheDragonKamiReborn copy() {
return new TheDragonKamiReborn(this);
}
}
class TheDragonKamiRebornEffect extends OneShotEffect {
TheDragonKamiRebornEffect() {
super(Outcome.Benefit);
staticText = "Look at the top three cards of your library. Exile one of them face down " +
"with a hatching counter on it, then put the rest on the bottom of your library in any order";
}
private TheDragonKamiRebornEffect(final TheDragonKamiRebornEffect effect) {
super(effect);
}
@Override
public TheDragonKamiRebornEffect copy() {
return new TheDragonKamiRebornEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 3));
if (cards.isEmpty()) {
return false;
}
TargetCard target = new TargetCardInLibrary();
player.choose(outcome, cards, target, game);
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
player.moveCards(card, Zone.EXILED, source, game);
card.setFaceDown(true, game);
card.addCounters(CounterType.HATCHLING.createInstance(), source, game);
}
cards.retainZone(Zone.LIBRARY, game);
player.putCardsOnBottomOfLibrary(card, game, source, true);
return true;
}
}

View file

@ -1,47 +1,45 @@
package mage.cards.t;
import mage.ApprovingObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.common.FilterNonlandCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetCard;
import mage.util.CardUtil;
import mage.watchers.common.SpellsCastWatcher;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author jeffwadsworth
*/
public final class TwinningGlass extends CardImpl {
private static final FilterCard filter = new FilterCard();
static {
filter.add(TwinningGlassPredicate.instance);
}
public TwinningGlass(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
// {1}, {T}: You may cast a nonland card from your hand without paying its mana cost if it has the same name as a spell that was cast this turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new TwinningGlassEffect(), new ManaCostsImpl("{1}"));
Ability ability = new SimpleActivatedAbility(
new CastFromHandForFreeEffect(filter).setText(
"you may cast a spell from your hand without paying its mana cost " +
"if it has the same name as a spell that was cast this turn"
), new GenericManaCost(1)
);
ability.addCost(new TapSourceCost());
this.addAbility(ability, new SpellsCastWatcher());
}
private TwinningGlass(final TwinningGlass card) {
@ -54,67 +52,14 @@ public final class TwinningGlass extends CardImpl {
}
}
class TwinningGlassEffect extends OneShotEffect {
public TwinningGlassEffect() {
super(Outcome.PlayForFree);
this.staticText = "You may cast a nonland card from your hand "
+ "without paying its mana cost if it has the same name "
+ "as a spell that was cast this turn";
}
public TwinningGlassEffect(final TwinningGlassEffect effect) {
super(effect);
}
enum TwinningGlassPredicate implements Predicate<Card> {
instance;
@Override
public TwinningGlassEffect copy() {
return new TwinningGlassEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
List<Spell> spells = new ArrayList<>();
Permanent twinningGlass = game.getPermanent(source.getSourceId());
Player controller = game.getPlayer(source.getControllerId());
public boolean apply(Card input, Game game) {
SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class);
if (twinningGlass == null) {
twinningGlass = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
}
if (twinningGlass != null
&& controller != null
&& watcher != null) {
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
if (watcher.getSpellsCastThisTurn(playerId) != null) {
for (Spell spell : watcher.getSpellsCastThisTurn(playerId)) {
spells.add(spell);
}
}
}
if (spells.isEmpty()) {
return false;
}
List<NamePredicate> predicates = spells.stream()
.map(Spell::getName)
.filter(Objects::nonNull)
.filter(s -> !s.isEmpty())
.map(NamePredicate::new)
.collect(Collectors.toList());
FilterNonlandCard filterCard = new FilterNonlandCard("nonland card that was cast this turn");
filterCard.add(Predicates.or(predicates));
TargetCard target = new TargetCard(0, 1, Zone.HAND, filterCard);
target.withChooseHint("free cast");
if (controller.choose(Outcome.PlayForFree, controller.getHand(), target, game)) {
Card chosenCard = game.getCard(target.getFirstTarget());
if (chosenCard != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(chosenCard, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), null);
return cardWasCast;
}
}
}
return false;
return watcher != null && watcher
.getAllSpellsCastThisTurn()
.anyMatch(spell -> CardUtil.haveSameNames(spell, input));
}
}

View file

@ -1,6 +1,5 @@
package mage.cards.v;
import mage.ApprovingObject;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
@ -8,7 +7,10 @@ import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.HasteAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.common.FilterInstantOrSorceryCard;
@ -16,10 +18,8 @@ import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary;
import mage.util.CardUtil;
import java.util.Set;
import java.util.UUID;
/**
@ -84,26 +84,11 @@ class VelomachusLoreholdEffect extends OneShotEffect {
if (controller == null || permanent == null) {
return false;
}
Set<Card> cardsSet = controller.getLibrary().getTopCards(game, 7);
Cards cards = new CardsImpl(cardsSet);
FilterCard filter = new FilterInstantOrSorceryCard(
"instant or sorcery card with mana value " + permanent.getPower().getValue() + " or less"
);
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 7));
FilterCard filter = new FilterInstantOrSorceryCard();
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, permanent.getPower().getValue() + 1));
TargetCard target = new TargetCardInLibrary(0, 1, filter);
controller.choose(Outcome.PlayForFree, cards, target, game);
Card card = controller.getLibrary().getCard(target.getFirstTarget(), game);
if (card == null) {
controller.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
}
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
if (cardWasCast) {
cards.remove(card);
}
CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, filter);
cards.retainZone(Zone.LIBRARY, game);
controller.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
}

View file

@ -1,24 +1,23 @@
package mage.cards.v;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterNonlandCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInExile;
import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
import java.util.UUID;
import mage.ApprovingObject;
/**
* @author LevelX2
@ -30,9 +29,8 @@ public final class VillainousWealth extends CardImpl {
// Target opponent exiles the top X cards of their library. You may cast any number of nonland cards
// with converted mana cost X or less from among them without paying their mana cost.
this.getSpellAbility().addTarget(new TargetOpponent());
this.getSpellAbility().addEffect(new VillainousWealthEffect());
this.getSpellAbility().addTarget(new TargetOpponent());
}
private VillainousWealth(final VillainousWealth card) {
@ -66,48 +64,16 @@ class VillainousWealthEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject mageObject = game.getObject(source.getSourceId());
if (controller != null && mageObject != null) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
FilterCard filter = new FilterNonlandCard();
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1));
UUID exileId = CardUtil.getCardExileZoneId(game, source);
if (player != null) {
Cards cardsToExile = new CardsImpl();
cardsToExile.addAll(player.getLibrary().getTopCards(game, source.getManaCostsToPay().getX()));
controller.moveCards(cardsToExile, Zone.EXILED, source, game);
if (controller.chooseUse(Outcome.PlayForFree, "Cast cards exiled with " + mageObject.getLogName()
+ " without paying its mana cost?", source, game)) {
OuterLoop:
while (cardsToExile.count(filter, game) > 0) {
if (!controller.canRespond()) {
return false;
}
TargetCardInExile target = new TargetCardInExile(0, 1, filter, exileId, false);
target.setNotTarget(true);
while (controller.canRespond()
&& cardsToExile.count(filter, game) > 0
&& controller.choose(Outcome.PlayForFree, cardsToExile, target, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
if (cardWasCast) {
cardsToExile.remove(card);
}
} else {
break OuterLoop;
}
target.clearChosen();
}
}
}
}
return true;
Player opponent = game.getPlayer(targetPointer.getFirst(game, source));
int xValue = source.getManaCostsToPay().getX();
if (controller == null || opponent == null || xValue < 1) {
return false;
}
return false;
Cards cards = new CardsImpl(opponent.getLibrary().getTopCards(game, xValue));
opponent.moveCards(cards, Zone.EXILED, source, game);
FilterCard filter = new FilterCard();
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1));
CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter);
return true;
}
}

View file

@ -1,30 +1,25 @@
package mage.cards.w;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.abilities.keyword.AfflictAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInHand;
import java.util.UUID;
/**
*
* @author spjspj
*/
public final class WildfireEternal extends CardImpl {
private static final FilterCard filter = new FilterInstantOrSorceryCard("an instant or sorcery spell");
public WildfireEternal(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
@ -35,10 +30,12 @@ public final class WildfireEternal extends CardImpl {
this.toughness = new MageInt(4);
// Afflict 4
addAbility(new AfflictAbility(4));
this.addAbility(new AfflictAbility(4));
// Whenever Wildfire Eternal attacks and isn't blocked, you may cast an instant or sorcery card from your hand without paying its mana cost.
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new WildfireEternalCastEffect(), false, true));
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(
new CastFromHandForFreeEffect(filter), false, true
));
}
private WildfireEternal(final WildfireEternal card) {
@ -50,45 +47,3 @@ public final class WildfireEternal extends CardImpl {
return new WildfireEternal(this);
}
}
class WildfireEternalCastEffect extends OneShotEffect {
public WildfireEternalCastEffect() {
super(Outcome.Benefit);
this.staticText = "you may cast an instant or sorcery card "
+ "from your hand without paying its mana cost";
}
public WildfireEternalCastEffect(final WildfireEternalCastEffect effect) {
super(effect);
}
@Override
public WildfireEternalCastEffect copy() {
return new WildfireEternalCastEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
FilterCard filter = new FilterInstantOrSorceryCard();
int cardsToCast = controller.getHand().count(filter, source.getControllerId(), source.getSourceId(), game);
if (cardsToCast > 0
&& controller.chooseUse(outcome, "Cast an instant or sorcery card from your "
+ "hand without paying its mana cost?", source, game)) {
TargetCardInHand target = new TargetCardInHand(filter);
controller.chooseTarget(outcome, target, source, game);
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
}
}
return true;
}
return false;
}
}

View file

@ -1,29 +1,36 @@
package mage.cards.y;
import java.util.UUID;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect;
import mage.abilities.effects.common.cost.CastFromHandForFreeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Duration;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import java.util.UUID;
/**
* @author fireshoes
*/
public final class YahennisExpertise extends CardImpl {
private static final FilterCard filter = new FilterCard("a spell with mana value 3 or less");
static {
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4));
}
public YahennisExpertise(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}");
// All creatures get -3/-3 until end of turn.
this.getSpellAbility().addEffect(new BoostAllEffect(-3, -3, Duration.EndOfTurn));
// You may cast a card with converted mana cost 3 or less from your hand without paying its mana cost.
this.getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(3).concatBy("<br>"));
this.getSpellAbility().addEffect(new CastFromHandForFreeEffect(filter).concatBy("<br>"));
}
private YahennisExpertise(final YahennisExpertise card) {

View file

@ -25,7 +25,8 @@ public final class CrimsonVowCommander extends ExpansionSet {
cards.add(new SetCardInfo("Anowon, the Ruin Sage", 118, Rarity.RARE, mage.cards.a.AnowonTheRuinSage.class));
cards.add(new SetCardInfo("Arcane Denial", 102, Rarity.COMMON, mage.cards.a.ArcaneDenial.class));
cards.add(new SetCardInfo("Arcane Signet", 159, Rarity.COMMON, mage.cards.a.ArcaneSignet.class));
cards.add(new SetCardInfo("Arterial Alchemy", 23, Rarity.RARE, mage.cards.a.ArterialAlchemy.class));
cards.add(new SetCardInfo("Arterial Alchemy", 23, Rarity.RARE, mage.cards.a.ArterialAlchemy.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Arterial Alchemy", 61, Rarity.RARE, mage.cards.a.ArterialAlchemy.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Avacyn's Judgment", 142, Rarity.RARE, mage.cards.a.AvacynsJudgment.class));
cards.add(new SetCardInfo("Azorius Chancery", 171, Rarity.UNCOMMON, mage.cards.a.AzoriusChancery.class));
cards.add(new SetCardInfo("Azorius Locket", 160, Rarity.COMMON, mage.cards.a.AzoriusLocket.class));
@ -38,8 +39,10 @@ public final class CrimsonVowCommander extends ExpansionSet {
cards.add(new SetCardInfo("Bloodsworn Steward", 144, Rarity.RARE, mage.cards.b.BloodswornSteward.class));
cards.add(new SetCardInfo("Bloodtracker", 122, Rarity.RARE, mage.cards.b.Bloodtracker.class));
cards.add(new SetCardInfo("Boreas Charger", 79, Rarity.RARE, mage.cards.b.BoreasCharger.class));
cards.add(new SetCardInfo("Breath of the Sleepless", 11, Rarity.RARE, mage.cards.b.BreathOfTheSleepless.class));
cards.add(new SetCardInfo("Breathkeeper Seraph", 31, Rarity.RARE, mage.cards.b.BreathkeeperSeraph.class));
cards.add(new SetCardInfo("Breath of the Sleepless", 11, Rarity.RARE, mage.cards.b.BreathOfTheSleepless.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Breath of the Sleepless", 49, Rarity.RARE, mage.cards.b.BreathOfTheSleepless.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Breathkeeper Seraph", 31, Rarity.RARE, mage.cards.b.BreathkeeperSeraph.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Breathkeeper Seraph", 69, Rarity.RARE, mage.cards.b.BreathkeeperSeraph.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Butcher of Malakir", 123, Rarity.RARE, mage.cards.b.ButcherOfMalakir.class));
cards.add(new SetCardInfo("Bygone Bishop", 80, Rarity.RARE, mage.cards.b.BygoneBishop.class));
cards.add(new SetCardInfo("Champion of Dusk", 124, Rarity.RARE, mage.cards.c.ChampionOfDusk.class));
@ -48,22 +51,27 @@ public final class CrimsonVowCommander extends ExpansionSet {
cards.add(new SetCardInfo("Commander's Sphere", 163, Rarity.COMMON, mage.cards.c.CommandersSphere.class));
cards.add(new SetCardInfo("Cordial Vampire", 125, Rarity.RARE, mage.cards.c.CordialVampire.class));
cards.add(new SetCardInfo("Crimson Honor Guard", 145, Rarity.RARE, mage.cards.c.CrimsonHonorGuard.class));
cards.add(new SetCardInfo("Crossway Troublemakers", 17, Rarity.RARE, mage.cards.c.CrosswayTroublemakers.class));
cards.add(new SetCardInfo("Crossway Troublemakers", 17, Rarity.RARE, mage.cards.c.CrosswayTroublemakers.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Crossway Troublemakers", 55, Rarity.RARE, mage.cards.c.CrosswayTroublemakers.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Crush Contraband", 81, Rarity.UNCOMMON, mage.cards.c.CrushContraband.class));
cards.add(new SetCardInfo("Custodi Soulbinders", 82, Rarity.RARE, mage.cards.c.CustodiSoulbinders.class));
cards.add(new SetCardInfo("Custodi Squire", 83, Rarity.COMMON, mage.cards.c.CustodiSquire.class));
cards.add(new SetCardInfo("Damnable Pact", 126, Rarity.RARE, mage.cards.d.DamnablePact.class));
cards.add(new SetCardInfo("Dark Impostor", 127, Rarity.RARE, mage.cards.d.DarkImpostor.class));
cards.add(new SetCardInfo("Darksteel Mutation", 84, Rarity.UNCOMMON, mage.cards.d.DarksteelMutation.class));
cards.add(new SetCardInfo("Disorder in the Court", 29, Rarity.RARE, mage.cards.d.DisorderInTheCourt.class));
cards.add(new SetCardInfo("Disorder in the Court", 29, Rarity.RARE, mage.cards.d.DisorderInTheCourt.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Disorder in the Court", 67, Rarity.RARE, mage.cards.d.DisorderInTheCourt.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Distant Melody", 103, Rarity.COMMON, mage.cards.d.DistantMelody.class));
cards.add(new SetCardInfo("Donal, Herald of Wings", 3, Rarity.MYTHIC, mage.cards.d.DonalHeraldOfWings.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Donal, Herald of Wings", 41, Rarity.MYTHIC, mage.cards.d.DonalHeraldOfWings.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Doom Weaver", 34, Rarity.RARE, mage.cards.d.DoomWeaver.class));
cards.add(new SetCardInfo("Doom Weaver", 34, Rarity.RARE, mage.cards.d.DoomWeaver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Doom Weaver", 72, Rarity.RARE, mage.cards.d.DoomWeaver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dovin, Grand Arbiter", 153, Rarity.MYTHIC, mage.cards.d.DovinGrandArbiter.class));
cards.add(new SetCardInfo("Drogskol Captain", 154, Rarity.UNCOMMON, mage.cards.d.DrogskolCaptain.class));
cards.add(new SetCardInfo("Drogskol Reinforcements", 5, Rarity.RARE, mage.cards.d.DrogskolReinforcements.class));
cards.add(new SetCardInfo("Ethereal Investigator", 12, Rarity.RARE, mage.cards.e.EtherealInvestigator.class));
cards.add(new SetCardInfo("Drogskol Reinforcements", 43, Rarity.RARE, mage.cards.d.DrogskolReinforcements.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Drogskol Reinforcements", 5, Rarity.RARE, mage.cards.d.DrogskolReinforcements.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ethereal Investigator", 12, Rarity.RARE, mage.cards.e.EtherealInvestigator.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ethereal Investigator", 50, Rarity.RARE, mage.cards.e.EtherealInvestigator.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Exotic Orchard", 173, Rarity.RARE, mage.cards.e.ExoticOrchard.class));
cards.add(new SetCardInfo("Falkenrath Gorger", 146, Rarity.RARE, mage.cards.f.FalkenrathGorger.class));
cards.add(new SetCardInfo("Falkenrath Noble", 128, Rarity.UNCOMMON, mage.cards.f.FalkenrathNoble.class));
@ -76,30 +84,42 @@ public final class CrimsonVowCommander extends ExpansionSet {
cards.add(new SetCardInfo("Geist of Saint Traft", 155, Rarity.MYTHIC, mage.cards.g.GeistOfSaintTraft.class));
cards.add(new SetCardInfo("Ghostly Pilferer", 105, Rarity.RARE, mage.cards.g.GhostlyPilferer.class));
cards.add(new SetCardInfo("Ghostly Prison", 87, Rarity.UNCOMMON, mage.cards.g.GhostlyPrison.class));
cards.add(new SetCardInfo("Glass-Cast Heart", 18, Rarity.RARE, mage.cards.g.GlassCastHeart.class));
cards.add(new SetCardInfo("Glass-Cast Heart", 18, Rarity.RARE, mage.cards.g.GlassCastHeart.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Glass-Cast Heart", 56, Rarity.RARE, mage.cards.g.GlassCastHeart.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hallowed Spiritkeeper", 88, Rarity.RARE, mage.cards.h.HallowedSpiritkeeper.class));
cards.add(new SetCardInfo("Hanged Executioner", 89, Rarity.RARE, mage.cards.h.HangedExecutioner.class));
cards.add(new SetCardInfo("Haunted Library", 6, Rarity.RARE, mage.cards.h.HauntedLibrary.class));
cards.add(new SetCardInfo("Haunting Imitation", 13, Rarity.RARE, mage.cards.h.HauntingImitation.class));
cards.add(new SetCardInfo("Hollowhenge Overlord", 36, Rarity.RARE, mage.cards.h.HollowhengeOverlord.class));
cards.add(new SetCardInfo("Imperious Mindbreaker", 33, Rarity.RARE, mage.cards.i.ImperiousMindbreaker.class));
cards.add(new SetCardInfo("Imposing Grandeur", 24, Rarity.RARE, mage.cards.i.ImposingGrandeur.class));
cards.add(new SetCardInfo("Haunted Library", 44, Rarity.RARE, mage.cards.h.HauntedLibrary.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Haunted Library", 6, Rarity.RARE, mage.cards.h.HauntedLibrary.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Haunting Imitation", 13, Rarity.RARE, mage.cards.h.HauntingImitation.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Haunting Imitation", 51, Rarity.RARE, mage.cards.h.HauntingImitation.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hollowhenge Overlord", 36, Rarity.RARE, mage.cards.h.HollowhengeOverlord.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hollowhenge Overlord", 74, Rarity.RARE, mage.cards.h.HollowhengeOverlord.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Imperious Mindbreaker", 33, Rarity.RARE, mage.cards.i.ImperiousMindbreaker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Imperious Mindbreaker", 71, Rarity.RARE, mage.cards.i.ImperiousMindbreaker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Imposing Grandeur", 24, Rarity.RARE, mage.cards.i.ImposingGrandeur.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Imposing Grandeur", 62, Rarity.RARE, mage.cards.i.ImposingGrandeur.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Imprisoned in the Moon", 106, Rarity.RARE, mage.cards.i.ImprisonedInTheMoon.class));
cards.add(new SetCardInfo("Indulgent Aristocrat", 130, Rarity.UNCOMMON, mage.cards.i.IndulgentAristocrat.class));
cards.add(new SetCardInfo("Kamber, the Plunderer", 19, Rarity.RARE, mage.cards.k.KamberThePlunderer.class));
cards.add(new SetCardInfo("Kamber, the Plunderer", 19, Rarity.RARE, mage.cards.k.KamberThePlunderer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kamber, the Plunderer", 57, Rarity.RARE, mage.cards.k.KamberThePlunderer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kami of the Crescent Moon", 107, Rarity.RARE, mage.cards.k.KamiOfTheCrescentMoon.class));
cards.add(new SetCardInfo("Karmic Guide", 90, Rarity.RARE, mage.cards.k.KarmicGuide.class));
cards.add(new SetCardInfo("Kirtar's Wrath", 91, Rarity.RARE, mage.cards.k.KirtarsWrath.class));
cards.add(new SetCardInfo("Knight of the White Orchid", 92, Rarity.RARE, mage.cards.k.KnightOfTheWhiteOrchid.class));
cards.add(new SetCardInfo("Laurine, the Diversion", 25, Rarity.RARE, mage.cards.l.LaurineTheDiversion.class));
cards.add(new SetCardInfo("Laurine, the Diversion", 25, Rarity.RARE, mage.cards.l.LaurineTheDiversion.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Laurine, the Diversion", 63, Rarity.RARE, mage.cards.l.LaurineTheDiversion.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Malakir Bloodwitch", 131, Rarity.RARE, mage.cards.m.MalakirBloodwitch.class));
cards.add(new SetCardInfo("Marble Diamond", 165, Rarity.COMMON, mage.cards.m.MarbleDiamond.class));
cards.add(new SetCardInfo("Markov Enforcer", 26, Rarity.RARE, mage.cards.m.MarkovEnforcer.class));
cards.add(new SetCardInfo("Markov Enforcer", 26, Rarity.RARE, mage.cards.m.MarkovEnforcer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Markov Enforcer", 64, Rarity.RARE, mage.cards.m.MarkovEnforcer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mentor of the Meek", 93, Rarity.RARE, mage.cards.m.MentorOfTheMeek.class));
cards.add(new SetCardInfo("Midnight Arsonist", 27, Rarity.RARE, mage.cards.m.MidnightArsonist.class));
cards.add(new SetCardInfo("Midnight Arsonist", 27, Rarity.RARE, mage.cards.m.MidnightArsonist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Midnight Arsonist", 65, Rarity.RARE, mage.cards.m.MidnightArsonist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Midnight Clock", 108, Rarity.RARE, mage.cards.m.MidnightClock.class));
cards.add(new SetCardInfo("Millicent, Restless Revenant", 1, Rarity.MYTHIC, mage.cards.m.MillicentRestlessRevenant.class));
cards.add(new SetCardInfo("Mirage Phalanx", 35, Rarity.RARE, mage.cards.m.MiragePhalanx.class));
cards.add(new SetCardInfo("Millicent, Restless Revenant", 1, Rarity.MYTHIC, mage.cards.m.MillicentRestlessRevenant.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Millicent, Restless Revenant", 39, Rarity.MYTHIC, mage.cards.m.MillicentRestlessRevenant.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mirage Phalanx", 35, Rarity.RARE, mage.cards.m.MiragePhalanx.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mirage Phalanx", 73, Rarity.RARE, mage.cards.m.MiragePhalanx.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mirror Entity", 94, Rarity.RARE, mage.cards.m.MirrorEntity.class));
cards.add(new SetCardInfo("Mob Rule", 147, Rarity.RARE, mage.cards.m.MobRule.class));
cards.add(new SetCardInfo("Molten Echoes", 148, Rarity.RARE, mage.cards.m.MoltenEchoes.class));
@ -109,47 +129,57 @@ public final class CrimsonVowCommander extends ExpansionSet {
cards.add(new SetCardInfo("Necropolis Regent", 132, Rarity.MYTHIC, mage.cards.n.NecropolisRegent.class));
cards.add(new SetCardInfo("Night's Whisper", 133, Rarity.COMMON, mage.cards.n.NightsWhisper.class));
cards.add(new SetCardInfo("Nirkana Revenant", 134, Rarity.MYTHIC, mage.cards.n.NirkanaRevenant.class));
cards.add(new SetCardInfo("Occult Epiphany", 14, Rarity.RARE, mage.cards.o.OccultEpiphany.class));
cards.add(new SetCardInfo("Olivia's Wrath", 20, Rarity.RARE, mage.cards.o.OliviasWrath.class));
cards.add(new SetCardInfo("Occult Epiphany", 14, Rarity.RARE, mage.cards.o.OccultEpiphany.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Occult Epiphany", 52, Rarity.RARE, mage.cards.o.OccultEpiphany.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Olivia's Wrath", 20, Rarity.RARE, mage.cards.o.OliviasWrath.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Olivia's Wrath", 58, Rarity.RARE, mage.cards.o.OliviasWrath.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Oyobi, Who Split the Heavens", 95, Rarity.RARE, mage.cards.o.OyobiWhoSplitTheHeavens.class));
cards.add(new SetCardInfo("Path of Ancestry", 177, Rarity.COMMON, mage.cards.p.PathOfAncestry.class));
cards.add(new SetCardInfo("Patron of the Vein", 135, Rarity.RARE, mage.cards.p.PatronOfTheVein.class));
cards.add(new SetCardInfo("Port Town", 178, Rarity.RARE, mage.cards.p.PortTown.class));
cards.add(new SetCardInfo("Prairie Stream", 179, Rarity.RARE, mage.cards.p.PrairieStream.class));
cards.add(new SetCardInfo("Predators' Hour", 21, Rarity.RARE, mage.cards.p.PredatorsHour.class));
cards.add(new SetCardInfo("Priest of the Blessed Graf", 7, Rarity.RARE, mage.cards.p.PriestOfTheBlessedGraf.class));
cards.add(new SetCardInfo("Predators' Hour", 21, Rarity.RARE, mage.cards.p.PredatorsHour.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Predators' Hour", 59, Rarity.RARE, mage.cards.p.PredatorsHour.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Priest of the Blessed Graf", 45, Rarity.RARE, mage.cards.p.PriestOfTheBlessedGraf.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Priest of the Blessed Graf", 7, Rarity.RARE, mage.cards.p.PriestOfTheBlessedGraf.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Promise of Bunrei", 96, Rarity.RARE, mage.cards.p.PromiseOfBunrei.class));
cards.add(new SetCardInfo("Rakdos Carnarium", 180, Rarity.UNCOMMON, mage.cards.r.RakdosCarnarium.class));
cards.add(new SetCardInfo("Rakdos Carnarium", 180, Rarity.COMMON, mage.cards.r.RakdosCarnarium.class));
cards.add(new SetCardInfo("Rakdos Charm", 156, Rarity.UNCOMMON, mage.cards.r.RakdosCharm.class));
cards.add(new SetCardInfo("Rakdos Signet", 166, Rarity.UNCOMMON, mage.cards.r.RakdosSignet.class));
cards.add(new SetCardInfo("Rakish Heir", 149, Rarity.UNCOMMON, mage.cards.r.RakishHeir.class));
cards.add(new SetCardInfo("Rattlechains", 110, Rarity.RARE, mage.cards.r.Rattlechains.class));
cards.add(new SetCardInfo("Reconnaissance Mission", 111, Rarity.UNCOMMON, mage.cards.r.ReconnaissanceMission.class));
cards.add(new SetCardInfo("Remorseful Cleric", 97, Rarity.RARE, mage.cards.r.RemorsefulCleric.class));
cards.add(new SetCardInfo("Rhoda, Geist Avenger", 8, Rarity.RARE, mage.cards.r.RhodaGeistAvenger.class));
cards.add(new SetCardInfo("Rhoda, Geist Avenger", 46, Rarity.RARE, mage.cards.r.RhodaGeistAvenger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Rhoda, Geist Avenger", 8, Rarity.RARE, mage.cards.r.RhodaGeistAvenger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sanctum Seeker", 136, Rarity.RARE, mage.cards.s.SanctumSeeker.class));
cards.add(new SetCardInfo("Scion of Opulence", 28, Rarity.RARE, mage.cards.s.ScionOfOpulence.class));
cards.add(new SetCardInfo("Scion of Opulence", 28, Rarity.RARE, mage.cards.s.ScionOfOpulence.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Scion of Opulence", 66, Rarity.RARE, mage.cards.s.ScionOfOpulence.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shacklegeist", 112, Rarity.RARE, mage.cards.s.Shacklegeist.class));
cards.add(new SetCardInfo("Shadowblood Ridge", 181, Rarity.RARE, mage.cards.s.ShadowbloodRidge.class));
cards.add(new SetCardInfo("Shadowgrange Archfiend", 22, Rarity.RARE, mage.cards.s.ShadowgrangeArchfiend.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shadowgrange Archfiend", 60, Rarity.RARE, mage.cards.s.ShadowgrangeArchfiend.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sinister Waltz", 30, Rarity.RARE, mage.cards.s.SinisterWaltz.class));
cards.add(new SetCardInfo("Sinister Waltz", 30, Rarity.RARE, mage.cards.s.SinisterWaltz.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sinister Waltz", 68, Rarity.RARE, mage.cards.s.SinisterWaltz.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sire of the Storm", 113, Rarity.UNCOMMON, mage.cards.s.SireOfTheStorm.class));
cards.add(new SetCardInfo("Sky Diamond", 167, Rarity.COMMON, mage.cards.s.SkyDiamond.class));
cards.add(new SetCardInfo("Skycloud Expanse", 182, Rarity.RARE, mage.cards.s.SkycloudExpanse.class));
cards.add(new SetCardInfo("Smoldering Marsh", 183, Rarity.RARE, mage.cards.s.SmolderingMarsh.class));
cards.add(new SetCardInfo("Sol Ring", 168, Rarity.UNCOMMON, mage.cards.s.SolRing.class));
cards.add(new SetCardInfo("Spectral Arcanist", 15, Rarity.RARE, mage.cards.s.SpectralArcanist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spectral Arcanist", 53, Rarity.RARE, mage.cards.s.SpectralArcanist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spectral Sailor", 114, Rarity.UNCOMMON, mage.cards.s.SpectralSailor.class));
cards.add(new SetCardInfo("Spectral Shepherd", 98, Rarity.UNCOMMON, mage.cards.s.SpectralShepherd.class));
cards.add(new SetCardInfo("Stensia Masquerade", 150, Rarity.UNCOMMON, mage.cards.s.StensiaMasquerade.class));
cards.add(new SetCardInfo("Storm of Souls", 9, Rarity.RARE, mage.cards.s.StormOfSouls.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Storm of Souls", 47, Rarity.RARE, mage.cards.s.StormOfSouls.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Storm of Souls", 9, Rarity.RARE, mage.cards.s.StormOfSouls.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Strefan, Maurer Progenitor", 2, Rarity.MYTHIC, mage.cards.s.StrefanMaurerProgenitor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Strefan, Maurer Progenitor", 40, Rarity.MYTHIC, mage.cards.s.StrefanMaurerProgenitor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Stromkirk Captain", 157, Rarity.UNCOMMON, mage.cards.s.StromkirkCaptain.class));
cards.add(new SetCardInfo("Stromkirk Condemned", 137, Rarity.RARE, mage.cards.s.StromkirkCondemned.class));
cards.add(new SetCardInfo("Stromkirk Occultist", 151, Rarity.RARE, mage.cards.s.StromkirkOccultist.class));
cards.add(new SetCardInfo("Sudden Salvation", 10, Rarity.RARE, mage.cards.s.SuddenSalvation.class));
cards.add(new SetCardInfo("Sudden Salvation", 10, Rarity.RARE, mage.cards.s.SuddenSalvation.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sudden Salvation", 48, Rarity.RARE, mage.cards.s.SuddenSalvation.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Supreme Phantom", 115, Rarity.RARE, mage.cards.s.SupremePhantom.class));
cards.add(new SetCardInfo("Swiftfoot Boots", 169, Rarity.UNCOMMON, mage.cards.s.SwiftfootBoots.class));
cards.add(new SetCardInfo("Swords to Plowshares", 99, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class));
@ -157,12 +187,15 @@ public final class CrimsonVowCommander extends ExpansionSet {
cards.add(new SetCardInfo("Temple of Enlightenment", 185, Rarity.RARE, mage.cards.t.TempleOfEnlightenment.class));
cards.add(new SetCardInfo("Temple of Malice", 186, Rarity.RARE, mage.cards.t.TempleOfMalice.class));
cards.add(new SetCardInfo("Temple of the False God", 187, Rarity.UNCOMMON, mage.cards.t.TempleOfTheFalseGod.class));
cards.add(new SetCardInfo("Thundering Mightmare", 37, Rarity.RARE, mage.cards.t.ThunderingMightmare.class));
cards.add(new SetCardInfo("Timin, Youthful Geist", 16, Rarity.RARE, mage.cards.t.TiminYouthfulGeist.class));
cards.add(new SetCardInfo("Thundering Mightmare", 37, Rarity.RARE, mage.cards.t.ThunderingMightmare.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thundering Mightmare", 75, Rarity.RARE, mage.cards.t.ThunderingMightmare.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Timin, Youthful Geist", 16, Rarity.RARE, mage.cards.t.TiminYouthfulGeist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Timin, Youthful Geist", 54, Rarity.RARE, mage.cards.t.TiminYouthfulGeist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Timothar, Baron of Bats", 4, Rarity.MYTHIC, mage.cards.t.TimotharBaronOfBats.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Timothar, Baron of Bats", 42, Rarity.MYTHIC, mage.cards.t.TimotharBaronOfBats.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Twilight Drover", 100, Rarity.RARE, mage.cards.t.TwilightDrover.class));
cards.add(new SetCardInfo("Umbris, Fear Manifest", 38, Rarity.MYTHIC, mage.cards.u.UmbrisFearManifest.class));
cards.add(new SetCardInfo("Umbris, Fear Manifest", 38, Rarity.MYTHIC, mage.cards.u.UmbrisFearManifest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Umbris, Fear Manifest", 76, Rarity.MYTHIC, mage.cards.u.UmbrisFearManifest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Unclaimed Territory", 188, Rarity.UNCOMMON, mage.cards.u.UnclaimedTerritory.class));
cards.add(new SetCardInfo("Underworld Connections", 138, Rarity.RARE, mage.cards.u.UnderworldConnections.class));
cards.add(new SetCardInfo("Unstable Obelisk", 170, Rarity.UNCOMMON, mage.cards.u.UnstableObelisk.class));
@ -171,7 +204,8 @@ public final class CrimsonVowCommander extends ExpansionSet {
cards.add(new SetCardInfo("Vampiric Dragon", 158, Rarity.RARE, mage.cards.v.VampiricDragon.class));
cards.add(new SetCardInfo("Vandalblast", 152, Rarity.UNCOMMON, mage.cards.v.Vandalblast.class));
cards.add(new SetCardInfo("Verity Circle", 116, Rarity.RARE, mage.cards.v.VerityCircle.class));
cards.add(new SetCardInfo("Wedding Ring", 32, Rarity.MYTHIC, mage.cards.w.WeddingRing.class));
cards.add(new SetCardInfo("Wedding Ring", 32, Rarity.MYTHIC, mage.cards.w.WeddingRing.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Wedding Ring", 70, Rarity.MYTHIC, mage.cards.w.WeddingRing.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Windborn Muse", 101, Rarity.RARE, mage.cards.w.WindbornMuse.class));
}
}

View file

@ -104,8 +104,10 @@ public final class ForgottenRealmsCommander extends ExpansionSet {
cards.add(new SetCardInfo("Exotic Orchard", 236, Rarity.RARE, mage.cards.e.ExoticOrchard.class));
cards.add(new SetCardInfo("Explore", 157, Rarity.COMMON, mage.cards.e.Explore.class));
cards.add(new SetCardInfo("Explorer's Scope", 205, Rarity.COMMON, mage.cards.e.ExplorersScope.class));
cards.add(new SetCardInfo("Extract Brain", 46, Rarity.RARE, mage.cards.e.ExtractBrain.class));
cards.add(new SetCardInfo("Fellwar Stone", 206, Rarity.UNCOMMON, mage.cards.f.FellwarStone.class));
cards.add(new SetCardInfo("Fertile Ground", 158, Rarity.COMMON, mage.cards.f.FertileGround.class));
cards.add(new SetCardInfo("Fevered Suspicion", 47, Rarity.RARE, mage.cards.f.FeveredSuspicion.class));
cards.add(new SetCardInfo("Fey Steed", 5, Rarity.RARE, mage.cards.f.FeySteed.class));
cards.add(new SetCardInfo("Fiend of the Shadows", 99, Rarity.RARE, mage.cards.f.FiendOfTheShadows.class));
cards.add(new SetCardInfo("Fiendlash", 31, Rarity.RARE, mage.cards.f.Fiendlash.class));
@ -217,6 +219,7 @@ public final class ForgottenRealmsCommander extends ExpansionSet {
cards.add(new SetCardInfo("Rishkar's Expertise", 170, Rarity.RARE, mage.cards.r.RishkarsExpertise.class));
cards.add(new SetCardInfo("Riverwise Augur", 93, Rarity.UNCOMMON, mage.cards.r.RiverwiseAugur.class));
cards.add(new SetCardInfo("Robe of Stars", 11, Rarity.RARE, mage.cards.r.RobeOfStars.class));
cards.add(new SetCardInfo("Rod of Absorption", 19, Rarity.RARE, mage.cards.r.RodOfAbsorption.class));
cards.add(new SetCardInfo("Ronom Unicorn", 71, Rarity.COMMON, mage.cards.r.RonomUnicorn.class));
cards.add(new SetCardInfo("Savage Ventmaw", 191, Rarity.UNCOMMON, mage.cards.s.SavageVentmaw.class));
cards.add(new SetCardInfo("Scourge of Valkas", 137, Rarity.RARE, mage.cards.s.ScourgeOfValkas.class));

View file

@ -24,18 +24,26 @@ public final class KamigawaNeonDynasty extends ExpansionSet {
cards.add(new SetCardInfo("Acquisition Octopus", 44, Rarity.UNCOMMON, mage.cards.a.AcquisitionOctopus.class));
cards.add(new SetCardInfo("Akki Ember-Keeper", 130, Rarity.COMMON, mage.cards.a.AkkiEmberKeeper.class));
cards.add(new SetCardInfo("Akki Ronin", 131, Rarity.COMMON, mage.cards.a.AkkiRonin.class));
cards.add(new SetCardInfo("Akki Ronin", 131, Rarity.COMMON, mage.cards.a.AkkiRonin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Akki Ronin", 319, Rarity.COMMON, mage.cards.a.AkkiRonin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Akki War Paint", 132, Rarity.COMMON, mage.cards.a.AkkiWarPaint.class));
cards.add(new SetCardInfo("Ambitious Assault", 133, Rarity.COMMON, mage.cards.a.AmbitiousAssault.class));
cards.add(new SetCardInfo("Ancestral Katana", 1, Rarity.COMMON, mage.cards.a.AncestralKatana.class));
cards.add(new SetCardInfo("Anchor to Reality", 45, Rarity.UNCOMMON, mage.cards.a.AnchorToReality.class));
cards.add(new SetCardInfo("Animus of Night's Reach", 109, Rarity.UNCOMMON, mage.cards.a.AnimusOfNightsReach.class));
cards.add(new SetCardInfo("Ao, the Dawn Sky", 2, Rarity.MYTHIC, mage.cards.a.AoTheDawnSky.class));
cards.add(new SetCardInfo("Architect of Restoration", 34, Rarity.RARE, mage.cards.a.ArchitectOfRestoration.class));
cards.add(new SetCardInfo("Ao, the Dawn Sky", 2, Rarity.MYTHIC, mage.cards.a.AoTheDawnSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ao, the Dawn Sky", 406, Rarity.MYTHIC, mage.cards.a.AoTheDawnSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ao, the Dawn Sky", 433, Rarity.MYTHIC, mage.cards.a.AoTheDawnSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Architect of Restoration", 34, Rarity.RARE, mage.cards.a.ArchitectOfRestoration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Architect of Restoration", 354, Rarity.RARE, mage.cards.a.ArchitectOfRestoration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Architect of Restoration", 442, Rarity.RARE, mage.cards.a.ArchitectOfRestoration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Armguard Familiar", 46, Rarity.COMMON, mage.cards.a.ArmguardFamiliar.class));
cards.add(new SetCardInfo("Asari Captain", 215, Rarity.UNCOMMON, mage.cards.a.AsariCaptain.class));
cards.add(new SetCardInfo("Asari Captain", 215, Rarity.UNCOMMON, mage.cards.a.AsariCaptain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Asari Captain", 327, Rarity.UNCOMMON, mage.cards.a.AsariCaptain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Assassin's Ink", 87, Rarity.UNCOMMON, mage.cards.a.AssassinsInk.class));
cards.add(new SetCardInfo("Atsushi, the Blazing Sky", 134, Rarity.MYTHIC, mage.cards.a.AtsushiTheBlazingSky.class));
cards.add(new SetCardInfo("Atsushi, the Blazing Sky", 134, Rarity.MYTHIC, mage.cards.a.AtsushiTheBlazingSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Atsushi, the Blazing Sky", 410, Rarity.MYTHIC, mage.cards.a.AtsushiTheBlazingSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Atsushi, the Blazing Sky", 463, Rarity.MYTHIC, mage.cards.a.AtsushiTheBlazingSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Automated Artificer", 239, Rarity.COMMON, mage.cards.a.AutomatedArtificer.class));
cards.add(new SetCardInfo("Awakened Awareness", 47, Rarity.UNCOMMON, mage.cards.a.AwakenedAwareness.class));
cards.add(new SetCardInfo("Azusa's Many Journeys", 172, Rarity.UNCOMMON, mage.cards.a.AzusasManyJourneys.class));
@ -44,18 +52,28 @@ public final class KamigawaNeonDynasty extends ExpansionSet {
cards.add(new SetCardInfo("Bearer of Memory", 174, Rarity.COMMON, mage.cards.b.BearerOfMemory.class));
cards.add(new SetCardInfo("Befriending the Moths", 4, Rarity.COMMON, mage.cards.b.BefriendingTheMoths.class));
cards.add(new SetCardInfo("Behold the Unspeakable", 48, Rarity.UNCOMMON, mage.cards.b.BeholdTheUnspeakable.class));
cards.add(new SetCardInfo("Biting-Palm Ninja", 88, Rarity.RARE, mage.cards.b.BitingPalmNinja.class));
cards.add(new SetCardInfo("Blade of the Oni", 89, Rarity.MYTHIC, mage.cards.b.BladeOfTheOni.class));
cards.add(new SetCardInfo("Blade-Blizzard Kitsune", 5, Rarity.UNCOMMON, mage.cards.b.BladeBlizzardKitsune.class));
cards.add(new SetCardInfo("Biting-Palm Ninja", 338, Rarity.RARE, mage.cards.b.BitingPalmNinja.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Biting-Palm Ninja", 452, Rarity.RARE, mage.cards.b.BitingPalmNinja.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Biting-Palm Ninja", 88, Rarity.RARE, mage.cards.b.BitingPalmNinja.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blade of the Oni", 377, Rarity.MYTHIC, mage.cards.b.BladeOfTheOni.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blade of the Oni", 420, Rarity.MYTHIC, mage.cards.b.BladeOfTheOni.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blade of the Oni", 453, Rarity.MYTHIC, mage.cards.b.BladeOfTheOni.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blade of the Oni", 89, Rarity.MYTHIC, mage.cards.b.BladeOfTheOni.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blade-Blizzard Kitsune", 331, Rarity.UNCOMMON, mage.cards.b.BladeBlizzardKitsune.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Blade-Blizzard Kitsune", 5, Rarity.UNCOMMON, mage.cards.b.BladeBlizzardKitsune.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bloodfell Caves", 264, Rarity.COMMON, mage.cards.b.BloodfellCaves.class));
cards.add(new SetCardInfo("Blossom Prancer", 175, Rarity.UNCOMMON, mage.cards.b.BlossomPrancer.class));
cards.add(new SetCardInfo("Blossoming Sands", 265, Rarity.COMMON, mage.cards.b.BlossomingSands.class));
cards.add(new SetCardInfo("Boon of Boseiju", 176, Rarity.UNCOMMON, mage.cards.b.BoonOfBoseiju.class));
cards.add(new SetCardInfo("Born to Drive", 6, Rarity.UNCOMMON, mage.cards.b.BornToDrive.class));
cards.add(new SetCardInfo("Boseiju Reaches Skyward", 177, Rarity.UNCOMMON, mage.cards.b.BoseijuReachesSkyward.class));
cards.add(new SetCardInfo("Boseiju, Who Endures", 266, Rarity.RARE, mage.cards.b.BoseijuWhoEndures.class));
cards.add(new SetCardInfo("Boseiju, Who Endures", 266, Rarity.RARE, mage.cards.b.BoseijuWhoEndures.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Boseiju, Who Endures", 412, Rarity.RARE, mage.cards.b.BoseijuWhoEndures.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Boseiju, Who Endures", 501, Rarity.RARE, mage.cards.b.BoseijuWhoEndures.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Branch of Boseiju", 177, Rarity.UNCOMMON, mage.cards.b.BranchOfBoseiju.class));
cards.add(new SetCardInfo("Brilliant Restoration", 7, Rarity.RARE, mage.cards.b.BrilliantRestoration.class));
cards.add(new SetCardInfo("Brilliant Restoration", 363, Rarity.RARE, mage.cards.b.BrilliantRestoration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Brilliant Restoration", 434, Rarity.RARE, mage.cards.b.BrilliantRestoration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Brilliant Restoration", 7, Rarity.RARE, mage.cards.b.BrilliantRestoration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bronze Cudgels", 240, Rarity.UNCOMMON, mage.cards.b.BronzeCudgels.class));
cards.add(new SetCardInfo("Bronzeplate Boar", 135, Rarity.UNCOMMON, mage.cards.b.BronzeplateBoar.class));
cards.add(new SetCardInfo("Brute Suit", 241, Rarity.COMMON, mage.cards.b.BruteSuit.class));
@ -63,45 +81,78 @@ public final class KamigawaNeonDynasty extends ExpansionSet {
cards.add(new SetCardInfo("Chainflail Centipede", 90, Rarity.COMMON, mage.cards.c.ChainflailCentipede.class));
cards.add(new SetCardInfo("Circuit Mender", 242, Rarity.UNCOMMON, mage.cards.c.CircuitMender.class));
cards.add(new SetCardInfo("Clawing Torment", 91, Rarity.COMMON, mage.cards.c.ClawingTorment.class));
cards.add(new SetCardInfo("Cloudsteel Kirin", 8, Rarity.RARE, mage.cards.c.CloudsteelKirin.class));
cards.add(new SetCardInfo("Coiling Stalker", 179, Rarity.COMMON, mage.cards.c.CoilingStalker.class));
cards.add(new SetCardInfo("Cloudsteel Kirin", 364, Rarity.RARE, mage.cards.c.CloudsteelKirin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cloudsteel Kirin", 435, Rarity.RARE, mage.cards.c.CloudsteelKirin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cloudsteel Kirin", 8, Rarity.RARE, mage.cards.c.CloudsteelKirin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Coiling Stalker", 179, Rarity.COMMON, mage.cards.c.CoilingStalker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Coiling Stalker", 346, Rarity.COMMON, mage.cards.c.CoilingStalker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Colossal Skyturtle", 216, Rarity.UNCOMMON, mage.cards.c.ColossalSkyturtle.class));
cards.add(new SetCardInfo("Commune with Spirits", 180, Rarity.COMMON, mage.cards.c.CommuneWithSpirits.class));
cards.add(new SetCardInfo("Containment Construct", 243, Rarity.UNCOMMON, mage.cards.c.ContainmentConstruct.class));
cards.add(new SetCardInfo("Covert Technician", 49, Rarity.UNCOMMON, mage.cards.c.CovertTechnician.class));
cards.add(new SetCardInfo("Covert Technician", 332, Rarity.UNCOMMON, mage.cards.c.CovertTechnician.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Covert Technician", 49, Rarity.UNCOMMON, mage.cards.c.CovertTechnician.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Crackling Emergence", 136, Rarity.COMMON, mage.cards.c.CracklingEmergence.class));
cards.add(new SetCardInfo("Debt to the Kami", 92, Rarity.COMMON, mage.cards.d.DebtToTheKami.class));
cards.add(new SetCardInfo("Discover the Impossible", 50, Rarity.UNCOMMON, mage.cards.d.DiscoverTheImpossible.class));
cards.add(new SetCardInfo("Dismal Backwater", 267, Rarity.COMMON, mage.cards.d.DismalBackwater.class));
cards.add(new SetCardInfo("Disruption Protocol", 51, Rarity.COMMON, mage.cards.d.DisruptionProtocol.class));
cards.add(new SetCardInfo("Dockside Chef", 93, Rarity.UNCOMMON, mage.cards.d.DocksideChef.class));
cards.add(new SetCardInfo("Dokuchi Shadow-Walker", 94, Rarity.COMMON, mage.cards.d.DokuchiShadowWalker.class));
cards.add(new SetCardInfo("Dokuchi Silencer", 95, Rarity.UNCOMMON, mage.cards.d.DokuchiSilencer.class));
cards.add(new SetCardInfo("Dokuchi Shadow-Walker", 339, Rarity.COMMON, mage.cards.d.DokuchiShadowWalker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dokuchi Shadow-Walker", 94, Rarity.COMMON, mage.cards.d.DokuchiShadowWalker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dokuchi Silencer", 340, Rarity.UNCOMMON, mage.cards.d.DokuchiSilencer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dokuchi Silencer", 95, Rarity.UNCOMMON, mage.cards.d.DokuchiSilencer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dragon-Kami's Egg", 181, Rarity.RARE, mage.cards.d.DragonKamisEgg.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dragon-Kami's Egg", 358, Rarity.RARE, mage.cards.d.DragonKamisEgg.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dragon-Kami's Egg", 473, Rarity.RARE, mage.cards.d.DragonKamisEgg.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dragonfly Suit", 9, Rarity.COMMON, mage.cards.d.DragonflySuit.class));
cards.add(new SetCardInfo("Dragonspark Reactor", 137, Rarity.UNCOMMON, mage.cards.d.DragonsparkReactor.class));
cards.add(new SetCardInfo("Dramatist's Puppet", 244, Rarity.COMMON, mage.cards.d.DramatistsPuppet.class));
cards.add(new SetCardInfo("Eater of Virtue", 245, Rarity.RARE, mage.cards.e.EaterOfVirtue.class));
cards.add(new SetCardInfo("Echo of Death's Wail", 124, Rarity.RARE, mage.cards.e.EchoOfDeathsWail.class));
cards.add(new SetCardInfo("Eater of Virtue", 245, Rarity.RARE, mage.cards.e.EaterOfVirtue.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eater of Virtue", 401, Rarity.RARE, mage.cards.e.EaterOfVirtue.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eater of Virtue", 496, Rarity.RARE, mage.cards.e.EaterOfVirtue.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Echo of Death's Wail", 124, Rarity.RARE, mage.cards.e.EchoOfDeathsWail.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Echo of Death's Wail", 356, Rarity.RARE, mage.cards.e.EchoOfDeathsWail.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Echo of Death's Wail", 462, Rarity.RARE, mage.cards.e.EchoOfDeathsWail.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ecologist's Terrarium", 246, Rarity.COMMON, mage.cards.e.EcologistsTerrarium.class));
cards.add(new SetCardInfo("Eiganjo Exemplar", 10, Rarity.COMMON, mage.cards.e.EiganjoExemplar.class));
cards.add(new SetCardInfo("Eiganjo Uprising", 217, Rarity.RARE, mage.cards.e.EiganjoUprising.class));
cards.add(new SetCardInfo("Eiganjo, Seat of the Empire", 268, Rarity.RARE, mage.cards.e.EiganjoSeatOfTheEmpire.class));
cards.add(new SetCardInfo("Eiganjo Exemplar", 10, Rarity.COMMON, mage.cards.e.EiganjoExemplar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eiganjo Exemplar", 309, Rarity.COMMON, mage.cards.e.EiganjoExemplar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eiganjo Uprising", 217, Rarity.RARE, mage.cards.e.EiganjoUprising.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eiganjo Uprising", 396, Rarity.RARE, mage.cards.e.EiganjoUprising.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eiganjo Uprising", 484, Rarity.RARE, mage.cards.e.EiganjoUprising.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eiganjo, Seat of the Empire", 268, Rarity.RARE, mage.cards.e.EiganjoSeatOfTheEmpire.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eiganjo, Seat of the Empire", 413, Rarity.RARE, mage.cards.e.EiganjoSeatOfTheEmpire.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eiganjo, Seat of the Empire", 502, Rarity.RARE, mage.cards.e.EiganjoSeatOfTheEmpire.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Enormous Energy Blade", 96, Rarity.UNCOMMON, mage.cards.e.EnormousEnergyBlade.class));
cards.add(new SetCardInfo("Enthusiastic Mechanaut", 218, Rarity.UNCOMMON, mage.cards.e.EnthusiasticMechanaut.class));
cards.add(new SetCardInfo("Enthusiastic Mechanaut", 218, Rarity.UNCOMMON, mage.cards.e.EnthusiasticMechanaut.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Enthusiastic Mechanaut", 509, Rarity.UNCOMMON, mage.cards.e.EnthusiasticMechanaut.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Era of Enlightenment", 11, Rarity.COMMON, mage.cards.e.EraOfEnlightenment.class));
cards.add(new SetCardInfo("Essence Capture", 52, Rarity.UNCOMMON, mage.cards.e.EssenceCapture.class));
cards.add(new SetCardInfo("Etching of Kumano", 152, Rarity.UNCOMMON, mage.cards.e.EtchingOfKumano.class));
cards.add(new SetCardInfo("Experimental Synthesizer", 138, Rarity.COMMON, mage.cards.e.ExperimentalSynthesizer.class));
cards.add(new SetCardInfo("Explosive Entry", 139, Rarity.COMMON, mage.cards.e.ExplosiveEntry.class));
cards.add(new SetCardInfo("Explosive Singularity", 140, Rarity.MYTHIC, mage.cards.e.ExplosiveSingularity.class));
cards.add(new SetCardInfo("Fable of the Mirror-Breaker", 141, Rarity.RARE, mage.cards.f.FableOfTheMirrorBreaker.class));
cards.add(new SetCardInfo("Explosive Singularity", 140, Rarity.MYTHIC, mage.cards.e.ExplosiveSingularity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Explosive Singularity", 383, Rarity.MYTHIC, mage.cards.e.ExplosiveSingularity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Explosive Singularity", 422, Rarity.MYTHIC, mage.cards.e.ExplosiveSingularity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Explosive Singularity", 464, Rarity.MYTHIC, mage.cards.e.ExplosiveSingularity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fable of the Mirror-Breaker", 141, Rarity.RARE, mage.cards.f.FableOfTheMirrorBreaker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fable of the Mirror-Breaker", 357, Rarity.RARE, mage.cards.f.FableOfTheMirrorBreaker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fable of the Mirror-Breaker", 465, Rarity.RARE, mage.cards.f.FableOfTheMirrorBreaker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fade into Antiquity", 182, Rarity.COMMON, mage.cards.f.FadeIntoAntiquity.class));
cards.add(new SetCardInfo("Fang of Shigeki", 183, Rarity.COMMON, mage.cards.f.FangOfShigeki.class));
cards.add(new SetCardInfo("Farewell", 13, Rarity.RARE, mage.cards.f.Farewell.class));
cards.add(new SetCardInfo("Fang of Shigeki", 183, Rarity.COMMON, mage.cards.f.FangOfShigeki.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fang of Shigeki", 347, Rarity.COMMON, mage.cards.f.FangOfShigeki.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Farewell", 13, Rarity.RARE, mage.cards.f.Farewell.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Farewell", 365, Rarity.RARE, mage.cards.f.Farewell.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Farewell", 417, Rarity.RARE, mage.cards.f.Farewell.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Farewell", 436, Rarity.RARE, mage.cards.f.Farewell.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Favor of Jukai", 184, Rarity.COMMON, mage.cards.f.FavorOfJukai.class));
cards.add(new SetCardInfo("Flame Discharge", 142, Rarity.UNCOMMON, mage.cards.f.FlameDischarge.class));
cards.add(new SetCardInfo("Forest", 291, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", 292, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", 301, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forest", 302, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Fragment of Konda", 12, Rarity.UNCOMMON, mage.cards.f.FragmentOfKonda.class));
cards.add(new SetCardInfo("Futurist Operative", 53, Rarity.UNCOMMON, mage.cards.f.FuturistOperative.class));
cards.add(new SetCardInfo("Futurist Operative", 333, Rarity.UNCOMMON, mage.cards.f.FuturistOperative.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Futurist Operative", 53, Rarity.UNCOMMON, mage.cards.f.FuturistOperative.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Futurist Sentinel", 54, Rarity.COMMON, mage.cards.f.FuturistSentinel.class));
cards.add(new SetCardInfo("Generous Visitor", 185, Rarity.UNCOMMON, mage.cards.g.GenerousVisitor.class));
cards.add(new SetCardInfo("Geothermal Kami", 186, Rarity.COMMON, mage.cards.g.GeothermalKami.class));
@ -113,217 +164,413 @@ public final class KamigawaNeonDynasty extends ExpansionSet {
cards.add(new SetCardInfo("Go-Shintai of Lost Wisdom", 55, Rarity.UNCOMMON, mage.cards.g.GoShintaiOfLostWisdom.class));
cards.add(new SetCardInfo("Go-Shintai of Shared Purpose", 14, Rarity.UNCOMMON, mage.cards.g.GoShintaiOfSharedPurpose.class));
cards.add(new SetCardInfo("Golden-Tail Disciple", 15, Rarity.COMMON, mage.cards.g.GoldenTailDisciple.class));
cards.add(new SetCardInfo("Goro-Goro, Disciple of Ryusei", 145, Rarity.RARE, mage.cards.g.GoroGoroDiscipleOfRyusei.class));
cards.add(new SetCardInfo("Goro-Goro, Disciple of Ryusei", 145, Rarity.RARE, mage.cards.g.GoroGoroDiscipleOfRyusei.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Goro-Goro, Disciple of Ryusei", 320, Rarity.RARE, mage.cards.g.GoroGoroDiscipleOfRyusei.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Goro-Goro, Disciple of Ryusei", 466, Rarity.RARE, mage.cards.g.GoroGoroDiscipleOfRyusei.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Grafted Growth", 188, Rarity.COMMON, mage.cards.g.GraftedGrowth.class));
cards.add(new SetCardInfo("Gravelighter", 98, Rarity.UNCOMMON, mage.cards.g.Gravelighter.class));
cards.add(new SetCardInfo("Greasefang, Okiba Boss", 220, Rarity.RARE, mage.cards.g.GreasefangOkibaBoss.class));
cards.add(new SetCardInfo("Greasefang, Okiba Boss", 220, Rarity.RARE, mage.cards.g.GreasefangOkibaBoss.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Greasefang, Okiba Boss", 397, Rarity.RARE, mage.cards.g.GreasefangOkibaBoss.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Greasefang, Okiba Boss", 485, Rarity.RARE, mage.cards.g.GreasefangOkibaBoss.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Greater Tanuki", 189, Rarity.COMMON, mage.cards.g.GreaterTanuki.class));
cards.add(new SetCardInfo("Guardians of Oboro", 56, Rarity.COMMON, mage.cards.g.GuardiansOfOboro.class));
cards.add(new SetCardInfo("Guardians of Oboro", 317, Rarity.COMMON, mage.cards.g.GuardiansOfOboro.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Guardians of Oboro", 56, Rarity.COMMON, mage.cards.g.GuardiansOfOboro.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hand of Enlightenment", 11, Rarity.COMMON, mage.cards.h.HandOfEnlightenment.class));
cards.add(new SetCardInfo("Harmonious Emergence", 190, Rarity.COMMON, mage.cards.h.HarmoniousEmergence.class));
cards.add(new SetCardInfo("Heiko Yamazaki, the General", 146, Rarity.UNCOMMON, mage.cards.h.HeikoYamazakiTheGeneral.class));
cards.add(new SetCardInfo("Heir of the Ancient Fang", 191, Rarity.COMMON, mage.cards.h.HeirOfTheAncientFang.class));
cards.add(new SetCardInfo("Hidetsugu Consumes All", 221, Rarity.MYTHIC, mage.cards.h.HidetsuguConsumesAll.class));
cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 99, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class));
cards.add(new SetCardInfo("Heiko Yamazaki, the General", 146, Rarity.UNCOMMON, mage.cards.h.HeikoYamazakiTheGeneral.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Heiko Yamazaki, the General", 321, Rarity.UNCOMMON, mage.cards.h.HeikoYamazakiTheGeneral.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Heir of the Ancient Fang", 191, Rarity.COMMON, mage.cards.h.HeirOfTheAncientFang.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Heir of the Ancient Fang", 325, Rarity.COMMON, mage.cards.h.HeirOfTheAncientFang.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hidetsugu Consumes All", 221, Rarity.MYTHIC, mage.cards.h.HidetsuguConsumesAll.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hidetsugu Consumes All", 361, Rarity.MYTHIC, mage.cards.h.HidetsuguConsumesAll.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hidetsugu Consumes All", 486, Rarity.MYTHIC, mage.cards.h.HidetsuguConsumesAll.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 378, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 429, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 430, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 431, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 432, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 454, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 99, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("High-Speed Hoverbike", 247, Rarity.UNCOMMON, mage.cards.h.HighSpeedHoverbike.class));
cards.add(new SetCardInfo("Hinata, Dawn-Crowned", 222, Rarity.RARE, mage.cards.h.HinataDawnCrowned.class));
cards.add(new SetCardInfo("Hinata, Dawn-Crowned", 222, Rarity.RARE, mage.cards.h.HinataDawnCrowned.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hinata, Dawn-Crowned", 398, Rarity.RARE, mage.cards.h.HinataDawnCrowned.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hinata, Dawn-Crowned", 487, Rarity.RARE, mage.cards.h.HinataDawnCrowned.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Historian's Wisdom", 192, Rarity.UNCOMMON, mage.cards.h.HistoriansWisdom.class));
cards.add(new SetCardInfo("Hotshot Mechanic", 16, Rarity.UNCOMMON, mage.cards.h.HotshotMechanic.class));
cards.add(new SetCardInfo("Imperial Moth", 4, Rarity.COMMON, mage.cards.i.ImperialMoth.class));
cards.add(new SetCardInfo("Imperial Oath", 17, Rarity.COMMON, mage.cards.i.ImperialOath.class));
cards.add(new SetCardInfo("Imperial Recovery Unit", 18, Rarity.UNCOMMON, mage.cards.i.ImperialRecoveryUnit.class));
cards.add(new SetCardInfo("Imperial Subduer", 19, Rarity.COMMON, mage.cards.i.ImperialSubduer.class));
cards.add(new SetCardInfo("Inkrise Infiltrator", 100, Rarity.COMMON, mage.cards.i.InkriseInfiltrator.class));
cards.add(new SetCardInfo("Imperial Subduer", 19, Rarity.COMMON, mage.cards.i.ImperialSubduer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Imperial Subduer", 310, Rarity.COMMON, mage.cards.i.ImperialSubduer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Inkrise Infiltrator", 100, Rarity.COMMON, mage.cards.i.InkriseInfiltrator.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Inkrise Infiltrator", 341, Rarity.COMMON, mage.cards.i.InkriseInfiltrator.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Intercessor's Arrest", 20, Rarity.COMMON, mage.cards.i.IntercessorsArrest.class));
cards.add(new SetCardInfo("Inventive Iteration", 57, Rarity.RARE, mage.cards.i.InventiveIteration.class));
cards.add(new SetCardInfo("Inventive Iteration", 355, Rarity.RARE, mage.cards.i.InventiveIteration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Inventive Iteration", 443, Rarity.RARE, mage.cards.i.InventiveIteration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Inventive Iteration", 57, Rarity.RARE, mage.cards.i.InventiveIteration.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invigorating Hot Spring", 223, Rarity.UNCOMMON, mage.cards.i.InvigoratingHotSpring.class));
cards.add(new SetCardInfo("Invoke Despair", 101, Rarity.RARE, mage.cards.i.InvokeDespair.class));
cards.add(new SetCardInfo("Invoke Justice", 21, Rarity.RARE, mage.cards.i.InvokeJustice.class));
cards.add(new SetCardInfo("Invoke the Ancients", 193, Rarity.RARE, mage.cards.i.InvokeTheAncients.class));
cards.add(new SetCardInfo("Invoke the Winds", 58, Rarity.RARE, mage.cards.i.InvokeTheWinds.class));
cards.add(new SetCardInfo("Invoke Calamity", 147, Rarity.RARE, mage.cards.i.InvokeCalamity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke Calamity", 384, Rarity.RARE, mage.cards.i.InvokeCalamity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke Calamity", 467, Rarity.RARE, mage.cards.i.InvokeCalamity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke Despair", 101, Rarity.RARE, mage.cards.i.InvokeDespair.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke Despair", 379, Rarity.RARE, mage.cards.i.InvokeDespair.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke Despair", 455, Rarity.RARE, mage.cards.i.InvokeDespair.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke Despair", 506, Rarity.RARE, mage.cards.i.InvokeDespair.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke Justice", 21, Rarity.RARE, mage.cards.i.InvokeJustice.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke Justice", 366, Rarity.RARE, mage.cards.i.InvokeJustice.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke Justice", 437, Rarity.RARE, mage.cards.i.InvokeJustice.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke the Ancients", 193, Rarity.RARE, mage.cards.i.InvokeTheAncients.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke the Ancients", 390, Rarity.RARE, mage.cards.i.InvokeTheAncients.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke the Ancients", 474, Rarity.RARE, mage.cards.i.InvokeTheAncients.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke the Winds", 370, Rarity.RARE, mage.cards.i.InvokeTheWinds.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke the Winds", 444, Rarity.RARE, mage.cards.i.InvokeTheWinds.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Invoke the Winds", 58, Rarity.RARE, mage.cards.i.InvokeTheWinds.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Iron Apprentice", 248, Rarity.COMMON, mage.cards.i.IronApprentice.class));
cards.add(new SetCardInfo("Ironhoof Boar", 148, Rarity.COMMON, mage.cards.i.IronhoofBoar.class));
cards.add(new SetCardInfo("Island", 285, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Isshin, Two Heavens as One", 224, Rarity.RARE, mage.cards.i.IsshinTwoHeavensAsOne.class));
cards.add(new SetCardInfo("Jin-Gitaxias, Progress Tyrant", 59, Rarity.MYTHIC, mage.cards.j.JinGitaxiasProgressTyrant.class));
cards.add(new SetCardInfo("Jugan Defends the Temple", 194, Rarity.MYTHIC, mage.cards.j.JuganDefendsTheTemple.class));
cards.add(new SetCardInfo("Jukai Naturalist", 225, Rarity.UNCOMMON, mage.cards.j.JukaiNaturalist.class));
cards.add(new SetCardInfo("Island", 286, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", 295, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Island", 296, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Isshin, Two Heavens as One", 224, Rarity.RARE, mage.cards.i.IsshinTwoHeavensAsOne.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Isshin, Two Heavens as One", 328, Rarity.RARE, mage.cards.i.IsshinTwoHeavensAsOne.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Isshin, Two Heavens as One", 488, Rarity.RARE, mage.cards.i.IsshinTwoHeavensAsOne.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jin-Gitaxias, Progress Tyrant", 307, Rarity.MYTHIC, mage.cards.j.JinGitaxiasProgressTyrant.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jin-Gitaxias, Progress Tyrant", 371, Rarity.MYTHIC, mage.cards.j.JinGitaxiasProgressTyrant.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jin-Gitaxias, Progress Tyrant", 427, Rarity.MYTHIC, mage.cards.j.JinGitaxiasProgressTyrant.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jin-Gitaxias, Progress Tyrant", 445, Rarity.MYTHIC, mage.cards.j.JinGitaxiasProgressTyrant.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jin-Gitaxias, Progress Tyrant", 59, Rarity.MYTHIC, mage.cards.j.JinGitaxiasProgressTyrant.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jugan Defends the Temple", 194, Rarity.MYTHIC, mage.cards.j.JuganDefendsTheTemple.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jugan Defends the Temple", 359, Rarity.MYTHIC, mage.cards.j.JuganDefendsTheTemple.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jugan Defends the Temple", 475, Rarity.MYTHIC, mage.cards.j.JuganDefendsTheTemple.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jukai Naturalist", 225, Rarity.UNCOMMON, mage.cards.j.JukaiNaturalist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jukai Naturalist", 510, Rarity.UNCOMMON, mage.cards.j.JukaiNaturalist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jukai Preserver", 195, Rarity.COMMON, mage.cards.j.JukaiPreserver.class));
cards.add(new SetCardInfo("Jukai Trainee", 196, Rarity.COMMON, mage.cards.j.JukaiTrainee.class));
cards.add(new SetCardInfo("Jukai Trainee", 196, Rarity.COMMON, mage.cards.j.JukaiTrainee.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jukai Trainee", 326, Rarity.COMMON, mage.cards.j.JukaiTrainee.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Jungle Hollow", 269, Rarity.COMMON, mage.cards.j.JungleHollow.class));
cards.add(new SetCardInfo("Junji, the Midnight Sky", 102, Rarity.MYTHIC, mage.cards.j.JunjiTheMidnightSky.class));
cards.add(new SetCardInfo("Kairi, the Swirling Sky", 60, Rarity.MYTHIC, mage.cards.k.KairiTheSwirlingSky.class));
cards.add(new SetCardInfo("Kaito Shizuki", 226, Rarity.MYTHIC, mage.cards.k.KaitoShizuki.class));
cards.add(new SetCardInfo("Junji, the Midnight Sky", 102, Rarity.MYTHIC, mage.cards.j.JunjiTheMidnightSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Junji, the Midnight Sky", 409, Rarity.MYTHIC, mage.cards.j.JunjiTheMidnightSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Junji, the Midnight Sky", 456, Rarity.MYTHIC, mage.cards.j.JunjiTheMidnightSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kairi, the Swirling Sky", 408, Rarity.MYTHIC, mage.cards.k.KairiTheSwirlingSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kairi, the Swirling Sky", 446, Rarity.MYTHIC, mage.cards.k.KairiTheSwirlingSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kairi, the Swirling Sky", 60, Rarity.MYTHIC, mage.cards.k.KairiTheSwirlingSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kaito Shizuki", 226, Rarity.MYTHIC, mage.cards.k.KaitoShizuki.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kaito Shizuki", 305, Rarity.MYTHIC, mage.cards.k.KaitoShizuki.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kaito Shizuki", 350, Rarity.MYTHIC, mage.cards.k.KaitoShizuki.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kaito Shizuki", 424, Rarity.MYTHIC, mage.cards.k.KaitoShizuki.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kaito's Pursuit", 103, Rarity.COMMON, mage.cards.k.KaitosPursuit.class));
cards.add(new SetCardInfo("Kami of Industry", 149, Rarity.COMMON, mage.cards.k.KamiOfIndustry.class));
cards.add(new SetCardInfo("Kami of Restless Shadows", 104, Rarity.COMMON, mage.cards.k.KamiOfRestlessShadows.class));
cards.add(new SetCardInfo("Kami of Terrible Secrets", 105, Rarity.COMMON, mage.cards.k.KamiOfTerribleSecrets.class));
cards.add(new SetCardInfo("Kami of Transience", 197, Rarity.RARE, mage.cards.k.KamiOfTransience.class));
cards.add(new SetCardInfo("Kami of Transience", 197, Rarity.RARE, mage.cards.k.KamiOfTransience.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kami of Transience", 391, Rarity.RARE, mage.cards.k.KamiOfTransience.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kami of Transience", 476, Rarity.RARE, mage.cards.k.KamiOfTransience.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kami's Flare", 150, Rarity.COMMON, mage.cards.k.KamisFlare.class));
cards.add(new SetCardInfo("Kappa Tech-Wrecker", 198, Rarity.UNCOMMON, mage.cards.k.KappaTechWrecker.class));
cards.add(new SetCardInfo("Kappa Tech-Wrecker", 198, Rarity.UNCOMMON, mage.cards.k.KappaTechWrecker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kappa Tech-Wrecker", 348, Rarity.UNCOMMON, mage.cards.k.KappaTechWrecker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kindled Fury", 151, Rarity.COMMON, mage.cards.k.KindledFury.class));
cards.add(new SetCardInfo("Kirin-Touched Orochi", 212, Rarity.RARE, mage.cards.k.KirinTouchedOrochi.class));
cards.add(new SetCardInfo("Kirin-Touched Orochi", 212, Rarity.RARE, mage.cards.k.KirinTouchedOrochi.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kirin-Touched Orochi", 360, Rarity.RARE, mage.cards.k.KirinTouchedOrochi.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kirin-Touched Orochi", 482, Rarity.RARE, mage.cards.k.KirinTouchedOrochi.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kitsune Ace", 22, Rarity.COMMON, mage.cards.k.KitsuneAce.class));
cards.add(new SetCardInfo("Kodama of the West Tree", 199, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class));
cards.add(new SetCardInfo("Kotose, the Silent Spider", 351, Rarity.RARE, mage.cards.k.KotoseTheSilentSpider.class));
cards.add(new SetCardInfo("Kodama of the West Tree", 199, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kodama of the West Tree", 392, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kodama of the West Tree", 423, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kodama of the West Tree", 477, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kotose, the Silent Spider", 228, Rarity.RARE, mage.cards.k.KotoseTheSilentSpider.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kotose, the Silent Spider", 351, Rarity.RARE, mage.cards.k.KotoseTheSilentSpider.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kotose, the Silent Spider", 490, Rarity.RARE, mage.cards.k.KotoseTheSilentSpider.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kumano Faces Kakkazan", 152, Rarity.UNCOMMON, mage.cards.k.KumanoFacesKakkazan.class));
cards.add(new SetCardInfo("Kura, the Boundless Sky", 200, Rarity.MYTHIC, mage.cards.k.KuraTheBoundlessSky.class));
cards.add(new SetCardInfo("Kyodai, Soul of Kamigawa", 23, Rarity.RARE, mage.cards.k.KyodaiSoulOfKamigawa.class));
cards.add(new SetCardInfo("Kura, the Boundless Sky", 200, Rarity.MYTHIC, mage.cards.k.KuraTheBoundlessSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kura, the Boundless Sky", 411, Rarity.MYTHIC, mage.cards.k.KuraTheBoundlessSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kura, the Boundless Sky", 478, Rarity.MYTHIC, mage.cards.k.KuraTheBoundlessSky.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kyodai, Soul of Kamigawa", 23, Rarity.RARE, mage.cards.k.KyodaiSoulOfKamigawa.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kyodai, Soul of Kamigawa", 407, Rarity.RARE, mage.cards.k.KyodaiSoulOfKamigawa.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kyodai, Soul of Kamigawa", 438, Rarity.RARE, mage.cards.k.KyodaiSoulOfKamigawa.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Leech Gauntlet", 106, Rarity.UNCOMMON, mage.cards.l.LeechGauntlet.class));
cards.add(new SetCardInfo("Lethal Exploit", 107, Rarity.COMMON, mage.cards.l.LethalExploit.class));
cards.add(new SetCardInfo("Life of Toshiro Umezawa", 108, Rarity.UNCOMMON, mage.cards.l.LifeOfToshiroUmezawa.class));
cards.add(new SetCardInfo("Light the Way", 24, Rarity.COMMON, mage.cards.l.LightTheWay.class));
cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 25, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class));
cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 25, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 367, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 439, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Likeness of the Seeker", 172, Rarity.UNCOMMON, mage.cards.l.LikenessOfTheSeeker.class));
cards.add(new SetCardInfo("Lion Sash", 26, Rarity.RARE, mage.cards.l.LionSash.class));
cards.add(new SetCardInfo("Living Breakthrough", 57, Rarity.RARE, mage.cards.l.LivingBreakthrough.class));
cards.add(new SetCardInfo("Lizard Blades", 153, Rarity.RARE, mage.cards.l.LizardBlades.class));
cards.add(new SetCardInfo("Lion Sash", 26, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lion Sash", 368, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lion Sash", 440, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Living Breakthrough", 355, Rarity.RARE, mage.cards.l.LivingBreakthrough.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Living Breakthrough", 443, Rarity.RARE, mage.cards.l.LivingBreakthrough.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Living Breakthrough", 57, Rarity.RARE, mage.cards.l.LivingBreakthrough.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lizard Blades", 153, Rarity.RARE, mage.cards.l.LizardBlades.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lizard Blades", 385, Rarity.RARE, mage.cards.l.LizardBlades.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lizard Blades", 468, Rarity.RARE, mage.cards.l.LizardBlades.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lucky Offering", 27, Rarity.COMMON, mage.cards.l.LuckyOffering.class));
cards.add(new SetCardInfo("Malicious Malfunction", 110, Rarity.UNCOMMON, mage.cards.m.MaliciousMalfunction.class));
cards.add(new SetCardInfo("March of Burgeoning Life", 201, Rarity.RARE, mage.cards.m.MarchOfBurgeoningLife.class));
cards.add(new SetCardInfo("March of Otherworldly Light", 28, Rarity.RARE, mage.cards.m.MarchOfOtherworldlyLight.class));
cards.add(new SetCardInfo("March of Reckless Joy", 154, Rarity.RARE, mage.cards.m.MarchOfRecklessJoy.class));
cards.add(new SetCardInfo("March of Swirling Mist", 61, Rarity.RARE, mage.cards.m.MarchOfSwirlingMist.class));
cards.add(new SetCardInfo("March of Wretched Sorrow", 111, Rarity.RARE, mage.cards.m.MarchOfWretchedSorrow.class));
cards.add(new SetCardInfo("March of Burgeoning Life", 201, Rarity.RARE, mage.cards.m.MarchOfBurgeoningLife.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Burgeoning Life", 393, Rarity.RARE, mage.cards.m.MarchOfBurgeoningLife.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Burgeoning Life", 479, Rarity.RARE, mage.cards.m.MarchOfBurgeoningLife.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Otherworldly Light", 28, Rarity.RARE, mage.cards.m.MarchOfOtherworldlyLight.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Otherworldly Light", 369, Rarity.RARE, mage.cards.m.MarchOfOtherworldlyLight.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Otherworldly Light", 441, Rarity.RARE, mage.cards.m.MarchOfOtherworldlyLight.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Reckless Joy", 154, Rarity.RARE, mage.cards.m.MarchOfRecklessJoy.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Reckless Joy", 386, Rarity.RARE, mage.cards.m.MarchOfRecklessJoy.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Reckless Joy", 469, Rarity.RARE, mage.cards.m.MarchOfRecklessJoy.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Swirling Mist", 372, Rarity.RARE, mage.cards.m.MarchOfSwirlingMist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Swirling Mist", 447, Rarity.RARE, mage.cards.m.MarchOfSwirlingMist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Swirling Mist", 61, Rarity.RARE, mage.cards.m.MarchOfSwirlingMist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Wretched Sorrow", 111, Rarity.RARE, mage.cards.m.MarchOfWretchedSorrow.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Wretched Sorrow", 380, Rarity.RARE, mage.cards.m.MarchOfWretchedSorrow.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("March of Wretched Sorrow", 457, Rarity.RARE, mage.cards.m.MarchOfWretchedSorrow.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Master's Rebuke", 202, Rarity.COMMON, mage.cards.m.MastersRebuke.class));
cards.add(new SetCardInfo("Mech Hangar", 270, Rarity.UNCOMMON, mage.cards.m.MechHangar.class));
cards.add(new SetCardInfo("Mechtitan Core", 249, Rarity.RARE, mage.cards.m.MechtitanCore.class));
cards.add(new SetCardInfo("Mechtitan Core", 249, Rarity.RARE, mage.cards.m.MechtitanCore.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mechtitan Core", 402, Rarity.RARE, mage.cards.m.MechtitanCore.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mechtitan Core", 497, Rarity.RARE, mage.cards.m.MechtitanCore.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Memory of Toshiro", 108, Rarity.UNCOMMON, mage.cards.m.MemoryOfToshiro.class));
cards.add(new SetCardInfo("Michiko's Reign of Truth", 29, Rarity.UNCOMMON, mage.cards.m.MichikosReignOfTruth.class));
cards.add(new SetCardInfo("Mindlink Mech", 62, Rarity.RARE, mage.cards.m.MindlinkMech.class));
cards.add(new SetCardInfo("Mirror Box", 250, Rarity.RARE, mage.cards.m.MirrorBox.class));
cards.add(new SetCardInfo("Mindlink Mech", 373, Rarity.RARE, mage.cards.m.MindlinkMech.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mindlink Mech", 448, Rarity.RARE, mage.cards.m.MindlinkMech.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mindlink Mech", 62, Rarity.RARE, mage.cards.m.MindlinkMech.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mirror Box", 250, Rarity.RARE, mage.cards.m.MirrorBox.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mirror Box", 403, Rarity.RARE, mage.cards.m.MirrorBox.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mirror Box", 498, Rarity.RARE, mage.cards.m.MirrorBox.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mirrorshell Crab", 63, Rarity.COMMON, mage.cards.m.MirrorshellCrab.class));
cards.add(new SetCardInfo("Mnemonic Sphere", 64, Rarity.COMMON, mage.cards.m.MnemonicSphere.class));
cards.add(new SetCardInfo("Mobilizer Mech", 65, Rarity.UNCOMMON, mage.cards.m.MobilizerMech.class));
cards.add(new SetCardInfo("Moon-Circuit Hacker", 67, Rarity.COMMON, mage.cards.m.MoonCircuitHacker.class));
cards.add(new SetCardInfo("Moon-Circuit Hacker", 334, Rarity.COMMON, mage.cards.m.MoonCircuitHacker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Moon-Circuit Hacker", 67, Rarity.COMMON, mage.cards.m.MoonCircuitHacker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Moonfolk Puzzlemaker", 68, Rarity.COMMON, mage.cards.m.MoonfolkPuzzlemaker.class));
cards.add(new SetCardInfo("Moonsnare Prototype", 69, Rarity.COMMON, mage.cards.m.MoonsnarePrototype.class));
cards.add(new SetCardInfo("Moonsnare Specialist", 70, Rarity.COMMON, mage.cards.m.MoonsnareSpecialist.class));
cards.add(new SetCardInfo("Moonsnare Specialist", 335, Rarity.COMMON, mage.cards.m.MoonsnareSpecialist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Moonsnare Specialist", 70, Rarity.COMMON, mage.cards.m.MoonsnareSpecialist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mothrider Patrol", 30, Rarity.COMMON, mage.cards.m.MothriderPatrol.class));
cards.add(new SetCardInfo("Mountain", 289, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mukotai Ambusher", 112, Rarity.COMMON, mage.cards.m.MukotaiAmbusher.class));
cards.add(new SetCardInfo("Mukotai Soulripper", 113, Rarity.RARE, mage.cards.m.MukotaiSoulripper.class));
cards.add(new SetCardInfo("Mountain", 290, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 299, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mountain", 300, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mukotai Ambusher", 112, Rarity.COMMON, mage.cards.m.MukotaiAmbusher.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mukotai Ambusher", 342, Rarity.COMMON, mage.cards.m.MukotaiAmbusher.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mukotai Soulripper", 113, Rarity.RARE, mage.cards.m.MukotaiSoulripper.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mukotai Soulripper", 381, Rarity.RARE, mage.cards.m.MukotaiSoulripper.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mukotai Soulripper", 458, Rarity.RARE, mage.cards.m.MukotaiSoulripper.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nameless Conqueror", 162, Rarity.COMMON, mage.cards.n.NamelessConqueror.class));
cards.add(new SetCardInfo("Naomi, Pillar of Order", 229, Rarity.UNCOMMON, mage.cards.n.NaomiPillarOfOrder.class));
cards.add(new SetCardInfo("Nashi, Moon Sage's Scion", 114, Rarity.MYTHIC, mage.cards.n.NashiMoonSagesScion.class));
cards.add(new SetCardInfo("Nashi, Moon Sage's Scion", 114, Rarity.MYTHIC, mage.cards.n.NashiMoonSagesScion.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nashi, Moon Sage's Scion", 343, Rarity.MYTHIC, mage.cards.n.NashiMoonSagesScion.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nashi, Moon Sage's Scion", 421, Rarity.MYTHIC, mage.cards.n.NashiMoonSagesScion.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nashi, Moon Sage's Scion", 459, Rarity.MYTHIC, mage.cards.n.NashiMoonSagesScion.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Network Disruptor", 71, Rarity.COMMON, mage.cards.n.NetworkDisruptor.class));
cards.add(new SetCardInfo("Network Terminal", 251, Rarity.COMMON, mage.cards.n.NetworkTerminal.class));
cards.add(new SetCardInfo("Nezumi Bladeblesser", 115, Rarity.COMMON, mage.cards.n.NezumiBladeblesser.class));
cards.add(new SetCardInfo("Nezumi Prowler", 116, Rarity.UNCOMMON, mage.cards.n.NezumiProwler.class));
cards.add(new SetCardInfo("Nezumi Bladeblesser", 115, Rarity.COMMON, mage.cards.n.NezumiBladeblesser.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nezumi Bladeblesser", 318, Rarity.COMMON, mage.cards.n.NezumiBladeblesser.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nezumi Prowler", 116, Rarity.UNCOMMON, mage.cards.n.NezumiProwler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nezumi Prowler", 344, Rarity.UNCOMMON, mage.cards.n.NezumiProwler.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nezumi Road Captain", 117, Rarity.COMMON, mage.cards.n.NezumiRoadCaptain.class));
cards.add(new SetCardInfo("Ninja's Kunai", 252, Rarity.COMMON, mage.cards.n.NinjasKunai.class));
cards.add(new SetCardInfo("Norika Yamazaki, the Poet", 31, Rarity.UNCOMMON, mage.cards.n.NorikaYamazakiThePoet.class));
cards.add(new SetCardInfo("O-Kagachi Made Manifest", 227, Rarity.MYTHIC, mage.cards.o.OKagachiMadeManifest.class));
cards.add(new SetCardInfo("Ogre-Head Helm", 155, Rarity.RARE, mage.cards.o.OgreHeadHelm.class));
cards.add(new SetCardInfo("Norika Yamazaki, the Poet", 31, Rarity.UNCOMMON, mage.cards.n.NorikaYamazakiThePoet.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Norika Yamazaki, the Poet", 311, Rarity.UNCOMMON, mage.cards.n.NorikaYamazakiThePoet.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("O-Kagachi Made Manifest", 227, Rarity.MYTHIC, mage.cards.o.OKagachiMadeManifest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("O-Kagachi Made Manifest", 362, Rarity.MYTHIC, mage.cards.o.OKagachiMadeManifest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("O-Kagachi Made Manifest", 489, Rarity.MYTHIC, mage.cards.o.OKagachiMadeManifest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ogre-Head Helm", 155, Rarity.RARE, mage.cards.o.OgreHeadHelm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ogre-Head Helm", 387, Rarity.RARE, mage.cards.o.OgreHeadHelm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ogre-Head Helm", 470, Rarity.RARE, mage.cards.o.OgreHeadHelm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Okiba Reckoner Raid", 117, Rarity.COMMON, mage.cards.o.OkibaReckonerRaid.class));
cards.add(new SetCardInfo("Okiba Salvage", 118, Rarity.UNCOMMON, mage.cards.o.OkibaSalvage.class));
cards.add(new SetCardInfo("Oni-Cult Anvil", 230, Rarity.UNCOMMON, mage.cards.o.OniCultAnvil.class));
cards.add(new SetCardInfo("Orochi Merge-Keeper", 203, Rarity.UNCOMMON, mage.cards.o.OrochiMergeKeeper.class));
cards.add(new SetCardInfo("Otawara, Soaring City", 271, Rarity.RARE, mage.cards.o.OtawaraSoaringCity.class));
cards.add(new SetCardInfo("Otawara, Soaring City", 271, Rarity.RARE, mage.cards.o.OtawaraSoaringCity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Otawara, Soaring City", 414, Rarity.RARE, mage.cards.o.OtawaraSoaringCity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Otawara, Soaring City", 503, Rarity.RARE, mage.cards.o.OtawaraSoaringCity.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Papercraft Decoy", 253, Rarity.COMMON, mage.cards.p.PapercraftDecoy.class));
cards.add(new SetCardInfo("Patchwork Automaton", 254, Rarity.UNCOMMON, mage.cards.p.PatchworkAutomaton.class));
cards.add(new SetCardInfo("Peerless Samurai", 156, Rarity.COMMON, mage.cards.p.PeerlessSamurai.class));
cards.add(new SetCardInfo("Peerless Samurai", 156, Rarity.COMMON, mage.cards.p.PeerlessSamurai.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Peerless Samurai", 322, Rarity.COMMON, mage.cards.p.PeerlessSamurai.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 283, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 284, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 293, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Plains", 294, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Planar Incision", 72, Rarity.COMMON, mage.cards.p.PlanarIncision.class));
cards.add(new SetCardInfo("Portrait of Michiko", 29, Rarity.UNCOMMON, mage.cards.p.PortraitOfMichiko.class));
cards.add(new SetCardInfo("Prodigy's Prototype", 231, Rarity.UNCOMMON, mage.cards.p.ProdigysPrototype.class));
cards.add(new SetCardInfo("Prosperous Thief", 73, Rarity.UNCOMMON, mage.cards.p.ProsperousThief.class));
cards.add(new SetCardInfo("Prosperous Thief", 336, Rarity.UNCOMMON, mage.cards.p.ProsperousThief.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Prosperous Thief", 73, Rarity.UNCOMMON, mage.cards.p.ProsperousThief.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Rabbit Battery", 157, Rarity.UNCOMMON, mage.cards.r.RabbitBattery.class));
cards.add(new SetCardInfo("Raiyuu, Storm's Edge", 232, Rarity.RARE, mage.cards.r.RaiyuuStormsEdge.class));
cards.add(new SetCardInfo("Raiyuu, Storm's Edge", 232, Rarity.RARE, mage.cards.r.RaiyuuStormsEdge.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Raiyuu, Storm's Edge", 329, Rarity.RARE, mage.cards.r.RaiyuuStormsEdge.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Raiyuu, Storm's Edge", 491, Rarity.RARE, mage.cards.r.RaiyuuStormsEdge.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Reality Heist", 75, Rarity.UNCOMMON, mage.cards.r.RealityHeist.class));
cards.add(new SetCardInfo("Reckoner Bankbuster", 255, Rarity.RARE, mage.cards.r.ReckonerBankbuster.class));
cards.add(new SetCardInfo("Reckoner Bankbuster", 255, Rarity.RARE, mage.cards.r.ReckonerBankbuster.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Reckoner Bankbuster", 404, Rarity.RARE, mage.cards.r.ReckonerBankbuster.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Reckoner Bankbuster", 499, Rarity.RARE, mage.cards.r.ReckonerBankbuster.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Reckoner Shakedown", 119, Rarity.COMMON, mage.cards.r.ReckonerShakedown.class));
cards.add(new SetCardInfo("Reckoner's Bargain", 120, Rarity.COMMON, mage.cards.r.ReckonersBargain.class));
cards.add(new SetCardInfo("Reflection of Kiki-Jiki", 141, Rarity.RARE, mage.cards.r.ReflectionOfKikiJiki.class));
cards.add(new SetCardInfo("Reflection of Kiki-Jiki", 141, Rarity.RARE, mage.cards.r.ReflectionOfKikiJiki.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Reflection of Kiki-Jiki", 357, Rarity.RARE, mage.cards.r.ReflectionOfKikiJiki.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Reflection of Kiki-Jiki", 465, Rarity.RARE, mage.cards.r.ReflectionOfKikiJiki.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Regent's Authority", 32, Rarity.COMMON, mage.cards.r.RegentsAuthority.class));
cards.add(new SetCardInfo("Reinforced Ronin", 158, Rarity.UNCOMMON, mage.cards.r.ReinforcedRonin.class));
cards.add(new SetCardInfo("Reinforced Ronin", 158, Rarity.UNCOMMON, mage.cards.r.ReinforcedRonin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Reinforced Ronin", 323, Rarity.UNCOMMON, mage.cards.r.ReinforcedRonin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Reito Sentinel", 256, Rarity.UNCOMMON, mage.cards.r.ReitoSentinel.class));
cards.add(new SetCardInfo("Remnant of the Rising Star", 194, Rarity.MYTHIC, mage.cards.r.RemnantOfTheRisingStar.class));
cards.add(new SetCardInfo("Remnant of the Rising Star", 194, Rarity.MYTHIC, mage.cards.r.RemnantOfTheRisingStar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Remnant of the Rising Star", 359, Rarity.MYTHIC, mage.cards.r.RemnantOfTheRisingStar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Remnant of the Rising Star", 475, Rarity.MYTHIC, mage.cards.r.RemnantOfTheRisingStar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Repel the Vile", 33, Rarity.COMMON, mage.cards.r.RepelTheVile.class));
cards.add(new SetCardInfo("Replication Specialist", 76, Rarity.UNCOMMON, mage.cards.r.ReplicationSpecialist.class));
cards.add(new SetCardInfo("Return to Action", 121, Rarity.COMMON, mage.cards.r.ReturnToAction.class));
cards.add(new SetCardInfo("Risona, Asari Commander", 233, Rarity.RARE, mage.cards.r.RisonaAsariCommander.class));
cards.add(new SetCardInfo("Risona, Asari Commander", 233, Rarity.RARE, mage.cards.r.RisonaAsariCommander.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Risona, Asari Commander", 330, Rarity.RARE, mage.cards.r.RisonaAsariCommander.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Risona, Asari Commander", 425, Rarity.RARE, mage.cards.r.RisonaAsariCommander.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Risona, Asari Commander", 492, Rarity.RARE, mage.cards.r.RisonaAsariCommander.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Roadside Reliquary", 272, Rarity.UNCOMMON, mage.cards.r.RoadsideReliquary.class));
cards.add(new SetCardInfo("Roaring Earth", 204, Rarity.UNCOMMON, mage.cards.r.RoaringEarth.class));
cards.add(new SetCardInfo("Rugged Highlands", 273, Rarity.COMMON, mage.cards.r.RuggedHighlands.class));
cards.add(new SetCardInfo("Runaway Trash-Bot", 257, Rarity.UNCOMMON, mage.cards.r.RunawayTrashBot.class));
cards.add(new SetCardInfo("Saiba Trespassers", 77, Rarity.COMMON, mage.cards.s.SaibaTrespassers.class));
cards.add(new SetCardInfo("Satoru Umezawa", 234, Rarity.RARE, mage.cards.s.SatoruUmezawa.class));
cards.add(new SetCardInfo("Satsuki, the Living Lore", 235, Rarity.RARE, mage.cards.s.SatsukiTheLivingLore.class));
cards.add(new SetCardInfo("Satoru Umezawa", 234, Rarity.RARE, mage.cards.s.SatoruUmezawa.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Satoru Umezawa", 352, Rarity.RARE, mage.cards.s.SatoruUmezawa.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Satoru Umezawa", 426, Rarity.RARE, mage.cards.s.SatoruUmezawa.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Satoru Umezawa", 493, Rarity.RARE, mage.cards.s.SatoruUmezawa.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Satoru Umezawa", 507, Rarity.RARE, mage.cards.s.SatoruUmezawa.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Satsuki, the Living Lore", 235, Rarity.RARE, mage.cards.s.SatsukiTheLivingLore.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Satsuki, the Living Lore", 399, Rarity.RARE, mage.cards.s.SatsukiTheLivingLore.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Satsuki, the Living Lore", 494, Rarity.RARE, mage.cards.s.SatsukiTheLivingLore.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Scoured Barrens", 274, Rarity.COMMON, mage.cards.s.ScouredBarrens.class));
cards.add(new SetCardInfo("Scrap Welder", 159, Rarity.RARE, mage.cards.s.ScrapWelder.class));
cards.add(new SetCardInfo("Scrap Welder", 159, Rarity.RARE, mage.cards.s.ScrapWelder.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Scrap Welder", 388, Rarity.RARE, mage.cards.s.ScrapWelder.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Scrap Welder", 471, Rarity.RARE, mage.cards.s.ScrapWelder.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Scrapyard Steelbreaker", 160, Rarity.COMMON, mage.cards.s.ScrapyardSteelbreaker.class));
cards.add(new SetCardInfo("Searchlight Companion", 258, Rarity.COMMON, mage.cards.s.SearchlightCompanion.class));
cards.add(new SetCardInfo("Season of Renewal", 205, Rarity.COMMON, mage.cards.s.SeasonOfRenewal.class));
cards.add(new SetCardInfo("Secluded Courtyard", 275, Rarity.UNCOMMON, mage.cards.s.SecludedCourtyard.class));
cards.add(new SetCardInfo("Secluded Courtyard", 275, Rarity.UNCOMMON, mage.cards.s.SecludedCourtyard.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Secluded Courtyard", 512, Rarity.UNCOMMON, mage.cards.s.SecludedCourtyard.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Seismic Wave", 161, Rarity.UNCOMMON, mage.cards.s.SeismicWave.class));
cards.add(new SetCardInfo("Selfless Samurai", 35, Rarity.UNCOMMON, mage.cards.s.SelflessSamurai.class));
cards.add(new SetCardInfo("Selfless Samurai", 312, Rarity.UNCOMMON, mage.cards.s.SelflessSamurai.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Selfless Samurai", 35, Rarity.UNCOMMON, mage.cards.s.SelflessSamurai.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Seshiro's Living Legacy", 210, Rarity.COMMON, mage.cards.s.SeshirosLivingLegacy.class));
cards.add(new SetCardInfo("Seven-Tail Mentor", 36, Rarity.COMMON, mage.cards.s.SevenTailMentor.class));
cards.add(new SetCardInfo("Shigeki, Jukai Visionary", 206, Rarity.RARE, mage.cards.s.ShigekiJukaiVisionary.class));
cards.add(new SetCardInfo("Seven-Tail Mentor", 313, Rarity.COMMON, mage.cards.s.SevenTailMentor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Seven-Tail Mentor", 36, Rarity.COMMON, mage.cards.s.SevenTailMentor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shigeki, Jukai Visionary", 206, Rarity.RARE, mage.cards.s.ShigekiJukaiVisionary.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shigeki, Jukai Visionary", 394, Rarity.RARE, mage.cards.s.ShigekiJukaiVisionary.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shigeki, Jukai Visionary", 480, Rarity.RARE, mage.cards.s.ShigekiJukaiVisionary.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Short Circuit", 78, Rarity.COMMON, mage.cards.s.ShortCircuit.class));
cards.add(new SetCardInfo("Shrine Steward", 259, Rarity.COMMON, mage.cards.s.ShrineSteward.class));
cards.add(new SetCardInfo("Silver-Fur Master", 236, Rarity.UNCOMMON, mage.cards.s.SilverFurMaster.class));
cards.add(new SetCardInfo("Silver-Fur Master", 236, Rarity.UNCOMMON, mage.cards.s.SilverFurMaster.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Silver-Fur Master", 353, Rarity.UNCOMMON, mage.cards.s.SilverFurMaster.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Silver-Fur Master", 511, Rarity.UNCOMMON, mage.cards.s.SilverFurMaster.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Simian Sling", 163, Rarity.COMMON, mage.cards.s.SimianSling.class));
cards.add(new SetCardInfo("Sky-Blessed Samurai", 37, Rarity.UNCOMMON, mage.cards.s.SkyBlessedSamurai.class));
cards.add(new SetCardInfo("Sky-Blessed Samurai", 314, Rarity.UNCOMMON, mage.cards.s.SkyBlessedSamurai.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sky-Blessed Samurai", 37, Rarity.UNCOMMON, mage.cards.s.SkyBlessedSamurai.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Skyswimmer Koi", 79, Rarity.COMMON, mage.cards.s.SkyswimmerKoi.class));
cards.add(new SetCardInfo("Sokenzan Smelter", 164, Rarity.UNCOMMON, mage.cards.s.SokenzanSmelter.class));
cards.add(new SetCardInfo("Sokenzan, Crucible of Defiance", 276, Rarity.RARE, mage.cards.s.SokenzanCrucibleOfDefiance.class));
cards.add(new SetCardInfo("Soul Transfer", 122, Rarity.RARE, mage.cards.s.SoulTransfer.class));
cards.add(new SetCardInfo("Sokenzan, Crucible of Defiance", 276, Rarity.RARE, mage.cards.s.SokenzanCrucibleOfDefiance.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sokenzan, Crucible of Defiance", 415, Rarity.RARE, mage.cards.s.SokenzanCrucibleOfDefiance.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sokenzan, Crucible of Defiance", 504, Rarity.RARE, mage.cards.s.SokenzanCrucibleOfDefiance.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Soul Transfer", 122, Rarity.RARE, mage.cards.s.SoulTransfer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Soul Transfer", 382, Rarity.RARE, mage.cards.s.SoulTransfer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Soul Transfer", 460, Rarity.RARE, mage.cards.s.SoulTransfer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spell Pierce", 80, Rarity.COMMON, mage.cards.s.SpellPierce.class));
cards.add(new SetCardInfo("Spinning Wheel Kick", 207, Rarity.UNCOMMON, mage.cards.s.SpinningWheelKick.class));
cards.add(new SetCardInfo("Spirit-Sister's Call", 237, Rarity.MYTHIC, mage.cards.s.SpiritSistersCall.class));
cards.add(new SetCardInfo("Spirited Companion", 38, Rarity.COMMON, mage.cards.s.SpiritedCompanion.class));
cards.add(new SetCardInfo("Spring-Leaf Avenger", 208, Rarity.RARE, mage.cards.s.SpringLeafAvenger.class));
cards.add(new SetCardInfo("Spirit-Sister's Call", 237, Rarity.MYTHIC, mage.cards.s.SpiritSistersCall.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spirit-Sister's Call", 400, Rarity.MYTHIC, mage.cards.s.SpiritSistersCall.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spirit-Sister's Call", 495, Rarity.MYTHIC, mage.cards.s.SpiritSistersCall.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spirited Companion", 38, Rarity.COMMON, mage.cards.s.SpiritedCompanion.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spirited Companion", 508, Rarity.COMMON, mage.cards.s.SpiritedCompanion.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spring-Leaf Avenger", 208, Rarity.RARE, mage.cards.s.SpringLeafAvenger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spring-Leaf Avenger", 349, Rarity.RARE, mage.cards.s.SpringLeafAvenger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spring-Leaf Avenger", 481, Rarity.RARE, mage.cards.s.SpringLeafAvenger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Storyweave", 209, Rarity.UNCOMMON, mage.cards.s.Storyweave.class));
cards.add(new SetCardInfo("Suit Up", 81, Rarity.COMMON, mage.cards.s.SuitUp.class));
cards.add(new SetCardInfo("Sunblade Samurai", 39, Rarity.COMMON, mage.cards.s.SunbladeSamurai.class));
cards.add(new SetCardInfo("Surgehacker Mech", 260, Rarity.RARE, mage.cards.s.SurgehackerMech.class));
cards.add(new SetCardInfo("Sunblade Samurai", 315, Rarity.COMMON, mage.cards.s.SunbladeSamurai.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sunblade Samurai", 39, Rarity.COMMON, mage.cards.s.SunbladeSamurai.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Surgehacker Mech", 260, Rarity.RARE, mage.cards.s.SurgehackerMech.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Surgehacker Mech", 405, Rarity.RARE, mage.cards.s.SurgehackerMech.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Surgehacker Mech", 500, Rarity.RARE, mage.cards.s.SurgehackerMech.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", 287, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", 288, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", 297, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swamp", 298, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swiftwater Cliffs", 277, Rarity.COMMON, mage.cards.s.SwiftwaterCliffs.class));
cards.add(new SetCardInfo("Takenuma, Abandoned Mire", 278, Rarity.RARE, mage.cards.t.TakenumaAbandonedMire.class));
cards.add(new SetCardInfo("Takenuma, Abandoned Mire", 278, Rarity.RARE, mage.cards.t.TakenumaAbandonedMire.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Takenuma, Abandoned Mire", 416, Rarity.RARE, mage.cards.t.TakenumaAbandonedMire.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Takenuma, Abandoned Mire", 505, Rarity.RARE, mage.cards.t.TakenumaAbandonedMire.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tales of Master Seshiro", 210, Rarity.COMMON, mage.cards.t.TalesOfMasterSeshiro.class));
cards.add(new SetCardInfo("Tameshi, Reality Architect", 82, Rarity.RARE, mage.cards.t.TameshiRealityArchitect.class));
cards.add(new SetCardInfo("Tameshi, Reality Architect", 375, Rarity.RARE, mage.cards.t.TameshiRealityArchitect.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tameshi, Reality Architect", 450, Rarity.RARE, mage.cards.t.TameshiRealityArchitect.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tameshi, Reality Architect", 82, Rarity.RARE, mage.cards.t.TameshiRealityArchitect.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tamiyo's Compleation", 83, Rarity.COMMON, mage.cards.t.TamiyosCompleation.class));
cards.add(new SetCardInfo("Tamiyo's Safekeeping", 211, Rarity.COMMON, mage.cards.t.TamiyosSafekeeping.class));
cards.add(new SetCardInfo("Tamiyo, Compleated Sage", 238, Rarity.MYTHIC, mage.cards.t.TamiyoCompleatedSage.class));
cards.add(new SetCardInfo("Tatsunari, Toad Rider", 123, Rarity.RARE, mage.cards.t.TatsunariToadRider.class));
cards.add(new SetCardInfo("Teachings of the Kirin", 212, Rarity.RARE, mage.cards.t.TeachingsOfTheKirin.class));
cards.add(new SetCardInfo("Tamiyo, Compleated Sage", 238, Rarity.MYTHIC, mage.cards.t.TamiyoCompleatedSage.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tamiyo, Compleated Sage", 306, Rarity.MYTHIC, mage.cards.t.TamiyoCompleatedSage.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tamiyo, Compleated Sage", 308, Rarity.MYTHIC, mage.cards.t.TamiyoCompleatedSage.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tamiyo, Compleated Sage", 428, Rarity.MYTHIC, mage.cards.t.TamiyoCompleatedSage.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tatsunari, Toad Rider", 123, Rarity.RARE, mage.cards.t.TatsunariToadRider.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tatsunari, Toad Rider", 345, Rarity.RARE, mage.cards.t.TatsunariToadRider.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tatsunari, Toad Rider", 461, Rarity.RARE, mage.cards.t.TatsunariToadRider.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Teachings of the Kirin", 212, Rarity.RARE, mage.cards.t.TeachingsOfTheKirin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Teachings of the Kirin", 360, Rarity.RARE, mage.cards.t.TeachingsOfTheKirin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Teachings of the Kirin", 482, Rarity.RARE, mage.cards.t.TeachingsOfTheKirin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tempered in Solitude", 165, Rarity.UNCOMMON, mage.cards.t.TemperedInSolitude.class));
cards.add(new SetCardInfo("Tezzeret, Betrayer of Flesh", 84, Rarity.MYTHIC, mage.cards.t.TezzeretBetrayerOfFlesh.class));
cards.add(new SetCardInfo("Tezzeret, Betrayer of Flesh", 304, Rarity.MYTHIC, mage.cards.t.TezzeretBetrayerOfFlesh.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tezzeret, Betrayer of Flesh", 376, Rarity.MYTHIC, mage.cards.t.TezzeretBetrayerOfFlesh.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tezzeret, Betrayer of Flesh", 419, Rarity.MYTHIC, mage.cards.t.TezzeretBetrayerOfFlesh.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tezzeret, Betrayer of Flesh", 84, Rarity.MYTHIC, mage.cards.t.TezzeretBetrayerOfFlesh.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Dragon-Kami Reborn", 181, Rarity.RARE, mage.cards.t.TheDragonKamiReborn.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Dragon-Kami Reborn", 358, Rarity.RARE, mage.cards.t.TheDragonKamiReborn.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Dragon-Kami Reborn", 473, Rarity.RARE, mage.cards.t.TheDragonKamiReborn.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Fall of Lord Konda", 12, Rarity.UNCOMMON, mage.cards.t.TheFallOfLordKonda.class));
cards.add(new SetCardInfo("The Kami War", 227, Rarity.MYTHIC, mage.cards.t.TheKamiWar.class));
cards.add(new SetCardInfo("The Kami War", 227, Rarity.MYTHIC, mage.cards.t.TheKamiWar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Kami War", 362, Rarity.MYTHIC, mage.cards.t.TheKamiWar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Kami War", 489, Rarity.MYTHIC, mage.cards.t.TheKamiWar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Long Reach of Night", 109, Rarity.UNCOMMON, mage.cards.t.TheLongReachOfNight.class));
cards.add(new SetCardInfo("The Modern Age", 66, Rarity.COMMON, mage.cards.t.TheModernAge.class));
cards.add(new SetCardInfo("The Reality Chip", 74, Rarity.RARE, mage.cards.t.TheRealityChip.class));
cards.add(new SetCardInfo("The Restoration of Eiganjo", 34, Rarity.RARE, mage.cards.t.TheRestorationOfEiganjo.class));
cards.add(new SetCardInfo("The Reality Chip", 374, Rarity.RARE, mage.cards.t.TheRealityChip.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Reality Chip", 449, Rarity.RARE, mage.cards.t.TheRealityChip.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Reality Chip", 74, Rarity.RARE, mage.cards.t.TheRealityChip.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Restoration of Eiganjo", 34, Rarity.RARE, mage.cards.t.TheRestorationOfEiganjo.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Restoration of Eiganjo", 354, Rarity.RARE, mage.cards.t.TheRestorationOfEiganjo.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Restoration of Eiganjo", 442, Rarity.RARE, mage.cards.t.TheRestorationOfEiganjo.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Shattered States Era", 162, Rarity.COMMON, mage.cards.t.TheShatteredStatesEra.class));
cards.add(new SetCardInfo("The Wandering Emperor", 42, Rarity.MYTHIC, mage.cards.t.TheWanderingEmperor.class));
cards.add(new SetCardInfo("The Wandering Emperor", 303, Rarity.MYTHIC, mage.cards.t.TheWanderingEmperor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Wandering Emperor", 316, Rarity.MYTHIC, mage.cards.t.TheWanderingEmperor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Wandering Emperor", 418, Rarity.MYTHIC, mage.cards.t.TheWanderingEmperor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Wandering Emperor", 42, Rarity.MYTHIC, mage.cards.t.TheWanderingEmperor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thirst for Knowledge", 85, Rarity.UNCOMMON, mage.cards.t.ThirstForKnowledge.class));
cards.add(new SetCardInfo("Thornwood Falls", 279, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class));
cards.add(new SetCardInfo("Thousand-Faced Shadow", 86, Rarity.RARE, mage.cards.t.ThousandFacedShadow.class));
cards.add(new SetCardInfo("Thundering Raiju", 166, Rarity.RARE, mage.cards.t.ThunderingRaiju.class));
cards.add(new SetCardInfo("Thousand-Faced Shadow", 337, Rarity.RARE, mage.cards.t.ThousandFacedShadow.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thousand-Faced Shadow", 451, Rarity.RARE, mage.cards.t.ThousandFacedShadow.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thousand-Faced Shadow", 86, Rarity.RARE, mage.cards.t.ThousandFacedShadow.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thundering Raiju", 166, Rarity.RARE, mage.cards.t.ThunderingRaiju.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thundering Raiju", 389, Rarity.RARE, mage.cards.t.ThunderingRaiju.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thundering Raiju", 472, Rarity.RARE, mage.cards.t.ThunderingRaiju.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thundersteel Colossus", 261, Rarity.COMMON, mage.cards.t.ThundersteelColossus.class));
cards.add(new SetCardInfo("Touch the Spirit Realm", 40, Rarity.UNCOMMON, mage.cards.t.TouchTheSpiritRealm.class));
cards.add(new SetCardInfo("Towashi Guide-Bot", 262, Rarity.UNCOMMON, mage.cards.t.TowashiGuideBot.class));
cards.add(new SetCardInfo("Towashi Songshaper", 167, Rarity.COMMON, mage.cards.t.TowashiSongshaper.class));
cards.add(new SetCardInfo("Tranquil Cove", 280, Rarity.COMMON, mage.cards.t.TranquilCove.class));
cards.add(new SetCardInfo("Tribute to Horobi", 124, Rarity.RARE, mage.cards.t.TributeToHorobi.class));
cards.add(new SetCardInfo("Tribute to Horobi", 124, Rarity.RARE, mage.cards.t.TributeToHorobi.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tribute to Horobi", 356, Rarity.RARE, mage.cards.t.TributeToHorobi.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tribute to Horobi", 462, Rarity.RARE, mage.cards.t.TributeToHorobi.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Twinshot Sniper", 168, Rarity.UNCOMMON, mage.cards.t.TwinshotSniper.class));
cards.add(new SetCardInfo("Twisted Embrace", 125, Rarity.COMMON, mage.cards.t.TwistedEmbrace.class));
cards.add(new SetCardInfo("Uncharted Haven", 281, Rarity.COMMON, mage.cards.u.UnchartedHaven.class));
cards.add(new SetCardInfo("Undercity Scrounger", 126, Rarity.COMMON, mage.cards.u.UndercityScrounger.class));
cards.add(new SetCardInfo("Unforgiving One", 127, Rarity.UNCOMMON, mage.cards.u.UnforgivingOne.class));
cards.add(new SetCardInfo("Unstoppable Ogre", 169, Rarity.COMMON, mage.cards.u.UnstoppableOgre.class));
cards.add(new SetCardInfo("Upriser Renegade", 170, Rarity.UNCOMMON, mage.cards.u.UpriserRenegade.class));
cards.add(new SetCardInfo("Upriser Renegade", 170, Rarity.UNCOMMON, mage.cards.u.UpriserRenegade.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Upriser Renegade", 324, Rarity.UNCOMMON, mage.cards.u.UpriserRenegade.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vector Glider", 66, Rarity.COMMON, mage.cards.v.VectorGlider.class));
cards.add(new SetCardInfo("Vessel of the All-Consuming", 221, Rarity.MYTHIC, mage.cards.v.VesselOfTheAllConsuming.class));
cards.add(new SetCardInfo("Vessel of the All-Consuming", 221, Rarity.MYTHIC, mage.cards.v.VesselOfTheAllConsuming.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vessel of the All-Consuming", 361, Rarity.MYTHIC, mage.cards.v.VesselOfTheAllConsuming.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vessel of the All-Consuming", 486, Rarity.MYTHIC, mage.cards.v.VesselOfTheAllConsuming.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Virus Beetle", 128, Rarity.COMMON, mage.cards.v.VirusBeetle.class));
cards.add(new SetCardInfo("Vision of the Unspeakable", 48, Rarity.UNCOMMON, mage.cards.v.VisionOfTheUnspeakable.class));
cards.add(new SetCardInfo("Voltage Surge", 171, Rarity.COMMON, mage.cards.v.VoltageSurge.class));
cards.add(new SetCardInfo("Walking Skyscraper", 263, Rarity.UNCOMMON, mage.cards.w.WalkingSkyscraper.class));
cards.add(new SetCardInfo("Wanderer's Intervention", 41, Rarity.COMMON, mage.cards.w.WanderersIntervention.class));
cards.add(new SetCardInfo("Weaver of Harmony", 213, Rarity.RARE, mage.cards.w.WeaverOfHarmony.class));
cards.add(new SetCardInfo("Weaver of Harmony", 213, Rarity.RARE, mage.cards.w.WeaverOfHarmony.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Weaver of Harmony", 395, Rarity.RARE, mage.cards.w.WeaverOfHarmony.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Weaver of Harmony", 483, Rarity.RARE, mage.cards.w.WeaverOfHarmony.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Webspinner Cuff", 214, Rarity.UNCOMMON, mage.cards.w.WebspinnerCuff.class));
cards.add(new SetCardInfo("When We Were Young", 43, Rarity.UNCOMMON, mage.cards.w.WhenWeWereYoung.class));
cards.add(new SetCardInfo("Wind-Scarred Crag", 282, Rarity.COMMON, mage.cards.w.WindScarredCrag.class));

View file

@ -143,7 +143,7 @@ public class BuybackTest extends CardTestPlayerBase {
// bolt 2 - cast (R) and copy as free cast (R), return reiterate with buyback (RRR)
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerA);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, {T}:");
setChoice(playerA, "Reiterate"); // free cast
setChoice(playerA, true); // cast for free
setChoice(playerA, true); // use buyback
addTarget(playerA, "Lightning Bolt"); // copy target
setChoice(playerA, false); // same bolt's target

View file

@ -670,7 +670,6 @@ public class KickerTest extends CardTestPlayerBase {
// attack and prepare free cast, use kicker
attack(1, playerA, "Etali, Primal Storm", playerB);
setChoice(playerA, true); // cast for free
setChoice(playerA, "Ardent Soldier"); // cast for free
setChoice(playerA, true); // use kicker
setStrictChooseMode(true);
@ -703,7 +702,6 @@ public class KickerTest extends CardTestPlayerBase {
// attack and prepare free cast
attack(1, playerA, "Etali, Primal Storm", playerB);
setChoice(playerA, true); // cast for free
setChoice(playerA, "Thieving Skydiver"); // cast for free
setChoice(playerA, true); // use kicker
setChoiceAmount(playerA, 2); // X=2 for Kicker X
addTarget(playerA, "Brain in a Jar"); // kicker's target (take control of artifact)

View file

@ -766,4 +766,122 @@ public class AdventureCardsTest extends CardTestPlayerBase {
execute();
assertAllCommandsUsed();
}
@Test
public void test_Cascade_CuriousPair() {
// If a player cascades into Curious Pair with Bloodbraid Elf they can cast either spell
removeAllCardsFromLibrary(playerA);
skipInitShuffling();
// Cascade
addCard(Zone.HAND, playerA, "Bloodbraid Elf"); // {2}{R}{G}
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
//
addCard(Zone.LIBRARY, playerA, "Swamp", 2);
addCard(Zone.LIBRARY, playerA, "Curious Pair", 1);
addCard(Zone.LIBRARY, playerA, "Island", 2);
// play elf with cascade
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bloodbraid Elf");
setChoice(playerA, true); // use free cast
setChoice(playerA, "Cast Treats to Share"); // can cast either
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Curious Pair", 0);
assertPermanentCount(playerA, "Food", 1);
assertExileCount(playerA, "Curious Pair", 1);
}
@Test
public void test_Cascade_FlaxenIntruder() {
// If a player cascades into Flaxen Intruder with Bloodbraid Elf they shouldn't be able to cast Welcome Home
removeAllCardsFromLibrary(playerA);
skipInitShuffling();
// Cascade
addCard(Zone.HAND, playerA, "Bloodbraid Elf"); // {2}{R}{G}
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
//
addCard(Zone.LIBRARY, playerA, "Swamp", 2);
addCard(Zone.LIBRARY, playerA, "Flaxen Intruder", 1);
addCard(Zone.LIBRARY, playerA, "Island", 2);
// play elf with cascade
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bloodbraid Elf");
setChoice(playerA, true); // use free cast
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Flaxen Intruder", 1);
assertPermanentCount(playerA, "Bear", 0);
}
@Test
public void test_SramsExpertise_CuriousPair() {
addCard(Zone.HAND, playerA, "Sram's Expertise");
addCard(Zone.HAND, playerA, "Curious Pair");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sram's Expertise");
setChoice(playerA, true); // use free cast
setChoice(playerA, "Cast Treats to Share");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Curious Pair", 0);
assertPermanentCount(playerA, "Food", 1);
assertPermanentCount(playerA, "Servo", 3);
assertExileCount(playerA, "Curious Pair", 1);
}
@Test
public void test_SramsExpertise_FlaxenIntruder() {
addCard(Zone.HAND, playerA, "Sram's Expertise");
addCard(Zone.HAND, playerA, "Flaxen Intruder");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sram's Expertise");
setChoice(playerA, true); // use free cast
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Flaxen Intruder", 1);
assertPermanentCount(playerA, "Bear", 0);
assertPermanentCount(playerA, "Servo", 3);
}
@Test
public void test_SramsExpertise_LonesomeUnicorn() {
addCard(Zone.HAND, playerA, "Sram's Expertise");
addCard(Zone.HAND, playerA, "Lonesome Unicorn");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sram's Expertise");
setChoice(playerA, true); // use free cast
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Lonesome Unicorn", 0);
assertPermanentCount(playerA, "Knight", 1);
assertPermanentCount(playerA, "Servo", 3);
assertExileCount(playerA, "Lonesome Unicorn", 1);
}
}

View file

@ -866,6 +866,44 @@ public class ModalDoubleFacesCardsTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "The Omenkeel", 1);
}
@Test
public void test_SramsExpertise_ValkiGodOfLies() {
addCard(Zone.HAND, playerA, "Sram's Expertise");
addCard(Zone.HAND, playerA, "Valki, God of Lies");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sram's Expertise");
setChoice(playerA, true); // use free cast
setChoice(playerA, TestPlayer.CHOICE_SKIP); // no choices for valki's etb exile
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Valki, God of Lies", 1);
assertPermanentCount(playerA, "Servo", 3);
}
@Test
public void test_SramsExpertise_CosimaGodOfTheVoyage() {
addCard(Zone.HAND, playerA, "Sram's Expertise");
addCard(Zone.HAND, playerA, "Cosima, God of the Voyage");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sram's Expertise");
setChoice(playerA, true); // use free cast
setChoice(playerA, "Cast The Omenkeel"); // can cast any side here
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "The Omenkeel", 1);
assertPermanentCount(playerA, "Servo", 3);
}
@Test
public void test_Copy_AsSpell() {
addCard(Zone.HAND, playerA, "Akoum Warrior", 1); // {5}{R}
@ -1000,4 +1038,4 @@ public class ModalDoubleFacesCardsTest extends CardTestPlayerBase {
execute();
assertAllCommandsUsed();
}
}
}

View file

@ -34,7 +34,6 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman");
addTarget(playerA, playerB);
setChoice(playerA, "Wear // Tear"); // select card
setChoice(playerA, true); // confirm to cast
setChoice(playerA, "Cast Tear"); // select tear side
addTarget(playerA, "Sanguine Bond"); // target for tear
@ -67,7 +66,6 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman");
addTarget(playerA, playerB);
setChoice(playerA, "Wear // Tear"); // select card
setChoice(playerA, true); // confirm to cast
setChoice(playerA, "Cast Wear"); // select wear side
addTarget(playerA, "Icy Manipulator"); // target for wear
@ -100,7 +98,6 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman");
addTarget(playerA, playerB);
setChoice(playerA, "Wear // Tear"); // select card
setChoice(playerA, true); // confirm to cast
setChoice(playerA, "Cast fused Wear // Tear"); // select fused
addTarget(playerA, "Icy Manipulator"); // target for wear
@ -137,7 +134,6 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase {
attack(2, playerB, "Etali, Primal Storm");
setChoice(playerB, true); // free cast
setChoice(playerB, "Fire // Ice"); // card to cast
setChoice(playerB, "Cast Fire"); // ability to cast
addTargetAmount(playerB, "Silvercoat Lion", 2);

View file

@ -4364,19 +4364,17 @@ public class TestPlayer implements Player {
@Override
public SpellAbility chooseAbilityForCast(Card card, Game game, boolean noMana) {
assertAliasSupportInChoices(false);
MageObject object = game.getObject(card.getId()); // must be object to find real abilities (example: commander)
Map<UUID, ActivatedAbility> useable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), object, game.getState().getZone(object.getId()), noMana);
String allInfo = useable.values().stream().map(Object::toString).collect(Collectors.joining("\n"));
Map<UUID, SpellAbility> useable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), object, game.getState().getZone(object.getId()), noMana);
if (useable.size() == 1) {
return (SpellAbility) useable.values().iterator().next();
return useable.values().iterator().next();
}
if (!choices.isEmpty()) {
for (ActivatedAbility ability : useable.values()) {
for (SpellAbility ability : useable.values()) {
if (ability.toString().startsWith(choices.get(0))) {
choices.remove(0);
return (SpellAbility) ability;
return ability;
}
}
@ -4384,6 +4382,7 @@ public class TestPlayer implements Player {
//Assert.fail("Wrong choice");
}
String allInfo = useable.values().stream().map(Object::toString).collect(Collectors.joining("\n"));
this.chooseStrictModeFailed("choice", game, getInfo(card) + " - can't select ability to cast.\n" + "Card's abilities:\n" + allInfo);
return computerPlayer.chooseAbilityForCast(card, game, noMana);
}

View file

@ -7,6 +7,7 @@ import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.keyword.FlashAbility;
import mage.cards.AdventureCardSpell;
import mage.cards.Card;
import mage.cards.SplitCard;
import mage.constants.*;
@ -69,7 +70,7 @@ public class SpellAbility extends ActivatedAbilityImpl {
// forced to cast (can be part id or main id)
Set<UUID> idsToCheck = new HashSet<>();
idsToCheck.add(object.getId());
if (object instanceof Card) {
if (object instanceof Card && !(object instanceof AdventureCardSpell)) {
idsToCheck.add(((Card) object).getMainCard().getId());
}
for (UUID idToCheck : idsToCheck) {

View file

@ -0,0 +1,48 @@
package mage.abilities.effects.common.cost;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardsImpl;
import mage.constants.Outcome;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
/**
* @author fireshoes - Original Code
* @author JRHerlehy - Implement as seperate class
* <p>
* Allows player to choose to cast as card from hand without paying its mana
* cost.
* </p>
*/
public class CastFromHandForFreeEffect extends OneShotEffect {
private final FilterCard filter;
public CastFromHandForFreeEffect(FilterCard filter) {
super(Outcome.PlayForFree);
this.filter = filter;
this.staticText = "you may cast " + filter.getMessage() + " from your hand without paying its mana cost";
}
public CastFromHandForFreeEffect(final CastFromHandForFreeEffect effect) {
super(effect);
this.filter = effect.filter;
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
return CardUtil.castSpellWithAttributesForFree(controller, source, game, new CardsImpl(controller.getHand()), filter);
}
@Override
public CastFromHandForFreeEffect copy() {
return new CastFromHandForFreeEffect(this);
}
}

View file

@ -1,115 +0,0 @@
package mage.abilities.effects.common.cost;
import mage.ApprovingObject;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.filter.FilterCard;
import mage.filter.common.FilterNonlandCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetCardInHand;
import mage.util.CardUtil;
import org.apache.log4j.Logger;
/**
* @author fireshoes - Original Code
* @author JRHerlehy - Implement as seperate class
* <p>
* Allows player to choose to cast as card from hand without paying its mana
* cost.
* </p>
* TODO: this doesn't work correctly with MDFCs or Adventures (see https://github.com/magefree/mage/issues/7742)
*/
public class CastWithoutPayingManaCostEffect extends OneShotEffect {
private final DynamicValue manaCost;
private final FilterCard filter;
private static final FilterCard defaultFilter
= new FilterNonlandCard("card with mana value %mv or less from your hand");
/**
* @param maxCost Maximum converted mana cost for this effect to apply to
*/
public CastWithoutPayingManaCostEffect(int maxCost) {
this(StaticValue.get(maxCost));
}
public CastWithoutPayingManaCostEffect(DynamicValue maxCost) {
this(maxCost, defaultFilter);
}
public CastWithoutPayingManaCostEffect(DynamicValue maxCost, FilterCard filter) {
super(Outcome.PlayForFree);
this.manaCost = maxCost;
this.filter = filter;
this.staticText = "you may cast a spell with mana value "
+ maxCost + " or less from your hand without paying its mana cost";
}
public CastWithoutPayingManaCostEffect(final CastWithoutPayingManaCostEffect effect) {
super(effect);
this.manaCost = effect.manaCost;
this.filter = effect.filter;
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
int cmc = manaCost.calculate(game, source, this);
FilterCard filter = this.filter.copy();
filter.setMessage(filter.getMessage().replace("%mv", "" + cmc));
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, cmc + 1));
Target target = new TargetCardInHand(filter);
if (!target.canChoose(
source.getSourceId(), controller.getId(), game
) || !controller.chooseUse(
Outcome.PlayForFree,
"Cast " + CardUtil.addArticle(filter.getMessage())
+ " without paying its mana cost?", source, game
)) {
return true;
}
Card cardToCast = null;
boolean cancel = false;
while (controller.canRespond()
&& !cancel) {
if (controller.chooseTarget(Outcome.PlayForFree, target, source, game)) {
cardToCast = game.getCard(target.getFirstTarget());
if (cardToCast != null) {
if (cardToCast.getSpellAbility() == null) {
Logger.getLogger(CastWithoutPayingManaCostEffect.class).fatal("Card: "
+ cardToCast.getName() + " is no land and has no spell ability!");
cancel = true;
}
if (cardToCast.getSpellAbility().canChooseTarget(game, controller.getId())) {
cancel = true;
}
}
} else {
cancel = true;
}
}
if (cardToCast != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(cardToCast, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null);
}
return true;
}
@Override
public CastWithoutPayingManaCostEffect copy() {
return new CastWithoutPayingManaCostEffect(this);
}
}

View file

@ -6,8 +6,7 @@ import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.Card;
import mage.cards.ModalDoubleFacesCardHalf;
import mage.cards.SplitCardHalf;
import mage.cards.SubCard;
import mage.constants.AsThoughEffectType;
import mage.constants.Duration;
import mage.constants.Outcome;
@ -156,12 +155,8 @@ class AftermathExileAsResolvesFromGraveyard extends ReplacementEffectImpl {
// wants to do that in the future.
UUID sourceId = source.getSourceId();
Card sourceCard = game.getCard(source.getSourceId());
if (sourceCard instanceof SplitCardHalf) {
sourceCard = ((SplitCardHalf) sourceCard).getParentCard();
sourceId = sourceCard.getId();
}
if (sourceCard instanceof ModalDoubleFacesCardHalf) {
sourceCard = ((ModalDoubleFacesCardHalf) sourceCard).getParentCard();
if (sourceCard instanceof SubCard) {
sourceCard = ((SubCard<?>) sourceCard).getParentCard();
sourceId = sourceCard.getId();
}
@ -178,11 +173,8 @@ class AftermathExileAsResolvesFromGraveyard extends ReplacementEffectImpl {
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Card sourceCard = game.getCard(source.getSourceId());
if (sourceCard instanceof SplitCardHalf) {
sourceCard = ((SplitCardHalf) sourceCard).getParentCard();
}
if (sourceCard instanceof ModalDoubleFacesCardHalf) {
sourceCard = ((ModalDoubleFacesCardHalf) sourceCard).getParentCard();
if (sourceCard instanceof SubCard) {
sourceCard = ((SubCard<?>) sourceCard).getParentCard();
}
if (sourceCard != null) {
Player player = game.getPlayer(sourceCard.getOwnerId());

View file

@ -1,23 +1,23 @@
package mage.abilities.keyword;
import mage.ApprovingObject;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.common.TargetCardInExile;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import mage.util.CardUtil;
/**
* Cascade A keyword ability that may let a player cast a random extra spell for
@ -152,45 +152,12 @@ class CascadeEffect extends OneShotEffect {
}
// You may cast that spell without paying its mana cost if its converted mana cost is less than this spell's converted mana cost.
List<Card> partsToCast = new ArrayList<>();
if (cardToCast != null) {
if (cardToCast instanceof SplitCard) {
partsToCast.add(((SplitCard) cardToCast).getLeftHalfCard());
partsToCast.add(((SplitCard) cardToCast).getRightHalfCard());
partsToCast.add(cardToCast);
} else if (cardToCast instanceof AdventureCard) {
partsToCast.add(((AdventureCard) cardToCast).getSpellCard());
partsToCast.add(cardToCast);
} else if (cardToCast instanceof ModalDoubleFacesCard) {
partsToCast.add(((ModalDoubleFacesCard) cardToCast).getLeftHalfCard());
partsToCast.add(((ModalDoubleFacesCard) cardToCast).getRightHalfCard());
} else {
partsToCast.add(cardToCast);
}
// remove too big cmc
partsToCast.removeIf(card -> card.getManaValue() >= sourceCost);
// remove non spells
partsToCast.removeIf(card -> card.getSpellAbility() == null);
}
String partsInfo = partsToCast.stream()
.map(MageObject::getIdName)
.collect(Collectors.joining(" or "));
if (cardToCast != null
&& partsToCast.size() > 0
&& controller.chooseUse(outcome, "Cast spell without paying its mana cost (" + partsInfo + ")?", source, game)) {
try {
// enable free cast for all compatible parts
partsToCast.forEach(card -> game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE));
controller.cast(controller.chooseAbilityForCast(cardToCast, game, true),
game, true, new ApprovingObject(source, game));
} finally {
partsToCast.forEach(card -> game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null));
}
}
FilterCard filter = new FilterCard();
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, sourceCost + 1));
CardUtil.castSpellWithAttributesForFree(controller, source, game, new CardsImpl(cardToCast), filter);
// Then put all cards exiled this way that weren't cast on the bottom of your library in a random order.
cardsToExile.removeIf(uuid -> game.getState().getZone(uuid) != Zone.EXILED);
cardsToExile.retainZone(Zone.EXILED, game);
return controller.putCardsOnBottomOfLibrary(cardsToExile, game, source, false);
}

View file

@ -5,6 +5,7 @@ import mage.abilities.AbilitiesImpl;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.constants.CardType;
import mage.constants.SpellAbilityType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
@ -13,7 +14,7 @@ import java.util.List;
import java.util.UUID;
/**
* @author TheElk801
* @author phulin
*/
public abstract class AdventureCard extends CardImpl {
@ -90,13 +91,11 @@ public abstract class AdventureCard extends CardImpl {
@Override
public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) {
switch (ability.getSpellAbilityType()) {
case ADVENTURE_SPELL:
return this.getSpellCard().cast(game, fromZone, ability, controllerId);
default:
this.getSpellCard().getSpellAbility().setControllerId(controllerId);
return super.cast(game, fromZone, ability, controllerId);
if (ability.getSpellAbilityType() == SpellAbilityType.ADVENTURE_SPELL) {
return this.getSpellCard().cast(game, fromZone, ability, controllerId);
}
this.getSpellCard().getSpellAbility().setControllerId(controllerId);
return super.cast(game, fromZone, ability, controllerId);
}
@Override

View file

@ -1,15 +1,10 @@
package mage.cards;
/**
*
* @author phulin
*/
public interface AdventureCardSpell extends Card {
public interface AdventureCardSpell extends SubCard<AdventureCard> {
@Override
AdventureCardSpell copy();
void setParentCard(AdventureCard card);
AdventureCard getParentCard();
}

View file

@ -0,0 +1,11 @@
package mage.cards;
/**
* @author TheElk801
*/
public interface CardWithHalves extends Card {
Card getLeftHalfCard();
Card getRightHalfCard();
}

View file

@ -45,4 +45,6 @@ public interface Cards extends Set<UUID>, Serializable {
Cards copy();
void retainZone(Zone zone, Game game);
void removeZone(Zone zone, Game game);
}

View file

@ -210,4 +210,9 @@ public class CardsImpl extends LinkedHashSet<UUID> implements Cards, Serializabl
public void retainZone(Zone zone, Game game) {
removeIf(uuid -> game.getState().getZone(uuid) != zone);
}
@Override
public void removeZone(Zone zone, Game game) {
removeIf(uuid -> game.getState().getZone(uuid) == zone);
}
}

View file

@ -22,7 +22,7 @@ import java.util.UUID;
/**
* @author JayDi85
*/
public abstract class ModalDoubleFacesCard extends CardImpl {
public abstract class ModalDoubleFacesCard extends CardImpl implements CardWithHalves {
protected Card leftHalfCard; // main card in all zone
protected Card rightHalfCard; // second side card, can be only in stack and battlefield zones

View file

@ -5,15 +5,11 @@ import mage.MageInt;
/**
* @author JayDi85
*/
public interface ModalDoubleFacesCardHalf extends Card {
public interface ModalDoubleFacesCardHalf extends SubCard<ModalDoubleFacesCard> {
@Override
ModalDoubleFacesCardHalf copy();
void setParentCard(ModalDoubleFacesCard card);
ModalDoubleFacesCard getParentCard();
void setPT(int power, int toughness);
void setPT(MageInt power, MageInt toughness);

View file

@ -18,7 +18,7 @@ import java.util.UUID;
/**
* @author LevelX2
*/
public abstract class SplitCard extends CardImpl {
public abstract class SplitCard extends CardImpl implements CardWithHalves {
protected Card leftHalfCard;
protected Card rightHalfCard;

View file

@ -3,12 +3,8 @@ package mage.cards;
/**
* @author LevelX2
*/
public interface SplitCardHalf extends Card {
public interface SplitCardHalf extends SubCard<SplitCard> {
@Override
SplitCardHalf copy();
void setParentCard(SplitCard card);
SplitCard getParentCard();
}

View file

@ -0,0 +1,8 @@
package mage.cards;
public interface SubCard<T extends Card> extends Card {
void setParentCard(T card);
T getParentCard();
}

View file

@ -1,7 +1,7 @@
package mage.filter.predicate.mageobject;
import mage.MageObject;
import mage.cards.ModalDoubleFacesCard;
import mage.cards.CardWithHalves;
import mage.cards.SplitCard;
import mage.constants.SpellAbilityType;
import mage.filter.predicate.Predicate;
@ -34,13 +34,9 @@ public class NamePredicate implements Predicate<MageObject> {
// If a player names a card, the player may name either half of a split card, but not both.
// A split card has the chosen name if one of its two names matches the chosen name.
// Same for modal double faces cards
if (input instanceof SplitCard) {
return CardUtil.haveSameNames(name, ((SplitCard) input).getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) ||
CardUtil.haveSameNames(name, ((SplitCard) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) ||
CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames);
} else if (input instanceof ModalDoubleFacesCard) {
return CardUtil.haveSameNames(name, ((ModalDoubleFacesCard) input).getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) ||
CardUtil.haveSameNames(name, ((ModalDoubleFacesCard) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) ||
if (input instanceof CardWithHalves) {
return CardUtil.haveSameNames(name, ((CardWithHalves) input).getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) ||
CardUtil.haveSameNames(name, ((CardWithHalves) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) ||
CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames);
} else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) {
SplitCard card = (SplitCard) ((Spell) input).getCard();

View file

@ -1,48 +1,51 @@
package mage.game.command.emblems;
import mage.ApprovingObject;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.choices.Choice;
import mage.choices.ChoiceImpl;
import mage.constants.*;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterOwnedCard;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.command.Emblem;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInExile;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetCardInYourGraveyard;
import mage.util.CardUtil;
import java.util.LinkedHashSet;
import java.util.Set;
/**
*
* @author weirddan455
*/
public class KayaTheInexorableEmblem extends Emblem {
public class KayaTheInexorableEmblem extends Emblem {
// 7: You get an emblem with "At the beginning of your upkeep, you may cast a legendary spell from your hand, from your graveyard, or from among cards you own in exile without paying its mana cost."
public KayaTheInexorableEmblem() {
this.setName("Emblem Kaya");
this.setExpansionSetCodeForImage("KHM");
this.getAbilities().add(new BeginningOfUpkeepTriggeredAbility(Zone.COMMAND, new KayaTheInexorableEmblemEffect(), TargetController.YOU, true, false));
this.getAbilities().add(new BeginningOfUpkeepTriggeredAbility(
Zone.COMMAND, new KayaTheInexorableEmblemEffect(),
TargetController.YOU, true, false
));
}
}
class KayaTheInexorableEmblemEffect extends OneShotEffect {
private static final FilterOwnedCard filter = new FilterOwnedCard();
private static final FilterCard filter = new FilterOwnedCard();
private static final FilterCard filter2 = new FilterCard();
private static final Set<String> choices = new LinkedHashSet<>();
static {
filter.add(SuperType.LEGENDARY.getPredicate());
filter.add(Predicates.not(CardType.LAND.getPredicate()));
filter2.add(SuperType.LEGENDARY.getPredicate());
choices.add("Hand");
choices.add("Graveyard");
choices.add("Exile");
@ -50,7 +53,8 @@ class KayaTheInexorableEmblemEffect extends OneShotEffect {
public KayaTheInexorableEmblemEffect() {
super(Outcome.PlayForFree);
this.staticText = "cast a legendary spell from your hand, from your graveyard, or from among cards you own in exile without paying its mana cost";
this.staticText = "cast a legendary spell from your hand, from your graveyard, " +
"or from among cards you own in exile without paying its mana cost";
}
private KayaTheInexorableEmblemEffect(final KayaTheInexorableEmblemEffect effect) {
@ -65,40 +69,26 @@ class KayaTheInexorableEmblemEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
Choice zoneChoice = new ChoiceImpl(true);
zoneChoice.setMessage("Cast a legendary spell from hand, graveyard, or exile");
zoneChoice.setChoices(choices);
zoneChoice.clearChoice();
if (player.choose(Outcome.PlayForFree, zoneChoice, game)) {
TargetCard target = null;
switch (zoneChoice.getChoice()) {
case "Hand":
target = new TargetCardInHand(0, 1, filter);
target.setTargetName("legendary spell from your hand");
break;
case "Graveyard":
target = new TargetCardInYourGraveyard(0, 1, filter, true);
target.setTargetName("legendary spell from your graveyard");
break;
case "Exile":
target = new TargetCardInExile(0, 1, filter, null, true);
target.setNotTarget(true);
target.setTargetName("legendary spell you own in exile");
break;
}
if (target != null && player.chooseTarget(Outcome.PlayForFree, target, source, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
boolean cardWasCast = player.cast(player.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
return cardWasCast;
}
}
}
if (player == null) {
return false;
}
return false;
Choice zoneChoice = new ChoiceImpl(true);
zoneChoice.setMessage("Cast a legendary spell from hand, graveyard, or exile");
zoneChoice.setChoices(choices);
zoneChoice.clearChoice();
player.choose(Outcome.PlayForFree, zoneChoice, game);
Cards cards = new CardsImpl();
switch (zoneChoice.getChoice()) {
case "Hand":
cards.addAll(player.getHand());
break;
case "Graveyard":
cards.addAll(player.getGraveyard());
break;
case "Exile":
cards.addAll(game.getExile().getCards(filter, game));
break;
}
return CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter2);
}
}

View file

@ -1571,72 +1571,75 @@ public abstract class PlayerImpl implements Player, Serializable {
* @param noMana
* @return
*/
public static LinkedHashMap<UUID, ActivatedAbility> getCastableSpellAbilities(Game game, UUID playerId, MageObject object, Zone zone, boolean noMana) {
public static LinkedHashMap<UUID, SpellAbility> getCastableSpellAbilities(Game game, UUID playerId, MageObject object, Zone zone, boolean noMana) {
// it uses simple check from spellCanBeActivatedRegularlyNow
// reason: no approved info here (e.g. forced to choose spell ability from cast card)
LinkedHashMap<UUID, ActivatedAbility> useable = new LinkedHashMap<>();
LinkedHashMap<UUID, SpellAbility> useable = new LinkedHashMap<>();
Abilities<Ability> allAbilities;
if (object instanceof Card) {
allAbilities = ((Card) object).getAbilities(game);
} else {
allAbilities = object.getAbilities();
}
for (Ability ability : allAbilities) {
if (ability instanceof SpellAbility) {
SpellAbility spellAbility = (SpellAbility) ability;
switch (spellAbility.getSpellAbilityType()) {
case BASE_ALTERNATE:
// rules:
// If you cast a spell without paying its mana cost, you cant choose to cast it for
// any alternative costs. You can, however, pay additional costs, such as kicker costs.
// If the card has any mandatory additional costs, those must be paid to cast the spell.
// (2021-02-05)
if (!noMana) {
if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) {
useable.put(spellAbility.getId(), spellAbility); // example: Chandra, Torch of Defiance +1 loyal ability
}
return useable;
for (SpellAbility spellAbility : allAbilities
.stream()
.filter(SpellAbility.class::isInstance)
.map(SpellAbility.class::cast)
.collect(Collectors.toList())) {
switch (spellAbility.getSpellAbilityType()) {
case BASE_ALTERNATE:
// rules:
// If you cast a spell without paying its mana cost, you cant choose to cast it for
// any alternative costs. You can, however, pay additional costs, such as kicker costs.
// If the card has any mandatory additional costs, those must be paid to cast the spell.
// (2021-02-05)
if (!noMana) {
if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) {
useable.put(spellAbility.getId(), spellAbility); // example: Chandra, Torch of Defiance +1 loyal ability
}
break;
case SPLIT_FUSED:
// rules:
// If you cast a split card with fuse from your hand without paying its mana cost,
// you can choose to use its fuse ability and cast both halves without paying their mana costs.
if (zone == Zone.HAND) {
if (spellAbility.canChooseTarget(game, playerId)) {
useable.put(spellAbility.getId(), spellAbility);
}
}
case SPLIT:
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(),
((SplitCard) object).getLeftHalfCard().getSpellAbility());
return useable;
}
break;
case SPLIT_FUSED:
// rules:
// If you cast a split card with fuse from your hand without paying its mana cost,
// you can choose to use its fuse ability and cast both halves without paying their mana costs.
if (zone == Zone.HAND) {
if (spellAbility.canChooseTarget(game, playerId)) {
useable.put(spellAbility.getId(), spellAbility);
}
}
case SPLIT:
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(
((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(),
((SplitCard) object).getLeftHalfCard().getSpellAbility()
);
}
if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(
((SplitCard) object).getRightHalfCard().getSpellAbility().getId(),
((SplitCard) object).getRightHalfCard().getSpellAbility()
);
}
return useable;
case SPLIT_AFTERMATH:
if (zone == Zone.GRAVEYARD) {
if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getRightHalfCard().getSpellAbility().getId(),
((SplitCard) object).getRightHalfCard().getSpellAbility());
}
return useable;
case SPLIT_AFTERMATH:
if (zone == Zone.GRAVEYARD) {
if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getRightHalfCard().getSpellAbility().getId(),
((SplitCard) object).getRightHalfCard().getSpellAbility());
}
} else {
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(),
((SplitCard) object).getLeftHalfCard().getSpellAbility());
}
} else {
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(),
((SplitCard) object).getLeftHalfCard().getSpellAbility());
}
return useable;
default:
if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) {
useable.put(spellAbility.getId(), spellAbility);
}
}
}
return useable;
default:
if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) {
useable.put(spellAbility.getId(), spellAbility);
}
}
}
return useable;

View file

@ -1,6 +1,7 @@
package mage.util;
import com.google.common.collect.ImmutableList;
import mage.ApprovingObject;
import mage.MageObject;
import mage.Mana;
import mage.abilities.Abilities;
@ -23,6 +24,7 @@ import mage.cards.*;
import mage.constants.*;
import mage.counters.Counter;
import mage.filter.Filter;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.game.CardState;
import mage.game.Game;
@ -36,6 +38,7 @@ import mage.game.permanent.token.Token;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetCard;
import mage.target.targetpointer.FixedTarget;
import mage.util.functions.CopyTokenFunction;
import org.apache.log4j.Logger;
@ -1196,6 +1199,126 @@ public final class CardUtil {
}
}
public interface SpellCastTracker {
boolean checkCard(Card card, Game game);
void addCard(Card card, Ability source, Game game);
}
private static List<Card> getCastableComponents(Card cardToCast, FilterCard filter, UUID sourceId, UUID playerId, Game game, SpellCastTracker spellCastTracker) {
List<Card> cards = new ArrayList<>();
if (cardToCast instanceof CardWithHalves) {
cards.add(((CardWithHalves) cardToCast).getLeftHalfCard());
cards.add(((CardWithHalves) cardToCast).getRightHalfCard());
} else if (cardToCast instanceof AdventureCard) {
cards.add(cardToCast);
cards.add(((AdventureCard) cardToCast).getSpellCard());
} else {
cards.add(cardToCast);
}
cards.removeIf(Objects::isNull);
cards.removeIf(card -> !filter.match(card, sourceId, playerId, game));
if (spellCastTracker != null) {
cards.removeIf(card -> spellCastTracker.checkCard(card, game));
}
return cards;
}
private static final FilterCard defaultFilter = new FilterCard("card to cast");
public static boolean castSpellWithAttributesForFree(Player player, Ability source, Game game, Cards cards, FilterCard filter) {
return castSpellWithAttributesForFree(player, source, game, cards, filter, null);
}
public static boolean castSpellWithAttributesForFree(Player player, Ability source, Game game, Cards cards, FilterCard filter, SpellCastTracker spellCastTracker) {
Map<UUID, List<Card>> cardMap = new HashMap<>();
for (Card card : cards.getCards(game)) {
List<Card> castableComponents = getCastableComponents(card, filter, source.getSourceId(), player.getId(), game, spellCastTracker);
if (!castableComponents.isEmpty()) {
cardMap.put(card.getId(), castableComponents);
}
}
Card cardToCast;
switch (cardMap.size()) {
case 0:
return false;
case 1:
cardToCast = cards.get(cardMap.keySet().stream().findFirst().orElse(null), game);
break;
default:
Cards castableCards = new CardsImpl(cardMap.keySet());
TargetCard target = new TargetCard(0, 1, Zone.ALL, defaultFilter);
target.setNotTarget(true);
player.choose(Outcome.PlayForFree, castableCards, target, game);
cardToCast = castableCards.get(target.getFirstTarget(), game);
}
if (cardToCast == null) {
return false;
}
List<Card> partsToCast = cardMap.get(cardToCast.getId());
String partsInfo = partsToCast
.stream()
.map(MageObject::getIdName)
.collect(Collectors.joining(" or "));
if (cardToCast == null
|| partsToCast.size() < 1
|| !player.chooseUse(
Outcome.PlayForFree, "Cast spell without paying its mana cost (" + partsInfo + ")?", source, game
)) {
return false;
}
partsToCast.forEach(card -> game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE));
boolean result = player.cast(
player.chooseAbilityForCast(cardToCast, game, true),
game, true, new ApprovingObject(source, game)
);
partsToCast.forEach(card -> game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null));
if (result && spellCastTracker != null) {
spellCastTracker.addCard(cardToCast, source, game);
}
if (player.isComputer() && !result) {
cards.remove(cardToCast);
}
return result;
}
private static boolean checkForPlayable(Cards cards, FilterCard filter, UUID sourceId, UUID playerId, Game game, SpellCastTracker spellCastTracker) {
return cards
.getCards(game)
.stream()
.anyMatch(card -> !getCastableComponents(card, filter, sourceId, playerId, game, spellCastTracker).isEmpty());
}
public static void castMultipleWithAttributeForFree(Player player, Ability source, Game game, Cards cards, FilterCard filter) {
castMultipleWithAttributeForFree(player, source, game, cards, filter, Integer.MAX_VALUE);
}
public static void castMultipleWithAttributeForFree(Player player, Ability source, Game game, Cards cards, FilterCard filter, int maxSpells) {
castMultipleWithAttributeForFree(player, source, game, cards, filter, maxSpells, null);
}
public static void castMultipleWithAttributeForFree(Player player, Ability source, Game game, Cards cards, FilterCard filter, int maxSpells, SpellCastTracker spellCastTracker) {
if (maxSpells == 1) {
CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter);
return;
}
int spellsCast = 0;
cards.removeZone(Zone.STACK, game);
while (player.canRespond() && spellsCast < maxSpells && !cards.isEmpty()) {
if (CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter, spellCastTracker)) {
spellsCast++;
cards.removeZone(Zone.STACK, game);
} else if (!checkForPlayable(
cards, filter, source.getSourceId(), player.getId(), game, spellCastTracker
) || !player.chooseUse(
Outcome.PlayForFree, "Continue casting spells?", source, game
)) {
break;
}
}
}
/**
* Pay life in effects
*

View file

@ -13,6 +13,7 @@ import mage.game.stack.Spell;
import mage.watchers.Watcher;
import java.util.*;
import java.util.stream.Stream;
/**
* @author LevelX2
@ -59,6 +60,10 @@ public class SpellsCastWatcher extends Watcher {
spellsCastFromGraveyard.clear();
}
public Stream<Spell> getAllSpellsCastThisTurn() {
return spellsCast.values().stream().flatMap(Collection::stream);
}
public List<Spell> getSpellsCastThisTurn(UUID playerId) {
return spellsCast.computeIfAbsent(playerId, x -> new ArrayList<>());
}