diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index 15dabfd8c1..c8515b2d16 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -1,8 +1,6 @@ package mage.view; import com.google.gson.annotations.Expose; -import java.util.*; -import java.util.stream.Collectors; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Abilities; @@ -31,6 +29,9 @@ import mage.target.Targets; import mage.util.CardUtil; import mage.util.SubTypeList; +import java.util.*; +import java.util.stream.Collectors; + /** * @author BetaSteward_at_googlemail.com */ @@ -95,6 +96,8 @@ public class CardView extends SimpleCardView { protected List rightSplitRules; protected String rightSplitTypeLine; + protected boolean isModalDoubleFacesCard; + protected ArtRect artRect = ArtRect.NORMAL; protected List targets; @@ -187,6 +190,8 @@ public class CardView extends SimpleCardView { this.rightSplitRules = cardView.rightSplitRules == null ? null : new ArrayList<>(cardView.rightSplitRules); this.rightSplitTypeLine = cardView.rightSplitTypeLine; + this.isModalDoubleFacesCard = cardView.isModalDoubleFacesCard; + this.artRect = cardView.artRect; this.targets = cardView.targets == null ? null : new ArrayList<>(cardView.targets); this.pairedCard = cardView.pairedCard; @@ -299,7 +304,7 @@ public class CardView extends SimpleCardView { } SplitCard splitCard = null; - if (card.isSplitCard()) { + if (card instanceof SplitCard) { splitCard = (SplitCard) card; rotate = (card.getSpellAbility().getSpellAbilityType()) != SpellAbilityType.SPLIT_AFTERMATH; } else if (card instanceof Spell) { @@ -316,6 +321,10 @@ public class CardView extends SimpleCardView { case SPLIT_RIGHT: rotate = true; break; + case MODAL_LEFT: + case MODAL_RIGHT: + rotate = false; + break; } } @@ -334,6 +343,12 @@ public class CardView extends SimpleCardView { fullCardName = card.getName(); // split card contains full name as normal this.manaCostLeft = splitCard.getLeftHalfCard().getManaCost().getSymbols(); this.manaCostRight = splitCard.getRightHalfCard().getManaCost().getSymbols(); + } else if (card instanceof ModalDoubleFacesCard) { + this.isModalDoubleFacesCard = true; + ModalDoubleFacesCard mainCard = ((ModalDoubleFacesCard) card); + fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName(); + this.manaCostLeft = mainCard.getLeftHalfCard().getManaCost().getSymbols(); + this.manaCostRight = mainCard.getRightHalfCard().getManaCost().getSymbols(); } else if (card instanceof AdventureCard) { AdventureCard adventureCard = ((AdventureCard) card); AdventureCardSpell adventureCardSpell = ((AdventureCardSpell) adventureCard.getSpellCard()); @@ -455,6 +470,7 @@ public class CardView extends SimpleCardView { // Determine what part of the art to slice out for spells on the stack which originate // from a split, fuse, or aftermath split card. + // Modal double faces cards draws as normal cards SpellAbilityType ty = spell.getSpellAbility().getSpellAbilityType(); if (ty == SpellAbilityType.SPLIT_RIGHT || ty == SpellAbilityType.SPLIT_LEFT || ty == SpellAbilityType.SPLIT_FUSED) { // Needs a special art rect diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java index 0d86bc7525..b4b0582418 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java @@ -1,9 +1,6 @@ package mage.deck; -import mage.cards.Card; -import mage.cards.ExpansionSet; -import mage.cards.Sets; -import mage.cards.SplitCard; +import mage.cards.*; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidatorErrorType; @@ -199,21 +196,27 @@ public class TinyLeaders extends Constructed { return false; } - //905.5b - Converted mana cost must be 3 or less + // 906.5b + // Each card must have a converted mana cost of three or less. Cards with {x} in their mana cost count X + // as zero for this purpose. Split cards are legal only if both of their halves would be legal independently. + List costs = new ArrayList<>(); if (card instanceof SplitCard) { - if (((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() > 3) { - addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid cost (" + ((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() + ')', true); - return false; - } - if (((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() > 3) { - addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid cost (" + ((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() + ')', true); - return false; - } - } else if (card.getManaCost().convertedManaCost() > 3) { - addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid cost (" + card.getManaCost().convertedManaCost() + ')', true); - return false; + costs.add(((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost()); + costs.add(((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost()); + } else if (card instanceof ModalDoubleFacesCard) { + costs.add(((ModalDoubleFacesCard) card).getLeftHalfCard().getManaCost().convertedManaCost()); + costs.add(((ModalDoubleFacesCard) card).getRightHalfCard().getManaCost().convertedManaCost()); + } else { + costs.add(card.getManaCost().convertedManaCost()); } - return true; + + return costs.stream().allMatch(cost -> { + if (cost > 3) { + addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid cost (" + cost + ')', true); + return false; + } + return true; + }); } /** diff --git a/Mage.Sets/src/mage/cards/a/AkoumTeeth.java b/Mage.Sets/src/mage/cards/a/AkoumTeeth.java deleted file mode 100644 index 4db7ed2a8a..0000000000 --- a/Mage.Sets/src/mage/cards/a/AkoumTeeth.java +++ /dev/null @@ -1,37 +0,0 @@ -package mage.cards.a; - -import mage.abilities.common.EntersBattlefieldTappedAbility; -import mage.abilities.mana.RedManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AkoumTeeth extends CardImpl { - - public AkoumTeeth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.modalDFC = true; - this.nightCard = true; - - // Akoum Teeth enters the battlefield tapped. - this.addAbility(new EntersBattlefieldTappedAbility()); - - // {T}: Add {R}. - this.addAbility(new RedManaAbility()); - } - - private AkoumTeeth(final AkoumTeeth card) { - super(card); - } - - @Override - public AkoumTeeth copy() { - return new AkoumTeeth(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AkoumWarrior.java b/Mage.Sets/src/mage/cards/a/AkoumWarrior.java index ee9d7a0995..f04192aab8 100644 --- a/Mage.Sets/src/mage/cards/a/AkoumWarrior.java +++ b/Mage.Sets/src/mage/cards/a/AkoumWarrior.java @@ -1,32 +1,38 @@ package mage.cards.a; import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.RedManaAbility; import mage.cards.CardSetInfo; +import mage.cards.ModalDoubleFacesCard; import mage.constants.CardType; import mage.constants.SubType; import java.util.UUID; /** - * @author TheElk801 + * @author JayDi85 */ -public final class AkoumWarrior extends CardImpl { +public final class AkoumWarrior extends ModalDoubleFacesCard { public AkoumWarrior(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}"); - - this.subtype.add(SubType.MINOTAUR); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - - this.modalDFC = true; - this.secondSideCardClazz = mage.cards.a.AkoumTeeth.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.MINOTAUR, SubType.WARRIOR}, "{5}{R}", + "Akoum Teeth", new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + // Akoum Warrior + // Creature — Minotaur Warrior + this.getLeftHalfCard().setPT(new MageInt(4), new MageInt(5)); // Trample - this.addAbility(TrampleAbility.getInstance()); + this.getLeftHalfCard().addAbility(TrampleAbility.getInstance()); + + // Akoum Teeth + // Akoum Teeth enters the battlefield tapped. + this.getRightHalfCard().addAbility(new EntersBattlefieldTappedAbility()); + // {T}: Add {R}. + this.getRightHalfCard().addAbility(new RedManaAbility()); } private AkoumWarrior(final AkoumWarrior card) { diff --git a/Mage.Sets/src/mage/cards/a/AssemblyHall.java b/Mage.Sets/src/mage/cards/a/AssemblyHall.java index a495718139..ad4186b86f 100644 --- a/Mage.Sets/src/mage/cards/a/AssemblyHall.java +++ b/Mage.Sets/src/mage/cards/a/AssemblyHall.java @@ -1,6 +1,5 @@ package mage.cards.a; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,7 +11,6 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; -import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.FilterCard; @@ -23,9 +21,11 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class AssemblyHall extends CardImpl { @@ -84,7 +84,7 @@ class AssemblyHallEffect extends OneShotEffect { return false; } controller.revealCards("from hand :" + sourceObject.getName(), new CardsImpl(cardToReveal), game); - String nameToSearch = cardToReveal.isSplitCard() ? ((SplitCard) cardToReveal).getLeftHalfCard().getName() : cardToReveal.getName(); + String nameToSearch = CardUtil.getCardNameForSameNameSearch(cardToReveal); FilterCard filterCard = new FilterCard("card named " + nameToSearch); filterCard.add(new NamePredicate(nameToSearch)); return new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filterCard), true, true).apply(game, source); diff --git a/Mage.Sets/src/mage/cards/b/BolassCitadel.java b/Mage.Sets/src/mage/cards/b/BolassCitadel.java index 03c06175b4..a3f56f3094 100644 --- a/Mage.Sets/src/mage/cards/b/BolassCitadel.java +++ b/Mage.Sets/src/mage/cards/b/BolassCitadel.java @@ -105,22 +105,39 @@ class BolassCitadelPlayTheTopCardEffect extends AsThoughEffectImpl { if (topCard == null || !topCard.getId().equals(objectIdToCast)) { return false; } - if (!topCard.isLand()) { - if (topCard instanceof SplitCard) { - SplitCardHalf leftCard = ((SplitCard) topCard).getLeftHalfCard(); - PayLifeCost lifeCost = new PayLifeCost(leftCard.getSpellAbility().getManaCosts().convertedManaCost()); - Costs leftCosts = new CostsImpl(); - leftCosts.add(lifeCost); - leftCosts.addAll(leftCard.getSpellAbility().getCosts()); - player.setCastSourceIdWithAlternateMana(leftCard.getId(), null, leftCosts); - SplitCardHalf rightCard = ((SplitCard) topCard).getRightHalfCard(); - lifeCost = new PayLifeCost(rightCard.getSpellAbility().getManaCosts().convertedManaCost()); - Costs rightCosts = new CostsImpl(); - rightCosts.add(lifeCost); - rightCosts.addAll(rightCard.getSpellAbility().getCosts()); - player.setCastSourceIdWithAlternateMana(rightCard.getId(), null, rightCosts); + if (topCard instanceof SplitCard || topCard instanceof ModalDoubleFacesCard) { + // double faces cards + Card card1; + Card card2; + if (topCard instanceof SplitCard) { + card1 = ((SplitCard) topCard).getLeftHalfCard(); + card2 = ((SplitCard) topCard).getRightHalfCard(); } else { + card1 = ((ModalDoubleFacesCard) topCard).getLeftHalfCard(); + card2 = ((ModalDoubleFacesCard) topCard).getRightHalfCard(); + } + + // left + if (!card1.isLand()) { + PayLifeCost lifeCost = new PayLifeCost(card1.getSpellAbility().getManaCosts().convertedManaCost()); + Costs newCosts = new CostsImpl(); + newCosts.add(lifeCost); + newCosts.addAll(card1.getSpellAbility().getCosts()); + player.setCastSourceIdWithAlternateMana(card1.getId(), null, newCosts); + } + + // right + if (!card2.isLand()) { + PayLifeCost lifeCost = new PayLifeCost(card2.getSpellAbility().getManaCosts().convertedManaCost()); + Costs newCosts = new CostsImpl(); + newCosts.add(lifeCost); + newCosts.addAll(card2.getSpellAbility().getCosts()); + player.setCastSourceIdWithAlternateMana(card2.getId(), null, newCosts); + } + } else { + // other single face cards + if (!topCard.isLand()) { if (affectedAbility == null) { affectedAbility = topCard.getSpellAbility(); } else { @@ -134,7 +151,6 @@ class BolassCitadelPlayTheTopCardEffect extends AsThoughEffectImpl { } } return true; - } return false; } diff --git a/Mage.Sets/src/mage/cards/d/DoubleHeader.java b/Mage.Sets/src/mage/cards/d/DoubleHeader.java index 7a483fb282..c42c282c03 100644 --- a/Mage.Sets/src/mage/cards/d/DoubleHeader.java +++ b/Mage.Sets/src/mage/cards/d/DoubleHeader.java @@ -1,8 +1,5 @@ - package mage.cards.d; -import java.util.UUID; -import java.util.regex.Pattern; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -11,18 +8,21 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.ModalDoubleFacesCard; import mage.cards.SplitCard; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.SpellAbilityType; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.stack.Spell; import mage.target.TargetPermanent; +import java.util.UUID; +import java.util.regex.Pattern; + /** - * * @author L_J */ public final class DoubleHeader extends CardImpl { @@ -34,7 +34,7 @@ public final class DoubleHeader extends CardImpl { } public DoubleHeader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.DRAKE); this.power = new MageInt(2); @@ -68,14 +68,16 @@ class DoubleHeaderPredicate implements Predicate { public boolean apply(MageObject input, Game game) { String name = input.getName(); if (input instanceof SplitCard) { - return hasTwoWords(((SplitCard)input).getLeftHalfCard().getName()) || hasTwoWords(((SplitCard)input).getRightHalfCard().getName()); - } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED){ - SplitCard card = (SplitCard) ((Spell)input).getCard(); + return hasTwoWords(((SplitCard) input).getLeftHalfCard().getName()) || hasTwoWords(((SplitCard) input).getRightHalfCard().getName()); + } else if (input instanceof ModalDoubleFacesCard) { + return hasTwoWords(((ModalDoubleFacesCard) input).getLeftHalfCard().getName()) || hasTwoWords(((ModalDoubleFacesCard) input).getRightHalfCard().getName()); + } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { + SplitCard card = (SplitCard) ((Spell) input).getCard(); return hasTwoWords(card.getLeftHalfCard().getName()) || hasTwoWords(card.getRightHalfCard().getName()); } else { if (name.contains(" // ")) { String leftName = name.substring(0, name.indexOf(" // ")); - String rightName = name.substring(name.indexOf(" // ") + 4, name.length()); + String rightName = name.substring(name.indexOf(" // ") + 4); return hasTwoWords(leftName) || hasTwoWords(rightName); } else { return hasTwoWords(name); diff --git a/Mage.Sets/src/mage/cards/e/EverythingamajigE.java b/Mage.Sets/src/mage/cards/e/EverythingamajigE.java index 6edc1f5d7e..4af2d0abfa 100644 --- a/Mage.Sets/src/mage/cards/e/EverythingamajigE.java +++ b/Mage.Sets/src/mage/cards/e/EverythingamajigE.java @@ -1,8 +1,5 @@ - package mage.cards.e; -import java.util.UUID; - import mage.MageObject; import mage.Mana; import mage.abilities.Ability; @@ -13,14 +10,11 @@ import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.mana.SimpleManaAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.SplitCard; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SpellAbilityType; @@ -35,24 +29,25 @@ import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author Ketsuban */ public final class EverythingamajigE extends CardImpl { public EverythingamajigE(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); // Zuran Orb // Sacrifice a land: You gain 2 life. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(2), new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT)))); - + // Ashnod's Altar // Sacrifice a creature: Add {C}{C} to your mana pool. SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT)); - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, - new BasicManaEffect(Mana.ColorlessMana(2), CreaturesYouControlCount.instance), + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, + new BasicManaEffect(Mana.ColorlessMana(2), CreaturesYouControlCount.instance), cost)); // Urza's Hot Tub @@ -117,21 +112,23 @@ class UrzasHotTubPredicate implements Predicate { public boolean apply(MageObject input, Game game) { String name = input.getName(); if (input instanceof SplitCard) { - return sharesWordWithName(((SplitCard)input).getLeftHalfCard().getName()) || sharesWordWithName(((SplitCard)input).getRightHalfCard().getName()); - } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED){ - SplitCard card = (SplitCard) ((Spell)input).getCard(); + return sharesWordWithName(((SplitCard) input).getLeftHalfCard().getName()) || sharesWordWithName(((SplitCard) input).getRightHalfCard().getName()); + } else if (input instanceof ModalDoubleFacesCard) { + return sharesWordWithName(((ModalDoubleFacesCard) input).getLeftHalfCard().getName()) || sharesWordWithName(((ModalDoubleFacesCard) input).getRightHalfCard().getName()); + } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { + SplitCard card = (SplitCard) ((Spell) input).getCard(); return sharesWordWithName(card.getLeftHalfCard().getName()) || sharesWordWithName(card.getRightHalfCard().getName()); } else { if (name.contains(" // ")) { String leftName = name.substring(0, name.indexOf(" // ")); - String rightName = name.substring(name.indexOf(" // ") + 4, name.length()); + String rightName = name.substring(name.indexOf(" // ") + 4); return sharesWordWithName(leftName) || sharesWordWithName(rightName); } else { return sharesWordWithName(name); } } } - + private boolean sharesWordWithName(String str) { if (referenceName == null || referenceName.equals("")) { return false; diff --git a/Mage.Sets/src/mage/cards/e/Extirpate.java b/Mage.Sets/src/mage/cards/e/Extirpate.java index 9cc7d046b2..ae5b3d676c 100644 --- a/Mage.Sets/src/mage/cards/e/Extirpate.java +++ b/Mage.Sets/src/mage/cards/e/Extirpate.java @@ -1,7 +1,5 @@ package mage.cards.e; -import java.util.List; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -9,7 +7,6 @@ import mage.abilities.keyword.SplitSecondAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SuperType; @@ -22,19 +19,22 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.List; +import java.util.UUID; /** - * * @author jonubuu */ public final class Extirpate extends CardImpl { - + private static final FilterCard filter = new FilterCard("card in a graveyard other than a basic land card"); - + static { filter.add(Predicates.not(Predicates.and(CardType.LAND.getPredicate(), SuperType.BASIC.getPredicate()))); } - + public Extirpate(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); @@ -46,11 +46,11 @@ public final class Extirpate extends CardImpl { this.getSpellAbility().addEffect(new ExtirpateEffect()); this.getSpellAbility().addTarget(new TargetCardInGraveyard(filter)); } - + public Extirpate(final Extirpate card) { super(card); } - + @Override public Extirpate copy() { return new Extirpate(this); @@ -58,7 +58,7 @@ public final class Extirpate extends CardImpl { } class ExtirpateEffect extends OneShotEffect { - + public ExtirpateEffect() { super(Outcome.Exile); this.staticText = "Choose target card in a graveyard other than " @@ -66,16 +66,16 @@ class ExtirpateEffect extends OneShotEffect { + "and library for any number of cards with the same name " + "as that card and exile them. Then that player shuffles their library"; } - + public ExtirpateEffect(final ExtirpateEffect effect) { super(effect); } - + @Override public ExtirpateEffect copy() { return new ExtirpateEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -90,7 +90,7 @@ class ExtirpateEffect extends OneShotEffect { // Exile all cards with the same name // Building a card filter with the name FilterCard filterNamedCard = new FilterCard(); - String nameToSearch = chosenCard.isSplitCard() ? ((SplitCard) chosenCard).getLeftHalfCard().getName() : chosenCard.getName(); + String nameToSearch = CardUtil.getCardNameForSameNameSearch(chosenCard); filterNamedCard.add(new NamePredicate(nameToSearch)); // The cards you're searching for must be found and exiled if they're in the graveyard because it's a public zone. @@ -133,5 +133,5 @@ class ExtirpateEffect extends OneShotEffect { } return false; } - + } diff --git a/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java b/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java index 45ca110895..2fd5fa352f 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java @@ -1,5 +1,6 @@ package mage.cards.e; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -21,7 +22,6 @@ import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import java.util.UUID; -import mage.ApprovingObject; /** * @author spjspj @@ -127,9 +127,12 @@ class EyeOfTheStormEffect1 extends OneShotEffect { // Check if owner of card is still in game card = game.getCard(uuid); if (card != null && game.getPlayer(card.getOwnerId()) != null) { - if (card.isSplitCard()) { + if (card instanceof SplitCard) { copiedCards.add(((SplitCard) card).getLeftHalfCard()); copiedCards.add(((SplitCard) card).getRightHalfCard()); + } else if (card instanceof ModalDoubleFacesCard) { + copiedCards.add(((ModalDoubleFacesCard) card).getLeftHalfCard()); + copiedCards.add(((ModalDoubleFacesCard) card).getRightHalfCard()); } else { copiedCards.add(card); } diff --git a/Mage.Sets/src/mage/cards/g/GrimoireThief.java b/Mage.Sets/src/mage/cards/g/GrimoireThief.java index 5504fb40ef..b9d10b886f 100644 --- a/Mage.Sets/src/mage/cards/g/GrimoireThief.java +++ b/Mage.Sets/src/mage/cards/g/GrimoireThief.java @@ -1,9 +1,5 @@ package mage.cards.g; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -24,8 +20,12 @@ import mage.players.Player; import mage.target.common.TargetOpponent; import mage.util.CardUtil; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class GrimoireThief extends CardImpl { @@ -197,30 +197,24 @@ class GrimoireThiefCounterspellEffect extends OneShotEffect { } // then counter any with the same name as the card exiled with Grimoire Thief for (Card card : cards.getCards(game)) { - for (Iterator iterator = game.getStack().iterator(); iterator.hasNext();) { + for (Iterator iterator = game.getStack().iterator(); iterator.hasNext(); ) { StackObject stackObject = iterator.next(); MageObject mageObject = game.getObject(card.getId()); - // handle split cards + String name1; + String name2; if (mageObject instanceof SplitCard) { - if (stackObject instanceof Spell - && (stackObject.getName().contains(((SplitCard) mageObject).getLeftHalfCard().getName()) - || stackObject.getName().contains(((SplitCard) mageObject).getRightHalfCard().getName()))) { - Spell spell = (Spell) stackObject; - game.getStack().counter(stackObject.getId(), source.getSourceId(), game); - game.informPlayers(sourceObject.getLogName() - + ": the split-card spell named " - + spell.getName() - + " was countered."); - } + name1 = ((SplitCard) mageObject).getLeftHalfCard().getName(); + name2 = ((SplitCard) mageObject).getRightHalfCard().getName(); + } else { + // modal double faces cards, adventure cards -- all have one name in non stack/battlefield zone + name1 = mageObject.getName(); + name2 = name1; } - if (stackObject instanceof Spell - && stackObject.getName().contains(card.getName())) { + + if (CardUtil.haveSameNames(stackObject, name1, game) || CardUtil.haveSameNames(stackObject, name2, game)) { Spell spell = (Spell) stackObject; - game.getStack().counter(spell.getId(), source.getSourceId(), game); - game.informPlayers(sourceObject.getLogName() - + ": the spell named " - + spell.getName() - + " was countered."); + game.getStack().counter(stackObject.getId(), source.getSourceId(), game); + game.informPlayers(sourceObject.getLogName() + ": spell " + spell.getIdName() + " was countered."); } } } diff --git a/Mage.Sets/src/mage/cards/h/HauntingEchoes.java b/Mage.Sets/src/mage/cards/h/HauntingEchoes.java index c3e2e60bb4..6be5cde65a 100644 --- a/Mage.Sets/src/mage/cards/h/HauntingEchoes.java +++ b/Mage.Sets/src/mage/cards/h/HauntingEchoes.java @@ -1,4 +1,3 @@ - package mage.cards.h; import mage.abilities.Ability; @@ -6,7 +5,6 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.FilterCard; @@ -16,12 +14,12 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; import java.util.List; import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class HauntingEchoes extends CardImpl { @@ -63,9 +61,10 @@ class HauntingEchoesEffect extends OneShotEffect { if (!StaticFilters.FILTER_CARD_BASIC_LAND.match(card, game)) { card.moveToExile(null, "", source.getSourceId(), game); - FilterCard filterCard = new FilterCard("cards named " + card.getName()); - String nameToSearch = card.isSplitCard() ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName(); + String nameToSearch = CardUtil.getCardNameForSameNameSearch(card); + FilterCard filterCard = new FilterCard("cards named " + nameToSearch); filterCard.add(new NamePredicate(nameToSearch)); + int count = targetPlayer.getLibrary().count(filterCard, game); TargetCardInLibrary target = new TargetCardInLibrary(count, count, filterCard); diff --git a/Mage.Sets/src/mage/cards/i/InfernalTutor.java b/Mage.Sets/src/mage/cards/i/InfernalTutor.java index eb4b152f66..d87437eb94 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalTutor.java +++ b/Mage.Sets/src/mage/cards/i/InfernalTutor.java @@ -1,6 +1,5 @@ package mage.cards.i; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.condition.common.HellbentCondition; @@ -12,7 +11,6 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; -import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.FilterCard; @@ -23,9 +21,11 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class InfernalTutor extends CardImpl { @@ -89,7 +89,7 @@ class InfernalTutorEffect extends OneShotEffect { FilterCard filterCard; if (cardToReveal != null) { controller.revealCards("from hand :" + sourceObject.getName(), new CardsImpl(cardToReveal), game); - String nameToSearch = cardToReveal.isSplitCard() ? ((SplitCard) cardToReveal).getLeftHalfCard().getName() : cardToReveal.getName(); + String nameToSearch = CardUtil.getCardNameForSameNameSearch(cardToReveal); filterCard = new FilterCard("card named " + nameToSearch); filterCard.add(new NamePredicate(nameToSearch)); } else { diff --git a/Mage.Sets/src/mage/cards/j/JestersScepter.java b/Mage.Sets/src/mage/cards/j/JestersScepter.java index 88c08a6595..e476ccee0a 100644 --- a/Mage.Sets/src/mage/cards/j/JestersScepter.java +++ b/Mage.Sets/src/mage/cards/j/JestersScepter.java @@ -161,14 +161,15 @@ class JestersScepterCost extends CostImpl { Card card = game.getCard(target.getFirstTarget()); if (card != null) { if (controller.moveCardToGraveyardWithInfo(card, sourceId, game, Zone.EXILED)) { - // Split Card check if (card instanceof SplitCard) { game.getState().setValue(sourceId + "_nameOfExiledCardPayment", ((SplitCard) card).getLeftHalfCard().getName()); game.getState().setValue(sourceId + "_nameOfExiledCardPayment2", ((SplitCard) card).getRightHalfCard().getName()); - paid = true; - return paid; + } else if (card instanceof ModalDoubleFacesCard) { + game.getState().setValue(sourceId + "_nameOfExiledCardPayment", ((ModalDoubleFacesCard) card).getLeftHalfCard().getName()); + game.getState().setValue(sourceId + "_nameOfExiledCardPayment2", ((ModalDoubleFacesCard) card).getRightHalfCard().getName()); + } else { + game.getState().setValue(sourceId + "_nameOfExiledCardPayment", card.getName()); } - game.getState().setValue(sourceId + "_nameOfExiledCardPayment", card.getName()); paid = true; } } diff --git a/Mage.Sets/src/mage/cards/l/LiarsPendulum.java b/Mage.Sets/src/mage/cards/l/LiarsPendulum.java index e30258077d..078496adf9 100644 --- a/Mage.Sets/src/mage/cards/l/LiarsPendulum.java +++ b/Mage.Sets/src/mage/cards/l/LiarsPendulum.java @@ -8,7 +8,6 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.SplitCard; import mage.cards.repository.CardRepository; import mage.choices.Choice; import mage.choices.ChoiceImpl; @@ -85,14 +84,6 @@ class LiarsPendulumEffect extends OneShotEffect { boolean rightGuess = !opponentGuess; for (Card card : controller.getHand().getCards(game)) { - if (card.isSplitCard()) { - SplitCard splitCard = (SplitCard) card; - if (splitCard.getLeftHalfCard().getName().equals(cardName)) { - rightGuess = opponentGuess; - } else if (splitCard.getRightHalfCard().getName().equals(cardName)) { - rightGuess = opponentGuess; - } - } if (CardUtil.haveSameNames(card, cardName, game)) { rightGuess = opponentGuess; } diff --git a/Mage.Sets/src/mage/cards/l/Lobotomy.java b/Mage.Sets/src/mage/cards/l/Lobotomy.java index fd202a3171..48f2099601 100644 --- a/Mage.Sets/src/mage/cards/l/Lobotomy.java +++ b/Mage.Sets/src/mage/cards/l/Lobotomy.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -18,9 +16,11 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.TargetPlayer; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class Lobotomy extends CardImpl { @@ -83,8 +83,8 @@ class LobotomyEffect extends OneShotEffect { FilterCard filterNamedCards = new FilterCard(); String nameToSearch = "---";// so no card matches if (chosenCard != null) { - nameToSearch = chosenCard.isSplitCard() ? ((SplitCard) chosenCard).getLeftHalfCard().getName() : chosenCard.getName(); - filterNamedCards.setMessage("cards named " + chosenCard.getName()); + nameToSearch = CardUtil.getCardNameForSameNameSearch(chosenCard); + filterNamedCards.setMessage("cards named " + nameToSearch); } filterNamedCards.add(new NamePredicate(nameToSearch)); Cards cardsToExile = new CardsImpl(); diff --git a/Mage.Sets/src/mage/cards/m/Mindreaver.java b/Mage.Sets/src/mage/cards/m/Mindreaver.java index 83def79c22..f2fda1722e 100644 --- a/Mage.Sets/src/mage/cards/m/Mindreaver.java +++ b/Mage.Sets/src/mage/cards/m/Mindreaver.java @@ -1,9 +1,5 @@ - package mage.cards.m; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -16,30 +12,30 @@ import mage.abilities.keyword.HeroicAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.SplitCard; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.SpellAbilityType; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterSpell; import mage.filter.predicate.Predicate; import mage.game.ExileZone; import mage.game.Game; -import mage.game.stack.Spell; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.TargetSpell; import mage.util.CardUtil; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Mindreaver extends CardImpl { public Mindreaver(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -121,16 +117,7 @@ class MindreaverNamePredicate implements Predicate { cardNames.add(card.getName()); } } - // 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. - if (input instanceof SplitCard) { - return cardNames.contains(((SplitCard) input).getLeftHalfCard().getName()) || cardNames.contains(((SplitCard) input).getRightHalfCard().getName()); - } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { - SplitCard card = (SplitCard) ((Spell) input).getCard(); - return cardNames.contains(card.getLeftHalfCard().getName()) || cardNames.contains(card.getRightHalfCard().getName()); - } else { - return cardNames.contains(input.getName()); - } + return cardNames.stream().anyMatch(needName -> CardUtil.haveSameNames(input, needName, game)); } @Override diff --git a/Mage.Sets/src/mage/cards/p/PanopticMirror.java b/Mage.Sets/src/mage/cards/p/PanopticMirror.java index c0f6193e1d..ad2bc5cca5 100644 --- a/Mage.Sets/src/mage/cards/p/PanopticMirror.java +++ b/Mage.Sets/src/mage/cards/p/PanopticMirror.java @@ -1,6 +1,5 @@ package mage.cards.p; -import java.util.UUID; import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -9,11 +8,7 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.effects.OneShotEffect; import mage.cards.*; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; @@ -24,8 +19,9 @@ import mage.target.TargetCard; import mage.target.common.TargetCardInHand; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author Plopman */ public final class PanopticMirror extends CardImpl { @@ -83,7 +79,7 @@ class PanopticMirrorExileEffect extends OneShotEffect { } TargetCardInHand target = new TargetCardInHand(filter); - if (player.choose(outcome.PlayForFree, target, source.getSourceId(), game)) { + if (player.choose(Outcome.PlayForFree, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { card.moveToExile(CardUtil.getCardExileZoneId(game, source), "Panoptic Mirror", source.getSourceId(), game); @@ -129,9 +125,12 @@ class PanopticMirrorCastEffect extends OneShotEffect { for (UUID uuid : PanopticMirror.getImprinted()) { Card card = game.getCard(uuid); if (card != null) { - if (card.isSplitCard()) { + if (card instanceof SplitCard) { cards.add(((SplitCard) card).getLeftHalfCard()); cards.add(((SplitCard) card).getRightHalfCard()); + } else if (card instanceof ModalDoubleFacesCard) { + cards.add(((ModalDoubleFacesCard) card).getLeftHalfCard()); + cards.add(((ModalDoubleFacesCard) card).getRightHalfCard()); } else { cards.add(card); } @@ -147,7 +146,7 @@ class PanopticMirrorCastEffect extends OneShotEffect { } if (cardToCopy != null) { Card copy = game.copyCard(cardToCopy, source, source.getControllerId()); - if (controller.chooseUse(outcome.PlayForFree, "Cast the copied card without paying mana cost?", source, game)) { + if (controller.chooseUse(Outcome.PlayForFree, "Cast the copied card without paying mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + copy.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copy, game, true), game, true, new ApprovingObject(source, game)); diff --git a/Mage.Sets/src/mage/cards/p/ParallaxTide.java b/Mage.Sets/src/mage/cards/p/ParallaxTide.java index fe86166b11..a1dfb245f5 100644 --- a/Mage.Sets/src/mage/cards/p/ParallaxTide.java +++ b/Mage.Sets/src/mage/cards/p/ParallaxTide.java @@ -24,7 +24,6 @@ public final class ParallaxTide extends CardImpl { public ParallaxTide(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); - // Fading 5 this.addAbility(new FadingAbility(5, this)); @@ -34,7 +33,7 @@ public final class ParallaxTide extends CardImpl { this.addAbility(ability); // When Parallax Tide leaves the battlefield, each player returns to the battlefield all cards they own exiled with Parallax Tide. - this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), splitCard)); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false)); } public ParallaxTide(final ParallaxTide card) { diff --git a/Mage.Sets/src/mage/cards/r/ReapIntellect.java b/Mage.Sets/src/mage/cards/r/ReapIntellect.java index ed1a2671fb..b9f13f7281 100644 --- a/Mage.Sets/src/mage/cards/r/ReapIntellect.java +++ b/Mage.Sets/src/mage/cards/r/ReapIntellect.java @@ -12,16 +12,17 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; import mage.players.Player; +import mage.target.TargetCard; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + import java.util.ArrayList; import java.util.List; import java.util.UUID; -import mage.target.TargetCard; /** - * * @author jeffwadsworth */ public final class ReapIntellect extends CardImpl { @@ -100,12 +101,11 @@ class ReapIntellectEffect extends OneShotEffect { List names = new ArrayList<>(); FilterCard filterNamedCards = new FilterCard(); for (Card card : exiledCards.getCards(game)) { + String nameToSearch = CardUtil.getCardNameForSameNameSearch(card); if (exiledCards.size() == 1) { - filterNamedCards.add(new NamePredicate(card.isSplitCard() - ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName())); + filterNamedCards.add(new NamePredicate(nameToSearch)); } else { - names.add(new NamePredicate(card.isSplitCard() - ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName())); + names.add(new NamePredicate(nameToSearch)); } } if (exiledCards.size() > 1) { diff --git a/Mage.Sets/src/mage/cards/s/ScytheSpecter.java b/Mage.Sets/src/mage/cards/s/ScytheSpecter.java index 0726c64693..baf7877692 100644 --- a/Mage.Sets/src/mage/cards/s/ScytheSpecter.java +++ b/Mage.Sets/src/mage/cards/s/ScytheSpecter.java @@ -1,4 +1,3 @@ - package mage.cards.s; import mage.MageInt; @@ -11,8 +10,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; @@ -24,7 +23,6 @@ import java.util.Map; import java.util.UUID; /** - * * @author jeffwadsworth */ public final class ScytheSpecter extends CardImpl { @@ -80,13 +78,7 @@ class ScytheSpecterEffect extends OneShotEffect { opponent.chooseTarget(Outcome.Discard, target, source, game); Card targetCard = game.getCard(target.getFirstTarget()); if (targetCard != null) { - if (targetCard.isSplitCard()) { //check Split Cards - if (targetCard.getSecondCardFace().getConvertedManaCost() < targetCard.getConvertedManaCost()) { - currentCMC = targetCard.getConvertedManaCost(); - } - } else { - currentCMC = targetCard.getConvertedManaCost(); - } + currentCMC = targetCard.getConvertedManaCost(); if (highestCMC <= currentCMC) { highestCMC = currentCMC; } diff --git a/Mage.Sets/src/mage/cards/s/SecretSalvage.java b/Mage.Sets/src/mage/cards/s/SecretSalvage.java index 50495f98a5..b80ed6dc01 100644 --- a/Mage.Sets/src/mage/cards/s/SecretSalvage.java +++ b/Mage.Sets/src/mage/cards/s/SecretSalvage.java @@ -1,16 +1,9 @@ - package mage.cards.s; -import java.util.UUID; 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.Cards; -import mage.cards.CardsImpl; -import mage.cards.SplitCard; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -21,9 +14,11 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SecretSalvage extends CardImpl { @@ -72,9 +67,11 @@ class SecretSalvageEffect extends OneShotEffect { Card targetCard = game.getCard(getTargetPointer().getFirst(game, source)); if (targetCard != null) { controller.moveCards(targetCard, Zone.EXILED, source, game); + + String nameToSearch = CardUtil.getCardNameForSameNameSearch(targetCard); FilterCard nameFilter = new FilterCard(); - String nameToSearch = targetCard.isSplitCard() ? ((SplitCard) targetCard).getLeftHalfCard().getName() : targetCard.getName(); nameFilter.add(new NamePredicate(nameToSearch)); + TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, nameFilter); if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/s/ShimianSpecter.java b/Mage.Sets/src/mage/cards/s/ShimianSpecter.java index c5a82bc53a..d0bb35fc5f 100644 --- a/Mage.Sets/src/mage/cards/s/ShimianSpecter.java +++ b/Mage.Sets/src/mage/cards/s/ShimianSpecter.java @@ -1,6 +1,5 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -10,10 +9,9 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.SplitCard; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterNonlandCard; @@ -23,9 +21,11 @@ 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 jeffwadsworth */ public final class ShimianSpecter extends CardImpl { @@ -103,9 +103,7 @@ class ShimianSpecterEffect extends OneShotEffect { FilterCard filterNamedCards = new FilterCard(); String nameToSearch = "---";// so no card matches if (chosenCard != null) { - nameToSearch = chosenCard.isSplitCard() - ? ((SplitCard) chosenCard).getLeftHalfCard().getName() - : chosenCard.getName(); + nameToSearch = CardUtil.getCardNameForSameNameSearch(chosenCard); } filterNamedCards.add(new NamePredicate(nameToSearch)); diff --git a/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java b/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java index 5fd5de0fe7..228cc2d4b9 100644 --- a/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java +++ b/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java @@ -1,6 +1,5 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -11,11 +10,9 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.GainAbilitySpellsEffect; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.LifelinkAbility; -import mage.cards.AdventureCardSpell; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.SplitCardHalf; import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterObject; @@ -26,6 +23,8 @@ import mage.game.events.ZoneChangeEvent; import mage.game.stack.Spell; import mage.players.Player; +import java.util.UUID; + /** * @author LevelX2 */ @@ -142,15 +141,7 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect && event.getTargetId().equals(spellId)) { if (game.getStack().getFirst() instanceof Spell) { Card cardOfSpell = ((Spell) game.getStack().getFirst()).getCard(); - if (cardOfSpell instanceof SplitCardHalf) { - return ((SplitCardHalf) cardOfSpell).getParentCard().getId().equals(spellId); - } else if (cardOfSpell instanceof AdventureCardSpell) { - return (((AdventureCardSpell) cardOfSpell).getParentCard().getId().equals(spellId)); - } else { - if (cardOfSpell.getId().equals(spellId)) { - return true; - } - } + return cardOfSpell.getMainCard().getId().equals(spellId); } } } diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java b/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java index 07a1884826..ee2c3e2426 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java +++ b/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java @@ -16,6 +16,7 @@ import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; +import mage.util.CardUtil; import java.util.HashSet; import java.util.Map; @@ -108,10 +109,12 @@ class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand { } } else { for (UUID cardToCheck : cardsToCheck) { - FilterCard nameFilter = new FilterCard(); Card card = game.getCard(cardToCheck); if (card != null) { - nameFilter.add(new NamePredicate(card.isSplitCard() ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName())); + String nameToSearch = CardUtil.getCardNameForSameNameSearch(card); + FilterCard nameFilter = new FilterCard(); + nameFilter.add(new NamePredicate(nameToSearch)); + if (cardsToCheck.count(nameFilter, game) > 1) { newPossibleTargets.add(cardToCheck); } @@ -133,8 +136,10 @@ class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand { } int possibleCards = 0; for (Card card : cardsToCheck.getCards(game)) { + String nameToSearch = CardUtil.getCardNameForSameNameSearch(card); FilterCard nameFilter = new FilterCard(); - nameFilter.add(new NamePredicate(card.isSplitCard() ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName())); + nameFilter.add(new NamePredicate(nameToSearch)); + if (cardsToCheck.count(nameFilter, game) > 1) { ++possibleCards; } @@ -149,10 +154,12 @@ class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand { if (card != null) { if (targets.size() == 1) { Card card2 = game.getCard(targets.entrySet().iterator().next().getKey()); - return card2 != null && card2.getName().equals(card.getName()); + return CardUtil.haveSameNames(card2, card); } else { + String nameToSearch = CardUtil.getCardNameForSameNameSearch(card); FilterCard nameFilter = new FilterCard(); - nameFilter.add(new NamePredicate(card.isSplitCard() ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName())); + nameFilter.add(new NamePredicate(nameToSearch)); + Player player = game.getPlayer(card.getOwnerId()); return player != null && player.getHand().getCards(nameFilter, game).size() > 1; } diff --git a/Mage.Sets/src/mage/cards/s/SurgicalExtraction.java b/Mage.Sets/src/mage/cards/s/SurgicalExtraction.java index dbecb75abc..47c622f7b7 100644 --- a/Mage.Sets/src/mage/cards/s/SurgicalExtraction.java +++ b/Mage.Sets/src/mage/cards/s/SurgicalExtraction.java @@ -5,7 +5,6 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SuperType; @@ -15,12 +14,13 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; import mage.players.Player; +import mage.target.TargetCard; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; import java.util.List; import java.util.UUID; -import mage.target.TargetCard; /** * @author North @@ -82,8 +82,7 @@ class SurgicalExtractionEffect extends OneShotEffect { if (chosenCard != null && controller != null) { Player owner = game.getPlayer(chosenCard.getOwnerId()); if (owner != null) { - String nameToSearch = chosenCard.isSplitCard() - ? ((SplitCard) chosenCard).getLeftHalfCard().getName() : chosenCard.getName(); + String nameToSearch = CardUtil.getCardNameForSameNameSearch(chosenCard); FilterCard filterNamedCard = new FilterCard("card named " + nameToSearch); filterNamedCard.add(new NamePredicate(nameToSearch)); diff --git a/Mage.Sets/src/mage/cards/t/TamiyoCollectorOfTales.java b/Mage.Sets/src/mage/cards/t/TamiyoCollectorOfTales.java index ce2b23fde2..40a6d01f92 100644 --- a/Mage.Sets/src/mage/cards/t/TamiyoCollectorOfTales.java +++ b/Mage.Sets/src/mage/cards/t/TamiyoCollectorOfTales.java @@ -17,6 +17,7 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; import java.util.UUID; @@ -131,13 +132,7 @@ class TamiyoCollectorOfTalesEffect extends OneShotEffect { Cards cards2 = new CardsImpl(); player.revealCards(source, cards, game); for (Card card : cards.getCards(game)) { - if (card.isSplitCard()) { - if (((SplitCard) card).getLeftHalfCard().getName().equals(choice.getChoice()) - || ((SplitCard) card).getRightHalfCard().getName().equals(choice.getChoice())) { - cards2.add(card); - } - } - if (card.getName().equals(choice.getChoice())) { + if (CardUtil.haveSameNames(card, choice.getChoice(), game)) { cards2.add(card); } } diff --git a/Mage.Sets/src/mage/cards/u/UrzasHotTub.java b/Mage.Sets/src/mage/cards/u/UrzasHotTub.java index 6a816e8d97..2e20988c31 100644 --- a/Mage.Sets/src/mage/cards/u/UrzasHotTub.java +++ b/Mage.Sets/src/mage/cards/u/UrzasHotTub.java @@ -1,7 +1,5 @@ - package mage.cards.u; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -10,10 +8,7 @@ import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.SplitCard; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SpellAbilityType; @@ -25,14 +20,15 @@ import mage.game.stack.Spell; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author L_J */ public class UrzasHotTub extends CardImpl { public UrzasHotTub(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // {2}, Discard a card: Search your library for a card that shares a complete word in its name with the discarded card, reveal it, put it into your hand, then shuffle your library. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UrzasHotTubEffect(), new ManaCostsImpl("{2}")); @@ -95,21 +91,23 @@ class UrzasHotTubPredicate implements Predicate { public boolean apply(MageObject input, Game game) { String name = input.getName(); if (input instanceof SplitCard) { - return sharesWordWithName(((SplitCard)input).getLeftHalfCard().getName()) || sharesWordWithName(((SplitCard)input).getRightHalfCard().getName()); - } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED){ - SplitCard card = (SplitCard) ((Spell)input).getCard(); + return sharesWordWithName(((SplitCard) input).getLeftHalfCard().getName()) || sharesWordWithName(((SplitCard) input).getRightHalfCard().getName()); + } else if (input instanceof ModalDoubleFacesCard) { + return sharesWordWithName(((ModalDoubleFacesCard) input).getLeftHalfCard().getName()) || sharesWordWithName(((ModalDoubleFacesCard) input).getRightHalfCard().getName()); + } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { + SplitCard card = (SplitCard) ((Spell) input).getCard(); return sharesWordWithName(card.getLeftHalfCard().getName()) || sharesWordWithName(card.getRightHalfCard().getName()); } else { if (name.contains(" // ")) { String leftName = name.substring(0, name.indexOf(" // ")); - String rightName = name.substring(name.indexOf(" // ") + 4, name.length()); + String rightName = name.substring(name.indexOf(" // ") + 4); return sharesWordWithName(leftName) || sharesWordWithName(rightName); } else { return sharesWordWithName(name); } } } - + private boolean sharesWordWithName(String str) { if (referenceName == null || referenceName == "") { return false; diff --git a/Mage.Sets/src/mage/sets/ZendikarRising.java b/Mage.Sets/src/mage/sets/ZendikarRising.java index 4e2fcbf7c5..8185e0314c 100644 --- a/Mage.Sets/src/mage/sets/ZendikarRising.java +++ b/Mage.Sets/src/mage/sets/ZendikarRising.java @@ -1,94 +1,15 @@ package mage.sets; import mage.cards.ExpansionSet; +import mage.cards.a.AkoumWarrior; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.Arrays; -import java.util.List; - /** * @author TheElk801 */ public final class ZendikarRising extends ExpansionSet { - private static final List unfinishedLand = Arrays.asList( - "Agadeem, the Undercrypt", - "Akoum Teeth", - "Bala Ged Sanctuary", - "Beyeen Coast", - "Blackbloom Bog", - "Branchloft Pathway", - "Boulderloft Pathway", - "Brightclimb Pathway", - "Grimclimb Pathway", - "Clearwater Pathway", - "Murkwater Pathway", - "Cragcrown Pathway", - "Timbercrown Pathway", - "Emeria, Shattered Skyclave", - "Glasspool Shore", - "Hagra Broodpit", - "Jwari Ruins", - "Kabira Plateau", - "Kazandu Valley", - "Kazuul's Cliffs", - "Khalni Territory", - "Makindi Mesas", - "Malakir Mire", - "Needleverge Pathway", - "Pillarverge Pathway", - "Ondu Skyruins", - "Pelakka Caverns", - "Riverglide Pathway", - "Lavaglide Pathway", - "Sea Gate, Reborn", - "Sejiri Glacier", - "Shatterskull, the Hammer Pass", - "Silundi Isle", - "Skyclave Basilica", - "Song-Mad Ruins", - "Spikefield Cave", - "Tangled Vale", - "Turntimber, Serpentine Wood", - "Umara Skyfalls", - "Valakut Stoneforge", - "Vastwood Thicket", - "Zof Bloodbog" - ); - private static final List unfinishedNonland = Arrays.asList( - "Agadeem's Awakening", - "Akoum Warrior", - "Bala Ged Recovery", - "Beyeen Veil", - "Blackbloom Rogue", - "Emeria's Call", - "Glasspool Mimic", - "Hagra Mauling", - "Jwari Disruption", - "Kabira Takedown", - "Kazandu Mammoth", - "Kazuul's Fury", - "Khalni Ambush", - "Makindi Stampede", - "Malakir Rebirth", - "Ondu Inversion", - "Pelakka Predation", - "Sea Gate Restoration", - "Sejiri Shelter", - "Shatterskull Smashing", - "Silundi Vision", - "Skyclave Cleric", - "Song-Mad Treachery", - "Spikefield Hazard", - "Tangled Florahedron", - "Turntimber Symbiosis", - "Umara Wizard", - "Valakut Awakening", - "Vastwood Fortification", - "Zof Consumption" - ); - private static final ZendikarRising instance = new ZendikarRising(); public static ZendikarRising getInstance() { @@ -110,30 +31,20 @@ public final class ZendikarRising extends ExpansionSet { cards.add(new SetCardInfo("Acquisitions Expert", 89, Rarity.UNCOMMON, mage.cards.a.AcquisitionsExpert.class)); cards.add(new SetCardInfo("Adventure Awaits", 177, Rarity.COMMON, mage.cards.a.AdventureAwaits.class)); - cards.add(new SetCardInfo("Agadeem's Awakening", 336, Rarity.MYTHIC, mage.cards.a.AgadeemsAwakening.class)); cards.add(new SetCardInfo("Agadeem's Awakening", 90, Rarity.MYTHIC, mage.cards.a.AgadeemsAwakening.class)); - cards.add(new SetCardInfo("Agadeem, the Undercrypt", 336, Rarity.MYTHIC, mage.cards.a.AgadeemTheUndercrypt.class)); cards.add(new SetCardInfo("Agadeem, the Undercrypt", 90, Rarity.MYTHIC, mage.cards.a.AgadeemTheUndercrypt.class)); - cards.add(new SetCardInfo("Akiri, Fearless Voyager", 220, Rarity.RARE, mage.cards.a.AkiriFearlessVoyager.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Akiri, Fearless Voyager", 365, Rarity.RARE, mage.cards.a.AkiriFearlessVoyager.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Akoum Hellhound", 133, Rarity.COMMON, mage.cards.a.AkoumHellhound.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Akoum Hellhound", 299, Rarity.COMMON, mage.cards.a.AkoumHellhound.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Akoum Teeth", 134, Rarity.UNCOMMON, mage.cards.a.AkoumTeeth.class)); - cards.add(new SetCardInfo("Akoum Warrior", 134, Rarity.UNCOMMON, mage.cards.a.AkoumWarrior.class)); + cards.add(new SetCardInfo("Akiri, Fearless Voyager", 220, Rarity.RARE, mage.cards.a.AkiriFearlessVoyager.class)); + cards.add(new SetCardInfo("Akoum Hellhound", 133, Rarity.COMMON, mage.cards.a.AkoumHellhound.class)); + cards.add(new SetCardInfo("Akoum Warrior", 134, Rarity.UNCOMMON, AkoumWarrior.class)); cards.add(new SetCardInfo("Allied Assault", 1, Rarity.UNCOMMON, mage.cards.a.AlliedAssault.class)); - cards.add(new SetCardInfo("Ancient Greenwarden", 178, Rarity.MYTHIC, mage.cards.a.AncientGreenwarden.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ancient Greenwarden", 357, Rarity.MYTHIC, mage.cards.a.AncientGreenwarden.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Angel of Destiny", 2, Rarity.MYTHIC, mage.cards.a.AngelOfDestiny.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Angel of Destiny", 314, Rarity.MYTHIC, mage.cards.a.AngelOfDestiny.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ancient Greenwarden", 178, Rarity.MYTHIC, mage.cards.a.AncientGreenwarden.class)); + cards.add(new SetCardInfo("Angel of Destiny", 2, Rarity.MYTHIC, mage.cards.a.AngelOfDestiny.class)); cards.add(new SetCardInfo("Angelheart Protector", 3, Rarity.COMMON, mage.cards.a.AngelheartProtector.class)); cards.add(new SetCardInfo("Anticognition", 45, Rarity.COMMON, mage.cards.a.Anticognition.class)); - cards.add(new SetCardInfo("Archon of Emeria", 315, Rarity.RARE, mage.cards.a.ArchonOfEmeria.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Archon of Emeria", 4, Rarity.RARE, mage.cards.a.ArchonOfEmeria.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Archpriest of Iona", 316, Rarity.RARE, mage.cards.a.ArchpriestOfIona.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Archpriest of Iona", 5, Rarity.RARE, mage.cards.a.ArchpriestOfIona.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Archon of Emeria", 4, Rarity.RARE, mage.cards.a.ArchonOfEmeria.class)); + cards.add(new SetCardInfo("Archpriest of Iona", 5, Rarity.RARE, mage.cards.a.ArchpriestOfIona.class)); cards.add(new SetCardInfo("Ardent Electromancer", 135, Rarity.COMMON, mage.cards.a.ArdentElectromancer.class)); - cards.add(new SetCardInfo("Ashaya, Soul of the Wild", 179, Rarity.MYTHIC, mage.cards.a.AshayaSoulOfTheWild.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ashaya, Soul of the Wild", 358, Rarity.MYTHIC, mage.cards.a.AshayaSoulOfTheWild.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ashaya, Soul of the Wild", 179, Rarity.MYTHIC, mage.cards.a.AshayaSoulOfTheWild.class)); cards.add(new SetCardInfo("Attended Healer", 6, Rarity.UNCOMMON, mage.cards.a.AttendedHealer.class)); cards.add(new SetCardInfo("Bala Ged Recovery", 180, Rarity.UNCOMMON, mage.cards.b.BalaGedRecovery.class)); cards.add(new SetCardInfo("Bala Ged Sanctuary", 180, Rarity.UNCOMMON, mage.cards.b.BalaGedSanctuary.class)); @@ -144,48 +55,32 @@ public final class ZendikarRising extends ExpansionSet { cards.add(new SetCardInfo("Blackbloom Rogue", 91, Rarity.UNCOMMON, mage.cards.b.BlackbloomRogue.class)); cards.add(new SetCardInfo("Blood Beckoning", 92, Rarity.COMMON, mage.cards.b.BloodBeckoning.class)); cards.add(new SetCardInfo("Blood Price", 93, Rarity.COMMON, mage.cards.b.BloodPrice.class)); - cards.add(new SetCardInfo("Bloodchief's Thirst", 388, Rarity.UNCOMMON, mage.cards.b.BloodchiefsThirst.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bloodchief's Thirst", 94, Rarity.UNCOMMON, mage.cards.b.BloodchiefsThirst.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bloodchief's Thirst", 94, Rarity.UNCOMMON, mage.cards.b.BloodchiefsThirst.class)); cards.add(new SetCardInfo("Boulderloft Pathway", 258, Rarity.RARE, mage.cards.b.BoulderloftPathway.class)); - cards.add(new SetCardInfo("Boulderloft Pathway", 284, Rarity.RARE, mage.cards.b.BoulderloftPathway.class)); cards.add(new SetCardInfo("Branchloft Pathway", 258, Rarity.RARE, mage.cards.b.BranchloftPathway.class)); - cards.add(new SetCardInfo("Branchloft Pathway", 284, Rarity.RARE, mage.cards.b.BranchloftPathway.class)); cards.add(new SetCardInfo("Brightclimb Pathway", 259, Rarity.RARE, mage.cards.b.BrightclimbPathway.class)); - cards.add(new SetCardInfo("Brightclimb Pathway", 285, Rarity.RARE, mage.cards.b.BrightclimbPathway.class)); cards.add(new SetCardInfo("Broken Wings", 181, Rarity.COMMON, mage.cards.b.BrokenWings.class)); - cards.add(new SetCardInfo("Brushfire Elemental", 221, Rarity.UNCOMMON, mage.cards.b.BrushfireElemental.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Brushfire Elemental", 311, Rarity.UNCOMMON, mage.cards.b.BrushfireElemental.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Brushfire Elemental", 221, Rarity.UNCOMMON, mage.cards.b.BrushfireElemental.class)); cards.add(new SetCardInfo("Bubble Snare", 47, Rarity.COMMON, mage.cards.b.BubbleSnare.class)); - cards.add(new SetCardInfo("Canopy Baloth", 182, Rarity.COMMON, mage.cards.c.CanopyBaloth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Canopy Baloth", 304, Rarity.COMMON, mage.cards.c.CanopyBaloth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Canyon Jerboa", 290, Rarity.UNCOMMON, mage.cards.c.CanyonJerboa.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Canyon Jerboa", 7, Rarity.UNCOMMON, mage.cards.c.CanyonJerboa.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Canopy Baloth", 182, Rarity.COMMON, mage.cards.c.CanopyBaloth.class)); + cards.add(new SetCardInfo("Canyon Jerboa", 7, Rarity.UNCOMMON, mage.cards.c.CanyonJerboa.class)); cards.add(new SetCardInfo("Cascade Seer", 48, Rarity.COMMON, mage.cards.c.CascadeSeer.class)); - cards.add(new SetCardInfo("Charix, the Raging Isle", 325, Rarity.RARE, mage.cards.c.CharixTheRagingIsle.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Charix, the Raging Isle", 386, Rarity.RARE, mage.cards.c.CharixTheRagingIsle.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Charix, the Raging Isle", 49, Rarity.RARE, mage.cards.c.CharixTheRagingIsle.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Charix, the Raging Isle", 49, Rarity.RARE, mage.cards.c.CharixTheRagingIsle.class)); cards.add(new SetCardInfo("Chilling Trap", 50, Rarity.COMMON, mage.cards.c.ChillingTrap.class)); cards.add(new SetCardInfo("Cinderclasm", 136, Rarity.UNCOMMON, mage.cards.c.Cinderclasm.class)); cards.add(new SetCardInfo("Cleansing Wildfire", 137, Rarity.COMMON, mage.cards.c.CleansingWildfire.class)); cards.add(new SetCardInfo("Clearwater Pathway", 260, Rarity.RARE, mage.cards.c.ClearwaterPathway.class)); - cards.add(new SetCardInfo("Clearwater Pathway", 286, Rarity.RARE, mage.cards.c.ClearwaterPathway.class)); cards.add(new SetCardInfo("Cleric of Chill Depths", 51, Rarity.COMMON, mage.cards.c.ClericOfChillDepths.class)); cards.add(new SetCardInfo("Cleric of Life's Bond", 222, Rarity.UNCOMMON, mage.cards.c.ClericOfLifesBond.class)); cards.add(new SetCardInfo("Cliffhaven Kitesail", 243, Rarity.COMMON, mage.cards.c.CliffhavenKitesail.class)); cards.add(new SetCardInfo("Cliffhaven Sell-Sword", 8, Rarity.COMMON, mage.cards.c.CliffhavenSellSword.class)); cards.add(new SetCardInfo("Concerted Defense", 52, Rarity.UNCOMMON, mage.cards.c.ConcertedDefense.class)); - cards.add(new SetCardInfo("Confounding Conundrum", 326, Rarity.RARE, mage.cards.c.ConfoundingConundrum.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Confounding Conundrum", 53, Rarity.RARE, mage.cards.c.ConfoundingConundrum.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Coralhelm Chronicler", 327, Rarity.RARE, mage.cards.c.CoralhelmChronicler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Coralhelm Chronicler", 54, Rarity.RARE, mage.cards.c.CoralhelmChronicler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Coveted Prize", 337, Rarity.RARE, mage.cards.c.CovetedPrize.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Coveted Prize", 95, Rarity.RARE, mage.cards.c.CovetedPrize.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Confounding Conundrum", 53, Rarity.RARE, mage.cards.c.ConfoundingConundrum.class)); + cards.add(new SetCardInfo("Coralhelm Chronicler", 54, Rarity.RARE, mage.cards.c.CoralhelmChronicler.class)); + cards.add(new SetCardInfo("Coveted Prize", 95, Rarity.RARE, mage.cards.c.CovetedPrize.class)); cards.add(new SetCardInfo("Cragcrown Pathway", 261, Rarity.RARE, mage.cards.c.CragcrownPathway.class)); - cards.add(new SetCardInfo("Cragcrown Pathway", 287, Rarity.RARE, mage.cards.c.CragcrownPathway.class)); - cards.add(new SetCardInfo("Cragplate Baloth", 183, Rarity.RARE, mage.cards.c.CragplateBaloth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cragplate Baloth", 359, Rarity.RARE, mage.cards.c.CragplateBaloth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Crawling Barrens", 262, Rarity.RARE, mage.cards.c.CrawlingBarrens.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Crawling Barrens", 378, Rarity.RARE, mage.cards.c.CrawlingBarrens.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cragplate Baloth", 183, Rarity.RARE, mage.cards.c.CragplateBaloth.class)); + cards.add(new SetCardInfo("Crawling Barrens", 262, Rarity.RARE, mage.cards.c.CrawlingBarrens.class)); cards.add(new SetCardInfo("Cunning Geysermage", 55, Rarity.COMMON, mage.cards.c.CunningGeysermage.class)); cards.add(new SetCardInfo("Dauntless Survivor", 184, Rarity.COMMON, mage.cards.d.DauntlessSurvivor.class)); cards.add(new SetCardInfo("Dauntless Unity", 9, Rarity.COMMON, mage.cards.d.DauntlessUnity.class)); @@ -194,71 +89,47 @@ public final class ZendikarRising extends ExpansionSet { cards.add(new SetCardInfo("Demon's Disciple", 97, Rarity.UNCOMMON, mage.cards.d.DemonsDisciple.class)); cards.add(new SetCardInfo("Disenchant", 10, Rarity.COMMON, mage.cards.d.Disenchant.class)); cards.add(new SetCardInfo("Drana's Silencer", 99, Rarity.COMMON, mage.cards.d.DranasSilencer.class)); - cards.add(new SetCardInfo("Drana, the Last Bloodchief", 338, Rarity.MYTHIC, mage.cards.d.DranaTheLastBloodchief.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Drana, the Last Bloodchief", 98, Rarity.MYTHIC, mage.cards.d.DranaTheLastBloodchief.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dreadwurm", 100, Rarity.COMMON, mage.cards.d.Dreadwurm.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dreadwurm", 297, Rarity.COMMON, mage.cards.d.Dreadwurm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Drana, the Last Bloodchief", 98, Rarity.MYTHIC, mage.cards.d.DranaTheLastBloodchief.class)); + cards.add(new SetCardInfo("Dreadwurm", 100, Rarity.COMMON, mage.cards.d.Dreadwurm.class)); cards.add(new SetCardInfo("Emeria Captain", 11, Rarity.UNCOMMON, mage.cards.e.EmeriaCaptain.class)); cards.add(new SetCardInfo("Emeria's Call", 12, Rarity.MYTHIC, mage.cards.e.EmeriasCall.class)); - cards.add(new SetCardInfo("Emeria's Call", 317, Rarity.MYTHIC, mage.cards.e.EmeriasCall.class)); cards.add(new SetCardInfo("Emeria, Shattered Skyclave", 12, Rarity.MYTHIC, mage.cards.e.EmeriaShatteredSkyclave.class)); - cards.add(new SetCardInfo("Emeria, Shattered Skyclave", 317, Rarity.MYTHIC, mage.cards.e.EmeriaShatteredSkyclave.class)); cards.add(new SetCardInfo("Expedition Champion", 138, Rarity.COMMON, mage.cards.e.ExpeditionChampion.class)); cards.add(new SetCardInfo("Expedition Diviner", 57, Rarity.COMMON, mage.cards.e.ExpeditionDiviner.class)); cards.add(new SetCardInfo("Expedition Healer", 13, Rarity.COMMON, mage.cards.e.ExpeditionHealer.class)); cards.add(new SetCardInfo("Expedition Skulker", 101, Rarity.COMMON, mage.cards.e.ExpeditionSkulker.class)); cards.add(new SetCardInfo("Farsight Adept", 14, Rarity.COMMON, mage.cards.f.FarsightAdept.class)); - cards.add(new SetCardInfo("Fearless Fledgling", 15, Rarity.UNCOMMON, mage.cards.f.FearlessFledgling.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fearless Fledgling", 291, Rarity.UNCOMMON, mage.cards.f.FearlessFledgling.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fearless Fledgling", 15, Rarity.UNCOMMON, mage.cards.f.FearlessFledgling.class)); cards.add(new SetCardInfo("Feed the Swarm", 102, Rarity.COMMON, mage.cards.f.FeedTheSwarm.class)); - cards.add(new SetCardInfo("Felidar Retreat", 16, Rarity.RARE, mage.cards.f.FelidarRetreat.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Felidar Retreat", 292, Rarity.RARE, mage.cards.f.FelidarRetreat.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Felidar Retreat", 16, Rarity.RARE, mage.cards.f.FelidarRetreat.class)); cards.add(new SetCardInfo("Field Research", 58, Rarity.COMMON, mage.cards.f.FieldResearch.class)); cards.add(new SetCardInfo("Fireblade Charger", 139, Rarity.UNCOMMON, mage.cards.f.FirebladeCharger.class)); cards.add(new SetCardInfo("Fissure Wizard", 140, Rarity.COMMON, mage.cards.f.FissureWizard.class)); cards.add(new SetCardInfo("Forest", 278, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Forest", 279, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Forest", 280, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Forest", 384, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Forsaken Monument", 244, Rarity.MYTHIC, mage.cards.f.ForsakenMonument.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forsaken Monument", 374, Rarity.MYTHIC, mage.cards.f.ForsakenMonument.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forsaken Monument", 244, Rarity.MYTHIC, mage.cards.f.ForsakenMonument.class)); cards.add(new SetCardInfo("Ghastly Gloomhunter", 103, Rarity.COMMON, mage.cards.g.GhastlyGloomhunter.class)); cards.add(new SetCardInfo("Glacial Grasp", 59, Rarity.COMMON, mage.cards.g.GlacialGrasp.class)); - cards.add(new SetCardInfo("Glasspool Mimic", 328, Rarity.RARE, mage.cards.g.GlasspoolMimic.class)); cards.add(new SetCardInfo("Glasspool Mimic", 60, Rarity.RARE, mage.cards.g.GlasspoolMimic.class)); - cards.add(new SetCardInfo("Glasspool Shore", 328, Rarity.RARE, mage.cards.g.GlasspoolShore.class)); cards.add(new SetCardInfo("Glasspool Shore", 60, Rarity.RARE, mage.cards.g.GlasspoolShore.class)); cards.add(new SetCardInfo("Gnarlid Colony", 185, Rarity.COMMON, mage.cards.g.GnarlidColony.class)); cards.add(new SetCardInfo("Goma Fada Vanguard", 141, Rarity.UNCOMMON, mage.cards.g.GomaFadaVanguard.class)); - cards.add(new SetCardInfo("Grakmaw, Skyclave Ravager", 223, Rarity.RARE, mage.cards.g.GrakmawSkyclaveRavager.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Grakmaw, Skyclave Ravager", 366, Rarity.RARE, mage.cards.g.GrakmawSkyclaveRavager.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Grakmaw, Skyclave Ravager", 223, Rarity.RARE, mage.cards.g.GrakmawSkyclaveRavager.class)); cards.add(new SetCardInfo("Grimclimb Pathway", 259, Rarity.RARE, mage.cards.g.GrimclimbPathway.class)); - cards.add(new SetCardInfo("Grimclimb Pathway", 285, Rarity.RARE, mage.cards.g.GrimclimbPathway.class)); cards.add(new SetCardInfo("Grotag Bug-Catcher", 142, Rarity.COMMON, mage.cards.g.GrotagBugCatcher.class)); cards.add(new SetCardInfo("Grotag Night-Runner", 143, Rarity.UNCOMMON, mage.cards.g.GrotagNightRunner.class)); cards.add(new SetCardInfo("Guul Draz Mucklord", 104, Rarity.COMMON, mage.cards.g.GuulDrazMucklord.class)); cards.add(new SetCardInfo("Hagra Broodpit", 106, Rarity.RARE, mage.cards.h.HagraBroodpit.class)); - cards.add(new SetCardInfo("Hagra Broodpit", 339, Rarity.RARE, mage.cards.h.HagraBroodpit.class)); cards.add(new SetCardInfo("Hagra Constrictor", 105, Rarity.COMMON, mage.cards.h.HagraConstrictor.class)); cards.add(new SetCardInfo("Hagra Mauling", 106, Rarity.RARE, mage.cards.h.HagraMauling.class)); - cards.add(new SetCardInfo("Hagra Mauling", 339, Rarity.RARE, mage.cards.h.HagraMauling.class)); cards.add(new SetCardInfo("Highborn Vampire", 107, Rarity.COMMON, mage.cards.h.HighbornVampire.class)); cards.add(new SetCardInfo("Inordinate Rage", 144, Rarity.COMMON, mage.cards.i.InordinateRage.class)); - cards.add(new SetCardInfo("Inscription of Abundance", 186, Rarity.RARE, mage.cards.i.InscriptionOfAbundance.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Inscription of Abundance", 360, Rarity.RARE, mage.cards.i.InscriptionOfAbundance.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Inscription of Insight", 329, Rarity.RARE, mage.cards.i.InscriptionOfInsight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Inscription of Insight", 61, Rarity.RARE, mage.cards.i.InscriptionOfInsight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Inscription of Ruin", 108, Rarity.RARE, mage.cards.i.InscriptionOfRuin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Inscription of Ruin", 340, Rarity.RARE, mage.cards.i.InscriptionOfRuin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Into the Roil", 387, Rarity.COMMON, mage.cards.i.IntoTheRoil.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Into the Roil", 62, Rarity.COMMON, mage.cards.i.IntoTheRoil.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Inscription of Abundance", 186, Rarity.RARE, mage.cards.i.InscriptionOfAbundance.class)); + cards.add(new SetCardInfo("Inscription of Insight", 61, Rarity.RARE, mage.cards.i.InscriptionOfInsight.class)); + cards.add(new SetCardInfo("Inscription of Ruin", 108, Rarity.RARE, mage.cards.i.InscriptionOfRuin.class)); + cards.add(new SetCardInfo("Into the Roil", 62, Rarity.COMMON, mage.cards.i.IntoTheRoil.class)); cards.add(new SetCardInfo("Iridescent Hornbeetle", 187, Rarity.UNCOMMON, mage.cards.i.IridescentHornbeetle.class)); cards.add(new SetCardInfo("Island", 269, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Island", 270, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Island", 271, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Island", 381, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Jace, Mirror Mage", 281, Rarity.MYTHIC, mage.cards.j.JaceMirrorMage.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jace, Mirror Mage", 63, Rarity.MYTHIC, mage.cards.j.JaceMirrorMage.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jace, Mirror Mage", 63, Rarity.MYTHIC, mage.cards.j.JaceMirrorMage.class)); cards.add(new SetCardInfo("Joraga Visionary", 188, Rarity.COMMON, mage.cards.j.JoragaVisionary.class)); cards.add(new SetCardInfo("Journey to Oblivion", 17, Rarity.UNCOMMON, mage.cards.j.JourneyToOblivion.class)); cards.add(new SetCardInfo("Jwari Disruption", 64, Rarity.UNCOMMON, mage.cards.j.JwariDisruption.class)); @@ -266,19 +137,13 @@ public final class ZendikarRising extends ExpansionSet { cards.add(new SetCardInfo("Kabira Outrider", 18, Rarity.COMMON, mage.cards.k.KabiraOutrider.class)); cards.add(new SetCardInfo("Kabira Plateau", 19, Rarity.UNCOMMON, mage.cards.k.KabiraPlateau.class)); cards.add(new SetCardInfo("Kabira Takedown", 19, Rarity.UNCOMMON, mage.cards.k.KabiraTakedown.class)); - cards.add(new SetCardInfo("Kargan Intimidator", 145, Rarity.RARE, mage.cards.k.KarganIntimidator.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kargan Intimidator", 347, Rarity.RARE, mage.cards.k.KarganIntimidator.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kargan Warleader", 224, Rarity.UNCOMMON, mage.cards.k.KarganWarleader.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kargan Warleader", 391, Rarity.UNCOMMON, mage.cards.k.KarganWarleader.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kaza, Roil Chaser", 225, Rarity.RARE, mage.cards.k.KazaRoilChaser.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kaza, Roil Chaser", 367, Rarity.RARE, mage.cards.k.KazaRoilChaser.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kargan Intimidator", 145, Rarity.RARE, mage.cards.k.KarganIntimidator.class)); + cards.add(new SetCardInfo("Kargan Warleader", 224, Rarity.UNCOMMON, mage.cards.k.KarganWarleader.class)); + cards.add(new SetCardInfo("Kaza, Roil Chaser", 225, Rarity.RARE, mage.cards.k.KazaRoilChaser.class)); cards.add(new SetCardInfo("Kazandu Mammoth", 189, Rarity.RARE, mage.cards.k.KazanduMammoth.class)); - cards.add(new SetCardInfo("Kazandu Mammoth", 305, Rarity.RARE, mage.cards.k.KazanduMammoth.class)); - cards.add(new SetCardInfo("Kazandu Nectarpot", 190, Rarity.COMMON, mage.cards.k.KazanduNectarpot.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kazandu Nectarpot", 306, Rarity.COMMON, mage.cards.k.KazanduNectarpot.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kazandu Nectarpot", 190, Rarity.COMMON, mage.cards.k.KazanduNectarpot.class)); cards.add(new SetCardInfo("Kazandu Stomper", 191, Rarity.COMMON, mage.cards.k.KazanduStomper.class)); cards.add(new SetCardInfo("Kazandu Valley", 189, Rarity.RARE, mage.cards.k.KazanduValley.class)); - cards.add(new SetCardInfo("Kazandu Valley", 305, Rarity.RARE, mage.cards.k.KazanduValley.class)); cards.add(new SetCardInfo("Kazuul's Cliffs", 146, Rarity.UNCOMMON, mage.cards.k.KazuulsCliffs.class)); cards.add(new SetCardInfo("Kazuul's Fury", 146, Rarity.UNCOMMON, mage.cards.k.KazuulsFury.class)); cards.add(new SetCardInfo("Khalni Ambush", 192, Rarity.UNCOMMON, mage.cards.k.KhalniAmbush.class)); @@ -287,39 +152,26 @@ public final class ZendikarRising extends ExpansionSet { cards.add(new SetCardInfo("Kor Blademaster", 21, Rarity.UNCOMMON, mage.cards.k.KorBlademaster.class)); cards.add(new SetCardInfo("Kor Celebrant", 22, Rarity.COMMON, mage.cards.k.KorCelebrant.class)); cards.add(new SetCardInfo("Lavaglide Pathway", 264, Rarity.RARE, mage.cards.l.LavaglidePathway.class)); - cards.add(new SetCardInfo("Lavaglide Pathway", 289, Rarity.RARE, mage.cards.l.LavaglidePathway.class)); - cards.add(new SetCardInfo("Legion Angel", 23, Rarity.RARE, mage.cards.l.LegionAngel.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Legion Angel", 318, Rarity.RARE, mage.cards.l.LegionAngel.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Leyline Tyrant", 147, Rarity.MYTHIC, mage.cards.l.LeylineTyrant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Leyline Tyrant", 348, Rarity.MYTHIC, mage.cards.l.LeylineTyrant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Linvala, Shield of Sea Gate", 226, Rarity.RARE, mage.cards.l.LinvalaShieldOfSeaGate.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Linvala, Shield of Sea Gate", 368, Rarity.RARE, mage.cards.l.LinvalaShieldOfSeaGate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Legion Angel", 23, Rarity.RARE, mage.cards.l.LegionAngel.class)); + cards.add(new SetCardInfo("Leyline Tyrant", 147, Rarity.MYTHIC, mage.cards.l.LeylineTyrant.class)); + cards.add(new SetCardInfo("Linvala, Shield of Sea Gate", 226, Rarity.RARE, mage.cards.l.LinvalaShieldOfSeaGate.class)); cards.add(new SetCardInfo("Lithoform Blight", 109, Rarity.UNCOMMON, mage.cards.l.LithoformBlight.class)); - cards.add(new SetCardInfo("Lithoform Engine", 245, Rarity.MYTHIC, mage.cards.l.LithoformEngine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lithoform Engine", 375, Rarity.MYTHIC, mage.cards.l.LithoformEngine.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Living Tempest", 65, Rarity.COMMON, mage.cards.l.LivingTempest.class)); - cards.add(new SetCardInfo("Lotus Cobra", 193, Rarity.RARE, mage.cards.l.LotusCobra.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lotus Cobra", 307, Rarity.RARE, mage.cards.l.LotusCobra.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lotus Cobra", 193, Rarity.RARE, mage.cards.l.LotusCobra.class)); cards.add(new SetCardInfo("Lullmage's Domination", 66, Rarity.UNCOMMON, mage.cards.l.LullmagesDomination.class)); cards.add(new SetCardInfo("Lullmage's Familiar", 227, Rarity.UNCOMMON, mage.cards.l.LullmagesFamiliar.class)); - cards.add(new SetCardInfo("Luminarch Aspirant", 24, Rarity.RARE, mage.cards.l.LuminarchAspirant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Luminarch Aspirant", 319, Rarity.RARE, mage.cards.l.LuminarchAspirant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Maddening Cacophony", 330, Rarity.RARE, mage.cards.m.MaddeningCacophony.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Maddening Cacophony", 67, Rarity.RARE, mage.cards.m.MaddeningCacophony.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Magmatic Channeler", 148, Rarity.RARE, mage.cards.m.MagmaticChanneler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Magmatic Channeler", 349, Rarity.RARE, mage.cards.m.MagmaticChanneler.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Luminarch Aspirant", 24, Rarity.RARE, mage.cards.l.LuminarchAspirant.class)); + cards.add(new SetCardInfo("Maddening Cacophony", 67, Rarity.RARE, mage.cards.m.MaddeningCacophony.class)); + cards.add(new SetCardInfo("Magmatic Channeler", 148, Rarity.RARE, mage.cards.m.MagmaticChanneler.class)); cards.add(new SetCardInfo("Makindi Mesas", 26, Rarity.UNCOMMON, mage.cards.m.MakindiMesas.class)); - cards.add(new SetCardInfo("Makindi Ox", 25, Rarity.COMMON, mage.cards.m.MakindiOx.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Makindi Ox", 293, Rarity.COMMON, mage.cards.m.MakindiOx.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Makindi Ox", 25, Rarity.COMMON, mage.cards.m.MakindiOx.class)); cards.add(new SetCardInfo("Makindi Stampede", 26, Rarity.UNCOMMON, mage.cards.m.MakindiStampede.class)); cards.add(new SetCardInfo("Malakir Blood-Priest", 110, Rarity.COMMON, mage.cards.m.MalakirBloodPriest.class)); cards.add(new SetCardInfo("Malakir Mire", 111, Rarity.UNCOMMON, mage.cards.m.MalakirMire.class)); cards.add(new SetCardInfo("Malakir Rebirth", 111, Rarity.UNCOMMON, mage.cards.m.MalakirRebirth.class)); cards.add(new SetCardInfo("Marauding Blight-Priest", 112, Rarity.COMMON, mage.cards.m.MaraudingBlightPriest.class)); - cards.add(new SetCardInfo("Master of Winds", 331, Rarity.RARE, mage.cards.m.MasterOfWinds.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Master of Winds", 68, Rarity.RARE, mage.cards.m.MasterOfWinds.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Maul of the Skyclaves", 27, Rarity.RARE, mage.cards.m.MaulOfTheSkyclaves.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Maul of the Skyclaves", 320, Rarity.RARE, mage.cards.m.MaulOfTheSkyclaves.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Master of Winds", 68, Rarity.RARE, mage.cards.m.MasterOfWinds.class)); + cards.add(new SetCardInfo("Maul of the Skyclaves", 27, Rarity.RARE, mage.cards.m.MaulOfTheSkyclaves.class)); cards.add(new SetCardInfo("Merfolk Falconer", 69, Rarity.UNCOMMON, mage.cards.m.MerfolkFalconer.class)); cards.add(new SetCardInfo("Merfolk Windrobber", 70, Rarity.UNCOMMON, mage.cards.m.MerfolkWindrobber.class)); cards.add(new SetCardInfo("Mesa Lynx", 28, Rarity.COMMON, mage.cards.m.MesaLynx.class)); @@ -327,66 +179,41 @@ public final class ZendikarRising extends ExpansionSet { cards.add(new SetCardInfo("Mind Carver", 113, Rarity.UNCOMMON, mage.cards.m.MindCarver.class)); cards.add(new SetCardInfo("Mind Drain", 114, Rarity.COMMON, mage.cards.m.MindDrain.class)); cards.add(new SetCardInfo("Molten Blast", 149, Rarity.COMMON, mage.cards.m.MoltenBlast.class)); - cards.add(new SetCardInfo("Moraug, Fury of Akoum", 150, Rarity.MYTHIC, mage.cards.m.MoraugFuryOfAkoum.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Moraug, Fury of Akoum", 300, Rarity.MYTHIC, mage.cards.m.MoraugFuryOfAkoum.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Moraug, Fury of Akoum", 150, Rarity.MYTHIC, mage.cards.m.MoraugFuryOfAkoum.class)); cards.add(new SetCardInfo("Moss-Pit Skeleton", 228, Rarity.UNCOMMON, mage.cards.m.MossPitSkeleton.class)); cards.add(new SetCardInfo("Mountain", 275, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 276, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 277, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 383, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Murasa Brute", 195, Rarity.COMMON, mage.cards.m.MurasaBrute.class)); cards.add(new SetCardInfo("Murasa Rootgrazer", 229, Rarity.UNCOMMON, mage.cards.m.MurasaRootgrazer.class)); cards.add(new SetCardInfo("Murasa Sproutling", 196, Rarity.UNCOMMON, mage.cards.m.MurasaSproutling.class)); cards.add(new SetCardInfo("Murkwater Pathway", 260, Rarity.RARE, mage.cards.m.MurkwaterPathway.class)); - cards.add(new SetCardInfo("Murkwater Pathway", 286, Rarity.RARE, mage.cards.m.MurkwaterPathway.class)); - cards.add(new SetCardInfo("Myriad Construct", 246, Rarity.RARE, mage.cards.m.MyriadConstruct.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Myriad Construct", 376, Rarity.RARE, mage.cards.m.MyriadConstruct.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myriad Construct", 246, Rarity.RARE, mage.cards.m.MyriadConstruct.class)); cards.add(new SetCardInfo("Nahiri's Binding", 29, Rarity.COMMON, mage.cards.n.NahirisBinding.class)); - cards.add(new SetCardInfo("Nahiri's Lithoforming", 151, Rarity.RARE, mage.cards.n.NahirisLithoforming.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nahiri's Lithoforming", 350, Rarity.RARE, mage.cards.n.NahirisLithoforming.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nahiri, Heir of the Ancients", 230, Rarity.MYTHIC, mage.cards.n.NahiriHeirOfTheAncients.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nahiri, Heir of the Ancients", 282, Rarity.MYTHIC, mage.cards.n.NahiriHeirOfTheAncients.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nahiri's Lithoforming", 151, Rarity.RARE, mage.cards.n.NahirisLithoforming.class)); + cards.add(new SetCardInfo("Nahiri, Heir of the Ancients", 230, Rarity.MYTHIC, mage.cards.n.NahiriHeirOfTheAncients.class)); cards.add(new SetCardInfo("Needleverge Pathway", 263, Rarity.RARE, mage.cards.n.NeedlevergePathway.class)); - cards.add(new SetCardInfo("Needleverge Pathway", 288, Rarity.RARE, mage.cards.n.NeedlevergePathway.class)); cards.add(new SetCardInfo("Negate", 71, Rarity.COMMON, mage.cards.n.Negate.class)); - cards.add(new SetCardInfo("Nighthawk Scavenger", 115, Rarity.RARE, mage.cards.n.NighthawkScavenger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nighthawk Scavenger", 341, Rarity.RARE, mage.cards.n.NighthawkScavenger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nighthawk Scavenger", 115, Rarity.RARE, mage.cards.n.NighthawkScavenger.class)); cards.add(new SetCardInfo("Nimana Skitter-Sneak", 116, Rarity.COMMON, mage.cards.n.NimanaSkitterSneak.class)); cards.add(new SetCardInfo("Nimana Skydancer", 117, Rarity.COMMON, mage.cards.n.NimanaSkydancer.class)); - cards.add(new SetCardInfo("Nimble Trapfinder", 332, Rarity.RARE, mage.cards.n.NimbleTrapfinder.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nimble Trapfinder", 72, Rarity.RARE, mage.cards.n.NimbleTrapfinder.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nissa of Shadowed Boughs", 231, Rarity.MYTHIC, mage.cards.n.NissaOfShadowedBoughs.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nissa of Shadowed Boughs", 283, Rarity.MYTHIC, mage.cards.n.NissaOfShadowedBoughs.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nimble Trapfinder", 72, Rarity.RARE, mage.cards.n.NimbleTrapfinder.class)); + cards.add(new SetCardInfo("Nissa of Shadowed Boughs", 231, Rarity.MYTHIC, mage.cards.n.NissaOfShadowedBoughs.class)); cards.add(new SetCardInfo("Nissa's Zendikon", 197, Rarity.COMMON, mage.cards.n.NissasZendikon.class)); - cards.add(new SetCardInfo("Nullpriest of Oblivion", 118, Rarity.RARE, mage.cards.n.NullpriestOfOblivion.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nullpriest of Oblivion", 342, Rarity.RARE, mage.cards.n.NullpriestOfOblivion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nullpriest of Oblivion", 118, Rarity.RARE, mage.cards.n.NullpriestOfOblivion.class)); cards.add(new SetCardInfo("Oblivion's Hunger", 119, Rarity.COMMON, mage.cards.o.OblivionsHunger.class)); - cards.add(new SetCardInfo("Omnath, Locus of Creation", 232, Rarity.MYTHIC, mage.cards.o.OmnathLocusOfCreation.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Omnath, Locus of Creation", 312, Rarity.MYTHIC, mage.cards.o.OmnathLocusOfCreation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Omnath, Locus of Creation", 232, Rarity.MYTHIC, mage.cards.o.OmnathLocusOfCreation.class)); cards.add(new SetCardInfo("Ondu Inversion", 30, Rarity.RARE, mage.cards.o.OnduInversion.class)); - cards.add(new SetCardInfo("Ondu Inversion", 321, Rarity.RARE, mage.cards.o.OnduInversion.class)); cards.add(new SetCardInfo("Ondu Skyruins", 30, Rarity.RARE, mage.cards.o.OnduSkyruins.class)); - cards.add(new SetCardInfo("Ondu Skyruins", 321, Rarity.RARE, mage.cards.o.OnduSkyruins.class)); - cards.add(new SetCardInfo("Orah, Skyclave Hierophant", 233, Rarity.RARE, mage.cards.o.OrahSkyclaveHierophant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Orah, Skyclave Hierophant", 369, Rarity.RARE, mage.cards.o.OrahSkyclaveHierophant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Orah, Skyclave Hierophant", 385, Rarity.RARE, mage.cards.o.OrahSkyclaveHierophant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Oran-Rief Ooze", 198, Rarity.RARE, mage.cards.o.OranRiefOoze.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Oran-Rief Ooze", 361, Rarity.RARE, mage.cards.o.OranRiefOoze.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Orah, Skyclave Hierophant", 233, Rarity.RARE, mage.cards.o.OrahSkyclaveHierophant.class)); + cards.add(new SetCardInfo("Oran-Rief Ooze", 198, Rarity.RARE, mage.cards.o.OranRiefOoze.class)); cards.add(new SetCardInfo("Paired Tactician", 31, Rarity.UNCOMMON, mage.cards.p.PairedTactician.class)); cards.add(new SetCardInfo("Pelakka Caverns", 120, Rarity.UNCOMMON, mage.cards.p.PelakkaCaverns.class)); cards.add(new SetCardInfo("Pelakka Predation", 120, Rarity.UNCOMMON, mage.cards.p.PelakkaPredation.class)); - cards.add(new SetCardInfo("Phylath, World Sculptor", 234, Rarity.RARE, mage.cards.p.PhylathWorldSculptor.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Phylath, World Sculptor", 313, Rarity.RARE, mage.cards.p.PhylathWorldSculptor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phylath, World Sculptor", 234, Rarity.RARE, mage.cards.p.PhylathWorldSculptor.class)); cards.add(new SetCardInfo("Pillarverge Pathway", 263, Rarity.RARE, mage.cards.p.PillarvergePathway.class)); - cards.add(new SetCardInfo("Pillarverge Pathway", 288, Rarity.RARE, mage.cards.p.PillarvergePathway.class)); cards.add(new SetCardInfo("Plains", 266, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Plains", 267, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Plains", 268, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Plains", 380, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Practiced Tactics", 32, Rarity.COMMON, mage.cards.p.PracticedTactics.class)); cards.add(new SetCardInfo("Pressure Point", 33, Rarity.COMMON, mage.cards.p.PressurePoint.class)); - cards.add(new SetCardInfo("Prowling Felidar", 294, Rarity.COMMON, mage.cards.p.ProwlingFelidar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Prowling Felidar", 34, Rarity.COMMON, mage.cards.p.ProwlingFelidar.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Prowling Felidar", 34, Rarity.COMMON, mage.cards.p.ProwlingFelidar.class)); cards.add(new SetCardInfo("Pyroclastic Hellion", 152, Rarity.COMMON, mage.cards.p.PyroclasticHellion.class)); cards.add(new SetCardInfo("Rabid Bite", 199, Rarity.COMMON, mage.cards.r.RabidBite.class)); cards.add(new SetCardInfo("Ravager's Mace", 235, Rarity.UNCOMMON, mage.cards.r.RavagersMace.class)); @@ -394,173 +221,116 @@ public final class ZendikarRising extends ExpansionSet { cards.add(new SetCardInfo("Relic Amulet", 247, Rarity.UNCOMMON, mage.cards.r.RelicAmulet.class)); cards.add(new SetCardInfo("Relic Axe", 248, Rarity.UNCOMMON, mage.cards.r.RelicAxe.class)); cards.add(new SetCardInfo("Relic Golem", 249, Rarity.UNCOMMON, mage.cards.r.RelicGolem.class)); - cards.add(new SetCardInfo("Relic Robber", 153, Rarity.RARE, mage.cards.r.RelicRobber.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Relic Robber", 351, Rarity.RARE, mage.cards.r.RelicRobber.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Relic Robber", 153, Rarity.RARE, mage.cards.r.RelicRobber.class)); cards.add(new SetCardInfo("Relic Vial", 250, Rarity.UNCOMMON, mage.cards.r.RelicVial.class)); cards.add(new SetCardInfo("Resolute Strike", 35, Rarity.COMMON, mage.cards.r.ResoluteStrike.class)); cards.add(new SetCardInfo("Risen Riptide", 73, Rarity.COMMON, mage.cards.r.RisenRiptide.class)); cards.add(new SetCardInfo("Riverglide Pathway", 264, Rarity.RARE, mage.cards.r.RiverglidePathway.class)); - cards.add(new SetCardInfo("Riverglide Pathway", 289, Rarity.RARE, mage.cards.r.RiverglidePathway.class)); cards.add(new SetCardInfo("Rockslide Sorcerer", 154, Rarity.UNCOMMON, mage.cards.r.RockslideSorcerer.class)); - cards.add(new SetCardInfo("Roil Eruption", 155, Rarity.COMMON, mage.cards.r.RoilEruption.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Roil Eruption", 389, Rarity.COMMON, mage.cards.r.RoilEruption.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Roiling Regrowth", 201, Rarity.UNCOMMON, mage.cards.r.RoilingRegrowth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Roiling Regrowth", 390, Rarity.UNCOMMON, mage.cards.r.RoilingRegrowth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Roiling Vortex", 156, Rarity.RARE, mage.cards.r.RoilingVortex.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Roiling Vortex", 352, Rarity.RARE, mage.cards.r.RoilingVortex.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Roil Eruption", 155, Rarity.COMMON, mage.cards.r.RoilEruption.class)); + cards.add(new SetCardInfo("Roiling Regrowth", 201, Rarity.UNCOMMON, mage.cards.r.RoilingRegrowth.class)); + cards.add(new SetCardInfo("Roiling Vortex", 156, Rarity.RARE, mage.cards.r.RoilingVortex.class)); cards.add(new SetCardInfo("Roost of Drakes", 74, Rarity.UNCOMMON, mage.cards.r.RoostOfDrakes.class)); - cards.add(new SetCardInfo("Ruin Crab", 295, Rarity.UNCOMMON, mage.cards.r.RuinCrab.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ruin Crab", 75, Rarity.UNCOMMON, mage.cards.r.RuinCrab.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ruin Crab", 75, Rarity.UNCOMMON, mage.cards.r.RuinCrab.class)); cards.add(new SetCardInfo("Scale the Heights", 202, Rarity.COMMON, mage.cards.s.ScaleTheHeights.class)); cards.add(new SetCardInfo("Scavenged Blade", 157, Rarity.COMMON, mage.cards.s.ScavengedBlade.class)); cards.add(new SetCardInfo("Scion of the Swarm", 121, Rarity.UNCOMMON, mage.cards.s.ScionOfTheSwarm.class)); cards.add(new SetCardInfo("Scorch Rider", 158, Rarity.COMMON, mage.cards.s.ScorchRider.class)); - cards.add(new SetCardInfo("Scourge of the Skyclaves", 122, Rarity.MYTHIC, mage.cards.s.ScourgeOfTheSkyclaves.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Scourge of the Skyclaves", 343, Rarity.MYTHIC, mage.cards.s.ScourgeOfTheSkyclaves.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Scute Swarm", 203, Rarity.RARE, mage.cards.s.ScuteSwarm.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Scute Swarm", 308, Rarity.RARE, mage.cards.s.ScuteSwarm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Scourge of the Skyclaves", 122, Rarity.MYTHIC, mage.cards.s.ScourgeOfTheSkyclaves.class)); + cards.add(new SetCardInfo("Scute Swarm", 203, Rarity.RARE, mage.cards.s.ScuteSwarm.class)); cards.add(new SetCardInfo("Sea Gate Banneret", 36, Rarity.COMMON, mage.cards.s.SeaGateBanneret.class)); cards.add(new SetCardInfo("Sea Gate Colossus", 251, Rarity.COMMON, mage.cards.s.SeaGateColossus.class)); - cards.add(new SetCardInfo("Sea Gate Restoration", 333, Rarity.MYTHIC, mage.cards.s.SeaGateRestoration.class)); cards.add(new SetCardInfo("Sea Gate Restoration", 76, Rarity.MYTHIC, mage.cards.s.SeaGateRestoration.class)); - cards.add(new SetCardInfo("Sea Gate Stormcaller", 334, Rarity.MYTHIC, mage.cards.s.SeaGateStormcaller.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sea Gate Stormcaller", 77, Rarity.MYTHIC, mage.cards.s.SeaGateStormcaller.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sea Gate, Reborn", 333, Rarity.MYTHIC, mage.cards.s.SeaGateReborn.class)); + cards.add(new SetCardInfo("Sea Gate Stormcaller", 77, Rarity.MYTHIC, mage.cards.s.SeaGateStormcaller.class)); cards.add(new SetCardInfo("Sea Gate, Reborn", 76, Rarity.MYTHIC, mage.cards.s.SeaGateReborn.class)); cards.add(new SetCardInfo("Seafloor Stalker", 78, Rarity.COMMON, mage.cards.s.SeafloorStalker.class)); cards.add(new SetCardInfo("Sejiri Glacier", 37, Rarity.UNCOMMON, mage.cards.s.SejiriGlacier.class)); cards.add(new SetCardInfo("Sejiri Shelter", 37, Rarity.UNCOMMON, mage.cards.s.SejiriShelter.class)); cards.add(new SetCardInfo("Shadow Stinger", 123, Rarity.UNCOMMON, mage.cards.s.ShadowStinger.class)); - cards.add(new SetCardInfo("Shadows' Verdict", 124, Rarity.RARE, mage.cards.s.ShadowsVerdict.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shadows' Verdict", 344, Rarity.RARE, mage.cards.s.ShadowsVerdict.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shatterskull Charger", 159, Rarity.RARE, mage.cards.s.ShatterskullCharger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shatterskull Charger", 353, Rarity.RARE, mage.cards.s.ShatterskullCharger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shadows' Verdict", 124, Rarity.RARE, mage.cards.s.ShadowsVerdict.class)); + cards.add(new SetCardInfo("Shatterskull Charger", 159, Rarity.RARE, mage.cards.s.ShatterskullCharger.class)); cards.add(new SetCardInfo("Shatterskull Minotaur", 160, Rarity.UNCOMMON, mage.cards.s.ShatterskullMinotaur.class)); cards.add(new SetCardInfo("Shatterskull Smashing", 161, Rarity.MYTHIC, mage.cards.s.ShatterskullSmashing.class)); - cards.add(new SetCardInfo("Shatterskull Smashing", 354, Rarity.MYTHIC, mage.cards.s.ShatterskullSmashing.class)); cards.add(new SetCardInfo("Shatterskull, the Hammer Pass", 161, Rarity.MYTHIC, mage.cards.s.ShatterskullTheHammerPass.class)); - cards.add(new SetCardInfo("Shatterskull, the Hammer Pass", 354, Rarity.MYTHIC, mage.cards.s.ShatterskullTheHammerPass.class)); cards.add(new SetCardInfo("Shell Shield", 79, Rarity.COMMON, mage.cards.s.ShellShield.class)); cards.add(new SetCardInfo("Shepherd of Heroes", 38, Rarity.COMMON, mage.cards.s.ShepherdOfHeroes.class)); cards.add(new SetCardInfo("Silundi Isle", 80, Rarity.UNCOMMON, mage.cards.s.SilundiIsle.class)); cards.add(new SetCardInfo("Silundi Vision", 80, Rarity.UNCOMMON, mage.cards.s.SilundiVision.class)); cards.add(new SetCardInfo("Sizzling Barrage", 162, Rarity.COMMON, mage.cards.s.SizzlingBarrage.class)); - cards.add(new SetCardInfo("Skyclave Apparition", 322, Rarity.RARE, mage.cards.s.SkyclaveApparition.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Skyclave Apparition", 39, Rarity.RARE, mage.cards.s.SkyclaveApparition.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Skyclave Apparition", 39, Rarity.RARE, mage.cards.s.SkyclaveApparition.class)); cards.add(new SetCardInfo("Skyclave Basilica", 40, Rarity.UNCOMMON, mage.cards.s.SkyclaveBasilica.class)); cards.add(new SetCardInfo("Skyclave Cleric", 40, Rarity.UNCOMMON, mage.cards.s.SkyclaveCleric.class)); - cards.add(new SetCardInfo("Skyclave Geopede", 163, Rarity.UNCOMMON, mage.cards.s.SkyclaveGeopede.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Skyclave Geopede", 301, Rarity.UNCOMMON, mage.cards.s.SkyclaveGeopede.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Skyclave Pick-Axe", 204, Rarity.UNCOMMON, mage.cards.s.SkyclavePickAxe.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Skyclave Pick-Axe", 309, Rarity.UNCOMMON, mage.cards.s.SkyclavePickAxe.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Skyclave Geopede", 163, Rarity.UNCOMMON, mage.cards.s.SkyclaveGeopede.class)); + cards.add(new SetCardInfo("Skyclave Pick-Axe", 204, Rarity.UNCOMMON, mage.cards.s.SkyclavePickAxe.class)); cards.add(new SetCardInfo("Skyclave Plunder", 81, Rarity.UNCOMMON, mage.cards.s.SkyclavePlunder.class)); - cards.add(new SetCardInfo("Skyclave Relic", 252, Rarity.RARE, mage.cards.s.SkyclaveRelic.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Skyclave Relic", 377, Rarity.RARE, mage.cards.s.SkyclaveRelic.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Skyclave Relic", 252, Rarity.RARE, mage.cards.s.SkyclaveRelic.class)); cards.add(new SetCardInfo("Skyclave Sentinel", 253, Rarity.COMMON, mage.cards.s.SkyclaveSentinel.class)); - cards.add(new SetCardInfo("Skyclave Shade", 125, Rarity.RARE, mage.cards.s.SkyclaveShade.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Skyclave Shade", 298, Rarity.RARE, mage.cards.s.SkyclaveShade.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Skyclave Shade", 125, Rarity.RARE, mage.cards.s.SkyclaveShade.class)); cards.add(new SetCardInfo("Skyclave Shadowcat", 126, Rarity.UNCOMMON, mage.cards.s.SkyclaveShadowcat.class)); - cards.add(new SetCardInfo("Skyclave Squid", 296, Rarity.COMMON, mage.cards.s.SkyclaveSquid.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Skyclave Squid", 82, Rarity.COMMON, mage.cards.s.SkyclaveSquid.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Skyclave Squid", 82, Rarity.COMMON, mage.cards.s.SkyclaveSquid.class)); cards.add(new SetCardInfo("Smite the Monstrous", 42, Rarity.COMMON, mage.cards.s.SmiteTheMonstrous.class)); cards.add(new SetCardInfo("Sneaking Guide", 164, Rarity.COMMON, mage.cards.s.SneakingGuide.class)); cards.add(new SetCardInfo("Soaring Thought-Thief", 236, Rarity.UNCOMMON, mage.cards.s.SoaringThoughtThief.class)); cards.add(new SetCardInfo("Song-Mad Ruins", 165, Rarity.UNCOMMON, mage.cards.s.SongMadRuins.class)); cards.add(new SetCardInfo("Song-Mad Treachery", 165, Rarity.UNCOMMON, mage.cards.s.SongMadTreachery.class)); - cards.add(new SetCardInfo("Soul Shatter", 127, Rarity.RARE, mage.cards.s.SoulShatter.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Soul Shatter", 345, Rarity.RARE, mage.cards.s.SoulShatter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soul Shatter", 127, Rarity.RARE, mage.cards.s.SoulShatter.class)); cards.add(new SetCardInfo("Spare Supplies", 254, Rarity.COMMON, mage.cards.s.SpareSupplies.class)); cards.add(new SetCardInfo("Spikefield Cave", 166, Rarity.UNCOMMON, mage.cards.s.SpikefieldCave.class)); cards.add(new SetCardInfo("Spikefield Hazard", 166, Rarity.UNCOMMON, mage.cards.s.SpikefieldHazard.class)); - cards.add(new SetCardInfo("Spitfire Lagac", 167, Rarity.COMMON, mage.cards.s.SpitfireLagac.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Spitfire Lagac", 302, Rarity.COMMON, mage.cards.s.SpitfireLagac.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spitfire Lagac", 167, Rarity.COMMON, mage.cards.s.SpitfireLagac.class)); cards.add(new SetCardInfo("Spoils of Adventure", 237, Rarity.UNCOMMON, mage.cards.s.SpoilsOfAdventure.class)); cards.add(new SetCardInfo("Springmantle Cleric", 205, Rarity.UNCOMMON, mage.cards.s.SpringmantleCleric.class)); - cards.add(new SetCardInfo("Squad Commander", 323, Rarity.RARE, mage.cards.s.SquadCommander.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Squad Commander", 41, Rarity.RARE, mage.cards.s.SquadCommander.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Squad Commander", 41, Rarity.RARE, mage.cards.s.SquadCommander.class)); cards.add(new SetCardInfo("Stonework Packbeast", 255, Rarity.COMMON, mage.cards.s.StoneworkPackbeast.class)); cards.add(new SetCardInfo("Strength of Solidarity", 206, Rarity.COMMON, mage.cards.s.StrengthOfSolidarity.class)); cards.add(new SetCardInfo("Subtle Strike", 128, Rarity.COMMON, mage.cards.s.SubtleStrike.class)); cards.add(new SetCardInfo("Sure-Footed Infiltrator", 83, Rarity.UNCOMMON, mage.cards.s.SureFootedInfiltrator.class)); cards.add(new SetCardInfo("Swamp", 272, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 273, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 274, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 382, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Swarm Shambler", 207, Rarity.RARE, mage.cards.s.SwarmShambler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swarm Shambler", 362, Rarity.RARE, mage.cards.s.SwarmShambler.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swarm Shambler", 207, Rarity.RARE, mage.cards.s.SwarmShambler.class)); cards.add(new SetCardInfo("Synchronized Spellcraft", 168, Rarity.COMMON, mage.cards.s.SynchronizedSpellcraft.class)); - cards.add(new SetCardInfo("Taborax, Hope's Demise", 129, Rarity.RARE, mage.cards.t.TaboraxHopesDemise.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Taborax, Hope's Demise", 346, Rarity.RARE, mage.cards.t.TaboraxHopesDemise.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Taborax, Hope's Demise", 129, Rarity.RARE, mage.cards.t.TaboraxHopesDemise.class)); cards.add(new SetCardInfo("Tajuru Blightblade", 208, Rarity.COMMON, mage.cards.t.TajuruBlightblade.class)); - cards.add(new SetCardInfo("Tajuru Paragon", 209, Rarity.RARE, mage.cards.t.TajuruParagon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tajuru Paragon", 363, Rarity.RARE, mage.cards.t.TajuruParagon.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tajuru Paragon", 209, Rarity.RARE, mage.cards.t.TajuruParagon.class)); cards.add(new SetCardInfo("Tajuru Snarecaster", 210, Rarity.COMMON, mage.cards.t.TajuruSnarecaster.class)); cards.add(new SetCardInfo("Tangled Florahedron", 211, Rarity.UNCOMMON, mage.cards.t.TangledFlorahedron.class)); cards.add(new SetCardInfo("Tangled Vale", 211, Rarity.UNCOMMON, mage.cards.t.TangledVale.class)); cards.add(new SetCardInfo("Taunting Arbormage", 212, Rarity.UNCOMMON, mage.cards.t.TauntingArbormage.class)); cards.add(new SetCardInfo("Tazeem Raptor", 43, Rarity.COMMON, mage.cards.t.TazeemRaptor.class)); cards.add(new SetCardInfo("Tazeem Roilmage", 84, Rarity.COMMON, mage.cards.t.TazeemRoilmage.class)); - cards.add(new SetCardInfo("Tazri, Beacon of Unity", 324, Rarity.MYTHIC, mage.cards.t.TazriBeaconOfUnity.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tazri, Beacon of Unity", 44, Rarity.MYTHIC, mage.cards.t.TazriBeaconOfUnity.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tazri, Beacon of Unity", 44, Rarity.MYTHIC, mage.cards.t.TazriBeaconOfUnity.class)); cards.add(new SetCardInfo("Teeterpeak Ambusher", 169, Rarity.COMMON, mage.cards.t.TeeterpeakAmbusher.class)); - cards.add(new SetCardInfo("Territorial Scythecat", 213, Rarity.COMMON, mage.cards.t.TerritorialScythecat.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Territorial Scythecat", 310, Rarity.COMMON, mage.cards.t.TerritorialScythecat.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Thieving Skydiver", 335, Rarity.RARE, mage.cards.t.ThievingSkydiver.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Thieving Skydiver", 85, Rarity.RARE, mage.cards.t.ThievingSkydiver.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Throne of Makindi", 265, Rarity.RARE, mage.cards.t.ThroneOfMakindi.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Throne of Makindi", 379, Rarity.RARE, mage.cards.t.ThroneOfMakindi.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Territorial Scythecat", 213, Rarity.COMMON, mage.cards.t.TerritorialScythecat.class)); + cards.add(new SetCardInfo("Thieving Skydiver", 85, Rarity.RARE, mage.cards.t.ThievingSkydiver.class)); + cards.add(new SetCardInfo("Throne of Makindi", 265, Rarity.RARE, mage.cards.t.ThroneOfMakindi.class)); cards.add(new SetCardInfo("Thundering Rebuke", 170, Rarity.UNCOMMON, mage.cards.t.ThunderingRebuke.class)); cards.add(new SetCardInfo("Thundering Sparkmage", 171, Rarity.UNCOMMON, mage.cards.t.ThunderingSparkmage.class)); cards.add(new SetCardInfo("Thwart the Grave", 130, Rarity.UNCOMMON, mage.cards.t.ThwartTheGrave.class)); cards.add(new SetCardInfo("Timbercrown Pathway", 261, Rarity.RARE, mage.cards.t.TimbercrownPathway.class)); - cards.add(new SetCardInfo("Timbercrown Pathway", 287, Rarity.RARE, mage.cards.t.TimbercrownPathway.class)); cards.add(new SetCardInfo("Tormenting Voice", 172, Rarity.COMMON, mage.cards.t.TormentingVoice.class)); cards.add(new SetCardInfo("Tuktuk Rubblefort", 173, Rarity.COMMON, mage.cards.t.TuktukRubblefort.class)); cards.add(new SetCardInfo("Turntimber Ascetic", 214, Rarity.COMMON, mage.cards.t.TurntimberAscetic.class)); cards.add(new SetCardInfo("Turntimber Symbiosis", 215, Rarity.MYTHIC, mage.cards.t.TurntimberSymbiosis.class)); - cards.add(new SetCardInfo("Turntimber Symbiosis", 364, Rarity.MYTHIC, mage.cards.t.TurntimberSymbiosis.class)); cards.add(new SetCardInfo("Turntimber, Serpentine Wood", 215, Rarity.MYTHIC, mage.cards.t.TurntimberSerpentineWood.class)); - cards.add(new SetCardInfo("Turntimber, Serpentine Wood", 364, Rarity.MYTHIC, mage.cards.t.TurntimberSerpentineWood.class)); cards.add(new SetCardInfo("Umara Mystic", 238, Rarity.UNCOMMON, mage.cards.u.UmaraMystic.class)); cards.add(new SetCardInfo("Umara Skyfalls", 86, Rarity.UNCOMMON, mage.cards.u.UmaraSkyfalls.class)); cards.add(new SetCardInfo("Umara Wizard", 86, Rarity.UNCOMMON, mage.cards.u.UmaraWizard.class)); cards.add(new SetCardInfo("Utility Knife", 256, Rarity.COMMON, mage.cards.u.UtilityKnife.class)); cards.add(new SetCardInfo("Valakut Awakening", 174, Rarity.RARE, mage.cards.v.ValakutAwakening.class)); - cards.add(new SetCardInfo("Valakut Awakening", 355, Rarity.RARE, mage.cards.v.ValakutAwakening.class)); - cards.add(new SetCardInfo("Valakut Exploration", 175, Rarity.RARE, mage.cards.v.ValakutExploration.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Valakut Exploration", 303, Rarity.RARE, mage.cards.v.ValakutExploration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Valakut Exploration", 175, Rarity.RARE, mage.cards.v.ValakutExploration.class)); cards.add(new SetCardInfo("Valakut Stoneforge", 174, Rarity.RARE, mage.cards.v.ValakutStoneforge.class)); - cards.add(new SetCardInfo("Valakut Stoneforge", 355, Rarity.RARE, mage.cards.v.ValakutStoneforge.class)); cards.add(new SetCardInfo("Vanquish the Weak", 131, Rarity.COMMON, mage.cards.v.VanquishTheWeak.class)); cards.add(new SetCardInfo("Vastwood Fortification", 216, Rarity.UNCOMMON, mage.cards.v.VastwoodFortification.class)); cards.add(new SetCardInfo("Vastwood Surge", 217, Rarity.UNCOMMON, mage.cards.v.VastwoodSurge.class)); cards.add(new SetCardInfo("Vastwood Thicket", 216, Rarity.UNCOMMON, mage.cards.v.VastwoodThicket.class)); - cards.add(new SetCardInfo("Verazol, the Split Current", 239, Rarity.RARE, mage.cards.v.VerazolTheSplitCurrent.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Verazol, the Split Current", 370, Rarity.RARE, mage.cards.v.VerazolTheSplitCurrent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Veteran Adventurer", 218, Rarity.UNCOMMON, mage.cards.v.VeteranAdventurer.class)); cards.add(new SetCardInfo("Vine Gecko", 219, Rarity.UNCOMMON, mage.cards.v.VineGecko.class)); - cards.add(new SetCardInfo("Wayward Guide-Beast", 176, Rarity.RARE, mage.cards.w.WaywardGuideBeast.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wayward Guide-Beast", 356, Rarity.RARE, mage.cards.w.WaywardGuideBeast.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wayward Guide-Beast", 176, Rarity.RARE, mage.cards.w.WaywardGuideBeast.class)); cards.add(new SetCardInfo("Windrider Wizard", 87, Rarity.UNCOMMON, mage.cards.w.WindriderWizard.class)); - cards.add(new SetCardInfo("Yasharn, Implacable Earth", 240, Rarity.RARE, mage.cards.y.YasharnImplacableEarth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Yasharn, Implacable Earth", 371, Rarity.RARE, mage.cards.y.YasharnImplacableEarth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Zagras, Thief of Heartbeats", 241, Rarity.RARE, mage.cards.z.ZagrasThiefOfHeartbeats.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Zagras, Thief of Heartbeats", 372, Rarity.RARE, mage.cards.z.ZagrasThiefOfHeartbeats.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Zareth San, the Trickster", 242, Rarity.RARE, mage.cards.z.ZarethSanTheTrickster.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Zareth San, the Trickster", 373, Rarity.RARE, mage.cards.z.ZarethSanTheTrickster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Yasharn, Implacable Earth", 240, Rarity.RARE, mage.cards.y.YasharnImplacableEarth.class)); + cards.add(new SetCardInfo("Zagras, Thief of Heartbeats", 241, Rarity.RARE, mage.cards.z.ZagrasThiefOfHeartbeats.class)); + cards.add(new SetCardInfo("Zareth San, the Trickster", 242, Rarity.RARE, mage.cards.z.ZarethSanTheTrickster.class)); cards.add(new SetCardInfo("Zof Bloodbog", 132, Rarity.UNCOMMON, mage.cards.z.ZofBloodbog.class)); cards.add(new SetCardInfo("Zof Consumption", 132, Rarity.UNCOMMON, mage.cards.z.ZofConsumption.class)); cards.add(new SetCardInfo("Zulaport Duelist", 88, Rarity.COMMON, mage.cards.z.ZulaportDuelist.class)); - - cards.removeIf(setCardInfo -> checkName(setCardInfo.getName())); // remove when mechanics are fully implemented - } - - private static boolean checkName(String name) { - boolean keepNonland = false; - keepNonland = true; // comment out this line to test front faces of MDFCs - if (keepNonland && unfinishedNonland.contains(name)) { - return true; - } - return unfinishedLand.contains(name); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaces/ModalDoubleFacesCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaces/ModalDoubleFacesCardsTest.java new file mode 100644 index 0000000000..d21c266abc --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaces/ModalDoubleFacesCardsTest.java @@ -0,0 +1,162 @@ +package org.mage.test.cards.cost.modaldoublefaces; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class ModalDoubleFacesCardsTest extends CardTestPlayerBase { + + @Test + public void test_Playable_AsCreature() { + removeAllCardsFromHand(playerA); + + // Akoum Warrior {5}{R} - creature + // Akoum Teeth - land + addCard(Zone.HAND, playerA, "Akoum Warrior"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6 - 1); + addCard(Zone.HAND, playerA, "Mountain", 1); + + // can't cast without mana, but can play land + checkPlayableAbility("before land left", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Akoum Warrior", false); + checkPlayableAbility("before land right", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Akoum Teeth", true); + checkPlayableAbility("before land both", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Akoum Warrior // Akoum Teeth", false); + + // play land + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain"); + // can cast creature, but can't play land + checkPlayableAbility("after land left", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Akoum Warrior", true); + checkPlayableAbility("after land right", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Akoum Teeth", false); + checkPlayableAbility("after land both", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Akoum Warrior // Akoum Teeth", false); + + // cast creature + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkHandCount("hand after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0); + checkPermanentCount("after cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 1); + checkPermanentCount("after cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Teeth", 0); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_Playable_AsLand() { + removeAllCardsFromHand(playerA); + + // Akoum Warrior {5}{R} - creature + // Akoum Teeth - land + addCard(Zone.HAND, playerA, "Akoum Warrior"); + addCard(Zone.HAND, playerA, "Mountain", 1); + + // cast and play restrictions tested in prev test, so use here simple land play + + checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}", false); + checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Mountain", true); + checkHandCount("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2); + + // play as land + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Teeth"); + checkHandCount("hand after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2 - 1); + checkPermanentCount("after play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 0); + checkPermanentCount("after play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Teeth", 1); + checkPlayableAbility("after play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}", false); + checkPlayableAbility("can't play second land", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Mountain", false); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_CostModification() { + removeAllCardsFromHand(playerA); + + // Akoum Warrior {5}{R} - creature + // Akoum Teeth - land + addCard(Zone.HAND, playerA, "Akoum Warrior"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6 - 3); + + addCustomEffect_SpellCostModification(playerA, -3); + + // cast creature + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkHandCount("hand after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0); + checkPermanentCount("after cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 1); + checkPermanentCount("after cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Teeth", 0); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_PlayFromNonHand_LibraryByBolassCitadel() { + removeAllCardsFromHand(playerA); + removeAllCardsFromLibrary(playerA); + + // Akoum Warrior {5}{R} - creature + // Akoum Teeth - land + addCard(Zone.LIBRARY, playerA, "Akoum Warrior"); + // + // You may play the top card of your library. If you cast a spell this way, pay life equal + // to its converted mana cost rather than pay its mana cost. + addCard(Zone.BATTLEFIELD, playerA, "Bolas's Citadel"); + + checkLibraryCount("library before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 1); + checkPlayableAbility("can play as land", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Akoum Warrior", true); + checkPlayableAbility("can play as creature", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Akoum Teeth", true); + + // play as creature + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkLibraryCount("library after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 0); + checkPermanentCount("after cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 1); + checkPermanentCount("after cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Teeth", 0); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20 - 6); // creature life pay instead mana + } + + @Test + public void test_PlayFromNonHand_GraveyardByYawgmothsAgenda() { + removeAllCardsFromHand(playerA); + removeAllCardsFromLibrary(playerA); + + // Akoum Warrior {5}{R} - creature + // Akoum Teeth - land + addCard(Zone.GRAVEYARD, playerA, "Akoum Warrior"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); + // + // You may play cards from your graveyard. + addCard(Zone.BATTLEFIELD, playerA, "Yawgmoth's Agenda"); + + checkGraveyardCount("grave before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 1); + checkPlayableAbility("can play as land", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Akoum Warrior", true); + checkPlayableAbility("can play as creature", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Akoum Teeth", true); + + // play as creature + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkGraveyardCount("grave after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 0); + checkPermanentCount("after cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 1); + checkPermanentCount("after cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Teeth", 0); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } +} \ No newline at end of file diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 088d3e1189..6047be8cfd 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -257,9 +257,12 @@ public class VerifyCardDataTest { int cardIndex = 0; for (Card card : CardScanner.getAllCards()) { cardIndex++; - if (card.isSplitCard()) { + if (card instanceof SplitCard) { check(((SplitCard) card).getLeftHalfCard(), cardIndex); check(((SplitCard) card).getRightHalfCard(), cardIndex); + } else if (card instanceof ModalDoubleFacesCard) { + check(((ModalDoubleFacesCard) card).getLeftHalfCard(), cardIndex); + check(((ModalDoubleFacesCard) card).getRightHalfCard(), cardIndex); } else { check(card, cardIndex); } @@ -1351,7 +1354,7 @@ public class VerifyCardDataTest { Card card = CardImpl.createCard(cardInfo.getClassName(), testSet); System.out.println(); System.out.println(card.getName() + " " + card.getManaCost().getText()); - if (card instanceof SplitCard) { + if (card instanceof SplitCard || card instanceof ModalDoubleFacesCard) { card.getAbilities().getRules(card.getName()).forEach(this::printAbilityText); } else { card.getRules().forEach(this::printAbilityText); diff --git a/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java index 8397a6e718..cb3dba2f6c 100644 --- a/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java @@ -3,13 +3,13 @@ package mage.abilities.effects; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; import mage.cards.Card; +import mage.cards.ModalDoubleFacesCard; +import mage.cards.SplitCard; import mage.constants.*; import mage.game.Game; +import mage.players.Player; import java.util.UUID; -import mage.cards.SplitCard; -import mage.cards.SplitCardHalf; -import mage.players.Player; /** * @author BetaSteward_at_googlemail.com @@ -22,7 +22,7 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements public AsThoughEffectImpl(AsThoughEffectType type, Duration duration, Outcome outcome) { this(type, duration, outcome, false); } - + public AsThoughEffectImpl(AsThoughEffectType type, Duration duration, Outcome outcome, boolean consumable) { super(duration, outcome); this.type = type; @@ -74,12 +74,12 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements * Internal method to do the neccessary to allow the card from objectId to be cast or played (if it's a land) without paying any mana. * Additional costs (like sacrificing or discarding) have still to be payed. * Checks if the card is of the correct type or in the correct zone have to be done before. - * - * @param objectId sourceId of the card to play - * @param source source ability that allows this effect + * + * @param objectId sourceId of the card to play + * @param source source ability that allows this effect * @param affectedControllerId player allowed to play the card * @param game - * @return + * @return */ protected boolean allowCardToPlayWithoutMana(UUID objectId, Ability source, UUID affectedControllerId, Game game) { Player player = game.getPlayer(affectedControllerId); @@ -89,9 +89,14 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements } if (!card.isLand()) { if (card instanceof SplitCard) { - SplitCardHalf leftCard = ((SplitCard) card).getLeftHalfCard(); + Card leftCard = ((SplitCard) card).getLeftHalfCard(); player.setCastSourceIdWithAlternateMana(leftCard.getId(), null, leftCard.getSpellAbility().getCosts()); - SplitCardHalf rightCard = ((SplitCard) card).getRightHalfCard(); + Card rightCard = ((SplitCard) card).getRightHalfCard(); + player.setCastSourceIdWithAlternateMana(rightCard.getId(), null, rightCard.getSpellAbility().getCosts()); + } else if (card instanceof ModalDoubleFacesCard) { + Card leftCard = ((ModalDoubleFacesCard) card).getLeftHalfCard(); + player.setCastSourceIdWithAlternateMana(leftCard.getId(), null, leftCard.getSpellAbility().getCosts()); + Card rightCard = ((ModalDoubleFacesCard) card).getRightHalfCard(); player.setCastSourceIdWithAlternateMana(rightCard.getId(), null, rightCard.getSpellAbility().getCosts()); } else { player.setCastSourceIdWithAlternateMana(objectId, null, card.getSpellAbility().getCosts()); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index db27aea89c..2f5ee5fa56 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -1,5 +1,6 @@ package mage.abilities.effects; +import mage.ApprovingObject; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.MageSingleton; @@ -7,6 +8,8 @@ import mage.abilities.StaticAbility; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect; import mage.abilities.effects.common.continuous.CommanderReplacementEffect; import mage.cards.*; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; import mage.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.Predicate; @@ -29,9 +32,6 @@ import java.io.Serializable; import java.util.*; import java.util.Map.Entry; import java.util.stream.Collectors; -import mage.ApprovingObject; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; /** * @author BetaSteward_at_googlemail.com @@ -334,7 +334,7 @@ public class ContinuousEffects implements Serializable { * @param event * @param game * @return a list of all {@link ReplacementEffect} that apply to the current - * event + * event */ private Map> getApplicableReplacementEffects(GameEvent event, Game game) { Map> replaceEffects = new HashMap<>(); @@ -343,7 +343,7 @@ public class ContinuousEffects implements Serializable { } // boolean checkLKI = event.getType().equals(EventType.ZONE_CHANGE) || event.getType().equals(EventType.DESTROYED_PERMANENT); //get all applicable transient Replacement effects - for (Iterator iterator = replacementEffects.iterator(); iterator.hasNext();) { + for (Iterator iterator = replacementEffects.iterator(); iterator.hasNext(); ) { ReplacementEffect effect = iterator.next(); if (!effect.checksEventType(event, game)) { continue; @@ -376,7 +376,7 @@ public class ContinuousEffects implements Serializable { } } - for (Iterator iterator = preventionEffects.iterator(); iterator.hasNext();) { + for (Iterator iterator = preventionEffects.iterator(); iterator.hasNext(); ) { PreventionEffect effect = iterator.next(); if (!effect.checksEventType(event, game)) { continue; @@ -507,7 +507,7 @@ public class ContinuousEffects implements Serializable { * @param controllerId * @param game * @return sourceId of the permitting effect if any exists otherwise returns - * null + * null */ public ApprovingObject asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) { List asThoughEffectsList = getApplicableAsThoughEffects(type, game); @@ -515,6 +515,8 @@ public class ContinuousEffects implements Serializable { UUID idToCheck; if (affectedAbility != null && affectedAbility.getSourceObject(game) instanceof SplitCardHalf) { idToCheck = ((SplitCardHalf) affectedAbility.getSourceObject(game)).getParentCard().getId(); + } else if (affectedAbility != null && affectedAbility.getSourceObject(game) instanceof ModalDoubleFacesCardHalf) { + idToCheck = ((ModalDoubleFacesCardHalf) affectedAbility.getSourceObject(game)).getParentCard().getId(); } else if (affectedAbility != null && affectedAbility.getSourceObject(game) instanceof AdventureCardSpell && !type.needPlayCardAbility()) { // adventure spell uses alternative characteristics for spell/stack @@ -523,6 +525,8 @@ public class ContinuousEffects implements Serializable { Card card = game.getCard(objectId); if (card instanceof SplitCardHalf) { idToCheck = ((SplitCardHalf) card).getParentCard().getId(); + } else if (card instanceof ModalDoubleFacesCardHalf) { + idToCheck = ((ModalDoubleFacesCardHalf) card).getParentCard().getId(); } else if (card instanceof AdventureCardSpell && !type.needPlayCardAbility()) { // adventure spell uses alternative characteristics for spell/stack @@ -568,24 +572,24 @@ public class ContinuousEffects implements Serializable { } else if (possibleApprovingObjects.size() > 1) { // Select the ability that you use to permit the action Map keyChoices = new HashMap<>(); - for(ApprovingObject approvingObject :possibleApprovingObjects) { - MageObject mageObject = game.getObject(approvingObject.getApprovingAbility().getSourceId()); - keyChoices.put(approvingObject.getApprovingAbility().getId().toString(), + for (ApprovingObject approvingObject : possibleApprovingObjects) { + MageObject mageObject = game.getObject(approvingObject.getApprovingAbility().getSourceId()); + keyChoices.put(approvingObject.getApprovingAbility().getId().toString(), (approvingObject.getApprovingAbility().getRule(mageObject == null ? "" : mageObject.getName())) - + (mageObject == null ? "" : " (" + mageObject.getIdName() + ")")); + + (mageObject == null ? "" : " (" + mageObject.getIdName() + ")")); } Choice choicePermitting = new ChoiceImpl(true); choicePermitting.setMessage("Choose the permitting object"); choicePermitting.setKeyChoices(keyChoices); Player player = game.getPlayer(controllerId); player.choose(Outcome.Detriment, choicePermitting, game); - for(ApprovingObject approvingObject: possibleApprovingObjects) { + for (ApprovingObject approvingObject : possibleApprovingObjects) { if (approvingObject.getApprovingAbility().getId().toString().equals(choicePermitting.getChoiceKey())) { return approvingObject; } } } - + } return null; @@ -833,7 +837,7 @@ public class ContinuousEffects implements Serializable { do { Map> rEffects = getApplicableReplacementEffects(event, game); // Remove all consumed effects (ability dependant) - for (Iterator it1 = rEffects.keySet().iterator(); it1.hasNext();) { + for (Iterator it1 = rEffects.keySet().iterator(); it1.hasNext(); ) { ReplacementEffect entry = it1.next(); if (consumed.containsKey(entry.getId()) /*&& !(entry instanceof CommanderReplacementEffect) */) { // 903.9. Set consumedAbilitiesIds = consumed.get(entry.getId()); @@ -1018,7 +1022,7 @@ public class ContinuousEffects implements Serializable { .entrySet() .stream() .filter(entry -> dependentTo.contains(entry.getKey().getId()) - && entry.getValue().contains(effect.getId())) + && entry.getValue().contains(effect.getId())) .forEach(entry -> { entry.getValue().remove(effect.getId()); dependentTo.remove(entry.getKey().getId()); @@ -1052,7 +1056,7 @@ public class ContinuousEffects implements Serializable { continue; } // check if waiting effects can be applied now - for (Iterator>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext();) { + for (Iterator>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext(); ) { Map.Entry> entry = iterator.next(); if (!appliedEffects.containsAll(entry.getValue())) { // all dependent to effects are applied now so apply the effect itself continue; diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java index a220a26a76..2d916541ad 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java @@ -8,6 +8,7 @@ import mage.abilities.condition.common.SourceIsSpellCondition; import mage.abilities.costs.AlternativeCostSourceAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.Card; +import mage.cards.ModalDoubleFacesCardHalf; import mage.cards.SplitCardHalf; import mage.constants.*; import mage.filter.FilterCard; @@ -21,7 +22,7 @@ import java.util.UUID; public class CastFromHandWithoutPayingManaCostEffect extends ContinuousEffectImpl { private final AlternativeCostSourceAbility alternativeCastingCostAbility; - + public CastFromHandWithoutPayingManaCostEffect() { this(StaticFilters.FILTER_CARDS_NON_LAND, true); } @@ -37,7 +38,7 @@ public class CastFromHandWithoutPayingManaCostEffect extends ContinuousEffectImp condition = new CompoundCondition(SourceIsSpellCondition.instance, IsBeingCastFromHandCondition.instance); } else { condition = SourceIsSpellCondition.instance; - } + } this.alternativeCastingCostAbility = new AlternativeCostSourceAbility(null, condition, null, filter, true); this.staticText = "You may cast " + filter.getMessage() + (fromHand ? " from your hand" : "") @@ -87,9 +88,9 @@ enum IsBeingCastFromHandCondition implements Condition { @Override public boolean apply(Game game, Ability source) { MageObject object = game.getObject(source.getSourceId()); - if (object instanceof SplitCardHalf) { - UUID splitCardId = ((Card) object).getMainCard().getId(); - object = game.getObject(splitCardId); + if (object instanceof SplitCardHalf || object instanceof ModalDoubleFacesCardHalf) { + UUID mainCardId = ((Card) object).getMainCard().getId(); + object = game.getObject(mainCardId); } if (object instanceof Spell) { // needed to check if it can be cast by alternate cost Spell spell = (Spell) object; diff --git a/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java b/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java index bb9c97f3cc..e457dafa1c 100644 --- a/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java @@ -1,24 +1,31 @@ package mage.abilities.keyword; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.*; +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.constants.*; +import mage.constants.AsThoughEffectType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.stack.Spell; import mage.players.Player; +import java.util.UUID; + /** * Aftermath - * + *

* TODO: Implement once we get details on the comprehensive rules meaning of the * ability - * + *

* Current text is a shell copied from Flashback * * @author stravant @@ -113,9 +120,7 @@ class AftermathCantCastFromHand extends ContinuousRuleModifyingEffectImpl { Card card = game.getCard(event.getSourceId()); if (card != null && card.getId().equals(source.getSourceId())) { Zone zone = game.getState().getZone(card.getId()); - if (zone != null && (zone != Zone.GRAVEYARD)) { - return true; - } + return zone != null && (zone != Zone.GRAVEYARD); } return false; } @@ -155,14 +160,16 @@ class AftermathExileAsResolvesFromGraveyard extends ReplacementEffectImpl { sourceCard = ((SplitCardHalf) sourceCard).getParentCard(); sourceId = sourceCard.getId(); } + if (sourceCard instanceof ModalDoubleFacesCardHalf) { + sourceCard = ((ModalDoubleFacesCardHalf) sourceCard).getParentCard(); + sourceId = sourceCard.getId(); + } if (event.getTargetId().equals(sourceId)) { // Moving this spell from stack to yard Spell spell = game.getStack().getSpell(source.getSourceId()); - if (spell != null && spell.getFromZone() == Zone.GRAVEYARD) { - // And this spell was cast from the graveyard, so we need to exile it - return true; - } + // And this spell was cast from the graveyard, so we need to exile it + return spell != null && spell.getFromZone() == Zone.GRAVEYARD; } } return false; @@ -174,6 +181,9 @@ class AftermathExileAsResolvesFromGraveyard extends ReplacementEffectImpl { if (sourceCard instanceof SplitCardHalf) { sourceCard = ((SplitCardHalf) sourceCard).getParentCard(); } + if (sourceCard instanceof ModalDoubleFacesCardHalf) { + sourceCard = ((ModalDoubleFacesCardHalf) sourceCard).getParentCard(); + } if (sourceCard != null) { Player player = game.getPlayer(sourceCard.getOwnerId()); if (player != null) { diff --git a/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java b/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java index 91143c8978..968ffeee61 100644 --- a/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java @@ -7,6 +7,7 @@ import mage.abilities.costs.Costs; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; +import mage.cards.ModalDoubleFacesCard; import mage.cards.SplitCard; import mage.constants.*; import mage.game.Game; @@ -68,12 +69,18 @@ public class FlashbackAbility extends SpellAbility { } // Flashback can never cast a split card by Fuse, because Fuse only works from hand // https://tappedout.net/mtg-questions/snapcaster-mage-and-flashback-on-a-fuse-card-one-or-both-halves-legal-targets/ - if (card.isSplitCard()) { + if (card instanceof SplitCard) { if (((SplitCard) card).getLeftHalfCard().getName().equals(abilityName)) { return ((SplitCard) card).getLeftHalfCard().getSpellAbility().canActivate(playerId, game); } else if (((SplitCard) card).getRightHalfCard().getName().equals(abilityName)) { return ((SplitCard) card).getRightHalfCard().getSpellAbility().canActivate(playerId, game); } + } else if (card instanceof ModalDoubleFacesCard) { + if (((ModalDoubleFacesCard) card).getLeftHalfCard().getName().equals(abilityName)) { + return ((ModalDoubleFacesCard) card).getLeftHalfCard().getSpellAbility().canActivate(playerId, game); + } else if (((ModalDoubleFacesCard) card).getRightHalfCard().getName().equals(abilityName)) { + return ((ModalDoubleFacesCard) card).getRightHalfCard().getSpellAbility().canActivate(playerId, game); + } } return card.getSpellAbility().canActivate(playerId, game); } @@ -87,12 +94,18 @@ public class FlashbackAbility extends SpellAbility { if (card != null) { if (spellAbilityToResolve == null) { SpellAbility spellAbilityCopy = null; - if (card.isSplitCard()) { + if (card instanceof SplitCard) { if (((SplitCard) card).getLeftHalfCard().getName().equals(abilityName)) { spellAbilityCopy = ((SplitCard) card).getLeftHalfCard().getSpellAbility().copy(); } else if (((SplitCard) card).getRightHalfCard().getName().equals(abilityName)) { spellAbilityCopy = ((SplitCard) card).getRightHalfCard().getSpellAbility().copy(); } + } else if (card instanceof ModalDoubleFacesCard) { + if (((ModalDoubleFacesCard) card).getLeftHalfCard().getName().equals(abilityName)) { + spellAbilityCopy = ((ModalDoubleFacesCard) card).getLeftHalfCard().getSpellAbility().copy(); + } else if (((ModalDoubleFacesCard) card).getRightHalfCard().getName().equals(abilityName)) { + spellAbilityCopy = ((ModalDoubleFacesCard) card).getRightHalfCard().getSpellAbility().copy(); + } } else { spellAbilityCopy = card.getSpellAbility().copy(); } diff --git a/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java b/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java index 82c157401c..21ec7047bd 100644 --- a/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java +++ b/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java @@ -1,8 +1,3 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.cards; import mage.abilities.Modes; diff --git a/Mage/src/main/java/mage/cards/Card.java b/Mage/src/main/java/mage/cards/Card.java index 364415d96d..e49bf7072f 100644 --- a/Mage/src/main/java/mage/cards/Card.java +++ b/Mage/src/main/java/mage/cards/Card.java @@ -1,7 +1,5 @@ package mage.cards; -import java.util.List; -import java.util.UUID; import mage.MageObject; import mage.Mana; import mage.abilities.Abilities; @@ -16,6 +14,9 @@ import mage.game.Game; import mage.game.GameState; import mage.game.permanent.Permanent; +import java.util.List; +import java.util.UUID; + public interface Card extends MageObject { UUID getOwnerId(); @@ -29,8 +30,9 @@ public interface Card extends MageObject { /** * For cards: return all basic and dynamic abilities * For permanents: return all basic and dynamic abilities + * * @param game - * @return + * @return */ Abilities getAbilities(Game game); @@ -62,8 +64,6 @@ public interface Card extends MageObject { String getFlipCardName(); - boolean isSplitCard(); - boolean isTransformable(); void setTransformable(boolean transformable); @@ -76,21 +76,23 @@ public interface Card extends MageObject { void addInfo(String key, String value, Game game); + // WARNING, don't add new move/remove methods (if you add then you must override it in all multi-part cards like Split or MDF) + /** * Moves the card to the specified zone * * @param zone * @param sourceId * @param game - * @param flag If zone - *

    - *
  • LIBRARY:
    • true - put on top
    • false - put on - * bottom
  • - *
  • BATTLEFIELD:
    • true - tapped
    • false - - * untapped
  • - *
  • GRAVEYARD:
    • true - not from Battlefield
    • false - from - * Battlefield
  • - *
+ * @param flag If zone + *
    + *
  • LIBRARY:
    • true - put on top
    • false - put on + * bottom
  • + *
  • BATTLEFIELD:
    • true - tapped
    • false - + * untapped
  • + *
  • GRAVEYARD:
    • true - not from Battlefield
    • false - from + * Battlefield
  • + *
* @return true if card was moved to zone */ boolean moveToZone(Zone zone, UUID sourceId, Game game, boolean flag); @@ -100,8 +102,8 @@ public interface Card extends MageObject { /** * Moves the card to an exile zone * - * @param exileId set to null for generic exile zone - * @param name used for exile zone with the specified exileId + * @param exileId set to null for generic exile zone + * @param name used for exile zone with the specified exileId * @param sourceId * @param game * @return true if card was moved to zone @@ -112,6 +114,7 @@ public interface Card extends MageObject { boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId); + // WARNING, don't add new move/remove methods (if you add then you must override it in all multi-parts card like Split Half or MDF Half) boolean removeFromZone(Game game, Zone fromZone, UUID sourceId); boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId); diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index e059075a16..65e69ebe74 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -57,7 +57,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card { protected boolean flipCard; protected String flipCardName; protected boolean usesVariousArt = false; - protected boolean splitCard; protected boolean morphCard; protected boolean modalDFC; // modal double faces card @@ -139,7 +138,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card { flipCard = card.flipCard; flipCardName = card.flipCardName; usesVariousArt = card.usesVariousArt; - splitCard = card.splitCard; morphCard = card.morphCard; modalDFC = card.modalDFC; @@ -563,13 +561,22 @@ public abstract class CardImpl extends MageObjectImpl implements Card { stackObject = game.getStack().getSpell(this.getId(), false); } - if (stackObject == null && (this instanceof SplitCard)) { // handle if half of Split cast is on the stack + // handle half of Split Cards on stack + if (stackObject == null && (this instanceof SplitCard)) { stackObject = game.getStack().getSpell(((SplitCard) this).getLeftHalfCard().getId(), false); if (stackObject == null) { stackObject = game.getStack().getSpell(((SplitCard) this).getRightHalfCard().getId(), false); } } + // handle half of Modal Double Faces Cards on stack + if (stackObject == null && (this instanceof ModalDoubleFacesCard)) { + stackObject = game.getStack().getSpell(((ModalDoubleFacesCard) this).getLeftHalfCard().getId(), false); + if (stackObject == null) { + stackObject = game.getStack().getSpell(((ModalDoubleFacesCard) this).getRightHalfCard().getId(), false); + } + } + if (stackObject == null && (this instanceof AdventureCard)) { stackObject = game.getStack().getSpell(((AdventureCard) this).getSpellCard().getId(), false); } @@ -687,10 +694,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card { @Override public final Card getSecondCardFace() { - // TODO: remove when MDFCs are implemented - if (modalDFC) { - return null; - } // init second side card on first call if (secondSideCardClazz == null && secondSideCard == null) { return null; @@ -726,11 +729,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card { return flipCardName; } - @Override - public boolean isSplitCard() { - return splitCard; - } - @Override public boolean getUsesVariousArt() { return usesVariousArt; diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacesCard.java b/Mage/src/main/java/mage/cards/ModalDoubleFacesCard.java new file mode 100644 index 0000000000..bfaaf1e7f3 --- /dev/null +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacesCard.java @@ -0,0 +1,184 @@ +package mage.cards; + +import mage.MageObject; +import mage.abilities.Abilities; +import mage.abilities.AbilitiesImpl; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.ZoneChangeEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author JayDi85 + */ +public abstract class ModalDoubleFacesCard extends CardImpl { + + protected Card leftHalfCard; + protected Card rightHalfCard; + + public ModalDoubleFacesCard(UUID ownerId, CardSetInfo setInfo, + CardType[] typesLeft, SubType[] subTypesLeft, String costsLeft, + String secondSideName, CardType[] typesRight, SubType[] subTypesRight, String costsRight) { + super(ownerId, setInfo, typesLeft, costsLeft + costsRight, SpellAbilityType.MODAL); + // main card name must be same as left side + leftHalfCard = new ModalDoubleFacesCardHalfImpl(this.getOwnerId(), new CardSetInfo(setInfo.getName(), setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), + typesLeft, subTypesLeft, costsLeft, this, SpellAbilityType.MODAL_LEFT); + rightHalfCard = new ModalDoubleFacesCardHalfImpl(this.getOwnerId(), new CardSetInfo(secondSideName, setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), + typesRight, subTypesRight, costsRight, this, SpellAbilityType.MODAL_RIGHT); + this.modalDFC = true; + } + + public ModalDoubleFacesCard(ModalDoubleFacesCard card) { + super(card); + this.leftHalfCard = card.getLeftHalfCard().copy(); + ((ModalDoubleFacesCardHalf) leftHalfCard).setParentCard(this); + this.rightHalfCard = card.rightHalfCard.copy(); + ((ModalDoubleFacesCardHalf) rightHalfCard).setParentCard(this); + } + + public ModalDoubleFacesCardHalf getLeftHalfCard() { + return (ModalDoubleFacesCardHalf) leftHalfCard; + } + + public ModalDoubleFacesCardHalf getRightHalfCard() { + return (ModalDoubleFacesCardHalf) rightHalfCard; + } + + @Override + public void assignNewId() { + super.assignNewId(); + leftHalfCard.assignNewId(); + rightHalfCard.assignNewId(); + } + + @Override + public void setCopy(boolean isCopy, MageObject copiedFrom) { + super.setCopy(isCopy, copiedFrom); + leftHalfCard.setCopy(isCopy, copiedFrom); + rightHalfCard.setCopy(isCopy, copiedFrom); + } + + @Override + public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List appliedEffects) { + if (super.moveToZone(toZone, sourceId, game, flag, appliedEffects)) { + game.getState().setZone(getLeftHalfCard().getId(), toZone); + game.getState().setZone(getRightHalfCard().getId(), toZone); + return true; + } + return false; + } + + @Override + public void setZone(Zone zone, Game game) { + super.setZone(zone, game); + game.setZone(getLeftHalfCard().getId(), zone); + game.setZone(getRightHalfCard().getId(), zone); + } + + @Override + public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List appliedEffects) { + if (super.moveToExile(exileId, name, sourceId, game, appliedEffects)) { + Zone currentZone = game.getState().getZone(getId()); + game.getState().setZone(getLeftHalfCard().getId(), currentZone); + game.getState().setZone(getRightHalfCard().getId(), currentZone); + return true; + } + return false; + } + + @Override + public boolean removeFromZone(Game game, Zone fromZone, UUID sourceId) { + // zone contains only one main card + return super.removeFromZone(game, fromZone, sourceId); + } + + @Override + public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) { + if (isCopy()) { // same as meld cards + super.updateZoneChangeCounter(game, event); + return; + } + super.updateZoneChangeCounter(game, event); + getLeftHalfCard().updateZoneChangeCounter(game, event); + getRightHalfCard().updateZoneChangeCounter(game, event); + } + + @Override + public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { + switch (ability.getSpellAbilityType()) { + case MODAL_LEFT: + return this.getLeftHalfCard().cast(game, fromZone, ability, controllerId); + case MODAL_RIGHT: + return this.getRightHalfCard().cast(game, fromZone, ability, controllerId); + default: + this.getLeftHalfCard().getSpellAbility().setControllerId(controllerId); + this.getRightHalfCard().getSpellAbility().setControllerId(controllerId); + return super.cast(game, fromZone, ability, controllerId); + } + } + + @Override + public Abilities getAbilities() { + Abilities allAbilites = new AbilitiesImpl<>(); + allAbilites.addAll(super.getAbilities()); + allAbilites.addAll(leftHalfCard.getAbilities()); + allAbilites.addAll(rightHalfCard.getAbilities()); + return allAbilites; + } + + public Abilities getSharedAbilities(Game game) { + return super.getAbilities(game); + } + + @Override + public Abilities getAbilities(Game game) { + Abilities allAbilites = new AbilitiesImpl<>(); + + // ignore default spell ability from main card (only halfes are actual) + for (Ability ability : super.getAbilities(game)) { + if (ability instanceof SpellAbility && ((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.MODAL) { + continue; + } + allAbilites.add(ability); + } + + allAbilites.addAll(leftHalfCard.getAbilities(game)); + allAbilites.addAll(rightHalfCard.getAbilities(game)); + return allAbilites; + } + + @Override + public List getRules() { + return new ArrayList<>(); + } + + @Override + public void setOwnerId(UUID ownerId) { + super.setOwnerId(ownerId); + abilities.setControllerId(ownerId); + leftHalfCard.getAbilities().setControllerId(ownerId); + leftHalfCard.setOwnerId(ownerId); + rightHalfCard.getAbilities().setControllerId(ownerId); + rightHalfCard.setOwnerId(ownerId); + } + + @Override + public int getConvertedManaCost() { + // Rules: + // The converted mana cost of a modal double-faced card is based on the characteristics of the + // face that’s being considered. On the stack and battlefield, consider whichever face is up. + // In all other zones, consider only the front face. This is different than how the converted + // mana cost of a transforming double-faced card is determined. + + // on stack or battlefield it must be half card with own cost + return getLeftHalfCard().getConvertedManaCost(); + } +} diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalf.java b/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalf.java new file mode 100644 index 0000000000..bb2c1364cf --- /dev/null +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalf.java @@ -0,0 +1,18 @@ +package mage.cards; + +import mage.MageInt; + +/** + * @author JayDi85 + */ +public interface ModalDoubleFacesCardHalf extends Card { + + @Override + ModalDoubleFacesCardHalf copy(); + + void setParentCard(ModalDoubleFacesCard card); + + ModalDoubleFacesCard getParentCard(); + + void setPT(MageInt power, MageInt toughtness); +} diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalfImpl.java b/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalfImpl.java new file mode 100644 index 0000000000..c8e8e7901b --- /dev/null +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalfImpl.java @@ -0,0 +1,101 @@ +package mage.cards; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; + +import java.util.List; +import java.util.UUID; + +/** + * @author JayDi85 + */ +public class ModalDoubleFacesCardHalfImpl extends CardImpl implements ModalDoubleFacesCardHalf { + + ModalDoubleFacesCard parentCard; + + public ModalDoubleFacesCardHalfImpl(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, SubType[] cardSubTypes, + String costs, ModalDoubleFacesCard parentCard, SpellAbilityType spellAbilityType) { + super(ownerId, setInfo, cardTypes, costs, spellAbilityType); + this.parentCard = parentCard; + } + + public ModalDoubleFacesCardHalfImpl(final ModalDoubleFacesCardHalfImpl card) { + super(card); + this.parentCard = card.parentCard; + } + + @Override + public UUID getOwnerId() { + return parentCard.getOwnerId(); + } + + @Override + public String getImageName() { + // TODO: own name? + return parentCard.getImageName(); + } + + @Override + public String getExpansionSetCode() { + // TODO: own set code? + return parentCard.getExpansionSetCode(); + } + + @Override + public String getCardNumber() { + // TODO: own card number? + return parentCard.getCardNumber(); + } + + @Override + public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List appliedEffects) { + return parentCard.moveToZone(toZone, sourceId, game, flag, appliedEffects); + } + + @Override + public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List appliedEffects) { + return parentCard.moveToExile(exileId, name, sourceId, game, appliedEffects); + } + + @Override + public boolean removeFromZone(Game game, Zone fromZone, UUID sourceId) { + return parentCard.removeFromZone(game, fromZone, sourceId); + } + + @Override + public ModalDoubleFacesCard getMainCard() { + return parentCard; + } + + @Override + public void setZone(Zone zone, Game game) { + game.setZone(parentCard.getId(), zone); + game.setZone(parentCard.getLeftHalfCard().getId(), zone); + game.setZone(parentCard.getRightHalfCard().getId(), zone); + } + + @Override + public ModalDoubleFacesCardHalfImpl copy() { + return new ModalDoubleFacesCardHalfImpl(this); + } + + @Override + public void setParentCard(ModalDoubleFacesCard card) { + this.parentCard = card; + } + + @Override + public ModalDoubleFacesCard getParentCard() { + return this.parentCard; + } + + @Override + public void setPT(MageInt power, MageInt toughness) { + this.power = power; + this.toughness = toughness; + } +} diff --git a/Mage/src/main/java/mage/cards/SplitCard.java b/Mage/src/main/java/mage/cards/SplitCard.java index 936339bf64..75298907b4 100644 --- a/Mage/src/main/java/mage/cards/SplitCard.java +++ b/Mage/src/main/java/mage/cards/SplitCard.java @@ -32,7 +32,6 @@ public abstract class SplitCard extends CardImpl { String[] names = setInfo.getName().split(" // "); leftHalfCard = new SplitCardHalfImpl(this.getOwnerId(), new CardSetInfo(names[0], setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), typesLeft, costsLeft, this, SpellAbilityType.SPLIT_LEFT); rightHalfCard = new SplitCardHalfImpl(this.getOwnerId(), new CardSetInfo(names[1], setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), typesRight, costsRight, this, SpellAbilityType.SPLIT_RIGHT); - this.splitCard = true; } public SplitCard(SplitCard card) { @@ -187,4 +186,15 @@ public abstract class SplitCard extends CardImpl { rightHalfCard.getAbilities().setControllerId(ownerId); rightHalfCard.setOwnerId(ownerId); } + + @Override + public int getConvertedManaCost() { + // 202.3d The converted mana cost of a split card not on the stack or of a fused split spell on the + // stack is determined from the combined mana costs of its halves. Otherwise, while a split card is + // on the stack, the converted mana cost of the spell is determined by the mana cost of the half + // that was chosen to be cast. See rule 708, “Split Cards.” + + // split card and it's halfes contains own mana costs, so no need to rewrite logic + return super.getConvertedManaCost(); + } } diff --git a/Mage/src/main/java/mage/cards/SplitCardHalf.java b/Mage/src/main/java/mage/cards/SplitCardHalf.java index 6baee1c294..76db56ce60 100644 --- a/Mage/src/main/java/mage/cards/SplitCardHalf.java +++ b/Mage/src/main/java/mage/cards/SplitCardHalf.java @@ -1,12 +1,6 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.cards; /** - * * @author LevelX2 */ public interface SplitCardHalf extends Card { diff --git a/Mage/src/main/java/mage/cards/SplitCardHalfImpl.java b/Mage/src/main/java/mage/cards/SplitCardHalfImpl.java index 4649864452..a1adb62bb4 100644 --- a/Mage/src/main/java/mage/cards/SplitCardHalfImpl.java +++ b/Mage/src/main/java/mage/cards/SplitCardHalfImpl.java @@ -1,8 +1,3 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.cards; import mage.constants.CardType; @@ -14,7 +9,6 @@ import java.util.List; import java.util.UUID; /** - * * @author LevelX2 */ public class SplitCardHalfImpl extends CardImpl implements SplitCardHalf { @@ -61,6 +55,11 @@ public class SplitCardHalfImpl extends CardImpl implements SplitCardHalf { return splitCardParent.moveToExile(exileId, name, sourceId, game, appliedEffects); } + @Override + public boolean removeFromZone(Game game, Zone fromZone, UUID sourceId) { + return splitCardParent.removeFromZone(game, fromZone, sourceId); + } + @Override public SplitCard getMainCard() { return splitCardParent; diff --git a/Mage/src/main/java/mage/cards/mock/MockCard.java b/Mage/src/main/java/mage/cards/mock/MockCard.java index 8598688a8d..44c9f1300d 100644 --- a/Mage/src/main/java/mage/cards/mock/MockCard.java +++ b/Mage/src/main/java/mage/cards/mock/MockCard.java @@ -20,6 +20,7 @@ import java.util.List; public class MockCard extends CardImpl { static public String ADVENTURE_NAME_SEPARATOR = " // "; + static public String MODAL_DOUBLE_FACES_NAME_SEPARATOR = " // "; // Needs to be here, as it is normally calculated from the // PlaneswalkerEntersWithLoyaltyAbility of the card... but the MockCard @@ -30,6 +31,7 @@ public class MockCard extends CardImpl { protected ManaCosts manaCostLeft; protected ManaCosts manaCostRight; protected String adventureSpellName; + protected String modalDoubleFacesSecondSideName; public MockCard(CardInfo card) { super(null, card.getName()); @@ -53,7 +55,6 @@ public class MockCard extends CardImpl { this.frameColor = card.getFrameColor(); this.frameStyle = card.getFrameStyle(); - this.splitCard = card.isSplitCard(); this.flipCard = card.isFlipCard(); this.transformable = card.isDoubleFaced(); @@ -66,6 +67,10 @@ public class MockCard extends CardImpl { this.adventureSpellName = card.getAdventureSpellName(); } + if (card.isModalDoubleFacesCard()) { + this.modalDoubleFacesSecondSideName = card.getModalDoubleFacesSecondSideName(); + } + if (this.isPlaneswalker()) { String startingLoyaltyString = card.getStartingLoyalty(); if (startingLoyaltyString.isEmpty()) { @@ -117,8 +122,14 @@ public class MockCard extends CardImpl { } public String getFullName(boolean showSecondName) { + if (!showSecondName) { + return getName(); + } + if (adventureSpellName != null) { return getName() + ADVENTURE_NAME_SEPARATOR + adventureSpellName; + } else if (modalDoubleFacesSecondSideName != null) { + return getName() + MODAL_DOUBLE_FACES_NAME_SEPARATOR + modalDoubleFacesSecondSideName; } else { return getName(); } diff --git a/Mage/src/main/java/mage/cards/mock/MockSplitCard.java b/Mage/src/main/java/mage/cards/mock/MockSplitCard.java index 7858ba1e65..d0b3b86113 100644 --- a/Mage/src/main/java/mage/cards/mock/MockSplitCard.java +++ b/Mage/src/main/java/mage/cards/mock/MockSplitCard.java @@ -35,7 +35,6 @@ public class MockSplitCard extends SplitCard { this.usesVariousArt = card.usesVariousArt(); this.color = card.getColor(); - this.splitCard = card.isSplitCard(); this.flipCard = card.isFlipCard(); this.transformable = card.isDoubleFaced(); diff --git a/Mage/src/main/java/mage/cards/repository/CardInfo.java b/Mage/src/main/java/mage/cards/repository/CardInfo.java index d369bac186..5ba20acb70 100644 --- a/Mage/src/main/java/mage/cards/repository/CardInfo.java +++ b/Mage/src/main/java/mage/cards/repository/CardInfo.java @@ -3,8 +3,6 @@ package mage.cards.repository; import com.j256.ormlite.field.DataType; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; -import java.util.*; -import java.util.stream.Collectors; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -17,6 +15,9 @@ import mage.util.CardUtil; import mage.util.SubTypeList; import org.apache.log4j.Logger; +import java.util.*; +import java.util.stream.Collectors; + /** * @author North */ @@ -103,6 +104,10 @@ public class CardInfo { protected boolean adventureCard; @DatabaseField protected String adventureSpellName; + @DatabaseField + protected boolean modalDoubleFacesCard; + @DatabaseField + protected String modalDoubleFacesSecondSideName; public enum ManaCostSide { LEFT, RIGHT, ALL @@ -121,7 +126,7 @@ public class CardInfo { this.toughness = card.getToughness().toString(); this.convertedManaCost = card.getConvertedManaCost(); this.rarity = card.getRarity(); - this.splitCard = card.isSplitCard(); + this.splitCard = card instanceof SplitCard; this.splitCardFuse = card.getSpellAbility() != null && card.getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED; this.splitCardAftermath = card.getSpellAbility() != null && card.getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_AFTERMATH; @@ -140,6 +145,11 @@ public class CardInfo { this.adventureSpellName = ((AdventureCard) card).getSpellCard().getName(); } + if (card instanceof ModalDoubleFacesCard) { + this.modalDoubleFacesCard = true; + this.modalDoubleFacesSecondSideName = ((ModalDoubleFacesCard) card).getRightHalfCard().getName(); + } + this.frameStyle = card.getFrameStyle().toString(); this.frameColor = card.getFrameColor(null).toString(); this.variousArt = card.getUsesVariousArt(); @@ -153,13 +163,17 @@ public class CardInfo { this.setSubtypes(card.getSubtype(null).stream().map(SubType::toString).collect(Collectors.toList())); this.setSuperTypes(card.getSuperType()); - // mana cost can contains multiple cards (split left/right, card/adventure) + // mana cost can contains multiple cards (split left/right, modal double faces, card/adventure) if (card instanceof SplitCard) { List manaCostLeft = ((SplitCard) card).getLeftHalfCard().getManaCost().getSymbols(); List manaCostRight = ((SplitCard) card).getRightHalfCard().getManaCost().getSymbols(); this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight)); + } else if (card instanceof ModalDoubleFacesCard) { + List manaCostLeft = ((ModalDoubleFacesCard) card).getLeftHalfCard().getManaCost().getSymbols(); + List manaCostRight = ((ModalDoubleFacesCard) card).getRightHalfCard().getManaCost().getSymbols(); + this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight)); } else if (card instanceof AdventureCard) { - List manaCostLeft = ((AdventureCard) card).getSpellCard().getManaCost().getSymbols(); // Spell from left like MTGA + List manaCostLeft = ((AdventureCard) card).getSpellCard().getManaCost().getSymbols(); List manaCostRight = card.getManaCost().getSymbols(); this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight)); } else { @@ -181,6 +195,19 @@ public class CardInfo { length += rule.length(); rulesList.add(rule); } + } else if (card instanceof ModalDoubleFacesCard) { + for (String rule : ((ModalDoubleFacesCard) card).getLeftHalfCard().getRules()) { + length += rule.length(); + rulesList.add(rule); + } + for (String rule : ((ModalDoubleFacesCard) card).getRightHalfCard().getRules()) { + length += rule.length(); + rulesList.add(rule); + } + for (String rule : card.getRules()) { + length += rule.length(); + rulesList.add(rule); + } } else { for (String rule : card.getRules()) { length += rule.length(); @@ -222,7 +249,6 @@ public class CardInfo { } } if (this.startingLoyalty == null) { - //Logger.getLogger(CardInfo.class).warn("Planeswalker `" + card.getName() + "` missing starting loyalty"); this.startingLoyalty = ""; } } else { @@ -447,4 +473,12 @@ public class CardInfo { public String getAdventureSpellName() { return adventureSpellName; } + + public boolean isModalDoubleFacesCard() { + return modalDoubleFacesCard; + } + + public String getModalDoubleFacesSecondSideName() { + return modalDoubleFacesSecondSideName; + } } diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 9df069865e..5da934fa63 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -34,9 +34,9 @@ public enum CardRepository { private static final String JDBC_URL = "jdbc:h2:file:./db/cards.h2;AUTO_SERVER=TRUE"; private static final String VERSION_ENTITY_NAME = "card"; // raise this if db structure was changed - private static final long CARD_DB_VERSION = 52; + private static final long CARD_DB_VERSION = 53; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 232; + private static final long CARD_CONTENT_VERSION = 233; private Dao cardDao; private Set classNames; private final RepositoryEventSource eventSource = new RepositoryEventSource(); diff --git a/Mage/src/main/java/mage/cards/repository/CardScanner.java b/Mage/src/main/java/mage/cards/repository/CardScanner.java index 6660c6da84..c6a224b232 100644 --- a/Mage/src/main/java/mage/cards/repository/CardScanner.java +++ b/Mage/src/main/java/mage/cards/repository/CardScanner.java @@ -59,7 +59,7 @@ public final class CardScanner { new CardSetInfo(setInfo.getName(), set.getCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), errorsList); if (card != null) { - cardsToAdd.add(new CardInfo(card)); + cardsToAdd.add(new CardInfo(card)); // normal, transformed, adventure, modal double faces -- all must have single face in db if (card instanceof SplitCard) { SplitCard splitCard = (SplitCard) card; cardsToAdd.add(new CardInfo(splitCard.getLeftHalfCard())); diff --git a/Mage/src/main/java/mage/constants/SpellAbilityType.java b/Mage/src/main/java/mage/constants/SpellAbilityType.java index 22427d77be..f32c86fa51 100644 --- a/Mage/src/main/java/mage/constants/SpellAbilityType.java +++ b/Mage/src/main/java/mage/constants/SpellAbilityType.java @@ -1,7 +1,6 @@ package mage.constants; /** - * * @author North */ public enum SpellAbilityType { @@ -13,7 +12,9 @@ public enum SpellAbilityType { SPLIT_FUSED("Split SpellAbility"), SPLIT_LEFT("LeftSplit SpellAbility"), SPLIT_RIGHT("RightSplit SpellAbility"), - MODE("Mode SpellAbility"), + MODAL("Modal SpellAbility"), // used for modal double faces cards + MODAL_LEFT("LeftModal SpellAbility"), + MODAL_RIGHT("RightModal SpellAbility"), SPLICE("Spliced SpellAbility"), ADVENTURE_SPELL("Adventure SpellAbility"); diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java index 58a5937d74..59ab086a66 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java @@ -1,7 +1,7 @@ - package mage.filter.predicate.mageobject; import mage.MageObject; +import mage.cards.ModalDoubleFacesCardHalf; import mage.cards.SplitCardHalf; import mage.constants.Zone; import mage.filter.predicate.Predicate; @@ -18,8 +18,13 @@ public enum MulticoloredPredicate implements Predicate { // 708.3. Each split card that consists of two halves with different colored mana symbols in their mana costs // is a multicolored card while it's not a spell on the stack. While it's a spell on the stack, it's only the // color or colors of the half or halves being cast. # - if (input instanceof SplitCardHalf && game.getState().getZone(input.getId()) != Zone.STACK) { + if (input instanceof SplitCardHalf + && game.getState().getZone(input.getId()) != Zone.STACK) { return 1 < ((SplitCardHalf) input).getMainCard().getColor(game).getColorCount(); + } else if (input instanceof ModalDoubleFacesCardHalf + && (game.getState().getZone(input.getId()) != Zone.STACK && game.getState().getZone(input.getId()) != Zone.BATTLEFIELD)) { + // While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face. + return 1 < ((ModalDoubleFacesCardHalf) input).getMainCard().getColor(game).getColorCount(); } else { return 1 < input.getColor(game).getColorCount(); } diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java index 294f2d18af..cb89353be3 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java @@ -1,6 +1,7 @@ package mage.filter.predicate.mageobject; import mage.MageObject; +import mage.cards.ModalDoubleFacesCard; import mage.cards.SplitCard; import mage.constants.SpellAbilityType; import mage.filter.predicate.Predicate; @@ -32,10 +33,15 @@ public class NamePredicate implements Predicate { } // 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) || + 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(); return CardUtil.haveSameNames(name, card.getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || diff --git a/Mage/src/main/java/mage/filter/predicate/other/CardTextPredicate.java b/Mage/src/main/java/mage/filter/predicate/other/CardTextPredicate.java index dc284f6200..33b78bcb93 100644 --- a/Mage/src/main/java/mage/filter/predicate/other/CardTextPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/other/CardTextPredicate.java @@ -2,6 +2,7 @@ package mage.filter.predicate.other; import mage.cards.AdventureCard; import mage.cards.Card; +import mage.cards.ModalDoubleFacesCard; import mage.cards.SplitCard; import mage.cards.mock.MockCard; import mage.constants.SubType; @@ -52,6 +53,8 @@ public class CardTextPredicate implements Predicate { String fullName = input.getName(); if (input instanceof MockCard) { fullName = ((MockCard) input).getFullName(true); + } else if (input instanceof ModalDoubleFacesCard) { + fullName = input.getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + ((ModalDoubleFacesCard) input).getRightHalfCard().getName(); } else if (input instanceof AdventureCard) { fullName = input.getName() + MockCard.ADVENTURE_NAME_SEPARATOR + ((AdventureCard) input).getSpellCard().getName(); } @@ -67,14 +70,14 @@ public class CardTextPredicate implements Predicate { } } - //separate by spaces + // separate by spaces String[] tokens = text.toLowerCase(Locale.ENGLISH).split(" "); for (String token : tokens) { boolean found = false; if (!token.isEmpty()) { // then try to find in rules if (inRules) { - if (input.isSplitCard()) { + if (input instanceof SplitCard) { for (String rule : ((SplitCard) input).getLeftHalfCard().getRules(game)) { if (rule.toLowerCase(Locale.ENGLISH).contains(token)) { found = true; @@ -88,6 +91,22 @@ public class CardTextPredicate implements Predicate { } } } + + if (input instanceof ModalDoubleFacesCard) { + for (String rule : ((ModalDoubleFacesCard) input).getLeftHalfCard().getRules(game)) { + if (rule.toLowerCase(Locale.ENGLISH).contains(token)) { + found = true; + break; + } + } + for (String rule : ((ModalDoubleFacesCard) input).getRightHalfCard().getRules(game)) { + if (rule.toLowerCase(Locale.ENGLISH).contains(token)) { + found = true; + break; + } + } + } + if (input instanceof AdventureCard) { for (String rule : ((AdventureCard) input).getSpellCard().getRules(game)) { if (rule.toLowerCase(Locale.ENGLISH).contains(token)) { @@ -96,6 +115,7 @@ public class CardTextPredicate implements Predicate { } } } + for (String rule : input.getRules(game)) { if (rule.toLowerCase(Locale.ENGLISH).contains(token)) { found = true; diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 2486fcfa80..4a558c0728 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -244,17 +244,29 @@ public abstract class GameImpl implements Game, Serializable { card.setOwnerId(ownerId); gameCards.put(card.getId(), card); state.addCard(card); - if (card.isSplitCard()) { + if (card instanceof SplitCard) { + // left Card leftCard = ((SplitCard) card).getLeftHalfCard(); leftCard.setOwnerId(ownerId); gameCards.put(leftCard.getId(), leftCard); state.addCard(leftCard); + // right Card rightCard = ((SplitCard) card).getRightHalfCard(); rightCard.setOwnerId(ownerId); gameCards.put(rightCard.getId(), rightCard); state.addCard(rightCard); - } - if (card instanceof AdventureCard) { + } else if (card instanceof ModalDoubleFacesCard) { + // left + Card leftCard = ((ModalDoubleFacesCard) card).getLeftHalfCard(); + leftCard.setOwnerId(ownerId); + gameCards.put(leftCard.getId(), leftCard); + state.addCard(leftCard); + // right + Card rightCard = ((ModalDoubleFacesCard) card).getRightHalfCard(); + rightCard.setOwnerId(ownerId); + gameCards.put(rightCard.getId(), rightCard); + state.addCard(rightCard); + } else if (card instanceof AdventureCard) { Card spellCard = ((AdventureCard) card).getSpellCard(); spellCard.setOwnerId(ownerId); gameCards.put(spellCard.getId(), spellCard); @@ -1911,7 +1923,7 @@ public abstract class GameImpl implements Game, Serializable { Iterator copiedCards = this.getState().getCopiedCards().iterator(); while (copiedCards.hasNext()) { Card card = copiedCards.next(); - if (card instanceof SplitCardHalf || card instanceof AdventureCardSpell) { + if (card instanceof SplitCardHalf || card instanceof AdventureCardSpell || card instanceof ModalDoubleFacesCardHalf) { continue; // only the main card is moves, not the halves (cause halfes is not copied - it uses original card -- TODO: need to fix (bugs with same card copy)? } Zone zone = state.getZone(card.getId()); diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java index 0496002adc..6f406d28f7 100644 --- a/Mage/src/main/java/mage/game/GameState.java +++ b/Mage/src/main/java/mage/game/GameState.java @@ -1,9 +1,5 @@ package mage.game; -import java.io.Serializable; -import java.util.*; -import static java.util.Collections.emptyList; -import java.util.stream.Collectors; import mage.MageObject; import mage.MageObjectReference; import mage.abilities.*; @@ -12,6 +8,7 @@ import mage.abilities.effects.ContinuousEffects; import mage.abilities.effects.Effect; import mage.cards.AdventureCard; import mage.cards.Card; +import mage.cards.ModalDoubleFacesCard; import mage.cards.SplitCard; import mage.constants.Zone; import mage.designations.Designation; @@ -40,6 +37,12 @@ import mage.util.ThreadLocalStringBuilder; import mage.watchers.Watcher; import mage.watchers.Watchers; +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; + +import static java.util.Collections.emptyList; + /** * @author BetaSteward_at_googlemail.com *

@@ -626,6 +629,7 @@ public class GameState implements Serializable, Copyable { // public void addMessage(String message) { // this.messages.add(message); // } + /** * Returns a list of all players of the game ignoring range or if a player * has lost or left the game. @@ -799,7 +803,7 @@ public class GameState implements Serializable, Copyable { for (Map.Entry> entry : eventsByKey.entrySet()) { Set movedCards = new LinkedHashSet<>(); Set movedTokens = new LinkedHashSet<>(); - for (Iterator it = entry.getValue().iterator(); it.hasNext();) { + for (Iterator it = entry.getValue().iterator(); it.hasNext(); ) { GameEvent event = it.next(); ZoneChangeEvent castEvent = (ZoneChangeEvent) event; UUID targetId = castEvent.getTargetId(); @@ -835,10 +839,14 @@ public class GameState implements Serializable, Copyable { } // TODO Watchers? // TODO Abilities? - if (card.isSplitCard()) { + if (card instanceof SplitCard) { removeCopiedCard(((SplitCard) card).getLeftHalfCard()); removeCopiedCard(((SplitCard) card).getRightHalfCard()); } + if (card instanceof ModalDoubleFacesCard) { + removeCopiedCard(((ModalDoubleFacesCard) card).getLeftHalfCard()); + removeCopiedCard(((ModalDoubleFacesCard) card).getRightHalfCard()); + } if (card instanceof AdventureCard) { removeCopiedCard(((AdventureCard) card).getSpellCard()); } @@ -1194,21 +1202,34 @@ public class GameState implements Serializable, Copyable { } public Card copyCard(Card cardToCopy, Ability source, Game game) { + // main card Card copiedCard = cardToCopy.copy(); copiedCard.assignNewId(); copiedCard.setOwnerId(source.getControllerId()); copiedCard.setCopy(true, cardToCopy); copiedCards.put(copiedCard.getId(), copiedCard); addCard(copiedCard); - if (copiedCard.isSplitCard()) { + + // other faces + if (copiedCard instanceof SplitCard) { + // left Card leftCard = ((SplitCard) copiedCard).getLeftHalfCard(); // TODO: must be new ID (bugs with same card copy)? copiedCards.put(leftCard.getId(), leftCard); addCard(leftCard); + // right Card rightCard = ((SplitCard) copiedCard).getRightHalfCard(); copiedCards.put(rightCard.getId(), rightCard); addCard(rightCard); - } - if (copiedCard instanceof AdventureCard) { + } else if (copiedCard instanceof ModalDoubleFacesCard) { + // left + Card leftCard = ((ModalDoubleFacesCard) copiedCard).getLeftHalfCard(); // TODO: must be new ID (bugs with same card copy)? + copiedCards.put(leftCard.getId(), leftCard); + addCard(leftCard); + // right + Card rightCard = ((ModalDoubleFacesCard) copiedCard).getRightHalfCard(); + copiedCards.put(rightCard.getId(), rightCard); + addCard(rightCard); + } else if (copiedCard instanceof AdventureCard) { Card spellCard = ((AdventureCard) copiedCard).getSpellCard(); copiedCards.put(spellCard.getId(), spellCard); addCard(spellCard); diff --git a/Mage/src/main/java/mage/game/ZonesHandler.java b/Mage/src/main/java/mage/game/ZonesHandler.java index 9c3b8775c8..7ede916bcb 100644 --- a/Mage/src/main/java/mage/game/ZonesHandler.java +++ b/Mage/src/main/java/mage/game/ZonesHandler.java @@ -1,9 +1,7 @@ package mage.game; -import mage.cards.Card; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.cards.MeldCard; +import mage.abilities.keyword.TransformAbility; +import mage.cards.*; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; @@ -19,7 +17,6 @@ import mage.players.Player; import mage.target.TargetCard; import java.util.*; -import mage.abilities.keyword.TransformAbility; /** * Created by samuelsandeen on 9/6/16. @@ -54,7 +51,7 @@ public final class ZonesHandler { public static List moveCards(List zoneChangeInfos, Game game) { // Handle Unmelded Meld Cards - for (ListIterator itr = zoneChangeInfos.listIterator(); itr.hasNext();) { + for (ListIterator itr = zoneChangeInfos.listIterator(); itr.hasNext(); ) { ZoneChangeInfo info = itr.next(); MeldCard card = game.getMeldCard(info.event.getTargetId()); // Copies should be handled as normal cards. @@ -106,6 +103,10 @@ public final class ZonesHandler { if (!(targetCard instanceof Permanent) && targetCard != null) { if (targetCard instanceof MeldCard) { cards = ((MeldCard) targetCard).getHalves(); + } else if (targetCard instanceof ModalDoubleFacesCard) { + cards = new CardsImpl(targetCard); + cards.add(((ModalDoubleFacesCard) targetCard).getLeftHalfCard()); + cards.add(((ModalDoubleFacesCard) targetCard).getRightHalfCard()); } else { cards = new CardsImpl(targetCard); } @@ -174,14 +175,19 @@ public final class ZonesHandler { throw new UnsupportedOperationException("to Zone " + toZone.toString() + " not supported yet"); } } + game.setZone(event.getTargetId(), event.getToZone()); - if (targetCard instanceof MeldCard && cards != null) { - if (event.getToZone() != Zone.BATTLEFIELD) { - ((MeldCard) targetCard).setMelded(false, game); - } + if (cards != null && (targetCard instanceof MeldCard || targetCard instanceof ModalDoubleFacesCard)) { + // update other parts too for (Card card : cards.getCards(game)) { game.setZone(card.getId(), event.getToZone()); } + // reset meld status + if (targetCard instanceof MeldCard) { + if (event.getToZone() != Zone.BATTLEFIELD) { + ((MeldCard) targetCard).setMelded(false, game); + } + } } } @@ -203,7 +209,7 @@ public final class ZonesHandler { if (info instanceof ZoneChangeInfo.Unmelded) { ZoneChangeInfo.Unmelded unmelded = (ZoneChangeInfo.Unmelded) info; MeldCard meld = game.getMeldCard(info.event.getTargetId()); - for (Iterator itr = unmelded.subInfo.iterator(); itr.hasNext();) { + for (Iterator itr = unmelded.subInfo.iterator(); itr.hasNext(); ) { ZoneChangeInfo subInfo = itr.next(); if (!maybeRemoveFromSourceZone(subInfo, game)) { itr.remove(); @@ -232,10 +238,10 @@ public final class ZonesHandler { if (info.faceDown) { card.setFaceDown(true, game); } else if (info.event.getToZone().equals(Zone.BATTLEFIELD)) { - if (!card.isPermanent() + if (!card.isPermanent() && (!card.isTransformable() || Boolean.FALSE.equals(game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId())))) { // Non permanents (Instants, Sorceries, ... stay in the zone they are if an abilty/effect tries to move it to the battlefield - return false; + return false; } } if (!game.replaceEvent(event)) { @@ -248,9 +254,10 @@ public final class ZonesHandler { Permanent permanent; if (card instanceof MeldCard) { permanent = new PermanentMeld(card, event.getPlayerId(), game); + } else if (card instanceof ModalDoubleFacesCard) { + throw new IllegalStateException("Try to move mdf card to battlefield instead half"); } else if (card instanceof Permanent) { - // This should never happen. - permanent = (Permanent) card; + throw new IllegalStateException("Try to move permanent card to battlefield"); } else { permanent = new PermanentCard(card, event.getPlayerId(), game); } diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index ac1ea12de4..1aa534dba1 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -712,11 +712,6 @@ public class Spell extends StackObjImpl implements Card { return null; } - @Override - public boolean isSplitCard() { - return false; - } - @Override public boolean isTransformable() { return false; diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 35eb507da3..3855446e34 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -1602,6 +1602,10 @@ public abstract class PlayerImpl implements Player, Serializable { needId1 = object.getId(); needId2 = ((SplitCard) object).getLeftHalfCard().getId(); needId3 = ((SplitCard) object).getRightHalfCard().getId(); + } else if (object instanceof ModalDoubleFacesCard) { + needId1 = object.getId(); + needId2 = ((ModalDoubleFacesCard) object).getLeftHalfCard().getId(); + needId3 = ((ModalDoubleFacesCard) object).getRightHalfCard().getId(); } else if (object instanceof AdventureCard) { needId1 = object.getId(); needId2 = ((AdventureCard) object).getMainCard().getId(); @@ -3402,10 +3406,16 @@ public abstract class PlayerImpl implements Player, Serializable { // BASIC abilities if (object instanceof SplitCard) { - SplitCard splitCard = (SplitCard) object; - getPlayableFromObjectSingle(game, fromZone, splitCard.getLeftHalfCard(), splitCard.getLeftHalfCard().getAbilities(game), availableMana, output); - getPlayableFromObjectSingle(game, fromZone, splitCard.getRightHalfCard(), splitCard.getRightHalfCard().getAbilities(game), availableMana, output); - getPlayableFromObjectSingle(game, fromZone, splitCard, splitCard.getSharedAbilities(game), availableMana, output); + SplitCard mainCard = (SplitCard) object; + getPlayableFromObjectSingle(game, fromZone, mainCard.getLeftHalfCard(), mainCard.getLeftHalfCard().getAbilities(game), availableMana, output); + getPlayableFromObjectSingle(game, fromZone, mainCard.getRightHalfCard(), mainCard.getRightHalfCard().getAbilities(game), availableMana, output); + getPlayableFromObjectSingle(game, fromZone, mainCard, mainCard.getSharedAbilities(game), availableMana, output); + } + if (object instanceof ModalDoubleFacesCard) { + ModalDoubleFacesCard mainCard = (ModalDoubleFacesCard) object; + getPlayableFromObjectSingle(game, fromZone, mainCard.getLeftHalfCard(), mainCard.getLeftHalfCard().getAbilities(game), availableMana, output); + getPlayableFromObjectSingle(game, fromZone, mainCard.getRightHalfCard(), mainCard.getRightHalfCard().getAbilities(game), availableMana, output); + getPlayableFromObjectSingle(game, fromZone, mainCard, mainCard.getSharedAbilities(game), availableMana, output); } else if (object instanceof AdventureCard) { // adventure must use different card characteristics for different spells (main or adventure) AdventureCard adventureCard = (AdventureCard) object; diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index ae1289cee1..04e55a4455 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -1,11 +1,5 @@ package mage.util; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.stream.Collectors; import mage.MageObject; import mage.Mana; import mage.abilities.Abilities; @@ -17,6 +11,8 @@ import mage.abilities.costs.mana.*; import mage.abilities.effects.ContinuousEffect; import mage.cards.Card; import mage.cards.MeldCard; +import mage.cards.ModalDoubleFacesCard; +import mage.cards.SplitCard; import mage.constants.*; import mage.filter.Filter; import mage.filter.predicate.mageobject.NamePredicate; @@ -31,6 +27,13 @@ import mage.players.Player; import mage.target.Target; import mage.util.functions.CopyTokenFunction; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; + /** * @author nantuko */ @@ -39,10 +42,10 @@ public final class CardUtil { private static final String SOURCE_EXILE_ZONE_TEXT = "SourceExileZone"; static final String[] numberStrings = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", - "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"}; + "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"}; static final String[] ordinalStrings = {"first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eightth", "ninth", - "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth", "twentieth"}; + "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth", "twentieth"}; public static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS"); @@ -877,4 +880,21 @@ public final class CardUtil { } } } + + /** + * Return card name for same name searching + * + * @param card + * @return + */ + public static String getCardNameForSameNameSearch(Card card) { + // it's ok to return one name only cause NamePredicate can find same card by first name + if (card instanceof SplitCard) { + return ((SplitCard) card).getLeftHalfCard().getName(); + } else if (card instanceof ModalDoubleFacesCard) { + return ((ModalDoubleFacesCard) card).getLeftHalfCard().getName(); + } else { + return card.getName(); + } + } }