diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java index 230c4e91ab7..2a26bbd9380 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java @@ -940,8 +940,13 @@ public abstract class CardPanel extends MagePermanent implements ComponentListen private void setGameCardSides(CardView gameCard) { if (this.cardSideMain == null) { // new card - this.cardSideMain = gameCard; - this.cardSideOther = gameCard.getSecondCardFace(); + if (gameCard instanceof PermanentView) { + this.cardSideMain = gameCard; + this.cardSideOther = gameCard.isTransformed() ? ((PermanentView) gameCard).getOriginal() : gameCard.getSecondCardFace(); + } else { + this.cardSideMain = gameCard; + this.cardSideOther = gameCard.getSecondCardFace(); + } } else { // updated card if (this.cardSideMain.getName().equals(gameCard.getName())) { diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java index 704395e0378..d81d5e797ae 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java @@ -558,12 +558,12 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements ); allCardsUrls.add(url); } - if (card.isModalDoubleFacedCard()) { - if (card.getModalDoubleFacedSecondSideName() == null || card.getModalDoubleFacedSecondSideName().trim().isEmpty()) { + if (card.isDoubleFacedCard()) { + if (card.getDoubleFacedSecondSideName() == null || card.getDoubleFacedSecondSideName().trim().isEmpty()) { throw new IllegalStateException("MDF card can't have empty name."); } CardDownloadData cardDownloadData = new CardDownloadData( - card.getModalDoubleFacedSecondSideName(), + card.getDoubleFacedSecondSideName(), card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index a1a41e0806a..4892830edbb 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -33,6 +33,7 @@ import mage.game.command.Dungeon; import mage.game.command.Emblem; import mage.game.command.Plane; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentCard; import mage.game.permanent.PermanentToken; import mage.game.permanent.token.Token; import mage.game.stack.Spell; @@ -116,7 +117,7 @@ public class CardView extends SimpleCardView { protected List rightSplitRules; protected String rightSplitTypeLine; - protected boolean isModalDoubleFacedCard; + protected boolean isDoubleFacedCard; protected ArtRect artRect = ArtRect.NORMAL; @@ -238,7 +239,7 @@ public class CardView extends SimpleCardView { this.rightSplitRules = cardView.rightSplitRules == null ? null : new ArrayList<>(cardView.rightSplitRules); this.rightSplitTypeLine = cardView.rightSplitTypeLine; - this.isModalDoubleFacedCard = cardView.isModalDoubleFacedCard; + this.isDoubleFacedCard = cardView.isDoubleFacedCard; this.artRect = cardView.artRect; this.targets = cardView.targets == null ? null : new ArrayList<>(cardView.targets); @@ -428,12 +429,18 @@ public class CardView extends SimpleCardView { this.manaCostLeftStr = splitCard.getLeftHalfCard().getManaCostSymbols(); this.manaCostRightStr = splitCard.getRightHalfCard().getManaCostSymbols(); } else if (card instanceof ModalDoubleFacedCard) { - this.isModalDoubleFacedCard = true; - ModalDoubleFacedCard mainCard = ((ModalDoubleFacedCard) card); + this.isDoubleFacedCard = true; + DoubleFacedCard mainCard = ((DoubleFacedCard) card); fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName(); this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols(); this.manaCostRightStr = mainCard.getRightHalfCard().getManaCostSymbols(); - } else if (card instanceof CardWithSpellOption) { + } else if (card instanceof TransformingDoubleFacedCard) { + this.isDoubleFacedCard = true; + DoubleFacedCard mainCard = ((DoubleFacedCard) card); + fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName(); + this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols(); + this.manaCostRightStr = new ArrayList<>(); + } else if (card instanceof CardWithSpellOption) { this.isSplitCard = true; CardWithSpellOption mainCard = ((CardWithSpellOption) card); leftSplitName = mainCard.getName(); @@ -531,13 +538,21 @@ public class CardView extends SimpleCardView { this.extraDeckCard = card.isExtraDeckCard(); + // TODO: can probably remove this after tdfc rework // transformable, double faces cards - this.transformable = card.isTransformable(); + if (!(sourceCard.getMainCard() instanceof DoubleFacedCard)) { + this.transformable = card.isTransformable(); - Card secondSideCard = card.getSecondCardFace(); - if (secondSideCard != null) { + Card secondSideCard = card.getSecondCardFace(); + if (secondSideCard != null) { + this.secondCardFace = new CardView(secondSideCard, game); + this.alternateName = secondCardFace.getName(); + } + } else if (card instanceof PermanentCard && card.isTransformable()) { + this.transformable = card.isTransformable(); + Card secondSideCard = (Card) ((PermanentCard) card).getOtherFace(); this.secondCardFace = new CardView(secondSideCard, game); - this.alternateName = secondCardFace.getName(); + this.alternateName = secondSideCard.getName(); } this.flipCard = card.isFlipCard(); @@ -545,11 +560,11 @@ public class CardView extends SimpleCardView { this.alternateName = card.getFlipCardName(); } - if (card instanceof ModalDoubleFacedCard) { + if (card instanceof DoubleFacedCard) { this.transformable = true; // enable GUI day/night button - ModalDoubleFacedCard mdfCard = (ModalDoubleFacedCard) card; - this.secondCardFace = new CardView(mdfCard.getRightHalfCard(), game); - this.alternateName = mdfCard.getRightHalfCard().getName(); + DoubleFacedCard doubleFacedCard = (DoubleFacedCard) card; + this.secondCardFace = new CardView(doubleFacedCard.getRightHalfCard(), game); + this.alternateName = doubleFacedCard.getRightHalfCard().getName(); } Card meldsToCard = card.getMeldsToCard(); 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 aaaa45006e8..c2c364d9cb5 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 @@ -206,9 +206,9 @@ public class TinyLeaders extends Constructed { if (card instanceof SplitCard) { costs.add(((SplitCard) card).getLeftHalfCard().getManaValue()); costs.add(((SplitCard) card).getRightHalfCard().getManaValue()); - } else if (card instanceof ModalDoubleFacedCard) { - costs.add(((ModalDoubleFacedCard) card).getLeftHalfCard().getManaValue()); - costs.add(((ModalDoubleFacedCard) card).getRightHalfCard().getManaValue()); + } else if (card instanceof DoubleFacedCard) { + costs.add(((DoubleFacedCard) card).getLeftHalfCard().getManaValue()); + costs.add(((DoubleFacedCard) card).getRightHalfCard().getManaValue()); } else { costs.add(card.getManaValue()); } diff --git a/Mage.Sets/src/mage/cards/a/AangAndLaOceansFury.java b/Mage.Sets/src/mage/cards/a/AangAndLaOceansFury.java deleted file mode 100644 index cd195db2c64..00000000000 --- a/Mage.Sets/src/mage/cards/a/AangAndLaOceansFury.java +++ /dev/null @@ -1,60 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.counter.AddCountersAllEffect; -import mage.abilities.keyword.ReachAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TappedPredicate; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AangAndLaOceansFury extends CardImpl { - - private static final FilterPermanent filter = new FilterControlledCreaturePermanent("tapped creature you control"); - - static { - filter.add(TappedPredicate.TAPPED); - } - - public AangAndLaOceansFury(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AVATAR); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.ALLY); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.nightCard = true; - - // Reach - this.addAbility(ReachAbility.getInstance()); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Whenever Aang and La attack, put a +1/+1 counter on each tapped creature you control. - this.addAbility(new AttacksTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter))); - } - - private AangAndLaOceansFury(final AangAndLaOceansFury card) { - super(card); - } - - @Override - public AangAndLaOceansFury copy() { - return new AangAndLaOceansFury(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AangAtTheCrossroads.java b/Mage.Sets/src/mage/cards/a/AangAtTheCrossroads.java index 4418a5a1ef8..d77dd1f2fc4 100644 --- a/Mage.Sets/src/mage/cards/a/AangAtTheCrossroads.java +++ b/Mage.Sets/src/mage/cards/a/AangAtTheCrossroads.java @@ -1,59 +1,81 @@ package mage.cards.a; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.common.TargetControlledLandPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class AangAtTheCrossroads extends CardImpl { +public final class AangAtTheCrossroads extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterCreatureCard("creature card with mana value 4 or less"); + private static final FilterPermanent saviorFilter = new FilterPermanent("land creatures"); static { filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 5)); + saviorFilter.add(CardType.LAND.getPredicate()); + saviorFilter.add(CardType.CREATURE.getPredicate()); } public AangAtTheCrossroads(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{W}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.AVATAR, SubType.ALLY}, "{2}{G}{W}{U}", + "Aang, Destined Savior", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR, SubType.ALLY}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.AVATAR); - this.subtype.add(SubType.ALLY); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.a.AangDestinedSavior.class; + this.getLeftHalfCard().setPT(3, 3); + this.getRightHalfCard().setPT(4, 4); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // When Aang enters, look at the top five cards of your library. You may put a creature card with mana value 4 or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( 5, 1, filter, PutCards.BATTLEFIELD, PutCards.BOTTOM_RANDOM ))); // When another creature you control leaves the battlefield, transform Aang at the beginning of the next upkeep. - this.addAbility(new TransformAbility()); - this.addAbility(new LeavesBattlefieldAllTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + this.getLeftHalfCard().addAbility(new LeavesBattlefieldAllTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new TransformSourceEffect()) - ).setText("transform {this} at the beginning of the next upkeep"), StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL)); + ).setText("transform {this} at the beginning of the next upkeep"), StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL) + .setTriggerPhrase("When another creature you control leaves the battlefield, ")); + + // Aang, Destined Savior + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Land creatures you control have vigilance. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, saviorFilter + ))); + + // At the beginning of combat on your turn, earthbend 2. + Ability ability = new BeginningOfCombatTriggeredAbility(new EarthbendTargetEffect(2)); + ability.addTarget(new TargetControlledLandPermanent()); + this.getRightHalfCard().addAbility(ability); } private AangAtTheCrossroads(final AangAtTheCrossroads card) { diff --git a/Mage.Sets/src/mage/cards/a/AangDestinedSavior.java b/Mage.Sets/src/mage/cards/a/AangDestinedSavior.java deleted file mode 100644 index 952fe02c8a1..00000000000 --- a/Mage.Sets/src/mage/cards/a/AangDestinedSavior.java +++ /dev/null @@ -1,66 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.keyword.EarthbendTargetEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.VigilanceAbility; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.FilterPermanent; -import mage.target.common.TargetControlledLandPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AangDestinedSavior extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent("land creatures"); - - static { - filter.add(CardType.LAND.getPredicate()); - filter.add(CardType.CREATURE.getPredicate()); - } - - public AangDestinedSavior(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AVATAR); - this.subtype.add(SubType.ALLY); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Land creatures you control have vigilance. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, filter - ))); - - // At the beginning of combat on your turn, earthbend 2. - Ability ability = new BeginningOfCombatTriggeredAbility(new EarthbendTargetEffect(2)); - ability.addTarget(new TargetControlledLandPermanent()); - this.addAbility(ability); - } - - private AangDestinedSavior(final AangDestinedSavior card) { - super(card); - } - - @Override - public AangDestinedSavior copy() { - return new AangDestinedSavior(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AangMasterOfElements.java b/Mage.Sets/src/mage/cards/a/AangMasterOfElements.java deleted file mode 100644 index 951e3c91215..00000000000 --- a/Mage.Sets/src/mage/cards/a/AangMasterOfElements.java +++ /dev/null @@ -1,112 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.Cost; -import mage.abilities.costs.CostImpl; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.common.DamagePlayersEffect; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.TargetController; -import mage.counters.CounterType; -import mage.filter.FilterCard; -import mage.game.Game; - -import java.util.Optional; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AangMasterOfElements extends CardImpl { - - private static final FilterCard filter = new FilterCard("spells"); - - public AangMasterOfElements(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AVATAR); - this.subtype.add(SubType.ALLY); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Spells you cast cost {W}{U}{B}{R}{G} less to cast. - this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect( - filter, new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), StaticValue.get(1), true - ))); - - // At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent. - this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.ANY, - new DoIfCostPaid(new GainLifeEffect(4), new AangMasterOfElementsCost()) - .addEffect(new DrawCardSourceControllerEffect(4).concatBy(",")) - .addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)) - .setText(", put four +1/+1 counters on him")) - .addEffect(new DamagePlayersEffect(4, TargetController.OPPONENT) - .setText(", and he deals 4 damage to each opponent")), - false - )); - } - - private AangMasterOfElements(final AangMasterOfElements card) { - super(card); - } - - @Override - public AangMasterOfElements copy() { - return new AangMasterOfElements(this); - } -} - -class AangMasterOfElementsCost extends CostImpl { - - AangMasterOfElementsCost() { - super(); - text = "transform {this}"; - } - - private AangMasterOfElementsCost(final AangMasterOfElementsCost cost) { - super(cost); - } - - @Override - public AangMasterOfElementsCost copy() { - return new AangMasterOfElementsCost(this); - } - - @Override - public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return Optional - .ofNullable(source.getSourcePermanentIfItStillExists(game)) - .filter(Card::isTransformable) - .isPresent(); - } - - @Override - public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - paid = Optional - .ofNullable(source.getSourcePermanentIfItStillExists(game)) - .filter(permanent -> permanent.transform(source, game)) - .isPresent(); - return paid; - } -} diff --git a/Mage.Sets/src/mage/cards/a/AangSwiftSavior.java b/Mage.Sets/src/mage/cards/a/AangSwiftSavior.java index a23c4d1af15..cf199e538c3 100644 --- a/Mage.Sets/src/mage/cards/a/AangSwiftSavior.java +++ b/Mage.Sets/src/mage/cards/a/AangSwiftSavior.java @@ -1,22 +1,28 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.WaterbendCost; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.effects.keyword.AirbendTargetEffect; import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterSpellOrPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.TappedPredicate; import mage.target.common.TargetSpellOrPermanent; import java.util.UUID; @@ -24,40 +30,52 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class AangSwiftSavior extends CardImpl { +public final class AangSwiftSavior extends TransformingDoubleFacedCard { private static final FilterSpellOrPermanent filter = new FilterSpellOrPermanent("other target creature or spell"); + private static final FilterPermanent laFilter = new FilterControlledCreaturePermanent("tapped creature you control"); + static { + } static { filter.getPermanentFilter().add(CardType.CREATURE.getPredicate()); filter.getPermanentFilter().add(AnotherPredicate.instance); + laFilter.add(TappedPredicate.TAPPED); } public AangSwiftSavior(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.AVATAR, SubType.ALLY}, "{1}{W}{U}", + "Aang and La, Ocean's Fury", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR, SubType.SPIRIT, SubType.ALLY}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.AVATAR); - this.subtype.add(SubType.ALLY); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.a.AangAndLaOceansFury.class; + this.getLeftHalfCard().setPT(2, 3); + this.getRightHalfCard().setPT(5, 5); // Flash - this.addAbility(FlashAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlashAbility.getInstance()); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // When Aang enters, airbend up to one other target creature or spell. Ability ability = new EntersBattlefieldTriggeredAbility(new AirbendTargetEffect()); ability.addTarget(new TargetSpellOrPermanent(0, 1, filter, false)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Waterbend {8}: Transform Aang. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new WaterbendCost(8))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new WaterbendCost(8))); + + // Aang and La, Ocean's Fury + + // Reach + this.getRightHalfCard().addAbility(ReachAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Whenever Aang and La attack, put a +1/+1 counter on each tapped creature you control. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), laFilter)).setTriggerPhrase("Whenever {this} attack, ")); } private AangSwiftSavior(final AangSwiftSavior card) { diff --git a/Mage.Sets/src/mage/cards/a/AberrantResearcher.java b/Mage.Sets/src/mage/cards/a/AberrantResearcher.java index 69e5b58f690..db75f8ba478 100644 --- a/Mage.Sets/src/mage/cards/a/AberrantResearcher.java +++ b/Mage.Sets/src/mage/cards/a/AberrantResearcher.java @@ -1,16 +1,16 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.players.Player; @@ -19,23 +19,26 @@ import java.util.UUID; /** * @author fireshoes */ -public final class AberrantResearcher extends CardImpl { +public final class AberrantResearcher extends TransformingDoubleFacedCard { public AberrantResearcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.INSECT); - this.power = new MageInt(3); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.INSECT}, "{3}{U}", + "Perfected Form", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.INSECT, SubType.HORROR}, "U"); - this.secondSideCardClazz = mage.cards.p.PerfectedForm.class; + this.getLeftHalfCard().setPT(3, 2); + this.getRightHalfCard().setPT(5, 4); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // At the beginning of your upkeep, put the top card of your library into your graveyard. If it's an instant or sorcery card, transform Aberrant Researcher. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AberrantResearcherEffect())); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new AberrantResearcherEffect())); + + // Perfected Form + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private AberrantResearcher(final AberrantResearcher card) { diff --git a/Mage.Sets/src/mage/cards/a/AccursedWitch.java b/Mage.Sets/src/mage/cards/a/AccursedWitch.java index c214b37dd02..b2f2f329017 100644 --- a/Mage.Sets/src/mage/cards/a/AccursedWitch.java +++ b/Mage.Sets/src/mage/cards/a/AccursedWitch.java @@ -1,49 +1,76 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; +import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.TransformAbility; -import mage.cards.Card; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.DoubleFacedCardHalf; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterCard; import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; import mage.players.Player; +import mage.target.TargetPlayer; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** * @author halljared */ -public final class AccursedWitch extends CardImpl { +public final class AccursedWitch extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterCard("spells"); public AccursedWitch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SHAMAN); - this.power = new MageInt(4); - this.toughness = new MageInt(2); - - this.secondSideCardClazz = mage.cards.i.InfectiousCurse.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN}, "{3}{B}", + "Infectious Curse", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA, SubType.CURSE}, "B"); + this.getLeftHalfCard().setPT(4, 2); // Spells your opponents cast that target Accursed Witch cost {1} less to cast. - this.addAbility(new SimpleStaticAbility( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility( new SpellsCostModificationThatTargetSourceEffect(-1, filter, TargetController.OPPONENT)) ); // When Accursed Witch dies, return it to the battlefield transformed under your control attached to target opponent. - this.addAbility(new TransformAbility()); Ability ability = new DiesSourceTriggeredAbility(new AccursedWitchReturnTransformedEffect()); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Infectious Curse + // Enchant player + TargetPlayer auraTarget = new TargetPlayer(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.Damage)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + + // Spells you cast that target enchanted player cost {1} less to cast. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new InfectiousCurseCostReductionEffect())); + + // At the beginning of enchanted player's upkeep, that player loses 1 life and you gain 1 life. + Ability upkeepAbility = new BeginningOfUpkeepTriggeredAbility( + TargetController.ENCHANTED, new LoseLifeTargetEffect(1).setText("that player loses 1 life"), + false + ); + upkeepAbility.addEffect(new GainLifeEffect(1).concatBy("and")); + this.getRightHalfCard().addAbility(upkeepAbility); } private AccursedWitch(final AccursedWitch card) { @@ -80,16 +107,67 @@ class AccursedWitchReturnTransformedEffect extends OneShotEffect { return false; } - Card card = game.getCard(source.getSourceId()); + DoubleFacedCardHalf card = (DoubleFacedCardHalf) game.getCard(source.getSourceId()); if (card == null) { return false; } game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - game.getState().setValue("attachTo:" + source.getSourceId(), attachTo.getId()); + game.getState().setValue("attachTo:" + card.getOtherSide().getId(), attachTo.getId()); if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { - attachTo.addAttachment(card.getId(), source, game); + attachTo.addAttachment(card.getOtherSide().getId(), source, game); } return true; } } +class InfectiousCurseCostReductionEffect extends CostModificationEffectImpl { + + InfectiousCurseCostReductionEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); + this.staticText = "Spells you cast that target enchanted player cost {1} less to cast"; + } + + private InfectiousCurseCostReductionEffect(InfectiousCurseCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + CardUtil.reduceCost(abilityToModify, 1); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if (!(abilityToModify instanceof SpellAbility)) { + return false; + } + + if (!source.isControlledBy(abilityToModify.getControllerId())) { + return false; + } + + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment == null || enchantment.getAttachedTo() == null) { + return false; + } + + Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId()); + Set allTargets; + if (spell != null) { + // real cast + allTargets = CardUtil.getAllSelectedTargets(abilityToModify, game); + } else { + // playable + allTargets = CardUtil.getAllPossibleTargets(abilityToModify, game); + } + + // try to reduce all the time (if it possible to target) + return allTargets.stream().anyMatch(target -> Objects.equals(target, enchantment.getAttachedTo())); + } + + @Override + public InfectiousCurseCostReductionEffect copy() { + return new InfectiousCurseCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AclazotzDeepestBetrayal.java b/Mage.Sets/src/mage/cards/a/AclazotzDeepestBetrayal.java index 06c22233f9f..3ffb59c98fc 100644 --- a/Mage.Sets/src/mage/cards/a/AclazotzDeepestBetrayal.java +++ b/Mage.Sets/src/mage/cards/a/AclazotzDeepestBetrayal.java @@ -1,16 +1,23 @@ package mage.cards.a; -import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInHandCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.BlackManaAbility; import mage.cards.*; import mage.constants.*; import mage.filter.StaticFilters; @@ -28,33 +35,43 @@ import java.util.UUID; /** * @author Susucr */ -public final class AclazotzDeepestBetrayal extends CardImpl { +public final class AclazotzDeepestBetrayal extends TransformingDoubleFacedCard { + private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 2, TargetController.ANY); + private static final Hint hint = new ConditionHint(condition); public AclazotzDeepestBetrayal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); - this.secondSideCardClazz = mage.cards.t.TempleOfTheDead.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BAT, SubType.GOD}, "{3}{B}{B}", + "Temple of the Dead", + new SuperType[]{}, new CardType[]{CardType.LAND}, new SubType[]{}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.BAT); - this.subtype.add(SubType.GOD); - this.power = new MageInt(4); - this.toughness = new MageInt(4); + this.getLeftHalfCard().setPT(4, 4); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // Whenever Aclazotz attacks, each opponent discards a card. For each opponent who can't, you draw a card. - this.addAbility(new AttacksTriggeredAbility(new AclazotzDeepestBetrayalEffect())); + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new AclazotzDeepestBetrayalEffect())); // Whenever an opponent discards a land card, create a 1/1 black Bat creature token with flying. - this.addAbility(new AclazotzDeepestBetrayalTriggeredAbility()); + this.getLeftHalfCard().addAbility(new AclazotzDeepestBetrayalTriggeredAbility()); // When Aclazotz dies, return it to the battlefield tapped and transformed under its owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesSourceTriggeredAbility(new AclazotzDeepestBetrayalTransformEffect())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new AclazotzDeepestBetrayalTransformEffect())); + + // Temple of the Dead + // {T}: Add {B}. + this.getRightHalfCard().addAbility(new BlackManaAbility()); + + // {2}{B}, {T}: Transform Temple of the Dead. Activate only if a player has one or fewer cards in hand and only as a sorcery. + Ability ability = new ActivateIfConditionActivatedAbility( + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}"), condition + ).setTiming(TimingRule.SORCERY); + ability.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability.addHint(hint)); } private AclazotzDeepestBetrayal(final AclazotzDeepestBetrayal card) { diff --git a/Mage.Sets/src/mage/cards/a/AcolyteOfTheInferno.java b/Mage.Sets/src/mage/cards/a/AcolyteOfTheInferno.java index 2fc675be257..8e0489ff96a 100644 --- a/Mage.Sets/src/mage/cards/a/AcolyteOfTheInferno.java +++ b/Mage.Sets/src/mage/cards/a/AcolyteOfTheInferno.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -28,7 +27,9 @@ public final class AcolyteOfTheInferno extends CardImpl { this.addAbility(new RenownAbility(1)); // Whenever Acolyte of the Inferno becomes blocked by a creature, it deals 2 damage to that creature - this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new DamageTargetEffect(2, true, "that creature", "it"), false)); + this.addAbility(new BecomesBlockedByCreatureTriggeredAbility( + new DamageTargetEffect(2, "it") + .withTargetDescription("that creature"), false)); } private AcolyteOfTheInferno(final AcolyteOfTheInferno card) { diff --git a/Mage.Sets/src/mage/cards/a/AdrenalineJockey.java b/Mage.Sets/src/mage/cards/a/AdrenalineJockey.java index 2eed3297193..5126774a212 100644 --- a/Mage.Sets/src/mage/cards/a/AdrenalineJockey.java +++ b/Mage.Sets/src/mage/cards/a/AdrenalineJockey.java @@ -41,7 +41,7 @@ public final class AdrenalineJockey extends CardImpl { // Whenever a player casts a spell, if it's not their turn, this creature deals 4 damage to them. this.addAbility(new SpellCastAllTriggeredAbility( - new DamageTargetEffect(4, true, "them"), + new DamageTargetEffect(4).withTargetDescription("them"), filter, false, SetTargetPointer.PLAYER )); diff --git a/Mage.Sets/src/mage/cards/a/AetherbladeAgent.java b/Mage.Sets/src/mage/cards/a/AetherbladeAgent.java index 8df4502e60a..bc7cd55d194 100644 --- a/Mage.Sets/src/mage/cards/a/AetherbladeAgent.java +++ b/Mage.Sets/src/mage/cards/a/AetherbladeAgent.java @@ -1,13 +1,13 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerOrBattleTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -16,23 +16,28 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class AetherbladeAgent extends CardImpl { +public final class AetherbladeAgent extends TransformingDoubleFacedCard { public AetherbladeAgent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.g.GitaxianMindstinger.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE}, "{1}{B}", + "Gitaxian Mindstinger", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.ROGUE}, "UB"); + this.getLeftHalfCard().setPT(1, 1); + this.getRightHalfCard().setPT(3, 3); // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); + this.getLeftHalfCard().addAbility(DeathtouchAbility.getInstance()); // {4}{U/P}: Transform Aetherblade Agent. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{U/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{U/P}"))); + + // Gitaxian Mindstinger + // Deathtouch + this.getRightHalfCard().addAbility(DeathtouchAbility.getInstance()); + + // Whenever Gitaxian Mindstinger deals combat damage to a player or battle, draw a card. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerOrBattleTriggeredAbility(new DrawCardSourceControllerEffect(1),false)); } private AetherbladeAgent(final AetherbladeAgent card) { diff --git a/Mage.Sets/src/mage/cards/a/AfflictedDeserter.java b/Mage.Sets/src/mage/cards/a/AfflictedDeserter.java index b5dc48b063c..00aba239c02 100644 --- a/Mage.Sets/src/mage/cards/a/AfflictedDeserter.java +++ b/Mage.Sets/src/mage/cards/a/AfflictedDeserter.java @@ -1,33 +1,49 @@ package mage.cards.a; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.OneShotEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetArtifactPermanent; +import java.util.Optional; import java.util.UUID; /** * @author BetaSteward */ -public final class AfflictedDeserter extends CardImpl { +public final class AfflictedDeserter extends TransformingDoubleFacedCard { public AfflictedDeserter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - - this.secondSideCardClazz = mage.cards.w.WerewolfRansacker.class; - - this.power = new MageInt(3); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{R}", + "Werewolf Ransacker", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); + this.getLeftHalfCard().setPT(3, 2); + this.getRightHalfCard().setPT(5, 4); // At the beginning of each upkeep, if no spells were cast last turn, transform Afflicted Deserter. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Werewolf Ransacker + // Whenever this creature transforms into Werewolf Ransacker, you may destroy target artifact. If that artifact is put into a graveyard this way, Werewolf Ransacker deals 3 damage to that artifact's controller. + Ability ability = new TransformIntoSourceTriggeredAbility(new WerewolfRansackerEffect(), true, true); + ability.addTarget(new TargetArtifactPermanent()); + this.getRightHalfCard().addAbility(ability); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Werewolf Ransacker. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); + } private AfflictedDeserter(final AfflictedDeserter card) { @@ -39,3 +55,39 @@ public final class AfflictedDeserter extends CardImpl { return new AfflictedDeserter(this); } } + +class WerewolfRansackerEffect extends OneShotEffect { + + WerewolfRansackerEffect() { + super(Outcome.DestroyPermanent); + staticText = "destroy target artifact. If that artifact is put into a graveyard this way, " + + "{this} deals 3 damage to that artifact's controller"; + } + + private WerewolfRansackerEffect(final WerewolfRansackerEffect effect) { + super(effect); + } + + @Override + public WerewolfRansackerEffect copy() { + return new WerewolfRansackerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + permanent.destroy(source, game); + if (game.getState().getZone(permanent.getId()) != Zone.GRAVEYARD) { + return true; + } + Optional.of(permanent) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .ifPresent(player -> player.damage(3, source, game)); + return true; + } +} + diff --git a/Mage.Sets/src/mage/cards/a/AjaniNacatlAvenger.java b/Mage.Sets/src/mage/cards/a/AjaniNacatlAvenger.java deleted file mode 100644 index 750cdcbb659..00000000000 --- a/Mage.Sets/src/mage/cards/a/AjaniNacatlAvenger.java +++ /dev/null @@ -1,190 +0,0 @@ -package mage.cards.a; - -import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.delayed.ReflexiveTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.counter.AddCountersAllEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterNonlandPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.filter.predicate.mageobject.ColorPredicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.permanent.token.CatWarrior21Token; -import mage.players.Player; -import mage.target.TargetPermanent; -import mage.target.common.TargetAnyTarget; -import mage.util.CardUtil; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * @author Susucr - */ -public final class AjaniNacatlAvenger extends CardImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(SubType.CAT, "Cat you control"); - - public AjaniNacatlAvenger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AJANI); - this.setStartingLoyalty(3); - - this.color.setRed(true); - this.color.setWhite(true); - this.nightCard = true; - - // +2: Put a +1/+1 counter on each Cat you control. - this.addAbility(new LoyaltyAbility( - new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), 2 - )); - - // 0: Create a 2/1 white Car Warrior creature token. When you do, if you control a red permanent other than Ajani, Nacatl Avenger, he deals damage equal to the number of creatures you control to any target. - this.addAbility(new LoyaltyAbility(new AjaniNacatlAvengerZeroEffect(), 0)); - - // -4: Each opponent chooses an artifact, a creature, an enchantment and a planeswalker from among the nonland permanents they control, then sacrifices the rest. - this.addAbility(new LoyaltyAbility(new AjaniNacatlAvengerMinusFourEffect(), -4)); - } - - private AjaniNacatlAvenger(final AjaniNacatlAvenger card) { - super(card); - } - - @Override - public AjaniNacatlAvenger copy() { - return new AjaniNacatlAvenger(this); - } -} - -class AjaniNacatlAvengerZeroEffect extends OneShotEffect { - - private static final FilterPermanent filter = new FilterPermanent("red permanent other than {this}"); - - static { - filter.add(new ColorPredicate(ObjectColor.RED)); - filter.add(AnotherPredicate.instance); - } - - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, true); - - AjaniNacatlAvengerZeroEffect() { - super(Outcome.PutCreatureInPlay); - staticText = "Create a 2/1 white Cat Warrior creature token. " - + "When you do, if you control a red permanent other than {this}, " - + "he deals damage equal to the number of creatures you control to any target."; - } - - private AjaniNacatlAvengerZeroEffect(final AjaniNacatlAvengerZeroEffect effect) { - super(effect); - } - - @Override - public AjaniNacatlAvengerZeroEffect copy() { - return new AjaniNacatlAvengerZeroEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - if (!new CreateTokenEffect(new CatWarrior21Token()).apply(game, source)) { - return false; - } - - ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility( - new DamageTargetEffect(CreaturesYouControlCount.PLURAL), - false, - "When you do, if you control a red permanent other than {this}, " - + "he deals damage equal to the number of creatures you control to any target.", - condition - ); - reflexive.addTarget(new TargetAnyTarget()); - game.fireReflexiveTriggeredAbility(reflexive, source); - return true; - } -} - -// Inspired by Mythos of Snapdax -class AjaniNacatlAvengerMinusFourEffect extends OneShotEffect { - - private static final List cardTypes = Arrays.asList( - CardType.ARTIFACT, - CardType.CREATURE, - CardType.ENCHANTMENT, - CardType.PLANESWALKER - ); - - AjaniNacatlAvengerMinusFourEffect() { - super(Outcome.Benefit); - staticText = "Each opponent chooses an artifact, a creature, an enchantment and a planeswalker " - + "from among the nonland permanents they control, then sacrifices the rest."; - } - - private AjaniNacatlAvengerMinusFourEffect(final AjaniNacatlAvengerMinusFourEffect effect) { - super(effect); - } - - @Override - public AjaniNacatlAvengerMinusFourEffect copy() { - return new AjaniNacatlAvengerMinusFourEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - - List playerList = game - .getOpponents(controller.getId()) - .stream() - .map(game::getPlayer) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - Set toKeep = new HashSet<>(); - for (Player player : playerList) { - for (CardType cardType : cardTypes) { - String message = CardUtil.addArticle(cardType.toString()); - FilterPermanent filter = new FilterNonlandPermanent(message); - filter.add(cardType.getPredicate()); - filter.add(new ControllerIdPredicate(player.getId())); - if (game.getBattlefield().count(filter, source.getControllerId(), source, game) == 0) { - continue; - } - TargetPermanent target = new TargetPermanent(filter); - target.withNotTarget(true); - player.choose(outcome, target, source, game); - toKeep.add(target.getFirstTarget()); - } - } - - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_NON_LAND, source.getControllerId(), game)) { - if (permanent == null || toKeep.contains(permanent.getId()) || !controller.hasOpponent(permanent.getControllerId(), game)) { - continue; - } - permanent.sacrifice(source, game); - } - return true; - } - -} diff --git a/Mage.Sets/src/mage/cards/a/AjaniNacatlPariah.java b/Mage.Sets/src/mage/cards/a/AjaniNacatlPariah.java index 9320de6fd90..4019b4f0545 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniNacatlPariah.java +++ b/Mage.Sets/src/mage/cards/a/AjaniNacatlPariah.java @@ -1,27 +1,49 @@ package mage.cards.a; -import mage.MageInt; -import mage.constants.Pronoun; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.common.DiesOneOrMoreTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.CatWarrior21Token; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetAnyTarget; +import mage.util.CardUtil; -import java.util.UUID; +import java.util.*; +import java.util.stream.Collectors; /** * @author Susucr */ -public final class AjaniNacatlPariah extends CardImpl { +public final class AjaniNacatlPariah extends TransformingDoubleFacedCard { public static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.CAT, "other Cats you control"); + private static final FilterControlledCreaturePermanent nacatlAvengerFilter = new FilterControlledCreaturePermanent(SubType.CAT, "Cat you control"); static { filter.add(AnotherPredicate.instance); @@ -29,25 +51,34 @@ public final class AjaniNacatlPariah extends CardImpl { } public AjaniNacatlPariah(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.CAT, SubType.WARRIOR}, "{1}{W}", + "Ajani, Nacatl Avenger", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.AJANI}, "RW"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.CAT); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(1); - this.toughness = new MageInt(2); - - this.secondSideCardClazz = mage.cards.a.AjaniNacatlAvenger.class; + this.getLeftHalfCard().setPT(1, 2); + this.getRightHalfCard().setStartingLoyalty(3); // When Ajani, Nacatl Pariah enters the battlefield, create a 2/1 white Cat Warrior creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new CatWarrior21Token()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new CatWarrior21Token()))); // Whenever one or more other Cats you control die, you may exile Ajani, then return him to the battlefield transformed under his owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesOneOrMoreTriggeredAbility( + this.getLeftHalfCard().addAbility(new DiesOneOrMoreTriggeredAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.HE), filter, true)); + + // Ajani, Nacatl Avenger + // +2: Put a +1/+1 counter on each Cat you control. + this.getRightHalfCard().addAbility(new LoyaltyAbility( + new AddCountersAllEffect(CounterType.P1P1.createInstance(), nacatlAvengerFilter), 2 + )); + + // 0: Create a 2/1 white Car Warrior creature token. When you do, if you control a red permanent other than Ajani, Nacatl Avenger, he deals damage equal to the number of creatures you control to any target. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new AjaniNacatlAvengerZeroEffect(), 0)); + + // -4: Each opponent chooses an artifact, a creature, an enchantment and a planeswalker from among the nonland permanents they control, then sacrifices the rest. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new AjaniNacatlAvengerMinusFourEffect(), -4)); } private AjaniNacatlPariah(final AjaniNacatlPariah card) { @@ -59,3 +90,116 @@ public final class AjaniNacatlPariah extends CardImpl { return new AjaniNacatlPariah(this); } } + +class AjaniNacatlAvengerZeroEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterPermanent("red permanent other than {this}"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + filter.add(AnotherPredicate.instance); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, true); + + AjaniNacatlAvengerZeroEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "Create a 2/1 white Cat Warrior creature token. " + + "When you do, if you control a red permanent other than {this}, " + + "he deals damage equal to the number of creatures you control to any target."; + } + + private AjaniNacatlAvengerZeroEffect(final AjaniNacatlAvengerZeroEffect effect) { + super(effect); + } + + @Override + public AjaniNacatlAvengerZeroEffect copy() { + return new AjaniNacatlAvengerZeroEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (!new CreateTokenEffect(new CatWarrior21Token()).apply(game, source)) { + return false; + } + + ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility( + new DamageTargetEffect(CreaturesYouControlCount.PLURAL), + false, + "When you do, if you control a red permanent other than {this}, " + + "he deals damage equal to the number of creatures you control to any target.", + condition + ); + reflexive.addTarget(new TargetAnyTarget()); + game.fireReflexiveTriggeredAbility(reflexive, source); + return true; + } +} + +// Inspired by Mythos of Snapdax +class AjaniNacatlAvengerMinusFourEffect extends OneShotEffect { + + private static final List cardTypes = Arrays.asList( + CardType.ARTIFACT, + CardType.CREATURE, + CardType.ENCHANTMENT, + CardType.PLANESWALKER + ); + + AjaniNacatlAvengerMinusFourEffect() { + super(Outcome.Benefit); + staticText = "Each opponent chooses an artifact, a creature, an enchantment and a planeswalker " + + "from among the nonland permanents they control, then sacrifices the rest."; + } + + private AjaniNacatlAvengerMinusFourEffect(final AjaniNacatlAvengerMinusFourEffect effect) { + super(effect); + } + + @Override + public AjaniNacatlAvengerMinusFourEffect copy() { + return new AjaniNacatlAvengerMinusFourEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + + List playerList = game + .getOpponents(controller.getId()) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + Set toKeep = new HashSet<>(); + for (Player player : playerList) { + for (CardType cardType : cardTypes) { + String message = CardUtil.addArticle(cardType.toString()); + FilterPermanent filter = new FilterNonlandPermanent(message); + filter.add(cardType.getPredicate()); + filter.add(new ControllerIdPredicate(player.getId())); + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) == 0) { + continue; + } + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + toKeep.add(target.getFirstTarget()); + } + } + + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_NON_LAND, source.getControllerId(), game)) { + if (permanent == null || toKeep.contains(permanent.getId()) || !controller.hasOpponent(permanent.getControllerId(), game)) { + continue; + } + permanent.sacrifice(source, game); + } + return true; + } + +} diff --git a/Mage.Sets/src/mage/cards/a/AlluringSuitor.java b/Mage.Sets/src/mage/cards/a/AlluringSuitor.java index b9ea71bbb06..229793ea3ac 100644 --- a/Mage.Sets/src/mage/cards/a/AlluringSuitor.java +++ b/Mage.Sets/src/mage/cards/a/AlluringSuitor.java @@ -1,35 +1,60 @@ package mage.cards.a; -import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.mana.UntilEndOfTurnManaEffect; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; +import mage.target.TargetPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class AlluringSuitor extends CardImpl { +public final class AlluringSuitor extends TransformingDoubleFacedCard { public AlluringSuitor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); - - this.subtype.add(SubType.VAMPIRE); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.d.DeadlyDancer.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "{2}{R}", + "Deadly Dancer", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "R"); + this.getLeftHalfCard().setPT(2, 3); + this.getRightHalfCard().setPT(3, 3); // When you attack with exactly two creatures, transform Alluring Suitor. - this.addAbility(new TransformAbility()); - this.addAbility(new AlluringSuitorTriggeredAbility()); + this.getLeftHalfCard().addAbility(new AlluringSuitorTriggeredAbility()); + + // Deadly Dancer + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // When this creature transforms into Deadly Dancer, add {R}{R}. Until end of turn, you don't lose this mana as steps and phases end. + this.getRightHalfCard().addAbility(new TransformIntoSourceTriggeredAbility(new UntilEndOfTurnManaEffect(Mana.RedMana(2)))); + + // {R}{R}: Deadly Dancer and another target creature each get +1/+0 until end of turn. + Ability ability = new SimpleActivatedAbility(new BoostSourceEffect( + 1, 0, Duration.EndOfTurn + ).setText("{this}"), new ManaCostsImpl<>("{R}{R}")); + ability.addEffect(new BoostTargetEffect(1, 0) + .setText("and another target creature each get +1/+0 until end of turn")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + this.getRightHalfCard().addAbility(ability); } private AlluringSuitor(final AlluringSuitor card) { diff --git a/Mage.Sets/src/mage/cards/a/AltarOfTheWretched.java b/Mage.Sets/src/mage/cards/a/AltarOfTheWretched.java index ef84be1744f..d17c4d340e1 100644 --- a/Mage.Sets/src/mage/cards/a/AltarOfTheWretched.java +++ b/Mage.Sets/src/mage/cards/a/AltarOfTheWretched.java @@ -1,45 +1,63 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; -import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.keyword.*; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.StaticFilters; +import mage.game.ExileZone; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.Set; +import java.util.UUID; /** * * @author jeffwadsworth */ -public final class AltarOfTheWretched extends CardImpl { +public final class AltarOfTheWretched extends TransformingDoubleFacedCard { public AltarOfTheWretched(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{B}"); - this.secondSideCardClazz = mage.cards.w.WretchedBonemass.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{B}", + "Wretched Bonemass", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SKELETON, SubType.HORROR}, "B"); + this.getRightHalfCard().setPT(0, 0); // When Altar of the Wretched enters the battlefield, you may sacrifice a nontoken creature. If you do, draw X cards, then mill X cards, where X is that creature’s power. - this.addAbility(new EntersBattlefieldTriggeredAbility(new AltarOfTheWretchedEffect(), true)); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new AltarOfTheWretchedEffect(), true)); // Craft with one or more creatures {2}{B}{B} - this.addAbility(new CraftAbility( + this.getLeftHalfCard().addAbility(new CraftAbility( "{2}{B}{B}", "one or more creatures", "other creatures you control and/or" + "creature cards in your graveyard", 1, Integer.MAX_VALUE, CardType.CREATURE.getPredicate() )); // {2}{B}: Return Altar of the Wretched from your graveyard to your hand. - this.addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl<>("{2}{B}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl<>("{2}{B}"))); + // Wretched Bonemass + // Wretched Bonemass’s power and toughness are each equal to the total power of the exiled cards used to craft it. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new SetBasePowerToughnessSourceEffect(WretchedBonemassDynamicValue.instance).setText("{this}'s power and toughness are each equal to the total power of the exiled cards used to craft it."))); + + // Wretched Bonemass has flying as long as an exiled card used to craft it has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new WretchedBonemassGainAbilityEffect())); } private AltarOfTheWretched(final AltarOfTheWretched card) { @@ -84,3 +102,124 @@ class AltarOfTheWretchedEffect extends OneShotEffect { return new AltarOfTheWretchedEffect(this); } } + + +enum WretchedBonemassDynamicValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int totalPower = 0; + Permanent permanent = sourceAbility.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return 0; + } + ExileZone exileZone = game + .getExile() + .getExileZone(CardUtil.getExileZoneId( + game, permanent.getId(), permanent.getZoneChangeCounter(game) - 2 + )); + if (exileZone == null) { + return 0; + } + for (Card card : exileZone.getCards(game)) { + totalPower += card.getPower().getValue(); + } + return totalPower; + } + + @Override + public WretchedBonemassDynamicValue copy() { + return this; + } + + @Override + public String getMessage() { + return "total power of the exiled cards used to craft it"; + } + + @Override + public String toString() { + return "0"; + } +} + +class WretchedBonemassGainAbilityEffect extends ContinuousEffectImpl { + + WretchedBonemassGainAbilityEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "{this} has flying as long as an exiled card used to craft it has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance."; + } + + private WretchedBonemassGainAbilityEffect(final WretchedBonemassGainAbilityEffect effect) { + super(effect); + } + + @Override + public WretchedBonemassGainAbilityEffect copy() { + return new WretchedBonemassGainAbilityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent wretchedBonemass = source.getSourcePermanentIfItStillExists(game); + if (wretchedBonemass != null) { + ExileZone exileZone = game + .getExile() + .getExileZone(CardUtil.getExileZoneId( + game, wretchedBonemass.getId(), wretchedBonemass.getZoneChangeCounter(game) - 2 + )); + if (exileZone != null + && !exileZone.isEmpty()) { + Set cardsInExile = exileZone.getCards(game); + for (Card card : cardsInExile) { + for (Ability a : card.getAbilities()) { + if (a instanceof FlyingAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof FirstStrikeAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof DoubleStrikeAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof DeathtouchAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof HasteAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof HexproofAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof IndestructibleAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof LifelinkAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof MenaceAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof ProtectionAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof IndestructibleAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof ReachAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof TrampleAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof VigilanceAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + } + } + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AmbitiousFarmhand.java b/Mage.Sets/src/mage/cards/a/AmbitiousFarmhand.java deleted file mode 100644 index b92a884539b..00000000000 --- a/Mage.Sets/src/mage/cards/a/AmbitiousFarmhand.java +++ /dev/null @@ -1,56 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.common.CovenCondition; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.abilities.hint.common.CovenHint; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.target.common.TargetCardInLibrary; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AmbitiousFarmhand extends CardImpl { - - public AmbitiousFarmhand(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.s.SeasonedCathar.class; - - // When Ambitious Farmhand enters the battlefield, you may search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. - this.addAbility(new EntersBattlefieldTriggeredAbility( - new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true), true - )); - - // Coven—{1}{W}{W}: Transform Ambitious Farmhand. Activate only if you control three or more creatures with different powers. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateIfConditionActivatedAbility( - new TransformSourceEffect(), new ManaCostsImpl<>("{1}{W}{W}"), CovenCondition.instance - ).setAbilityWord(AbilityWord.COVEN).addHint(CovenHint.instance)); - } - - private AmbitiousFarmhand(final AmbitiousFarmhand card) { - super(card); - } - - @Override - public AmbitiousFarmhand copy() { - return new AmbitiousFarmhand(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AnakinSkywalker.java b/Mage.Sets/src/mage/cards/a/AnakinSkywalker.java index 45af92015a5..ef74b2c0b17 100644 --- a/Mage.Sets/src/mage/cards/a/AnakinSkywalker.java +++ b/Mage.Sets/src/mage/cards/a/AnakinSkywalker.java @@ -1,18 +1,22 @@ package mage.cards.a; -import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; @@ -20,38 +24,45 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.Iterator; import java.util.UUID; /** * @author Styxo */ -public final class AnakinSkywalker extends CardImpl { +public final class AnakinSkywalker extends TransformingDoubleFacedCard { public AnakinSkywalker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{B}{R}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SITH); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.secondSideCardClazz = mage.cards.d.DarthVader.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SITH}, "{3}{U}{B}{R}", + "Darth Vader", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SITH}, "B"); + this.getLeftHalfCard().setPT(4, 4); + this.getRightHalfCard().setPT(4, 4); // Whenever another creature dies, put a +1/+1 counter on Anakin Skywalker. - this.addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, true)); + this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, true)); // Sacrifice another creature: Target creature gets -1/-1 until end of turn. Activate this ability only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-1, -1, Duration.EndOfTurn), new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // If Anakin Skywalker would be destroyed, regenerate, then transform him instead. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleStaticAbility(new AnakinSkywalkerEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new AnakinSkywalkerEffect())); + + // Darth Vader + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Whenever Darth Vader attacks, creatures defending player controls get -1/-1 until end of turn for each +1/+1 counter on Darth Vader. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new UnboostCreaturesDefendingPlayerEffect(), false, null, SetTargetPointer.PLAYER)); } @@ -101,3 +112,47 @@ class AnakinSkywalkerEffect extends ReplacementEffectImpl { return new AnakinSkywalkerEffect(this); } } + + +class UnboostCreaturesDefendingPlayerEffect extends ContinuousEffectImpl { + + UnboostCreaturesDefendingPlayerEffect() { + super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.UnboostCreature); + staticText = "creatures defending player controls get -1/-1 until end of turn for each +1/+1 counter on Darth Vader"; + } + + private UnboostCreaturesDefendingPlayerEffect(final UnboostCreaturesDefendingPlayerEffect effect) { + super(effect); + } + + @Override + public UnboostCreaturesDefendingPlayerEffect copy() { + return new UnboostCreaturesDefendingPlayerEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + if (getAffectedObjectsSet()) { + for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, getTargetPointer().getFirst(game, source), game)) { + affectedObjectList.add(new MageObjectReference(creature, game)); + } + } + } + + @Override + public boolean apply(Game game, Ability source) { + for (Iterator it = affectedObjectList.iterator(); it.hasNext(); ) { + Permanent permanent = it.next().getPermanent(game); + if (permanent != null) { + int unboostCount = -1 * new CountersSourceCount(CounterType.P1P1).calculate(game, source, this); + permanent.addPower(unboostCount); + permanent.addToughness(unboostCount); + } else { + it.remove(); + } + } + return true; + } +} + diff --git a/Mage.Sets/src/mage/cards/a/AncientOfTheEquinox.java b/Mage.Sets/src/mage/cards/a/AncientOfTheEquinox.java deleted file mode 100644 index af17bdb0e39..00000000000 --- a/Mage.Sets/src/mage/cards/a/AncientOfTheEquinox.java +++ /dev/null @@ -1,42 +0,0 @@ - -package mage.cards.a; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author LevelX2 - */ -public final class AncientOfTheEquinox extends CardImpl { - - public AncientOfTheEquinox(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.TREEFOLK); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setGreen(true); - - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - // Hexproof - this.addAbility(HexproofAbility.getInstance()); - } - - private AncientOfTheEquinox(final AncientOfTheEquinox card) { - super(card); - } - - @Override - public AncientOfTheEquinox copy() { - return new AncientOfTheEquinox(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AngelicEnforcer.java b/Mage.Sets/src/mage/cards/a/AngelicEnforcer.java deleted file mode 100644 index 4a28dd92a8d..00000000000 --- a/Mage.Sets/src/mage/cards/a/AngelicEnforcer.java +++ /dev/null @@ -1,59 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.ControllerLifeCount; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.HexproofAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Zone; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AngelicEnforcer extends CardImpl { - - public AngelicEnforcer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ANGEL); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setWhite(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // You have hexproof. - this.addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance()))); - - // Angelic Enforcer's power and toughness are each equal to your life total. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect( - ControllerLifeCount.instance - ).setText("{this}'s power and toughness are each equal to your life total"))); - - // Whenever Angelic Enforcer attacks, double your life total. - this.addAbility(new AttacksTriggeredAbility(new GainLifeEffect( - ControllerLifeCount.instance - ).setText("double your life total"))); - } - - private AngelicEnforcer(final AngelicEnforcer card) { - super(card); - } - - @Override - public AngelicEnforcer copy() { - return new AngelicEnforcer(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AnotherChance.java b/Mage.Sets/src/mage/cards/a/AnotherChance.java index 943b1733290..852c2354d48 100644 --- a/Mage.Sets/src/mage/cards/a/AnotherChance.java +++ b/Mage.Sets/src/mage/cards/a/AnotherChance.java @@ -26,7 +26,7 @@ public final class AnotherChance extends CardImpl { // You may mill two cards. Then return up to two creature cards from your graveyard to your hand. this.getSpellAbility().addEffect(new AnotherChanceMillEffect()); this.getSpellAbility().addEffect(new OneShotNonTargetEffect(new ReturnFromGraveyardToHandTargetEffect().setText("Then return up to two creature cards from your graveyard to your hand."), - new TargetCardInYourGraveyard(0, 2, StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD, true)).withTargetDescription("up to two creature cards").concatBy("Then ")); + new TargetCardInYourGraveyard(0, 2, StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD, true)).withTargetDescription("up to two creature cards")); } private AnotherChance(final AnotherChance card) { diff --git a/Mage.Sets/src/mage/cards/a/ApexObservatory.java b/Mage.Sets/src/mage/cards/a/ApexObservatory.java deleted file mode 100644 index 47f9acc8c89..00000000000 --- a/Mage.Sets/src/mage/cards/a/ApexObservatory.java +++ /dev/null @@ -1,241 +0,0 @@ -package mage.cards.a; - -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.common.EntersBattlefieldTappedAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.choices.Choice; -import mage.choices.ChoiceCardType; -import mage.constants.*; -import mage.game.ExileZone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.util.CardUtil; - -import java.util.*; -import java.util.stream.Collectors; -import mage.abilities.SpellAbility; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; - -/** - * @author jeffwadsworth - */ -public class ApexObservatory extends CardImpl { - - public ApexObservatory(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, null); - - this.nightCard = true; - - // Apex Observatory enters the battlefield tapped. - this.addAbility(new EntersBattlefieldTappedAbility()); - - // As it enters, choose a card type shared among two exiled cards used to craft it. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseCardTypeEffect())); - - // The next spell you cast this turn of the chosen type can be cast without paying its mana cost. - this.addAbility(new SimpleActivatedAbility(new ApexObservatoryEffect(), new TapSourceCost())); - } - - private ApexObservatory(final ApexObservatory card) { - super(card); - } - - @Override - public ApexObservatory copy() { - return new ApexObservatory(this); - } -} - -class ChooseCardTypeEffect extends OneShotEffect { - - public ChooseCardTypeEffect() { - super(Outcome.Neutral); - staticText = "choose a card type shared among two exiled cards used to craft it."; - } - - protected ChooseCardTypeEffect(final ChooseCardTypeEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getPermanentEntering(source.getSourceId()); - List exiledCardsCardType = new ArrayList<>(); - if (mageObject == null) { - mageObject = game.getObject(source); - } - if (controller != null && mageObject != null) { - Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent == null) { - return false; - } - // chase the exile zone down... - ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source, game.getState().getZoneChangeCounter(mageObject.getId()) - 1)); - if (exileZone == null) { - return false; - } - for (Card card : exileZone.getCards(game)) { - exiledCardsCardType.addAll(card.getCardType(game)); - } - Choice cardTypeChoice = new ChoiceCardType(); - cardTypeChoice.getChoices().clear(); - cardTypeChoice.getChoices().addAll(exiledCardsCardType.stream().map(CardType::toString).collect(Collectors.toList())); - // find only card types that each card shares; some cards have more than 1 card type - Map cardTypeCounts = new HashMap<>(); - for (String cardType : cardTypeChoice.getChoices()) { - cardTypeCounts.put(cardType, 0); - } - - for (Card c : exileZone.getCards(game)) { - for (CardType cardType : c.getCardType(game)) { - if (cardTypeCounts.containsKey(cardType.toString())) { - cardTypeCounts.put(cardType.toString(), cardTypeCounts.get(cardType.toString()) + 1); - } - } - } - - List sharedCardTypes = new ArrayList<>(); - int numExiledCards = exileZone.getCards(game).size(); - for (Map.Entry entry : cardTypeCounts.entrySet()) { - if (entry.getValue() == numExiledCards) { - sharedCardTypes.add(entry.getKey()); - } - } - // handle situations like the double-faced instant/land Jwari Disruption // Jwari Ruins - if (sharedCardTypes.isEmpty()) { - game.informPlayers(mageObject.getIdName() + " No exiled cards shared a type in exile, so nothing is done."); - if (mageObject instanceof Permanent) { - ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("No exiled cards have the same card type."), game); - } - return false; - } - cardTypeChoice.getChoices().retainAll(sharedCardTypes); - if (controller.choose(Outcome.Benefit, cardTypeChoice, game)) { - if (!game.isSimulation()) { - game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + cardTypeChoice.getChoice()); - } - game.getState().setValue("ApexObservatoryType_" + source.getSourceId().toString(), cardTypeChoice.getChoice()); - if (mageObject instanceof Permanent) { - ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen card type: " + cardTypeChoice.getChoice()), game); - } - return true; - } - } - return false; - } - - @Override - public ChooseCardTypeEffect copy() { - return new ChooseCardTypeEffect(this); - } -} - -class ApexObservatoryEffect extends OneShotEffect { - - ApexObservatoryEffect() { - super(Outcome.Benefit); - staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost."; - } - - private ApexObservatoryEffect(final ApexObservatoryEffect effect) { - super(effect); - } - - @Override - public ApexObservatoryEffect copy() { - return new ApexObservatoryEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - String chosenCardType = (String) game.getState().getValue("ApexObservatoryType_" + source.getSourceId().toString()); - if (chosenCardType == null) { - return false; - } - game.addEffect(new ApexObservatoryCastWithoutManaEffect(chosenCardType, source.getControllerId()), source); - return true; - } -} - -class ApexObservatoryCastWithoutManaEffect extends CostModificationEffectImpl { - - private final String chosenCardType; - private final UUID playerId; - private boolean used = false; - - ApexObservatoryCastWithoutManaEffect(String chosenCardType, UUID playerId) { - super(Duration.EndOfTurn, Outcome.Benefit, CostModificationType.SET_COST); - this.chosenCardType = chosenCardType; - this.playerId = playerId; - staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost"; - } - - private ApexObservatoryCastWithoutManaEffect(final ApexObservatoryCastWithoutManaEffect effect) { - super(effect); - this.chosenCardType = effect.chosenCardType; - this.playerId = effect.playerId; - this.used = effect.used; - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - // Ask the player if they want to use the effect - Player controller = game.getPlayer(playerId); - if (controller != null) { - MageObject spell = abilityToModify.getSourceObject(game); - if (spell != null && !game.isSimulation()) { - String message = "Cast " + spell.getIdName() + " without paying its mana cost?"; - if (controller.chooseUse(Outcome.Benefit, message, source, game)) { - // Set the cost to zero - abilityToModify.getManaCostsToPay().clear(); - // Mark as used - used = true; - game.informPlayers(controller.getLogName() + " casts " + spell.getIdName() + " without paying its mana cost."); - return true; - } else { - // Player chose not to use the effect - return false; - } - } - } - return false; - } - - @Override - public ApexObservatoryCastWithoutManaEffect copy() { - return new ApexObservatoryCastWithoutManaEffect(this); - } - - @Override - public boolean isInactive(Ability source, Game game) { - return used || super.isInactive(source, game); - } - - @Override - public boolean applies(Ability ability, Ability source, Game game) { - if (used) { - return false; - } - if (!ability.isControlledBy(playerId)) { - return false; - } - if (!(ability instanceof SpellAbility)) { - return false; - } - MageObject object = game.getObject(ability.getSourceId()); - if (object != null && object.getCardType(game).stream() - .anyMatch(cardType -> cardType.toString().equals(chosenCardType))) { - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/a/AppaLoyalSkyBison.java b/Mage.Sets/src/mage/cards/a/AppaLoyalSkyBison.java index 1be12ec9283..337f02de580 100644 --- a/Mage.Sets/src/mage/cards/a/AppaLoyalSkyBison.java +++ b/Mage.Sets/src/mage/cards/a/AppaLoyalSkyBison.java @@ -12,8 +12,12 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetNonlandPermanent; import java.util.UUID; @@ -22,6 +26,13 @@ import java.util.UUID; */ public final class AppaLoyalSkyBison extends CardImpl { + private static final FilterPermanent filter = new FilterNonlandPermanent("another target nonland permanent you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(TargetController.YOU.getControllerPredicate()); + } + public AppaLoyalSkyBison(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); @@ -39,8 +50,8 @@ public final class AppaLoyalSkyBison extends CardImpl { Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance())); ability.addTarget(new TargetControlledCreaturePermanent()); - // * Airbend another target nonland permanent you control.. - ability.addMode(new Mode(new AirbendTargetEffect()).addTarget(new TargetNonlandPermanent())); + // * Airbend another target nonland permanent you control. + ability.addMode(new Mode(new AirbendTargetEffect()).addTarget(new TargetPermanent(filter))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ArcTrail.java b/Mage.Sets/src/mage/cards/a/ArcTrail.java index 703e3c7ecf8..e0a9fe36d2d 100644 --- a/Mage.Sets/src/mage/cards/a/ArcTrail.java +++ b/Mage.Sets/src/mage/cards/a/ArcTrail.java @@ -7,6 +7,7 @@ import mage.constants.CardType; import mage.filter.common.FilterAnyTarget; import mage.filter.common.FilterPermanentOrPlayer; import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.target.common.TargetAnyTarget; import mage.target.common.TargetPermanentOrPlayer; import java.util.UUID; @@ -16,8 +17,7 @@ import java.util.UUID; */ public final class ArcTrail extends CardImpl { - private static final FilterPermanentOrPlayer filter1 = new FilterAnyTarget("creature, player or planeswalker to deal 2 damage"); - private static final FilterPermanentOrPlayer filter2 = new FilterAnyTarget("another creature, player or planeswalker to deal 1 damage"); + private static final FilterPermanentOrPlayer filter2 = new FilterAnyTarget("another target"); static { filter2.getPermanentFilter().add(new AnotherTargetPredicate(2)); @@ -29,7 +29,7 @@ public final class ArcTrail extends CardImpl { // Arc Trail deals 2 damage to any target and 1 damage to another target this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(2, 1)); - this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(filter1) + this.getSpellAbility().addTarget(new TargetAnyTarget() .withChooseHint("to deal 2 damage").setTargetTag(1)); this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(filter2) .withChooseHint("to deal 1 damage").setTargetTag(2)); diff --git a/Mage.Sets/src/mage/cards/a/ArceeAcrobaticCoupe.java b/Mage.Sets/src/mage/cards/a/ArceeAcrobaticCoupe.java deleted file mode 100644 index 93028094ebc..00000000000 --- a/Mage.Sets/src/mage/cards/a/ArceeAcrobaticCoupe.java +++ /dev/null @@ -1,112 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.dynamicvalue.common.SavedDamageValue; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.LivingMetalAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.counters.CounterType; -import mage.game.Controllable; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.Spell; -import mage.target.Target; - -import java.util.Collection; -import java.util.Objects; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ArceeAcrobaticCoupe extends CardImpl { - - public ArceeAcrobaticCoupe(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setRed(true); - this.color.setWhite(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Whenever you cast a spell that targets one or more creatures or Vehicles you control, put that many +1/+1 counters on Arcee. Convert Arcee. - this.addAbility(new ArceeAcrobaticCoupeTriggeredAbility()); - } - - private ArceeAcrobaticCoupe(final ArceeAcrobaticCoupe card) { - super(card); - } - - @Override - public ArceeAcrobaticCoupe copy() { - return new ArceeAcrobaticCoupe(this); - } -} - -class ArceeAcrobaticCoupeTriggeredAbility extends SpellCastControllerTriggeredAbility { - - ArceeAcrobaticCoupeTriggeredAbility() { - super(new AddCountersSourceEffect( - CounterType.P1P1.createInstance(0), - SavedDamageValue.MANY, false - ), false); - this.addEffect(new TransformSourceEffect()); - } - - private ArceeAcrobaticCoupeTriggeredAbility(final ArceeAcrobaticCoupeTriggeredAbility ability) { - super(ability); - } - - @Override - public ArceeAcrobaticCoupeTriggeredAbility copy() { - return new ArceeAcrobaticCoupeTriggeredAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!super.checkTrigger(event, game)) { - return false; - } - Spell spell = game.getSpell(event.getTargetId()); - if (spell == null) { - return false; - } - int targets = spell - .getStackAbility() - .getTargets() - .stream() - .map(Target::getTargets) - .flatMap(Collection::stream) - .map(game::getPermanent) - .filter(Objects::nonNull) - .filter(permanent -> permanent.isCreature(game) - || permanent.hasSubtype(SubType.VEHICLE, game)) - .map(Controllable::getControllerId) - .map(this::isControlledBy) - .mapToInt(x -> x ? 1 : 0) - .sum(); - if (targets > 0) { - this.getEffects().setValue("damage", targets); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever you cast a spell that targets one or more creatures or Vehicles " + - "you control, put that many +1/+1 counters on {this}. Convert {this}."; - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArceeSharpshooter.java b/Mage.Sets/src/mage/cards/a/ArceeSharpshooter.java index 5376b5b76a3..a606ec7d07e 100644 --- a/Mage.Sets/src/mage/cards/a/ArceeSharpshooter.java +++ b/Mage.Sets/src/mage/cards/a/ArceeSharpshooter.java @@ -1,44 +1,54 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.LivingMetalAbility; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.target.Target; import mage.target.common.TargetCreaturePermanent; +import java.util.Collection; +import java.util.Objects; import java.util.UUID; /** * @author TheElk801 */ -public final class ArceeSharpshooter extends CardImpl { +public final class ArceeSharpshooter extends TransformingDoubleFacedCard { public ArceeSharpshooter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{R}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{1}{R}{W}", + "Arcee, Acrobatic Coupe", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "RW"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.a.ArceeAcrobaticCoupe.class; + this.getLeftHalfCard().setPT(2, 2); + this.getRightHalfCard().setPT(2, 2); // More Than Meets the Eye {R}{W} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{R}{W}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{R}{W}")); // First strike - this.addAbility(FirstStrikeAbility.getInstance()); + this.getLeftHalfCard().addAbility(FirstStrikeAbility.getInstance()); // {1}, Remove one or more +1/+1 counters from Arcee: It deals that much damage to target creature. Convert Arcee. Ability ability = new SimpleActivatedAbility( @@ -49,7 +59,14 @@ public final class ArceeSharpshooter extends CardImpl { ability.addCost(new RemoveVariableCountersSourceCost(CounterType.P1P1, 1)); ability.addEffect(new TransformSourceEffect().setText("convert {this}")); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Arcee, Acrobatic Coupe + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Whenever you cast a spell that targets one or more creatures or Vehicles you control, put that many +1/+1 counters on Arcee. Convert Arcee. + this.getRightHalfCard().addAbility(new ArceeAcrobaticCoupeTriggeredAbility()); } private ArceeSharpshooter(final ArceeSharpshooter card) { @@ -61,3 +78,59 @@ public final class ArceeSharpshooter extends CardImpl { return new ArceeSharpshooter(this); } } + +class ArceeAcrobaticCoupeTriggeredAbility extends SpellCastControllerTriggeredAbility { + + ArceeAcrobaticCoupeTriggeredAbility() { + super(new AddCountersSourceEffect( + CounterType.P1P1.createInstance(0), + SavedDamageValue.MANY, false + ), false); + this.addEffect(new TransformSourceEffect()); + } + + private ArceeAcrobaticCoupeTriggeredAbility(final ArceeAcrobaticCoupeTriggeredAbility ability) { + super(ability); + } + + @Override + public ArceeAcrobaticCoupeTriggeredAbility copy() { + return new ArceeAcrobaticCoupeTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!super.checkTrigger(event, game)) { + return false; + } + Spell spell = game.getSpell(event.getTargetId()); + if (spell == null) { + return false; + } + int targets = spell + .getStackAbility() + .getTargets() + .stream() + .map(Target::getTargets) + .flatMap(Collection::stream) + .map(game::getPermanent) + .filter(Objects::nonNull) + .filter(permanent -> permanent.isCreature(game) + || permanent.hasSubtype(SubType.VEHICLE, game)) + .map(Controllable::getControllerId) + .map(this::isControlledBy) + .mapToInt(x -> x ? 1 : 0) + .sum(); + if (targets > 0) { + this.getEffects().setValue("damage", targets); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever you cast a spell that targets one or more creatures or Vehicles " + + "you control, put that many +1/+1 counters on {this}. Convert {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArchangelAvacyn.java b/Mage.Sets/src/mage/cards/a/ArchangelAvacyn.java index 6f4b2eb2aa9..34a0e408081 100644 --- a/Mage.Sets/src/mage/cards/a/ArchangelAvacyn.java +++ b/Mage.Sets/src/mage/cards/a/ArchangelAvacyn.java @@ -1,66 +1,86 @@ package mage.cards.a; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.*; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AnotherPredicate; import java.util.UUID; /** * @author fireshoes */ -public final class ArchangelAvacyn extends CardImpl { +public final class ArchangelAvacyn extends TransformingDoubleFacedCard { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a non-Angel creature you control"); + private static final FilterCreaturePermanent nonAngelFilter = new FilterCreaturePermanent("a non-Angel creature you control"); + private static final FilterPermanent otherCreatureFilter = new FilterCreaturePermanent("other creature"); static { - filter.add(Predicates.not(SubType.ANGEL.getPredicate())); - filter.add(TargetController.YOU.getControllerPredicate()); + otherCreatureFilter.add(AnotherPredicate.instance); + nonAngelFilter.add(Predicates.not(SubType.ANGEL.getPredicate())); + nonAngelFilter.add(TargetController.YOU.getControllerPredicate()); } public ArchangelAvacyn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "{3}{W}{W}", + "Avacyn, the Purifier", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "R"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ANGEL); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.secondSideCardClazz = mage.cards.a.AvacynThePurifier.class; + this.getLeftHalfCard().setPT(4, 4); + this.getRightHalfCard().setPT(6, 5); // Flash - this.addAbility(FlashAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlashAbility.getInstance()); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // When Archangel Avacyn enters the battlefield, creatures you control gain indestructible until end of turn. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect( IndestructibleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES ), false)); // When a non-Angel creature you control dies, transform Archangel Avacyn at the beginning of the next upkeep. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesCreatureTriggeredAbility( + this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility( new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new TransformSourceEffect()) - ).setText("transform {this} at the beginning of the next upkeep"), false, filter + ).setText("transform {this} at the beginning of the next upkeep"), false, nonAngelFilter ).setTriggerPhrase("When a non-Angel creature you control dies, ")); + + // Avacyn, the Purifier + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent. + Ability ability = new TransformIntoSourceTriggeredAbility( + new DamageAllEffect(3, "it", otherCreatureFilter) + ); + ability.addEffect(new DamagePlayersEffect(3, TargetController.OPPONENT).setText("and each opponent")); + this.getRightHalfCard().addAbility(ability); } private ArchangelAvacyn(final ArchangelAvacyn card) { diff --git a/Mage.Sets/src/mage/cards/a/ArguelsBloodFast.java b/Mage.Sets/src/mage/cards/a/ArguelsBloodFast.java index d6966008224..a7787944d99 100644 --- a/Mage.Sets/src/mage/cards/a/ArguelsBloodFast.java +++ b/Mage.Sets/src/mage/cards/a/ArguelsBloodFast.java @@ -1,42 +1,56 @@ package mage.cards.a; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.FatefulHourCondition; import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author TheElk801 */ -public final class ArguelsBloodFast extends CardImpl { +public final class ArguelsBloodFast extends TransformingDoubleFacedCard { public ArguelsBloodFast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); - - this.supertype.add(SuperType.LEGENDARY); - this.secondSideCardClazz = mage.cards.t.TempleOfAclazotz.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{1}{B}", + "Temple of Aclazotz", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{},""); // {1}{B}, Pay 2 life: Draw a card. Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}{B}")); ability.addCost(new PayLifeCost(2)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the beginning of your upkeep, if you have 5 or less life, you may transform Arguel's Blood Fast. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true ).withInterveningIf(FatefulHourCondition.instance)); + + // Temple of Aclazotz + // {T}: Add {B} + this.getRightHalfCard().addAbility(new BlackManaAbility()); + + // {T}, Sacrifice a creature: You gain life equal to the sacrificed creature's toughness. + Ability activatedAbility = new SimpleActivatedAbility(new GainLifeEffect(SacrificeCostCreaturesToughness.instance) + .setText("you gain life equal to the sacrificed creature's toughness"), new TapSourceCost()); + activatedAbility.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); + this.getRightHalfCard().addAbility(activatedAbility); } private ArguelsBloodFast(final ArguelsBloodFast card) { diff --git a/Mage.Sets/src/mage/cards/a/ArlinnEmbracedByTheMoon.java b/Mage.Sets/src/mage/cards/a/ArlinnEmbracedByTheMoon.java deleted file mode 100644 index 8a6b011c2e0..00000000000 --- a/Mage.Sets/src/mage/cards/a/ArlinnEmbracedByTheMoon.java +++ /dev/null @@ -1,68 +0,0 @@ -package mage.cards.a; - -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.StaticFilters; -import mage.game.command.emblems.ArlinnEmbracedByTheMoonEmblem; -import mage.target.common.TargetAnyTarget; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class ArlinnEmbracedByTheMoon extends CardImpl { - - public ArlinnEmbracedByTheMoon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ARLINN); - this.color.setRed(true); - this.color.setGreen(true); - - this.nightCard = true; - - // +1: Creatures you control get +1/+1 and gain trample until end of turn. - Ability ability = new LoyaltyAbility(new BoostControlledEffect( - 1, 1, Duration.EndOfTurn, - StaticFilters.FILTER_PERMANENT_CREATURE - ).setText("Creatures you control get +1/+1"), 1); - ability.addEffect(new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_PERMANENT_CREATURE - ).setText("and gain trample until end of turn")); - this.addAbility(ability); - - // -1: Arlinn, Embraced by the Moon deals 3 damage to any target. Transform Arlinn, Embraced by the Moon. - this.addAbility(new TransformAbility()); - ability = new LoyaltyAbility(new DamageTargetEffect(3), -1); - ability.addTarget(new TargetAnyTarget()); - ability.addEffect(new TransformSourceEffect()); - this.addAbility(ability); - - // -6: You get an emblem with "Creatures you control have haste and '{T}: This creature deals damage equal to its power to any target.'" - this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new ArlinnEmbracedByTheMoonEmblem()), -6)); - } - - private ArlinnEmbracedByTheMoon(final ArlinnEmbracedByTheMoon card) { - super(card); - } - - @Override - public ArlinnEmbracedByTheMoon copy() { - return new ArlinnEmbracedByTheMoon(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArlinnKord.java b/Mage.Sets/src/mage/cards/a/ArlinnKord.java index dbb9593deb6..b0c98a77768 100644 --- a/Mage.Sets/src/mage/cards/a/ArlinnKord.java +++ b/Mage.Sets/src/mage/cards/a/ArlinnKord.java @@ -3,19 +3,26 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.game.command.emblems.ArlinnEmbracedByTheMoonEmblem; import mage.game.permanent.token.WolfToken; +import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -23,16 +30,14 @@ import java.util.UUID; /** * @author fireshoes */ -public final class ArlinnKord extends CardImpl { +public final class ArlinnKord extends TransformingDoubleFacedCard { public ArlinnKord(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{G}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ARLINN); - - this.secondSideCardClazz = mage.cards.a.ArlinnEmbracedByTheMoon.class; - - this.setStartingLoyalty(3); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "{2}{R}{G}", + "Arlinn, Embraced by the Moon", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "RG"); + this.getLeftHalfCard().setStartingLoyalty(3); // +1: Until end of turn, up to one target creature gets +2/+2 and gains vigilance and haste. Ability ability = new LoyaltyAbility(new BoostTargetEffect( @@ -45,13 +50,34 @@ public final class ArlinnKord extends CardImpl { HasteAbility.getInstance(), Duration.EndOfTurn ).setText("and haste")); ability.addTarget(new TargetCreaturePermanent(0, 1)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // 0: Create a 2/2 green Wolf creature token. Transform Arlinn Kord. - this.addAbility(new TransformAbility()); ability = new LoyaltyAbility(new CreateTokenEffect(new WolfToken()), 0); ability.addEffect(new TransformSourceEffect()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Arlinn, Embraced by the Moon + // +1: Creatures you control get +1/+1 and gain trample until end of turn. + ability = new LoyaltyAbility(new BoostControlledEffect( + 1, 1, Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("Creatures you control get +1/+1"), 1); + ability.addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("and gain trample until end of turn")); + this.getRightHalfCard().addAbility(ability); + + // -1: Arlinn, Embraced by the Moon deals 3 damage to any target. Transform Arlinn, Embraced by the Moon. + ability = new LoyaltyAbility(new DamageTargetEffect(3), -1); + ability.addTarget(new TargetAnyTarget()); + ability.addEffect(new TransformSourceEffect()); + this.getRightHalfCard().addAbility(ability); + + // -6: You get an emblem with "Creatures you control have haste and '{T}: This creature deals damage equal to its power to any target.'" + this.getRightHalfCard().addAbility(new LoyaltyAbility(new GetEmblemEffect(new ArlinnEmbracedByTheMoonEmblem()), -6)); + } private ArlinnKord(final ArlinnKord card) { diff --git a/Mage.Sets/src/mage/cards/a/ArlinnTheMoonsFury.java b/Mage.Sets/src/mage/cards/a/ArlinnTheMoonsFury.java deleted file mode 100644 index bc906251947..00000000000 --- a/Mage.Sets/src/mage/cards/a/ArlinnTheMoonsFury.java +++ /dev/null @@ -1,118 +0,0 @@ -package mage.cards.a; - -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.mana.BasicManaEffect; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ArlinnTheMoonsFury extends CardImpl { - - public ArlinnTheMoonsFury(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ARLINN); - this.setStartingLoyalty(4); - this.color.setRed(true); - this.color.setGreen(true); - this.nightCard = true; - - // Nightbound - this.addAbility(new NightboundAbility()); - - // +2: Add {R}{G}. - this.addAbility(new LoyaltyAbility(new BasicManaEffect(new Mana( - 0, 0, 0, 1, 1, 0, 0, 0 - )), 2)); - - // 0: Until end of turn, Arlinn, the Moon's Fury becomes a 5/5 Werewolf creature with trample, indestructible, and haste. - this.addAbility(new LoyaltyAbility(new ArlinnTheMoonsFuryEffect(), 0)); - } - - private ArlinnTheMoonsFury(final ArlinnTheMoonsFury card) { - super(card); - } - - @Override - public ArlinnTheMoonsFury copy() { - return new ArlinnTheMoonsFury(this); - } -} - -class ArlinnTheMoonsFuryEffect extends ContinuousEffectImpl { - - ArlinnTheMoonsFuryEffect() { - super(Duration.EndOfTurn, Outcome.Benefit); - staticText = "until end of turn, {this} becomes a 5/5 Werewolf creature with trample, indestructible, and haste"; - this.dependencyTypes.add(DependencyType.BecomeCreature); - } - - private ArlinnTheMoonsFuryEffect(final ArlinnTheMoonsFuryEffect effect) { - super(effect); - } - - @Override - public ArlinnTheMoonsFuryEffect copy() { - return new ArlinnTheMoonsFuryEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent == null) { - discard(); - return false; - } - switch (layer) { - case TypeChangingEffects_4: - permanent.removeAllCardTypes(game); - permanent.addCardType(game, CardType.CREATURE); - permanent.removeAllCreatureTypes(game); - permanent.addSubType(game, SubType.WEREWOLF); - return true; - case AbilityAddingRemovingEffects_6: - permanent.addAbility(TrampleAbility.getInstance(), source.getSourceId(), game); - permanent.addAbility(IndestructibleAbility.getInstance(), source.getSourceId(), game); - permanent.addAbility(HasteAbility.getInstance(), source.getSourceId(), game); - return true; - case PTChangingEffects_7: - if (sublayer == SubLayer.SetPT_7b) { - permanent.getPower().setModifiedBaseValue(5); - permanent.getToughness().setModifiedBaseValue(5); - return true; - } - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean hasLayer(Layer layer) { - switch (layer) { - case TypeChangingEffects_4: - case AbilityAddingRemovingEffects_6: - case PTChangingEffects_7: - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java b/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java index 92dcafb438e..08c36ff72a4 100644 --- a/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java +++ b/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java @@ -1,21 +1,23 @@ package mage.cards.a; +import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.EntersWithCountersControlledEffect; import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; -import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.keyword.*; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.WolfToken; import java.util.UUID; @@ -23,20 +25,20 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ArlinnThePacksHope extends CardImpl { +public final class ArlinnThePacksHope extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterCreatureCard("creature spells"); public ArlinnThePacksHope(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{G}"); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ARLINN); - this.setStartingLoyalty(4); - this.secondSideCardClazz = mage.cards.a.ArlinnTheMoonsFury.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "{2}{R}{G}", + "Arlinn, the Moon's Fury", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "RG"); + this.getLeftHalfCard().setStartingLoyalty(4); + this.getRightHalfCard().setStartingLoyalty(4); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); // +1: Until your next turn, you may cast creature spells as though they had flash, and each creature you control enters the battlefield with an additional +1/+1 counter on it. Ability ability = new LoyaltyAbility(new CastAsThoughItHadFlashAllEffect( @@ -45,10 +47,23 @@ public final class ArlinnThePacksHope extends CardImpl { ability.addEffect(new EntersWithCountersControlledEffect( StaticFilters.FILTER_PERMANENT_CREATURE, CounterType.P1P1.createInstance(), false ).concatBy(", and")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // −3: Create two 2/2 green Wolf creature tokens. - this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new WolfToken(), 2), -3)); + this.getLeftHalfCard().addAbility(new LoyaltyAbility(new CreateTokenEffect(new WolfToken(), 2), -3)); + + // Arlinn, the Moon's Fury + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); + + // +2: Add {R}{G}. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new BasicManaEffect(new Mana( + 0, 0, 0, 1, 1, 0, 0, 0 + )), 2)); + + // 0: Until end of turn, Arlinn, the Moon's Fury becomes a 5/5 Werewolf creature with trample, indestructible, and haste. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new ArlinnTheMoonsFuryEffect(), 0)); + } private ArlinnThePacksHope(final ArlinnThePacksHope card) { @@ -60,3 +75,66 @@ public final class ArlinnThePacksHope extends CardImpl { return new ArlinnThePacksHope(this); } } + +class ArlinnTheMoonsFuryEffect extends ContinuousEffectImpl { + + ArlinnTheMoonsFuryEffect() { + super(Duration.EndOfTurn, Outcome.Benefit); + staticText = "until end of turn, {this} becomes a 5/5 Werewolf creature with trample, indestructible, and haste"; + this.dependencyTypes.add(DependencyType.BecomeCreature); + } + + private ArlinnTheMoonsFuryEffect(final ArlinnTheMoonsFuryEffect effect) { + super(effect); + } + + @Override + public ArlinnTheMoonsFuryEffect copy() { + return new ArlinnTheMoonsFuryEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + discard(); + return false; + } + switch (layer) { + case TypeChangingEffects_4: + permanent.removeAllCardTypes(game); + permanent.addCardType(game, CardType.CREATURE); + permanent.removeAllCreatureTypes(game); + permanent.addSubType(game, SubType.WEREWOLF); + return true; + case AbilityAddingRemovingEffects_6: + permanent.addAbility(TrampleAbility.getInstance(), source.getSourceId(), game); + permanent.addAbility(IndestructibleAbility.getInstance(), source.getSourceId(), game); + permanent.addAbility(HasteAbility.getInstance(), source.getSourceId(), game); + return true; + case PTChangingEffects_7: + if (sublayer == SubLayer.SetPT_7b) { + permanent.getPower().setModifiedBaseValue(5); + permanent.getToughness().setModifiedBaseValue(5); + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + switch (layer) { + case TypeChangingEffects_4: + case AbilityAddingRemovingEffects_6: + case PTChangingEffects_7: + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArrowStorm.java b/Mage.Sets/src/mage/cards/a/ArrowStorm.java index 7d68830e13d..02c720d83ca 100644 --- a/Mage.Sets/src/mage/cards/a/ArrowStorm.java +++ b/Mage.Sets/src/mage/cards/a/ArrowStorm.java @@ -7,7 +7,6 @@ import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; import mage.constants.CardType; import mage.target.common.TargetAnyTarget; import mage.watchers.common.PlayerAttackedWatcher; @@ -30,7 +29,7 @@ public final class ArrowStorm extends CardImpl { this.getSpellAbility().addTarget(new TargetAnyTarget()); // Raid - If you attacked with a creature this turn, instead Arrow Storm deals 5 damage to that creature or player and the damage can't be prevented. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(5, false), + new DamageTargetEffect(5).withCantBePrevented(), RaidCondition.instance, "

Raid — If you attacked this turn, instead {this} deals 5 damage to that permanent or player and the damage can't be prevented")); this.getSpellAbility().addWatcher(new PlayerAttackedWatcher()); diff --git a/Mage.Sets/src/mage/cards/a/AshmouthHound.java b/Mage.Sets/src/mage/cards/a/AshmouthHound.java index 4fcfac4c2ab..5e9241b9555 100644 --- a/Mage.Sets/src/mage/cards/a/AshmouthHound.java +++ b/Mage.Sets/src/mage/cards/a/AshmouthHound.java @@ -23,7 +23,7 @@ public final class AshmouthHound extends CardImpl { this.toughness = new MageInt(1); // Whenever Ashmouth Hound blocks or becomes blocked by a creature, Ashmouth Hound deals 1 damage to that creature. - this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1, true, "that creature"))); + this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that creature"))); } private AshmouthHound(final AshmouthHound card) { diff --git a/Mage.Sets/src/mage/cards/a/AuroraOfEmrakul.java b/Mage.Sets/src/mage/cards/a/AuroraOfEmrakul.java deleted file mode 100644 index 0ed7789746d..00000000000 --- a/Mage.Sets/src/mage/cards/a/AuroraOfEmrakul.java +++ /dev/null @@ -1,49 +0,0 @@ - -package mage.cards.a; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.LoseLifeOpponentsEffect; -import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class AuroraOfEmrakul extends CardImpl { - - public AuroraOfEmrakul(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.REFLECTION); - this.power = new MageInt(1); - this.toughness = new MageInt(4); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); - - // Whenever Aurora of Emrakul attacks, each opponent loses 3 life. - this.addAbility(new AttacksTriggeredAbility(new LoseLifeOpponentsEffect(3),false)); - } - - private AuroraOfEmrakul(final AuroraOfEmrakul card) { - super(card); - } - - @Override - public AuroraOfEmrakul copy() { - return new AuroraOfEmrakul(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AutumnalGloom.java b/Mage.Sets/src/mage/cards/a/AutumnalGloom.java index b7d0f232ddf..cb36799b9bc 100644 --- a/Mage.Sets/src/mage/cards/a/AutumnalGloom.java +++ b/Mage.Sets/src/mage/cards/a/AutumnalGloom.java @@ -6,12 +6,14 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.AbilityWord; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.TargetController; import java.util.UUID; @@ -19,20 +21,28 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class AutumnalGloom extends CardImpl { +public final class AutumnalGloom extends TransformingDoubleFacedCard { public AutumnalGloom(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); - this.secondSideCardClazz = mage.cards.a.AncientOfTheEquinox.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{2}{G}", + "Ancient of the Equinox", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.TREEFOLK}, "G"); + this.getRightHalfCard().setPT(4, 4); // {B}: Put the top card of your library into your graveyard. - this.addAbility(new SimpleActivatedAbility(new MillCardsControllerEffect(1), new ManaCostsImpl<>("{B}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new MillCardsControllerEffect(1), new ManaCostsImpl<>("{B}"))); // Delirium — At the beginning of your end step, if there are four or more card types among cards in your graveyard, transform Autumnal Gloom. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility( + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility( TargetController.YOU, new TransformSourceEffect(), false, DeliriumCondition.instance ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); + + // Ancient of the Equinox + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + // Hexproof + this.getRightHalfCard().addAbility(HexproofAbility.getInstance()); } private AutumnalGloom(final AutumnalGloom card) { diff --git a/Mage.Sets/src/mage/cards/a/AvabruckCaretaker.java b/Mage.Sets/src/mage/cards/a/AvabruckCaretaker.java index eaec30e14aa..56cd948b985 100644 --- a/Mage.Sets/src/mage/cards/a/AvabruckCaretaker.java +++ b/Mage.Sets/src/mage/cards/a/AvabruckCaretaker.java @@ -1,14 +1,18 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.NightboundAbility; import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; @@ -19,29 +23,49 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class AvabruckCaretaker extends CardImpl { +public final class AvabruckCaretaker extends TransformingDoubleFacedCard { public AvabruckCaretaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.h.HollowhengeHuntmaster.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{4}{G}{G}", + "Hollowhenge Huntmaster", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); + this.getLeftHalfCard().setPT(4, 4); + this.getRightHalfCard().setPT(6, 6); // Hexproof - this.addAbility(HexproofAbility.getInstance()); + this.getLeftHalfCard().addAbility(HexproofAbility.getInstance()); // At the beginning of combat on your turn, put two +1/+1 counters on another target creature you control. Ability ability = new BeginningOfCombatTriggeredAbility( new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)) ); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Hollowhenge Huntmaster + // Hexproof + this.getRightHalfCard().addAbility(HexproofAbility.getInstance()); + + // Other permanents you control have hexproof. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + HexproofAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENTS, true + ))); + + // At the beginning of combat on your turn, put two +1/+1 counters on each creature you control. + this.getRightHalfCard().addAbility(new BeginningOfCombatTriggeredAbility( + new AddCountersAllEffect( + CounterType.P1P1.createInstance(2), + StaticFilters.FILTER_CONTROLLED_CREATURE + ) + )); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private AvabruckCaretaker(final AvabruckCaretaker card) { diff --git a/Mage.Sets/src/mage/cards/a/AvacynThePurifier.java b/Mage.Sets/src/mage/cards/a/AvacynThePurifier.java deleted file mode 100644 index fc2d87749c9..00000000000 --- a/Mage.Sets/src/mage/cards/a/AvacynThePurifier.java +++ /dev/null @@ -1,62 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.DamageAllEffect; -import mage.abilities.effects.common.DamagePlayersEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.TargetController; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class AvacynThePurifier extends CardImpl { - - private static final FilterPermanent filter = new FilterCreaturePermanent("other creature"); - - static { - filter.add(AnotherPredicate.instance); - } - - public AvacynThePurifier(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ANGEL); - this.power = new MageInt(6); - this.toughness = new MageInt(5); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent. - Ability ability = new TransformIntoSourceTriggeredAbility( - new DamageAllEffect(3, "it", filter) - ); - ability.addEffect(new DamagePlayersEffect(3, TargetController.OPPONENT).setText("and each opponent")); - this.addAbility(ability); - } - - private AvacynThePurifier(final AvacynThePurifier card) { - super(card); - } - - @Override - public AvacynThePurifier copy() { - return new AvacynThePurifier(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AvacynianMissionaries.java b/Mage.Sets/src/mage/cards/a/AvacynianMissionaries.java index 400732c969f..e0aa0fdc661 100644 --- a/Mage.Sets/src/mage/cards/a/AvacynianMissionaries.java +++ b/Mage.Sets/src/mage/cards/a/AvacynianMissionaries.java @@ -1,37 +1,43 @@ package mage.cards.a; -import java.util.UUID; - -import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.Ability; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.condition.common.EquippedSourceCondition; +import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; /** * @author fireshoes */ -public final class AvacynianMissionaries extends CardImpl { +public final class AvacynianMissionaries extends TransformingDoubleFacedCard { public AvacynianMissionaries(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - - this.secondSideCardClazz = mage.cards.l.LunarchInquisitors.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{3}{W}", + "Lunarch Inquisitors", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "W"); + this.getLeftHalfCard().setPT(3, 3); + this.getRightHalfCard().setPT(4, 4); // At the beginning of your end step, if Avacynian Missionaries is equipped, transform it. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.YOU, new TransformSourceEffect().setText("transform it"), + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.YOU, new TransformSourceEffect().setText("transform it"), false, EquippedSourceCondition.instance)); + // Lunarch Inquisitors + // When this creature transforms into Lunarch Inquisitors, you may exile another target creature until Lunarch Inquisitors leaves the battlefield. + Ability ability = new TransformIntoSourceTriggeredAbility(new ExileUntilSourceLeavesEffect(), true); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + this.getRightHalfCard().addAbility(ability); } private AvacynianMissionaries(final AvacynianMissionaries card) { diff --git a/Mage.Sets/src/mage/cards/a/AvalancheOfSector7.java b/Mage.Sets/src/mage/cards/a/AvalancheOfSector7.java index 863b8b6def2..911a52fe8da 100644 --- a/Mage.Sets/src/mage/cards/a/AvalancheOfSector7.java +++ b/Mage.Sets/src/mage/cards/a/AvalancheOfSector7.java @@ -65,7 +65,7 @@ public final class AvalancheOfSector7 extends CardImpl { class AvalancheOfSector7TriggeredAbility extends TriggeredAbilityImpl { AvalancheOfSector7TriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player")); setTriggerPhrase("Whenever an opponent activates an ability of an artifact they control, "); } diff --git a/Mage.Sets/src/mage/cards/a/AvatarAang.java b/Mage.Sets/src/mage/cards/a/AvatarAang.java index 24be5ad614e..71ddf626fc6 100644 --- a/Mage.Sets/src/mage/cards/a/AvatarAang.java +++ b/Mage.Sets/src/mage/cards/a/AvatarAang.java @@ -1,50 +1,80 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.*; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FirebendingAbility; import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; import mage.game.Game; import mage.game.events.GameEvent; import mage.watchers.Watcher; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import java.util.UUID; /** * @author TheElk801 */ -public final class AvatarAang extends CardImpl { +public final class AvatarAang extends TransformingDoubleFacedCard { + + private static final FilterCard filter = new FilterCard("spells"); public AvatarAang(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}{W}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.AVATAR, SubType.ALLY}, "{R}{G}{W}{U}", + "Aang, Master of Elements", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR, SubType.ALLY}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.AVATAR); - this.subtype.add(SubType.ALLY); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.secondSideCardClazz = mage.cards.a.AangMasterOfElements.class; + this.getLeftHalfCard().setPT(4, 4); + this.getRightHalfCard().setPT(6, 6); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Firebending 2 - this.addAbility(new FirebendingAbility(2)); + this.getLeftHalfCard().addAbility(new FirebendingAbility(2)); // Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang. - this.addAbility(new AvatarAangTriggeredAbility()); + this.getLeftHalfCard().addAbility(new AvatarAangTriggeredAbility()); + + // Aang, Master of Elements + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Spells you cast cost {W}{U}{B}{R}{G} less to cast. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect( + filter, new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), StaticValue.get(1), true + ))); + + // At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.ANY, + new DoIfCostPaid(new GainLifeEffect(4), new AangMasterOfElementsCost()) + .addEffect(new DrawCardSourceControllerEffect(4).concatBy(",")) + .addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)) + .setText(", put four +1/+1 counters on him")) + .addEffect(new DamagePlayersEffect(4, TargetController.OPPONENT) + .setText(", and he deals 4 damage to each opponent")), + false + )); } private AvatarAang(final AvatarAang card) { @@ -154,3 +184,37 @@ class AvatarAangWatcher extends Watcher { return game.getState().getWatcher(AvatarAangWatcher.class).checkPlayer(source.getControllerId()); } } + +class AangMasterOfElementsCost extends CostImpl { + + AangMasterOfElementsCost() { + super(); + text = "transform {this}"; + } + + private AangMasterOfElementsCost(final AangMasterOfElementsCost cost) { + super(cost); + } + + @Override + public AangMasterOfElementsCost copy() { + return new AangMasterOfElementsCost(this); + } + + @Override + public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + return Optional + .ofNullable(source.getSourcePermanentIfItStillExists(game)) + .filter(Card::isTransformable) + .isPresent(); + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + paid = Optional + .ofNullable(source.getSourcePermanentIfItStillExists(game)) + .filter(permanent -> permanent.transform(source, game)) + .isPresent(); + return paid; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AvatarDestiny.java b/Mage.Sets/src/mage/cards/a/AvatarDestiny.java new file mode 100644 index 00000000000..c3e3e34b5bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AvatarDestiny.java @@ -0,0 +1,110 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.continuous.AddCardSubtypeAttachedEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AvatarDestiny extends CardImpl { + + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE); + + public AvatarDestiny(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget)); + + // Enchanted creature gets +1/+1 for each creature card in your graveyard and is an Avatar in addition to its other types. + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(xValue, xValue)); + ability.addEffect(new AddCardSubtypeAttachedEffect( + SubType.AVATAR, AttachmentType.AURA + ).setText("and is an Avatar in addition to its other types")); + this.addAbility(ability); + + // When enchanted creature dies, mill cards equal to its power. Return this card to its owner's hand and up to one creature card milled this way to the battlefield under your control. + this.addAbility(new DiesAttachedTriggeredAbility(new AvatarDestinyEffect(), "enchanted creature")); + } + + private AvatarDestiny(final AvatarDestiny card) { + super(card); + } + + @Override + public AvatarDestiny copy() { + return new AvatarDestiny(this); + } +} + +class AvatarDestinyEffect extends OneShotEffect { + + AvatarDestinyEffect() { + super(Outcome.Benefit); + staticText = "mill cards equal to its power. Return this card to its owner's hand and up to one " + + "creature card milled this way to the battlefield under your control"; + } + + private AvatarDestinyEffect(final AvatarDestinyEffect effect) { + super(effect); + } + + @Override + public AvatarDestinyEffect copy() { + return new AvatarDestinyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int count = Optional + .ofNullable((Permanent) getValue("attachedTo")) + .map(MageObject::getPower) + .map(MageInt::getValue) + .orElse(0); + Cards cards = player.millCards(count, source, game); + game.processAction(); + new ReturnToHandSourceEffect(false, true).apply(game, source); + TargetCard target = new TargetCard(0, 1, Zone.ALL, StaticFilters.FILTER_CARD_CREATURE); + target.withNotTarget(true); + player.choose(Outcome.PutCreatureInPlay, cards, target, source, game); + player.moveCards( + game.getCard(target.getFirstTarget()), Zone.BATTLEFIELD, source, + game, true, false, false, null + ); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AvatarKyoshiEarthbender.java b/Mage.Sets/src/mage/cards/a/AvatarKyoshiEarthbender.java index 3f10bdf55f9..69f20bef3cf 100644 --- a/Mage.Sets/src/mage/cards/a/AvatarKyoshiEarthbender.java +++ b/Mage.Sets/src/mage/cards/a/AvatarKyoshiEarthbender.java @@ -41,7 +41,7 @@ public final class AvatarKyoshiEarthbender extends CardImpl { ))); // At the beginning of combat on your turn, earthbend 8, then untap that land. - Ability ability = new BeginningOfCombatTriggeredAbility(new EarthbendTargetEffect(8)); + Ability ability = new BeginningOfCombatTriggeredAbility(new EarthbendTargetEffect(8, false)); ability.addEffect(new UntapTargetEffect().setText(", then untap that land")); ability.addTarget(new TargetControlledLandPermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AvatarYangchen.java b/Mage.Sets/src/mage/cards/a/AvatarYangchen.java new file mode 100644 index 00000000000..558ecad122c --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AvatarYangchen.java @@ -0,0 +1,57 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.CastSecondSpellTriggeredAbility; +import mage.abilities.effects.keyword.AirbendTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AvatarYangchen extends CardImpl { + + private static final FilterPermanent filter = new FilterNonlandPermanent("other target nonland permanent"); + + static { + filter.add(AnotherPredicate.instance); + } + + public AvatarYangchen(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.AVATAR); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + this.nightCard = true; + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you cast your second spell each turn, airbend up to one other target nonland permanent. + Ability ability = new CastSecondSpellTriggeredAbility(new AirbendTargetEffect()); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.addAbility(ability); + } + + private AvatarYangchen(final AvatarYangchen card) { + super(card); + } + + @Override + public AvatarYangchen copy() { + return new AvatarYangchen(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AwokenDemon.java b/Mage.Sets/src/mage/cards/a/AwokenDemon.java deleted file mode 100644 index dabf328e6ce..00000000000 --- a/Mage.Sets/src/mage/cards/a/AwokenDemon.java +++ /dev/null @@ -1,34 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AwokenDemon extends CardImpl { - - public AwokenDemon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.DEMON); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - } - - private AwokenDemon(final AwokenDemon card) { - super(card); - } - - @Override - public AwokenDemon copy() { - return new AwokenDemon(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AyaraFurnaceQueen.java b/Mage.Sets/src/mage/cards/a/AyaraFurnaceQueen.java deleted file mode 100644 index 686133de413..00000000000 --- a/Mage.Sets/src/mage/cards/a/AyaraFurnaceQueen.java +++ /dev/null @@ -1,109 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.keyword.HasteAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetCardInYourGraveyard; -import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AyaraFurnaceQueen extends CardImpl { - - private static final FilterCard filter = new FilterCard("artifact or creature card from your graveyard"); - - static { - filter.add(Predicates.or( - CardType.ARTIFACT.getPredicate(), - CardType.CREATURE.getPredicate() - )); - } - - public AyaraFurnaceQueen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.ELF); - this.subtype.add(SubType.NOBLE); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.color.setRed(true); - this.nightCard = true; - - // At the beginning of combat on your turn, return up to one target artifact or creature card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step. - Ability ability = new BeginningOfCombatTriggeredAbility( - new AyaraFurnaceQueenEffect() - ); - ability.addTarget(new TargetCardInYourGraveyard(0, 1, filter)); - this.addAbility(ability); - } - - private AyaraFurnaceQueen(final AyaraFurnaceQueen card) { - super(card); - } - - @Override - public AyaraFurnaceQueen copy() { - return new AyaraFurnaceQueen(this); - } -} - -class AyaraFurnaceQueenEffect extends OneShotEffect { - - AyaraFurnaceQueenEffect() { - super(Outcome.Benefit); - staticText = "return up to one target artifact or creature card from your graveyard " + - "to the battlefield. It gains haste. Exile it at the beginning of the next end step"; - } - - private AyaraFurnaceQueenEffect(final AyaraFurnaceQueenEffect effect) { - super(effect); - } - - @Override - public AyaraFurnaceQueenEffect copy() { - return new AyaraFurnaceQueenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Card card = game.getCard(getTargetPointer().getFirst(game, source)); - if (player == null || card == null) { - return false; - } - Permanent permanent = CardUtil.getPermanentFromCardPutToBattlefield(card, game); - if (permanent == null) { - return false; - } - game.addEffect(new GainAbilityTargetEffect( - HasteAbility.getInstance(), Duration.Custom - ).setTargetPointer(new FixedTarget(permanent.getId(), game)), source); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( - new ExileTargetEffect().setText("exile it") - .setTargetPointer(new FixedTarget(permanent.getId(), game)), - TargetController.ANY - ), source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/a/AyaraWidowOfTheRealm.java b/Mage.Sets/src/mage/cards/a/AyaraWidowOfTheRealm.java index 5fa76e7bcb9..84ca40120a5 100644 --- a/Mage.Sets/src/mage/cards/a/AyaraWidowOfTheRealm.java +++ b/Mage.Sets/src/mage/cards/a/AyaraWidowOfTheRealm.java @@ -1,49 +1,66 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.SacrificeCostManaValue; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterCard; import mage.filter.FilterOpponent; import mage.filter.StaticFilters; import mage.filter.common.FilterPermanentOrPlayer; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetPermanentOrPlayer; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; import java.util.UUID; /** * @author TheElk801 */ -public final class AyaraWidowOfTheRealm extends CardImpl { +public final class AyaraWidowOfTheRealm extends TransformingDoubleFacedCard { private static final DynamicValue xValue = SacrificeCostManaValue.PERMANENT; private static final FilterPermanentOrPlayer filter = new FilterPermanentOrPlayer( "opponent or battle", StaticFilters.FILTER_PERMANENT_BATTLE, new FilterOpponent() ); + private static final FilterCard furnaceQueenFilter = new FilterCard("artifact or creature card from your graveyard"); + + static { + furnaceQueenFilter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate() + )); + } public AyaraWidowOfTheRealm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELF); - this.subtype.add(SubType.NOBLE); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.a.AyaraFurnaceQueen.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELF, SubType.NOBLE}, "{1}{B}{B}", + "Ayara, Furnace Queen", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.ELF, SubType.NOBLE}, "BR"); + this.getLeftHalfCard().setPT(3, 3); + this.getRightHalfCard().setPT(4, 4); // {T}, Sacrifice another creature or artifact: Ayara, Widow of the Realm deals X damage to target opponent or battle and you gain X life, where X is the sacrificed permanent's mana value. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(xValue) @@ -51,11 +68,18 @@ public final class AyaraWidowOfTheRealm extends CardImpl { ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE_OR_ARTIFACT)); ability.addEffect(new GainLifeEffect(xValue).setText("and you gain X life, where X is the sacrificed permanent's mana value")); ability.addTarget(new TargetPermanentOrPlayer(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {5}{R/P}: Transform Ayara. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{R/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{R/P}"))); + + // Ayara, Furnace Queen + // At the beginning of combat on your turn, return up to one target artifact or creature card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step. + Ability triggeredAbility = new BeginningOfCombatTriggeredAbility( + new AyaraFurnaceQueenEffect() + ); + triggeredAbility.addTarget(new TargetCardInYourGraveyard(0, 1, furnaceQueenFilter)); + this.getRightHalfCard().addAbility(triggeredAbility); } private AyaraWidowOfTheRealm(final AyaraWidowOfTheRealm card) { @@ -67,3 +91,43 @@ public final class AyaraWidowOfTheRealm extends CardImpl { return new AyaraWidowOfTheRealm(this); } } + +class AyaraFurnaceQueenEffect extends OneShotEffect { + + AyaraFurnaceQueenEffect() { + super(Outcome.Benefit); + staticText = "return up to one target artifact or creature card from your graveyard " + + "to the battlefield. It gains haste. Exile it at the beginning of the next end step"; + } + + private AyaraFurnaceQueenEffect(final AyaraFurnaceQueenEffect effect) { + super(effect); + } + + @Override + public AyaraFurnaceQueenEffect copy() { + return new AyaraFurnaceQueenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (player == null || card == null) { + return false; + } + Permanent permanent = CardUtil.getPermanentFromCardPutToBattlefield(card, game); + if (permanent == null) { + return false; + } + game.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.Custom + ).setTargetPointer(new FixedTarget(permanent.getId(), game)), source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ExileTargetEffect().setText("exile it") + .setTargetPointer(new FixedTarget(permanent.getId(), game)), + TargetController.ANY + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AzorsGateway.java b/Mage.Sets/src/mage/cards/a/AzorsGateway.java index 4a6f94a4a39..8e86cef827c 100644 --- a/Mage.Sets/src/mage/cards/a/AzorsGateway.java +++ b/Mage.Sets/src/mage/cards/a/AzorsGateway.java @@ -1,23 +1,26 @@ package mage.cards.a; import mage.MageObject; +import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.ControllerLifeCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.DynamicManaAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; import mage.game.ExileZone; import mage.game.Game; @@ -31,18 +34,17 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class AzorsGateway extends CardImpl { +public final class AzorsGateway extends TransformingDoubleFacedCard { public AzorsGateway(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - - this.supertype.add(SuperType.LEGENDARY); - this.secondSideCardClazz = mage.cards.s.SanctumOfTheSun.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}", + "Sanctum of the Sun", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, ""); // {1}, {T}: Draw a card, then exile a card from your hand. // If cards with five or more different converted mana costs are exiled with Azor's Gateway, // you gain 5 life, untap Azor's Gateway, and transform it. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); ability.addEffect(new AzorsGatewayEffect()); @@ -50,7 +52,13 @@ public final class AzorsGateway extends CardImpl { new GainLifeEffect(5), AzorsGatewayCondition.instance, "If cards with five or more " + "different mana values are exiled with {this}, you gain 5 life, untap {this}, and transform it." ).addEffect(new UntapSourceEffect()).addEffect(new TransformSourceEffect())); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Sanctum of the Sun + // {T}: Add X mana of any one color, where X is your life total. + this.getRightHalfCard().addAbility(new DynamicManaAbility(new Mana(0, 0, 0, 0, 0, 0, 1, 0), ControllerLifeCount.instance, new TapSourceCost(), + "Add X mana of any one color, where X is your life total", true)); + } private AzorsGateway(final AzorsGateway card) { diff --git a/Mage.Sets/src/mage/cards/a/AzulaCunningUsurper.java b/Mage.Sets/src/mage/cards/a/AzulaCunningUsurper.java new file mode 100644 index 00000000000..2efc85c5dc7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AzulaCunningUsurper.java @@ -0,0 +1,218 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.AsThoughManaEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FirebendingAbility; +import mage.cards.*; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.ExileZone; +import mage.game.Game; +import mage.players.ManaPoolItem; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AzulaCunningUsurper extends CardImpl { + + public AzulaCunningUsurper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Firebending 2 + this.addAbility(new FirebendingAbility(2)); + + // When Azula enters, target opponent exiles a nontoken creature they control, then they exile a nonland card from their graveyard. + Ability ability = new EntersBattlefieldTriggeredAbility(new AzulaCunningUsurperExileEffect()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + // During your turn, you may cast cards exiled with Azula and you may cast them as though they had flash. Mana of any type can be spent to cast those spells. + ability = new SimpleStaticAbility(new AzulaCunningUsurperCastEffect()); + ability.addEffect(new AzulaCunningUsurperFlashEffect()); + ability.addEffect(new AzulaCunningUsurperManaEffect()); + this.addAbility(ability); + } + + private AzulaCunningUsurper(final AzulaCunningUsurper card) { + super(card); + } + + @Override + public AzulaCunningUsurper copy() { + return new AzulaCunningUsurper(this); + } +} + +class AzulaCunningUsurperExileEffect extends OneShotEffect { + + AzulaCunningUsurperExileEffect() { + super(Outcome.Benefit); + staticText = "target opponent exiles a nontoken creature they control, " + + "then they exile a nonland card from their graveyard"; + } + + private AzulaCunningUsurperExileEffect(final AzulaCunningUsurperExileEffect effect) { + super(effect); + } + + @Override + public AzulaCunningUsurperExileEffect copy() { + return new AzulaCunningUsurperExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + if (game.getBattlefield().contains(StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN, player.getId(), source, game, 1)) { + TargetPermanent target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN); + target.withNotTarget(true); + player.choose(Outcome.Exile, target, source, game); + cards.add(target.getFirstTarget()); + } + if (player.getGraveyard().count(StaticFilters.FILTER_CARD_A_NON_CREATURE, game) > 0) { + TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_A_NON_CREATURE); + target.withNotTarget(true); + player.choose(Outcome.Exile, target, source, game); + cards.add(target.getFirstTarget()); + } + return player.moveCardsToExile( + cards.getCards(game), source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceLogName(game, source) + ); + } +} + +class AzulaCunningUsurperCastEffect extends AsThoughEffectImpl { + + AzulaCunningUsurperCastEffect() { + super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "during your turn, you may cast cards exiled with {this}"; + } + + private AzulaCunningUsurperCastEffect(final AzulaCunningUsurperCastEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public AzulaCunningUsurperCastEffect copy() { + return new AzulaCunningUsurperCastEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (!source.isControlledBy(affectedControllerId) || !game.isActivePlayer(affectedControllerId)) { + return false; + } + Card card = game.getCard(objectId); + if (card == null || card.isLand(game)) { + return false; + } + ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return exileZone != null && exileZone.contains(objectId); + } +} + +class AzulaCunningUsurperFlashEffect extends AsThoughEffectImpl { + + AzulaCunningUsurperFlashEffect() { + super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "and you may cast them as though they had flash"; + } + + private AzulaCunningUsurperFlashEffect(final AzulaCunningUsurperFlashEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public AzulaCunningUsurperFlashEffect copy() { + return new AzulaCunningUsurperFlashEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (!source.isControlledBy(affectedControllerId) || !game.isActivePlayer(affectedControllerId)) { + return false; + } + Card card = game.getCard(objectId); + if (card == null || card.isLand(game)) { + return false; + } + ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return exileZone != null && exileZone.contains(objectId); + } +} + +class AzulaCunningUsurperManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { + + AzulaCunningUsurperManaEffect() { + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "Mana of any type can be spent to cast those spells"; + } + + private AzulaCunningUsurperManaEffect(final AzulaCunningUsurperManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public AzulaCunningUsurperManaEffect copy() { + return new AzulaCunningUsurperManaEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (!source.isControlledBy(affectedControllerId) || !game.isActivePlayer(affectedControllerId)) { + return false; + } + Card card = game.getCard(objectId); + if (card == null || card.isLand(game)) { + return false; + } + ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return exileZone != null && exileZone.contains(objectId); + } + + @Override + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AzusasManyJourneys.java b/Mage.Sets/src/mage/cards/a/AzusasManyJourneys.java index b62d3daf6f5..1f240eb0840 100644 --- a/Mage.Sets/src/mage/cards/a/AzusasManyJourneys.java +++ b/Mage.Sets/src/mage/cards/a/AzusasManyJourneys.java @@ -1,45 +1,51 @@ package mage.cards.a; -import java.util.UUID; - +import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; import mage.abilities.common.SagaAbility; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.UntapLandsEffect; import mage.abilities.effects.common.continuous.PlayAdditionalLandsControllerEffect; -import mage.abilities.keyword.TransformAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SagaChapter; import mage.constants.SubType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; + +import java.util.UUID; /** * * @author weirddan455 */ -public final class AzusasManyJourneys extends CardImpl { +public final class AzusasManyJourneys extends TransformingDoubleFacedCard { public AzusasManyJourneys(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{G}", + "Likeness of the Seeker", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.MONK}, "G"); - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.l.LikenessOfTheSeeker.class; + this.getRightHalfCard().setPT(3, 3); // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I — You may play an additional land this turn. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new PlayAdditionalLandsControllerEffect(1, Duration.EndOfTurn)); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_I, new PlayAdditionalLandsControllerEffect(1, Duration.EndOfTurn)); // II — You gain 3 life. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new GainLifeEffect(3)); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new GainLifeEffect(3)); // III — Exile this Saga, then return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Likeness of the Seeker + // Whenever Likeness of the Seeker becomes blocked, untap up to three lands you control. + this.getRightHalfCard().addAbility(new BecomesBlockedSourceTriggeredAbility(new UntapLandsEffect(3, true, true), false)); } private AzusasManyJourneys(final AzusasManyJourneys card) { diff --git a/Mage.Sets/src/mage/cards/b/BaboonSpirit.java b/Mage.Sets/src/mage/cards/b/BaboonSpirit.java index c3c9c72746d..655bc2179cf 100644 --- a/Mage.Sets/src/mage/cards/b/BaboonSpirit.java +++ b/Mage.Sets/src/mage/cards/b/BaboonSpirit.java @@ -47,7 +47,7 @@ public final class BaboonSpirit extends CardImpl { // {3}{U}: Exile another target creature you control. Return it to the battlefield under its owner's control at the beginning of the next end step. Ability ability = new SimpleActivatedAbility( - new ExileReturnBattlefieldNextEndStepTargetEffect(), new ManaCostsImpl<>("{3}{U}") + new ExileReturnBattlefieldNextEndStepTargetEffect().withTextThatCard(false), new ManaCostsImpl<>("{3}{U}") ); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/Badgermole.java b/Mage.Sets/src/mage/cards/b/Badgermole.java index 24d46635ab7..e849ecf4ea9 100644 --- a/Mage.Sets/src/mage/cards/b/Badgermole.java +++ b/Mage.Sets/src/mage/cards/b/Badgermole.java @@ -39,7 +39,7 @@ public final class Badgermole extends CardImpl { this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( TrampleAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES_P1P1 - ))); + ).setText("creatures you control with +1/+1 counters on them have trample"))); } private Badgermole(final Badgermole card) { diff --git a/Mage.Sets/src/mage/cards/b/BahamutWardenOfLight.java b/Mage.Sets/src/mage/cards/b/BahamutWardenOfLight.java deleted file mode 100644 index ccd8cd3eb2a..00000000000 --- a/Mage.Sets/src/mage/cards/b/BahamutWardenOfLight.java +++ /dev/null @@ -1,71 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.AddCountersAllEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.counters.CounterType; -import mage.filter.StaticFilters; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BahamutWardenOfLight extends CardImpl { - - public BahamutWardenOfLight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.DRAGON); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.nightCard = true; - this.color.setWhite(true); - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I, II -- Wings of Light -- Put a +1/+1 counter on each other creature you control. Those creatures gain flying until end of turn. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, ability -> { - ability.addEffect(new AddCountersAllEffect( - CounterType.P1P1.createInstance(), StaticFilters.FILTER_OTHER_CONTROLLED_CREATURE - )); - ability.addEffect(new GainAbilityControlledEffect( - FlyingAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_CONTROLLED_CREATURE - ).setText("Those creatures gain flying until end of turn")); - ability.withFlavorWord("Wings of Light"); - }); - - // III -- Gigaflare -- Destroy target permanent. Exile Bahamut, then return it to the battlefield. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, ability -> { - ability.addEffect(new DestroyTargetEffect()); - ability.addEffect(new ExileSourceAndReturnFaceUpEffect()); - ability.addTarget(new TargetPermanent()); - ability.withFlavorWord("Gigaflare"); - }); - this.addAbility(sagaAbility); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private BahamutWardenOfLight(final BahamutWardenOfLight card) { - super(card); - } - - @Override - public BahamutWardenOfLight copy() { - return new BahamutWardenOfLight(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BaithookAngler.java b/Mage.Sets/src/mage/cards/b/BaithookAngler.java index 1c3126ea98f..792fa6b9075 100644 --- a/Mage.Sets/src/mage/cards/b/BaithookAngler.java +++ b/Mage.Sets/src/mage/cards/b/BaithookAngler.java @@ -1,10 +1,9 @@ package mage.cards.b; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,19 +12,25 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BaithookAngler extends CardImpl { +public final class BaithookAngler extends TransformingDoubleFacedCard { public BaithookAngler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.h.HookHauntDrifter.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{1}{U}", + "Hook-Haunt Drifter", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U" + ); + this.getLeftHalfCard().setPT(2, 1); + this.getRightHalfCard().setPT(1, 2); // Disturb {1}{U} - this.addAbility(new DisturbAbility(this, "{1}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{1}{U}")); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // If Hook-Haunt Drifter would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private BaithookAngler(final BaithookAngler card) { diff --git a/Mage.Sets/src/mage/cards/b/BalambGardenAirborne.java b/Mage.Sets/src/mage/cards/b/BalambGardenAirborne.java deleted file mode 100644 index 7b34006109d..00000000000 --- a/Mage.Sets/src/mage/cards/b/BalambGardenAirborne.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.keyword.CrewAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BalambGardenAirborne extends CardImpl { - - public BalambGardenAirborne(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(5); - this.toughness = new MageInt(4); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever Balamb Garden attacks, draw a card. - this.addAbility(new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1))); - - // Crew 1 - this.addAbility(new CrewAbility(1)); - } - - private BalambGardenAirborne(final BalambGardenAirborne card) { - super(card); - } - - @Override - public BalambGardenAirborne copy() { - return new BalambGardenAirborne(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BalambGardenSeeDAcademy.java b/Mage.Sets/src/mage/cards/b/BalambGardenSeeDAcademy.java index 723330f7b88..7c45b3ce32c 100644 --- a/Mage.Sets/src/mage/cards/b/BalambGardenSeeDAcademy.java +++ b/Mage.Sets/src/mage/cards/b/BalambGardenSeeDAcademy.java @@ -1,6 +1,7 @@ package mage.cards.b; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.CostAdjuster; @@ -8,17 +9,20 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.mana.BlueManaAbility; import mage.abilities.mana.GreenManaAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; @@ -30,29 +34,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BalambGardenSeeDAcademy extends CardImpl { +public final class BalambGardenSeeDAcademy extends TransformingDoubleFacedCard { public BalambGardenSeeDAcademy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.subtype.add(SubType.TOWN); - this.secondSideCardClazz = mage.cards.b.BalambGardenAirborne.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.LAND}, new SubType[]{SubType.TOWN}, "", + "Balamb Garden, Airborne", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, ""); + this.getRightHalfCard().setPT(5, 4); // This land enters tapped. - this.addAbility(new EntersBattlefieldTappedAbility()); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTappedAbility()); // Add {G} or {U}. - this.addAbility(new GreenManaAbility()); - this.addAbility(new BlueManaAbility()); + this.getLeftHalfCard().addAbility(new GreenManaAbility()); + this.getLeftHalfCard().addAbility(new BlueManaAbility()); // {5}{G}{U}, {T}: Transform this land. This ability costs {1} less to activate for each other Town you control. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{G}{U}")); ability.addCost(new TapSourceCost()); ability.addEffect(new InfoEffect("This ability costs {1} less to activate for each other Town you control")); - this.addAbility(ability + this.getLeftHalfCard().addAbility(ability .setCostAdjuster(BalambGardenSeeDAcademyAdjuster.instance) .addHint(BalambGardenSeeDAcademyAdjuster.getHint())); + + // Balamb Garden, Airborne + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever Balamb Garden attacks, draw a card. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1))); + + // Crew 1 + this.getRightHalfCard().addAbility(new CrewAbility(1)); } private BalambGardenSeeDAcademy(final BalambGardenSeeDAcademy card) { diff --git a/Mage.Sets/src/mage/cards/b/BallistaWatcher.java b/Mage.Sets/src/mage/cards/b/BallistaWatcher.java index 809f160eda2..3ae2e3066ec 100644 --- a/Mage.Sets/src/mage/cards/b/BallistaWatcher.java +++ b/Mage.Sets/src/mage/cards/b/BallistaWatcher.java @@ -1,16 +1,23 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.common.TargetAnyTarget; import java.util.UUID; @@ -18,17 +25,16 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BallistaWatcher extends CardImpl { +public final class BallistaWatcher extends TransformingDoubleFacedCard { public BallistaWatcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER, SubType.WEREWOLF}, "{2}{R}{R}", + "Ballista Wielder", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.b.BallistaWielder.class; + // Ballista Watcher + this.getLeftHalfCard().setPT(4, 3); // {2}{R}, {T}: Ballista Watcher deals 1 damage to any target. Ability ability = new SimpleActivatedAbility( @@ -36,10 +42,21 @@ public final class BallistaWatcher extends CardImpl { ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Ballista Wielder + this.getRightHalfCard().setPT(5, 5); + + // {2}{R}: Ballista Wielder deals 1 damage to any target. A creature dealt damage this way can't block this turn. + Ability weilderAbility = new SimpleActivatedAbility(new BallistaWielderEffect(), new ManaCostsImpl<>("{2}{R}")); + weilderAbility.addTarget(new TargetAnyTarget()); + this.getRightHalfCard().addAbility(weilderAbility); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private BallistaWatcher(final BallistaWatcher card) { @@ -51,3 +68,34 @@ public final class BallistaWatcher extends CardImpl { return new BallistaWatcher(this); } } + +class BallistaWielderEffect extends OneShotEffect { + + BallistaWielderEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 1 damage to any target. A creature dealt damage this way can't block this turn"; + } + + private BallistaWielderEffect(final BallistaWielderEffect effect) { + super(effect); + } + + @Override + public BallistaWielderEffect copy() { + return new BallistaWielderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + return player != null && player.damage(1, source, game) > 0; + } + if (permanent.damage(1, source, game) <= 0) { + return false; + } + game.addEffect(new CantBlockTargetEffect(Duration.EndOfTurn), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BallistaWielder.java b/Mage.Sets/src/mage/cards/b/BallistaWielder.java deleted file mode 100644 index 81c2dd0ad50..00000000000 --- a/Mage.Sets/src/mage/cards/b/BallistaWielder.java +++ /dev/null @@ -1,85 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.combat.CantBlockTargetEffect; -import mage.abilities.keyword.NightboundAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetAnyTarget; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BallistaWielder extends CardImpl { - - public BallistaWielder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setRed(true); - this.nightCard = true; - - // {2}{R}: Ballista Wielder deals 1 damage to any target. A creature dealt damage this way can't block this turn. - Ability ability = new SimpleActivatedAbility(new BallistaWielderEffect(), new ManaCostsImpl<>("{2}{R}")); - ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private BallistaWielder(final BallistaWielder card) { - super(card); - } - - @Override - public BallistaWielder copy() { - return new BallistaWielder(this); - } -} - -class BallistaWielderEffect extends OneShotEffect { - - BallistaWielderEffect() { - super(Outcome.Benefit); - staticText = "{this} deals 1 damage to any target. A creature dealt damage this way can't block this turn"; - } - - private BallistaWielderEffect(final BallistaWielderEffect effect) { - super(effect); - } - - @Override - public BallistaWielderEffect copy() { - return new BallistaWielderEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null) { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - return player != null && player.damage(1, source, game) > 0; - } - if (permanent.damage(1, source, game) <= 0) { - return false; - } - game.addEffect(new CantBlockTargetEffect(Duration.EndOfTurn), source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BanebladeScoundrel.java b/Mage.Sets/src/mage/cards/b/BanebladeScoundrel.java index 7645832128f..8615e59e7cf 100644 --- a/Mage.Sets/src/mage/cards/b/BanebladeScoundrel.java +++ b/Mage.Sets/src/mage/cards/b/BanebladeScoundrel.java @@ -1,11 +1,13 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.common.LoseLifeTargetControllerEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; @@ -17,31 +19,47 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BanebladeScoundrel extends CardImpl { +public final class BanebladeScoundrel extends TransformingDoubleFacedCard { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking {this}"); static { filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); } public BanebladeScoundrel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE, SubType.WEREWOLF}, "{3}{B}", + "Baneclaw Marauder", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "B"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.b.BaneclawMarauder.class; + // Baneblade Scoundrel + this.getLeftHalfCard().setPT(4, 3); // Whenever Baneblade Scoundrel becomes blocked, each creature blocking it gets -1/-1 until end of turn. - this.addAbility(new BecomesBlockedSourceTriggeredAbility(new BoostAllEffect( + this.getLeftHalfCard().addAbility(new BecomesBlockedSourceTriggeredAbility(new BoostAllEffect( -1, -1, Duration.EndOfTurn, filter, false ).setText("each creature blocking it gets -1/-1 until end of turn"), false)); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Baneclaw Marauder + this.getRightHalfCard().setPT(5, 4); + + // Whenever Baneclaw Marauder becomes blocked, each creature blocking it gets -1/-1 until end of turn. + this.getRightHalfCard().addAbility(new BecomesBlockedSourceTriggeredAbility(new BoostAllEffect( + -1, -1, Duration.EndOfTurn, filter, false + ).setText("each creature blocking it gets -1/-1 until end of turn"), false)); + + // Whenever a creature blocking Baneclaw Marauder dies, its controller loses 1 life. + this.getRightHalfCard().addAbility(new DiesCreatureTriggeredAbility( + new LoseLifeTargetControllerEffect(1) + .setText("that creature's controller loses 1 life"), + false, filter, true + )); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private BanebladeScoundrel(final BanebladeScoundrel card) { diff --git a/Mage.Sets/src/mage/cards/b/BaneclawMarauder.java b/Mage.Sets/src/mage/cards/b/BaneclawMarauder.java deleted file mode 100644 index 668dd16535e..00000000000 --- a/Mage.Sets/src/mage/cards/b/BaneclawMarauder.java +++ /dev/null @@ -1,63 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; -import mage.abilities.common.DiesCreatureTriggeredAbility; -import mage.abilities.effects.common.LoseLifeTargetControllerEffect; -import mage.abilities.effects.common.continuous.BoostAllEffect; -import mage.abilities.keyword.NightboundAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BaneclawMarauder extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature blocking {this}"); - - static { - filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); - } - - public BaneclawMarauder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - - // Whenever Baneclaw Marauder becomes blocked, each creature blocking it gets -1/-1 until end of turn. - this.addAbility(new BecomesBlockedSourceTriggeredAbility(new BoostAllEffect( - -1, -1, Duration.EndOfTurn, filter, false - ).setText("each creature blocking it gets -1/-1 until end of turn"), false)); - - // Whenever a creature blocking Baneclaw Marauder dies, its controller loses 1 life. - this.addAbility(new DiesCreatureTriggeredAbility( - new LoseLifeTargetControllerEffect(1) - .setText("that creature's controller loses 1 life"), - false, filter, true - )); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private BaneclawMarauder(final BaneclawMarauder card) { - super(card); - } - - @Override - public BaneclawMarauder copy() { - return new BaneclawMarauder(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BarretWallace.java b/Mage.Sets/src/mage/cards/b/BarretWallace.java index d7e9c48f3ad..df2a98d233d 100644 --- a/Mage.Sets/src/mage/cards/b/BarretWallace.java +++ b/Mage.Sets/src/mage/cards/b/BarretWallace.java @@ -49,10 +49,10 @@ public final class BarretWallace extends CardImpl { // Whenever Barret Wallace attacks, it deals damage equal to the number of equipped creatures you control to defending player. this.addAbility(new AttacksTriggeredAbility( - new DamageTargetEffect(xValue, true, "it") + new DamageTargetEffect(xValue) .setText("it deals damage equal to the number of equipped creatures you control to defending player"), false, null, SetTargetPointer.PLAYER - ).withRuleTextReplacement(true).addHint(hint)); + ).addHint(hint)); } private BarretWallace(final BarretWallace card) { diff --git a/Mage.Sets/src/mage/cards/b/BearerOfOverwhelmingTruths.java b/Mage.Sets/src/mage/cards/b/BearerOfOverwhelmingTruths.java deleted file mode 100644 index 655b7b2834a..00000000000 --- a/Mage.Sets/src/mage/cards/b/BearerOfOverwhelmingTruths.java +++ /dev/null @@ -1,45 +0,0 @@ - -package mage.cards.b; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.keyword.InvestigateEffect; -import mage.abilities.keyword.ProwessAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class BearerOfOverwhelmingTruths extends CardImpl { - - public BearerOfOverwhelmingTruths(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.HUMAN, SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.color.setBlue(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Prowess - this.addAbility(new ProwessAbility()); - - // Whenever Bearer of Overwhelming Truths deals combat damage to a player, investigate. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new InvestigateEffect(), false)); - } - - private BearerOfOverwhelmingTruths(final BearerOfOverwhelmingTruths card) { - super(card); - } - - @Override - public BearerOfOverwhelmingTruths copy() { - return new BearerOfOverwhelmingTruths(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BefriendingTheMoths.java b/Mage.Sets/src/mage/cards/b/BefriendingTheMoths.java index 23ce37cae8a..5bfa5cc39ce 100644 --- a/Mage.Sets/src/mage/cards/b/BefriendingTheMoths.java +++ b/Mage.Sets/src/mage/cards/b/BefriendingTheMoths.java @@ -6,9 +6,8 @@ import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SagaChapter; import mage.constants.SubType; @@ -19,20 +18,20 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BefriendingTheMoths extends CardImpl { +public final class BefriendingTheMoths extends TransformingDoubleFacedCard { public BefriendingTheMoths(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.i.ImperialMoth.class; + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{3}{W}", + "Imperial Moth", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.INSECT}, "W"); + // Befriending the Moths // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(getLeftHalfCard()); // I, II — Target creature you control gets +1/+1 and gains flying until end of turn. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, new Effects( new BoostTargetEffect(1, 1) .setText("target creature you control gets +1/+1"), @@ -42,10 +41,14 @@ public final class BefriendingTheMoths extends CardImpl { ); // III — Exile this Saga, then return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + sagaAbility.addChapterEffect(getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility); + // Imperial Moth + this.getRightHalfCard().setPT(2, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private BefriendingTheMoths(final BefriendingTheMoths card) { diff --git a/Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java b/Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java index c42d0c20e54..bbf412e6f26 100644 --- a/Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java +++ b/Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java @@ -1,15 +1,19 @@ package mage.cards.b; import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.HeckbentCondition; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.keyword.ScryEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SagaChapter; @@ -21,35 +25,49 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BeholdTheUnspeakable extends CardImpl { +public final class BeholdTheUnspeakable extends TransformingDoubleFacedCard { public BeholdTheUnspeakable(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.v.VisionOfTheUnspeakable.class; + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{3}{U}{U}", + "Vision of the Unspeakable", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U"); + // Behold the Unspeakable // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(getLeftHalfCard()); // I — Creatures you don't control get -2/-0 until your next turn. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new BoostAllEffect( + sagaAbility.addChapterEffect(getLeftHalfCard(), SagaChapter.CHAPTER_I, new BoostAllEffect( -2, 0, Duration.UntilYourNextTurn, StaticFilters.FILTER_CREATURES_YOU_DONT_CONTROL, false )); // II — If you have one or fewer cards in hand, draw four cards. Otherwise, scry 2, then draw two cards. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new ConditionalOneShotEffect( + sagaAbility.addChapterEffect(getLeftHalfCard(), SagaChapter.CHAPTER_II, new ConditionalOneShotEffect( new DrawCardSourceControllerEffect(4), new ScryEffect(2), HeckbentCondition.instance, "if you have one or fewer cards in hand, " + "draw four cards. Otherwise, scry 2, then draw two cards" ).addOtherwiseEffect(new DrawCardSourceControllerEffect(2))); // III — Exile this Saga, then return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + sagaAbility.addChapterEffect(getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility); + // Vision of the Unspeakable + this.getRightHalfCard().setPT(0, 0); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Vision of the Unspeakable gets +1/+1 for each card in your hand. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostSourceEffect( + CardsInControllerHandCount.ANY_SINGULAR, + CardsInControllerHandCount.ANY_SINGULAR, + Duration.WhileOnBattlefield + ))); } private BeholdTheUnspeakable(final BeholdTheUnspeakable card) { diff --git a/Mage.Sets/src/mage/cards/b/BeifongsBountyHunters.java b/Mage.Sets/src/mage/cards/b/BeifongsBountyHunters.java index c1253abe2e9..6c47f575379 100644 --- a/Mage.Sets/src/mage/cards/b/BeifongsBountyHunters.java +++ b/Mage.Sets/src/mage/cards/b/BeifongsBountyHunters.java @@ -42,7 +42,7 @@ public final class BeifongsBountyHunters extends CardImpl { // Whenever a nonland creature you control dies, earthbend X, where X is that creature's power. Ability ability = new DiesCreatureTriggeredAbility( - new EarthbendTargetEffect(BeifongsBountyHuntersValue.instance), false, filter + new EarthbendTargetEffect(BeifongsBountyHuntersValue.instance, true), false, filter ); ability.addTarget(new TargetControlledLandPermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BelenonWarAnthem.java b/Mage.Sets/src/mage/cards/b/BelenonWarAnthem.java deleted file mode 100644 index 432533a985b..00000000000 --- a/Mage.Sets/src/mage/cards/b/BelenonWarAnthem.java +++ /dev/null @@ -1,35 +0,0 @@ -package mage.cards.b; - -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BelenonWarAnthem extends CardImpl { - - public BelenonWarAnthem(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.color.setWhite(true); - this.nightCard = true; - - // Creatures you control get +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); - } - - private BelenonWarAnthem(final BelenonWarAnthem card) { - super(card); - } - - @Override - public BelenonWarAnthem copy() { - return new BelenonWarAnthem(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BelovedBeggar.java b/Mage.Sets/src/mage/cards/b/BelovedBeggar.java index a07558efdd3..6ee16a8e389 100644 --- a/Mage.Sets/src/mage/cards/b/BelovedBeggar.java +++ b/Mage.Sets/src/mage/cards/b/BelovedBeggar.java @@ -1,10 +1,10 @@ package mage.cards.b; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,20 +13,27 @@ import java.util.UUID; /** * @author weirddan455 */ -public final class BelovedBeggar extends CardImpl { +public final class BelovedBeggar extends TransformingDoubleFacedCard { public BelovedBeggar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(0); - this.toughness = new MageInt(4); - - this.secondSideCardClazz = mage.cards.g.GenerousSoul.class; + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{1}{W}", + "Generous Soul", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "W"); + this.getLeftHalfCard().setPT(0, 4); + this.getRightHalfCard().setPT(4, 4); // Disturb {4}{W}{W} - this.addAbility(new DisturbAbility(this, "{4}{W}{W}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{4}{W}{W}")); + + // Generous Soul + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // If Generous Soul would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private BelovedBeggar(final BelovedBeggar card) { diff --git a/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java b/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java index 7fd9c9d7903..f9f263deb35 100644 --- a/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java +++ b/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java @@ -39,7 +39,7 @@ public final class BenBenAkkiHermit extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(new PermanentsOnBattlefieldCount(filter), true), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(new PermanentsOnBattlefieldCount(filter)), new TapSourceCost()); ability.addTarget(new TargetAttackingCreature()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BereavedSurvivor.java b/Mage.Sets/src/mage/cards/b/BereavedSurvivor.java index 463b0716483..28e3e704c72 100644 --- a/Mage.Sets/src/mage/cards/b/BereavedSurvivor.java +++ b/Mage.Sets/src/mage/cards/b/BereavedSurvivor.java @@ -1,37 +1,56 @@ package mage.cards.b; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.SubType; +import mage.filter.FilterCard; import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; /** * @author TheElk801 */ -public final class BereavedSurvivor extends CardImpl { +public final class BereavedSurvivor extends TransformingDoubleFacedCard { + private static final FilterCard filter + = new FilterCreatureCard("creature card with mana value 2 or less from your graveyard"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3)); + } public BereavedSurvivor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{2}{W}", + "Dauntless Avenger", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER}, "W"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.d.DauntlessAvenger.class; + // Bereaved Survivor + this.getLeftHalfCard().setPT(2, 1); // When another creature you control dies, transform Bereaved Survivor. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesCreatureTriggeredAbility( + this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility( new TransformSourceEffect(), false, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE ).setTriggerPhrase("When another creature you control dies, ")); + + // Dauntless Avenger + this.getRightHalfCard().setPT(3, 2); + + // Whenever Dauntless Avenger attacks, return target creature card with mana value 2 or less from your graveyard to the battlefield tapped and attacking. + Ability ability = new AttacksTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(true, true)); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.getRightHalfCard().addAbility(ability); } private BereavedSurvivor(final BereavedSurvivor card) { diff --git a/Mage.Sets/src/mage/cards/b/BindingGeist.java b/Mage.Sets/src/mage/cards/b/BindingGeist.java index df255c28543..68c7ed88e96 100644 --- a/Mage.Sets/src/mage/cards/b/BindingGeist.java +++ b/Mage.Sets/src/mage/cards/b/BindingGeist.java @@ -1,15 +1,20 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.EnchantAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponentsCreaturePermanent; import java.util.UUID; @@ -17,23 +22,38 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BindingGeist extends CardImpl { +public final class BindingGeist extends TransformingDoubleFacedCard { public BindingGeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{2}{U}", + "Spectral Binding", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "U"); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(3); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.s.SpectralBinding.class; + // Binding Geist + this.getLeftHalfCard().setPT(3, 1); // Whenever Binding Geist attacks, target creature an opponent controls gets -2/-0 until end of turn. Ability ability = new AttacksTriggeredAbility(new BoostTargetEffect(-2, 0)); ability.addTarget(new TargetOpponentsCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Spectral Binding + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); // Disturb {1}{U} - this.addAbility(new DisturbAbility(this, "{1}{U}")); + // needs to be added after right half has spell ability target set + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{1}{U}")); + + // Enchanted creature gets -2/-0. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(-2, 0))); + + // If Spectral Binding would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private BindingGeist(final BindingGeist card) { diff --git a/Mage.Sets/src/mage/cards/b/BiolumeEgg.java b/Mage.Sets/src/mage/cards/b/BiolumeEgg.java index 9f5b8140020..83ed25e5abc 100644 --- a/Mage.Sets/src/mage/cards/b/BiolumeEgg.java +++ b/Mage.Sets/src/mage/cards/b/BiolumeEgg.java @@ -1,22 +1,22 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SacrificeSourceTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.players.Player; @@ -25,28 +25,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BiolumeEgg extends CardImpl { +public final class BiolumeEgg extends TransformingDoubleFacedCard { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent(SubType.ISLAND, "Islands"); public BiolumeEgg(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SERPENT, SubType.EGG}, "{2}{U}", + "Biolume Serpent", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SERPENT}, "U"); - this.subtype.add(SubType.SERPENT); - this.subtype.add(SubType.EGG); - this.power = new MageInt(0); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.b.BiolumeSerpent.class; + // Biolume Egg + this.getLeftHalfCard().setPT(0, 4); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // When Biolume Egg enters the battlefield, scry 2. - this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); // When you sacrifice Biolume Egg, return it to the battlefield transformed under its owner's control at the beginning of the next end step. - this.addAbility(new TransformAbility()); - this.addAbility(new SacrificeSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + this.getLeftHalfCard().addAbility(new SacrificeSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new BiolumeEggEffect()), true ).setText("return it to the battlefield transformed under its owner's control at the beginning of the next end step"), false, true)); + + // Biolume Serpent + this.getRightHalfCard().setPT(4, 4); + + // Sacrifice two Islands: Biolume Serpent can't be blocked this turn. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility( + new CantBeBlockedSourceEffect(Duration.EndOfTurn), + new SacrificeTargetCost(2, filter) + )); } private BiolumeEgg(final BiolumeEgg card) { diff --git a/Mage.Sets/src/mage/cards/b/BiolumeSerpent.java b/Mage.Sets/src/mage/cards/b/BiolumeSerpent.java deleted file mode 100644 index bcee214b7b3..00000000000 --- a/Mage.Sets/src/mage/cards/b/BiolumeSerpent.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.filter.common.FilterControlledPermanent; -import mage.target.common.TargetControlledPermanent; -import mage.target.common.TargetSacrifice; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BiolumeSerpent extends CardImpl { - - private static final FilterControlledPermanent filter - = new FilterControlledPermanent(SubType.ISLAND, "Islands"); - - public BiolumeSerpent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SERPENT); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlue(true); - this.nightCard = true; - - // Sacrifice two Islands: Biolume Serpent can't be blocked this turn. - this.addAbility(new SimpleActivatedAbility( - new CantBeBlockedSourceEffect(Duration.EndOfTurn), - new SacrificeTargetCost(2, filter) - )); - } - - private BiolumeSerpent(final BiolumeSerpent card) { - super(card); - } - - @Override - public BiolumeSerpent copy() { - return new BiolumeSerpent(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BirdAdmirer.java b/Mage.Sets/src/mage/cards/b/BirdAdmirer.java index b724b703f26..5eb9664ae7d 100644 --- a/Mage.Sets/src/mage/cards/b/BirdAdmirer.java +++ b/Mage.Sets/src/mage/cards/b/BirdAdmirer.java @@ -1,10 +1,10 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.keyword.NightboundAbility; import mage.abilities.keyword.ReachAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,23 +13,31 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BirdAdmirer extends CardImpl { +public final class BirdAdmirer extends TransformingDoubleFacedCard { public BirdAdmirer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ARCHER, SubType.WEREWOLF}, "{2}{G}", + "Wing Shredder", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ARCHER); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(1); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.w.WingShredder.class; + // Bird Admirer + this.getLeftHalfCard().setPT(1, 4); // Reach - this.addAbility(ReachAbility.getInstance()); + this.getLeftHalfCard().addAbility(ReachAbility.getInstance()); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Wing Shredder + this.getRightHalfCard().setPT(3, 5); + + // Reach + this.getRightHalfCard().addAbility(ReachAbility.getInstance()); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private BirdAdmirer(final BirdAdmirer card) { diff --git a/Mage.Sets/src/mage/cards/b/BladewheelChariot.java b/Mage.Sets/src/mage/cards/b/BladewheelChariot.java deleted file mode 100644 index aa6b22cf8aa..00000000000 --- a/Mage.Sets/src/mage/cards/b/BladewheelChariot.java +++ /dev/null @@ -1,60 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; -import mage.abilities.keyword.CrewAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.filter.common.FilterControlledArtifactPermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetControlledPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BladewheelChariot extends CardImpl { - - private static final FilterControlledPermanent filter - = new FilterControlledArtifactPermanent("other untapped artifacts you control"); - - static { - filter.add(AnotherPredicate.instance); - filter.add(TappedPredicate.UNTAPPED); - } - - public BladewheelChariot(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.nightCard = true; - this.color.setWhite(true); - - // Tap two other untapped artifacts you control: Bladewheel Chariot becomes an artifact creature until end of turn. - this.addAbility(new SimpleActivatedAbility(new AddCardTypeSourceEffect( - Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE - ).setText("{this} becomes an artifact creature until end of turn"), new TapTargetCost(new TargetControlledPermanent(2, filter)))); - - // Crew 1 - this.addAbility(new CrewAbility(1)); - } - - private BladewheelChariot(final BladewheelChariot card) { - super(card); - } - - @Override - public BladewheelChariot copy() { - return new BladewheelChariot(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BlightreaperThallid.java b/Mage.Sets/src/mage/cards/b/BlightreaperThallid.java index a5cd19e5727..2410b9e2b66 100644 --- a/Mage.Sets/src/mage/cards/b/BlightreaperThallid.java +++ b/Mage.Sets/src/mage/cards/b/BlightreaperThallid.java @@ -1,33 +1,48 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.meta.OrTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.permanent.token.PhyrexianSaprolingToken; import java.util.UUID; /** * @author TheElk801 */ -public final class BlightreaperThallid extends CardImpl { +public final class BlightreaperThallid extends TransformingDoubleFacedCard { public BlightreaperThallid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.FUNGUS}, "{1}{B}", + "Blightsower Thallid", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.FUNGUS}, "BG"); - this.subtype.add(SubType.FUNGUS); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.b.BlightsowerThallid.class; + // Blightreaper Thallid + this.getLeftHalfCard().setPT(2, 2); // {3}{G/P}: Transform Blightreaper Thallid. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{G/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{G/P}"))); + + // Blightsower Thallid + this.getRightHalfCard().setPT(3, 3); + + // When this creature transforms into Blightsower Thallid or dies, create a 1/1 green Phyrexian Saproling creature token. + this.getRightHalfCard().addAbility(new OrTriggeredAbility( + Zone.BATTLEFIELD, new CreateTokenEffect(new PhyrexianSaprolingToken()), false, + "When this creature transforms into {this} or dies, ", + new TransformIntoSourceTriggeredAbility(null), + new DiesSourceTriggeredAbility(null, false) + )); } private BlightreaperThallid(final BlightreaperThallid card) { diff --git a/Mage.Sets/src/mage/cards/b/BlightsowerThallid.java b/Mage.Sets/src/mage/cards/b/BlightsowerThallid.java deleted file mode 100644 index 62a5dd8ab40..00000000000 --- a/Mage.Sets/src/mage/cards/b/BlightsowerThallid.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.DiesSourceTriggeredAbility; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.meta.OrTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.permanent.token.PhyrexianSaprolingToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BlightsowerThallid extends CardImpl { - - public BlightsowerThallid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.FUNGUS); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.color.setGreen(true); - this.nightCard = true; - - // When this creature transforms into Blightsower Thallid or dies, create a 1/1 green Phyrexian Saproling creature token. - this.addAbility(new OrTriggeredAbility( - Zone.BATTLEFIELD, new CreateTokenEffect(new PhyrexianSaprolingToken()), false, - "When this creature transforms into {this} or dies, ", - new TransformIntoSourceTriggeredAbility(null), - new DiesSourceTriggeredAbility(null, false) - )); - } - - private BlightsowerThallid(final BlightsowerThallid card) { - super(card); - } - - @Override - public BlightsowerThallid copy() { - return new BlightsowerThallid(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BlitzwingAdaptiveAssailant.java b/Mage.Sets/src/mage/cards/b/BlitzwingAdaptiveAssailant.java deleted file mode 100644 index bf76a3de6bd..00000000000 --- a/Mage.Sets/src/mage/cards/b/BlitzwingAdaptiveAssailant.java +++ /dev/null @@ -1,83 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.LivingMetalAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.util.RandomUtil; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BlitzwingAdaptiveAssailant extends CardImpl { - - public BlitzwingAdaptiveAssailant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - this.color.setBlack(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // At the beginning of combat on your turn, choose flying or indestructible at random. Blitzwing gains that ability until end of turn. - this.addAbility(new BeginningOfCombatTriggeredAbility( - new BlitzwingAdaptiveAssailantEffect() - )); - - // Whenever Blitzwing deals combat damage to a player, convert it. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new TransformSourceEffect().setText("convert it"), false - )); - } - - private BlitzwingAdaptiveAssailant(final BlitzwingAdaptiveAssailant card) { - super(card); - } - - @Override - public BlitzwingAdaptiveAssailant copy() { - return new BlitzwingAdaptiveAssailant(this); - } -} - -class BlitzwingAdaptiveAssailantEffect extends OneShotEffect { - - BlitzwingAdaptiveAssailantEffect() { - super(Outcome.Benefit); - staticText = "choose flying or indestructible at random. {this} gains that ability until end of turn"; - } - - private BlitzwingAdaptiveAssailantEffect(final BlitzwingAdaptiveAssailantEffect effect) { - super(effect); - } - - @Override - public BlitzwingAdaptiveAssailantEffect copy() { - return new BlitzwingAdaptiveAssailantEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Ability ability = RandomUtil.nextBoolean() ? FlyingAbility.getInstance() : IndestructibleAbility.getInstance(); - game.informPlayers(ability.getRule() + " has been chosen"); - game.addEffect(new GainAbilitySourceEffect(ability, Duration.EndOfTurn), source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BlitzwingCruelTormentor.java b/Mage.Sets/src/mage/cards/b/BlitzwingCruelTormentor.java index effa3be1f7a..22583cb96c9 100644 --- a/Mage.Sets/src/mage/cards/b/BlitzwingCruelTormentor.java +++ b/Mage.Sets/src/mage/cards/b/BlitzwingCruelTormentor.java @@ -1,17 +1,24 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.LivingMetalAbility; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.util.RandomUtil; import mage.watchers.common.PlayerLostLifeWatcher; import java.util.UUID; @@ -19,26 +26,43 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BlitzwingCruelTormentor extends CardImpl { +public final class BlitzwingCruelTormentor extends TransformingDoubleFacedCard { public BlitzwingCruelTormentor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{5}{B}", + "Blitzwing Adaptive Assailant", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "B"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(6); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.b.BlitzwingAdaptiveAssailant.class; + + // Blitzwing, Cruel Tormentor + this.getLeftHalfCard().setPT(6, 5); // More Than Meets the Eye {3}{B} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{3}{B}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{3}{B}")); // At the beginning of your end step, target opponent loses life equal to the life that player lost this turn. If no life is lost this way, convert Blitzwing. Ability ability = new BeginningOfEndStepTriggeredAbility( new BlitzwingCruelTormentorEffect() ); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Blitzwing Adaptive Assailant + this.getRightHalfCard().setPT(3, 5); + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // At the beginning of combat on your turn, choose flying or indestructible at random. Blitzwing gains that ability until end of turn. + this.getRightHalfCard().addAbility(new BeginningOfCombatTriggeredAbility( + new BlitzwingAdaptiveAssailantEffect() + )); + + // Whenever Blitzwing deals combat damage to a player, convert it. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new TransformSourceEffect().setText("convert it"), false + )); } private BlitzwingCruelTormentor(final BlitzwingCruelTormentor card) { @@ -81,3 +105,28 @@ class BlitzwingCruelTormentorEffect extends OneShotEffect { return permanent != null && permanent.transform(source, game); } } + +class BlitzwingAdaptiveAssailantEffect extends OneShotEffect { + + BlitzwingAdaptiveAssailantEffect() { + super(Outcome.Benefit); + staticText = "choose flying or indestructible at random. {this} gains that ability until end of turn"; + } + + private BlitzwingAdaptiveAssailantEffect(final BlitzwingAdaptiveAssailantEffect effect) { + super(effect); + } + + @Override + public BlitzwingAdaptiveAssailantEffect copy() { + return new BlitzwingAdaptiveAssailantEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Ability ability = RandomUtil.nextBoolean() ? FlyingAbility.getInstance() : IndestructibleAbility.getInstance(); + game.informPlayers(ability.getRule() + " has been chosen"); + game.addEffect(new GainAbilitySourceEffect(ability, Duration.EndOfTurn), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java b/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java index 8cc8653d882..8a0186c8386 100644 --- a/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java +++ b/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java @@ -1,9 +1,8 @@ - package mage.cards.b; -import mage.MageInt; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; @@ -11,17 +10,19 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.constants.Duration; import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.VampireToken; import java.util.UUID; @@ -29,33 +30,46 @@ import java.util.UUID; /** * @author Loki */ -public final class BloodlineKeeper extends CardImpl { +public final class BloodlineKeeper extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterControlledPermanent(SubType.VAMPIRE, "you control five or more Vampires"); private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 4); private static final Hint hint = new ValueHint("Vampires you control", new PermanentsOnBattlefieldCount(filter)); + private static final FilterCreaturePermanent lordOfLineageFilter = new FilterCreaturePermanent(SubType.VAMPIRE, "Vampire creatures"); public BloodlineKeeper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); - this.subtype.add(SubType.VAMPIRE); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "{2}{B}{B}", + "Lord of Lineage", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "B"); - this.power = new MageInt(3); - this.toughness = new MageInt(3); + // Bloodline Keeper + this.getLeftHalfCard().setPT(3, 3); - this.secondSideCardClazz = mage.cards.l.LordOfLineage.class; - - this.addAbility(FlyingAbility.getInstance()); + // Flying + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // {T}: Create a 2/2 black Vampire creature token with flying. - this.addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new VampireToken()), new TapSourceCost())); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new VampireToken()), new TapSourceCost())); // {B}: Transform Bloodline Keeper. Activate this ability only if you control five or more Vampires. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateIfConditionActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateIfConditionActivatedAbility( new TransformSourceEffect(), new ManaCostsImpl<>("{B}"), condition ).addHint(hint)); + + // Lord of Lineage + this.getRightHalfCard().setPT(5, 5); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Other Vampire creatures you control get +2/+2. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, lordOfLineageFilter, true))); + + // {T}: Create a 2/2 black Vampire creature token with flying. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new VampireToken()), new TapSourceCost())); + } private BloodlineKeeper(final BloodlineKeeper card) { diff --git a/Mage.Sets/src/mage/cards/b/BloodswornKnight.java b/Mage.Sets/src/mage/cards/b/BloodswornKnight.java deleted file mode 100644 index ac11ba87537..00000000000 --- a/Mage.Sets/src/mage/cards/b/BloodswornKnight.java +++ /dev/null @@ -1,65 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.common.DiscardCardCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; -import mage.abilities.effects.common.TapSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; -import mage.abilities.keyword.IndestructibleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author weirddan455 - */ -public final class BloodswornKnight extends CardImpl { - - private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURES); - - public BloodswornKnight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setBlack(true); - - // Back half of Bloodsworn Squire - this.nightCard = true; - - // Bloodsworn Knight's power and toughness are each equal to the number of creature cards in your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(xValue))); - - // {1}{B}, Discard a card: Bloodsworn Knight gains indestructible until end of turn. Tap it. - Ability ability = new SimpleActivatedAbility( - new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), - new ManaCostsImpl<>("{1}{B}") - ); - ability.addCost(new DiscardCardCost()); - ability.addEffect(new TapSourceEffect().setText("tap it")); - this.addAbility(ability); - } - - private BloodswornKnight(final BloodswornKnight card) { - super(card); - } - - @Override - public BloodswornKnight copy() { - return new BloodswornKnight(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BloodswornSquire.java b/Mage.Sets/src/mage/cards/b/BloodswornSquire.java index a13ac16a0a7..024c1363925 100644 --- a/Mage.Sets/src/mage/cards/b/BloodswornSquire.java +++ b/Mage.Sets/src/mage/cards/b/BloodswornSquire.java @@ -1,41 +1,45 @@ package mage.cards.b; -import java.util.UUID; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.TransformAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; +import mage.constants.Zone; import mage.filter.StaticFilters; +import java.util.UUID; + /** * * @author weirddan455 */ -public final class BloodswornSquire extends CardImpl { +public final class BloodswornSquire extends TransformingDoubleFacedCard { + + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURES); public BloodswornSquire(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.SOLDIER}, "{3}{B}", + "Bloodsworn Knight", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.KNIGHT}, "B"); - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.b.BloodswornKnight.class; - - this.addAbility(new TransformAbility()); + // Bloodsworn Squire + this.getLeftHalfCard().setPT(3, 3); // {1}{B}, Discard a card: Bloodsworn Squire gains indestructible until end of turn. Tap it. Then if there are four or more creature cards in your graveyard, transform Bloodsworn Squire. Ability ability = new SimpleActivatedAbility( @@ -49,7 +53,22 @@ public final class BloodswornSquire extends CardImpl { new CardsInControllerGraveyardCondition(4, StaticFilters.FILTER_CARD_CREATURES), "Then if there are four or more creature cards in your graveyard, transform {this}" )); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Bloodsworn Knight + this.getRightHalfCard().setPT(0, 0); + + // Bloodsworn Knight's power and toughness are each equal to the number of creature cards in your graveyard. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(xValue))); + + // {1}{B}, Discard a card: Bloodsworn Knight gains indestructible until end of turn. Tap it. + ability = new SimpleActivatedAbility( + new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), + new ManaCostsImpl<>("{1}{B}") + ); + ability.addCost(new DiscardCardCost()); + ability.addEffect(new TapSourceEffect().setText("tap it")); + this.getRightHalfCard().addAbility(ability); } private BloodswornSquire(final BloodswornSquire card) { diff --git a/Mage.Sets/src/mage/cards/b/BoilingRockRioter.java b/Mage.Sets/src/mage/cards/b/BoilingRockRioter.java index 3c703be49a6..117abeba8e4 100644 --- a/Mage.Sets/src/mage/cards/b/BoilingRockRioter.java +++ b/Mage.Sets/src/mage/cards/b/BoilingRockRioter.java @@ -32,7 +32,7 @@ import java.util.UUID; public final class BoilingRockRioter extends CardImpl { private static final FilterControlledPermanent filter - = new FilterControlledPermanent(SubType.ALLY, "untaped Ally you control"); + = new FilterControlledPermanent(SubType.ALLY, "untapped Ally you control"); static { filter.add(TappedPredicate.UNTAPPED); diff --git a/Mage.Sets/src/mage/cards/b/BondedHerdbeast.java b/Mage.Sets/src/mage/cards/b/BondedHerdbeast.java index aa422331237..205bd40eae0 100644 --- a/Mage.Sets/src/mage/cards/b/BondedHerdbeast.java +++ b/Mage.Sets/src/mage/cards/b/BondedHerdbeast.java @@ -1,12 +1,11 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -15,19 +14,25 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BondedHerdbeast extends CardImpl { +public final class BondedHerdbeast extends TransformingDoubleFacedCard { public BondedHerdbeast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BEAST}, "{4}{G}", + "Plated Kilnbeast", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.BEAST}, "RG"); - this.subtype.add(SubType.BEAST); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.p.PlatedKilnbeast.class; + // Bonded Herdbeast + this.getLeftHalfCard().setPT(4, 5); // {4}{R/P}: Transform Bonded Herdbeast. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{R/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{R/P}"))); + + // Plated Kilnbeast + this.getRightHalfCard().setPT(7, 5); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); } private BondedHerdbeast(final BondedHerdbeast card) { diff --git a/Mage.Sets/src/mage/cards/b/BonecrusherGiant.java b/Mage.Sets/src/mage/cards/b/BonecrusherGiant.java index c20f2a16940..8fc5ea889d1 100644 --- a/Mage.Sets/src/mage/cards/b/BonecrusherGiant.java +++ b/Mage.Sets/src/mage/cards/b/BonecrusherGiant.java @@ -29,9 +29,8 @@ public final class BonecrusherGiant extends AdventureCard { // Whenever Bonecrusher Giant becomes the target of a spell, Bonecrusher Giant deals 2 damage to that spell's controller. this.addAbility(new BecomesTargetSourceTriggeredAbility( - new DamageTargetEffect( - 2, true, "that spell's controller", "{this}" - ), StaticFilters.FILTER_SPELL_A, SetTargetPointer.PLAYER, false) + new DamageTargetEffect(2).withTargetDescription("that spell's controller"), + StaticFilters.FILTER_SPELL_A, SetTargetPointer.PLAYER, false) .withRuleTextReplacement(false)); // Stomp diff --git a/Mage.Sets/src/mage/cards/b/BoobyTrap.java b/Mage.Sets/src/mage/cards/b/BoobyTrap.java index e26b8ebf1af..2cec841bf46 100644 --- a/Mage.Sets/src/mage/cards/b/BoobyTrap.java +++ b/Mage.Sets/src/mage/cards/b/BoobyTrap.java @@ -51,8 +51,11 @@ public final class BoobyTrap extends CardImpl { class BoobyTrapTriggeredAbility extends TriggeredAbilityImpl { - public BoobyTrapTriggeredAbility() { - super(Zone.BATTLEFIELD, new DoIfCostPaid(new DamageTargetEffect(10, true, "that player"), new SacrificeSourceCost(), "", false), false); + BoobyTrapTriggeredAbility() { + super(Zone.BATTLEFIELD, new DoIfCostPaid( + new DamageTargetEffect(10).withTargetDescription("that player"), + new SacrificeSourceCost(), "", false + ), false); } private BoobyTrapTriggeredAbility(final BoobyTrapTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/b/BoscoJustABear.java b/Mage.Sets/src/mage/cards/b/BoscoJustABear.java index fb19192af94..9fd115d629f 100644 --- a/Mage.Sets/src/mage/cards/b/BoscoJustABear.java +++ b/Mage.Sets/src/mage/cards/b/BoscoJustABear.java @@ -47,7 +47,7 @@ public final class BoscoJustABear extends CardImpl { // {2}{G}, Sacrifice a Food: Put two +1/+1 counters on Bosco. He gains trample until end of turn. Ability ability = new SimpleActivatedAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{2}{G}") + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), new ManaCostsImpl<>("{2}{G}") ); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_FOOD)); ability.addEffect(new GainAbilitySourceEffect( diff --git a/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java b/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java index 120cf07a3ab..7e5bc35d11a 100644 --- a/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java +++ b/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java @@ -1,13 +1,17 @@ package mage.cards.b; import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.LandsYouControlCount; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.ReachAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SagaChapter; import mage.constants.SubType; import mage.filter.FilterCard; @@ -21,22 +25,23 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BoseijuReachesSkyward extends CardImpl { +public final class BoseijuReachesSkyward extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterBasicCard(SubType.FOREST, "basic Forest cards"); public BoseijuReachesSkyward(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.b.BranchOfBoseiju.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{3}{G}", + "Branch of Boseiju", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.PLANT}, "G"); + // Boseiju Reaches Skyward // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(getLeftHalfCard()); // I — Search your library for up to two basic Forest cards, reveal them, put them into your hand, then shuffle. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, + getLeftHalfCard(), SagaChapter.CHAPTER_I, new SearchLibraryPutInHandEffect(new TargetCardInLibrary( 0, 2, filter ), true) @@ -44,16 +49,25 @@ public final class BoseijuReachesSkyward extends CardImpl { // II — Put up to one target land card from your graveyard on top of your library. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, + getLeftHalfCard(), SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, new PutOnLibraryTargetEffect(true), new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_LAND_FROM_YOUR_GRAVEYARD) ); // III — Exile this Saga, then return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + sagaAbility.addChapterEffect(getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility); + // Branch of Boseiju + this.getRightHalfCard().setPT(0, 0); + + // Reach + this.getRightHalfCard().addAbility(ReachAbility.getInstance()); + + // Branch of Boseiju gets +1/+1 for each land you control. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostSourceEffect( + LandsYouControlCount.instance, LandsYouControlCount.instance, Duration.WhileOnBattlefield + ).setText("{this} gets +1/+1 for each land you control"))); } private BoseijuReachesSkyward(final BoseijuReachesSkyward card) { diff --git a/Mage.Sets/src/mage/cards/b/BottomlessPoolLockerRoom.java b/Mage.Sets/src/mage/cards/b/BottomlessPoolLockerRoom.java index 7ad36a46cf3..24bbd2026fa 100644 --- a/Mage.Sets/src/mage/cards/b/BottomlessPoolLockerRoom.java +++ b/Mage.Sets/src/mage/cards/b/BottomlessPoolLockerRoom.java @@ -1,21 +1,17 @@ package mage.cards.b; -import java.util.UUID; - import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; import mage.abilities.common.UnlockThisDoorTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardSetInfo; import mage.cards.RoomCard; -import mage.constants.CardType; -import mage.constants.SetTargetPointer; -import mage.constants.SpellAbilityType; -import mage.constants.SubType; -import mage.constants.TargetController; +import mage.constants.*; import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author oscscull */ @@ -38,14 +34,14 @@ public final class BottomlessPoolLockerRoom extends RoomCard { UnlockThisDoorTriggeredAbility left = new UnlockThisDoorTriggeredAbility( new ReturnToHandTargetEffect(), false, true); left.addTarget(new TargetCreaturePermanent(0, 1)); + this.getLeftHalfCard().addAbility(left); // Right half ability - "Whenever one or more creatures you control deal combat damage to a player, draw a card." DealsDamageToAPlayerAllTriggeredAbility right = new DealsDamageToAPlayerAllTriggeredAbility( new DrawCardSourceControllerEffect(1), StaticFilters.FILTER_CONTROLLED_A_CREATURE, false, SetTargetPointer.PLAYER, true, true, TargetController.OPPONENT); - - this.addRoomAbilities(left, right); + this.getRightHalfCard().addAbility(right); } private BottomlessPoolLockerRoom(final BottomlessPoolLockerRoom card) { diff --git a/Mage.Sets/src/mage/cards/b/BraidedNet.java b/Mage.Sets/src/mage/cards/b/BraidedNet.java index 1457bd6054b..c6cb8b39632 100644 --- a/Mage.Sets/src/mage/cards/b/BraidedNet.java +++ b/Mage.Sets/src/mage/cards/b/BraidedNet.java @@ -5,20 +5,28 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.hint.common.ArtifactYouControlHint; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.TargetPermanent; import java.util.UUID; @@ -26,7 +34,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BraidedNet extends CardImpl { +public final class BraidedNet extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterNonlandPermanent("another target nonland permanent"); @@ -35,11 +43,14 @@ public final class BraidedNet extends CardImpl { } public BraidedNet(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); - this.secondSideCardClazz = mage.cards.b.BraidedQuipu.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{U}", + "Braided Quipu", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "U"); + // Braided Net // Braided Net enters the battlefield with three net counters on it. - this.addAbility(new EntersBattlefieldAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.NET.createInstance(3)), "with three net counters on it" )); @@ -49,10 +60,20 @@ public final class BraidedNet extends CardImpl { ability.addCost(new RemoveCountersSourceCost(CounterType.NET.createInstance())); ability.addEffect(new BraidedNetEffect()); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Craft with artifact {1}{U} - this.addAbility(new CraftAbility("{1}{U}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{1}{U}")); + + // Braided Quipu + // {3}{U}, {T}: Draw a card for each artifact you control, then put Braided Quipu into its owner's library third from the top. + ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(ArtifactYouControlCount.instance), new ManaCostsImpl<>("{3}{U}") + ); + ability.addCost(new TapSourceCost()); + ability.addEffect(new BraidedQuipuEffect()); + this.getRightHalfCard().addAbility(ability.addHint(ArtifactYouControlHint.instance)); + } private BraidedNet(final BraidedNet card) { @@ -100,3 +121,29 @@ class BraidedNetEffect extends RestrictionEffect { return permanent == null || !permanent.isTapped(); } } + +class BraidedQuipuEffect extends OneShotEffect { + + BraidedQuipuEffect() { + super(Outcome.Benefit); + staticText = ", then put {this} into its owner's library third from the top"; + } + + private BraidedQuipuEffect(final BraidedQuipuEffect effect) { + super(effect); + } + + @Override + public BraidedQuipuEffect copy() { + return new BraidedQuipuEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + return player != null + && permanent != null + && player.putCardOnTopXOfLibrary(permanent, game, source, 3, true); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BraidedQuipu.java b/Mage.Sets/src/mage/cards/b/BraidedQuipu.java deleted file mode 100644 index e68735e4d47..00000000000 --- a/Mage.Sets/src/mage/cards/b/BraidedQuipu.java +++ /dev/null @@ -1,74 +0,0 @@ -package mage.cards.b; - -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.hint.common.ArtifactYouControlHint; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BraidedQuipu extends CardImpl { - - public BraidedQuipu(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - this.nightCard = true; - this.color.setBlue(true); - - // {3}{U}, {T}: Draw a card for each artifact you control, then put Braided Quipu into its owner's library third from the top. - Ability ability = new SimpleActivatedAbility( - new DrawCardSourceControllerEffect(ArtifactYouControlCount.instance), new ManaCostsImpl<>("{3}{U}") - ); - ability.addCost(new TapSourceCost()); - ability.addEffect(new BraidedQuipuEffect()); - this.addAbility(ability.addHint(ArtifactYouControlHint.instance)); - } - - private BraidedQuipu(final BraidedQuipu card) { - super(card); - } - - @Override - public BraidedQuipu copy() { - return new BraidedQuipu(this); - } -} - -class BraidedQuipuEffect extends OneShotEffect { - - BraidedQuipuEffect() { - super(Outcome.Benefit); - staticText = ", then put {this} into its owner's library third from the top"; - } - - private BraidedQuipuEffect(final BraidedQuipuEffect effect) { - super(effect); - } - - @Override - public BraidedQuipuEffect copy() { - return new BraidedQuipuEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = source.getSourcePermanentIfItStillExists(game); - return player != null - && permanent != null - && player.putCardOnTopXOfLibrary(permanent, game, source, 3, true); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BranchOfBoseiju.java b/Mage.Sets/src/mage/cards/b/BranchOfBoseiju.java deleted file mode 100644 index 7f721738d42..00000000000 --- a/Mage.Sets/src/mage/cards/b/BranchOfBoseiju.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.LandsYouControlCount; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.keyword.ReachAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BranchOfBoseiju extends CardImpl { - - public BranchOfBoseiju(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.PLANT); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setGreen(true); - this.nightCard = true; - - // Reach - this.addAbility(ReachAbility.getInstance()); - - // Branch of Boseiju gets +1/+1 for each land you control. - this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( - LandsYouControlCount.instance, LandsYouControlCount.instance, Duration.WhileOnBattlefield - ).setText("{this} gets +1/+1 for each land you control"))); - } - - private BranchOfBoseiju(final BranchOfBoseiju card) { - super(card); - } - - @Override - public BranchOfBoseiju copy() { - return new BranchOfBoseiju(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BrandedHowler.java b/Mage.Sets/src/mage/cards/b/BrandedHowler.java deleted file mode 100644 index 4aac4619373..00000000000 --- a/Mage.Sets/src/mage/cards/b/BrandedHowler.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.b; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class BrandedHowler extends CardImpl { - - public BrandedHowler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Branded Howler. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private BrandedHowler(final BrandedHowler card) { - super(card); - } - - @Override - public BrandedHowler copy() { - return new BrandedHowler(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java b/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java index 16459284827..1c9bc9ec276 100644 --- a/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java +++ b/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java @@ -1,6 +1,7 @@ package mage.cards.b; import mage.abilities.Ability; +import mage.abilities.common.CastSpellPaidBySourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.DescendedThisTurnCondition; @@ -11,16 +12,17 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.RemoveAllCountersSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.keyword.DiscoverEffect; +import mage.abilities.mana.RedManaAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.TargetController; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.counters.CounterType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.PermanentPredicate; import mage.game.Game; +import mage.game.stack.Spell; import mage.players.Player; import mage.watchers.common.DescendedWatcher; @@ -29,21 +31,27 @@ import java.util.UUID; /** * @author Susucr */ -public final class BrasssTunnelGrinder extends CardImpl { +public final class BrasssTunnelGrinder extends TransformingDoubleFacedCard { private static final Condition condition = new SourceHasCounterCondition(CounterType.BORE, 3); + private static final FilterSpell filter = new FilterSpell("a permanent spell"); + + static { + filter.add(PermanentPredicate.instance); + } + public BrasssTunnelGrinder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{R}"); - this.secondSideCardClazz = mage.cards.t.TecutlanTheSearingRift.class; - - this.supertype.add(SuperType.LEGENDARY); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{R}", + "Tecutlan, the Searing Rift", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{SubType.CAVE}, ""); + // Brass's Tunnel-Grinder // When Brass's Tunnel-Grinder enters the battlefield, discard any number of cards, then draw that many cards plus one. - this.addAbility(new EntersBattlefieldTriggeredAbility(new BrasssTunnelGrinderEffect())); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new BrasssTunnelGrinderEffect())); // At the beginning of your end step, if you descended this turn, put a bore counter on Brass's Tunnel-Grinder. Then if there are three or more bore counters on it, remove those counters and transform it. - this.addAbility(new TransformAbility()); Ability ability = new BeginningOfEndStepTriggeredAbility( TargetController.YOU, new AddCountersSourceEffect(CounterType.BORE.createInstance()), false, DescendedThisTurnCondition.instance @@ -53,7 +61,18 @@ public final class BrasssTunnelGrinder extends CardImpl { "Then if there are three or more bore counters on it, remove those counters and transform it" ).addEffect(new TransformSourceEffect())); ability.addHint(DescendedThisTurnCount.getHint()); - this.addAbility(ability, new DescendedWatcher()); + ability.addWatcher(new DescendedWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // Tecutlan, the Searing Rift + // {T}: Add {R}. + this.getRightHalfCard().addAbility(new RedManaAbility()); + + // Whenever you cast a permanent spell using mana produced by Tecutlan, the Searing Rift, discover X, where X is that spell's mana value. + this.getRightHalfCard().addAbility(new CastSpellPaidBySourceTriggeredAbility( + new TecutlanTheSearingRiftEffect(), + filter, true + )); } private BrasssTunnelGrinder(final BrasssTunnelGrinder card) { @@ -94,3 +113,35 @@ class BrasssTunnelGrinderEffect extends OneShotEffect { return true; } } + +class TecutlanTheSearingRiftEffect extends OneShotEffect { + + TecutlanTheSearingRiftEffect() { + super(Outcome.Benefit); + staticText = "discover X, where X is that spell's mana value"; + } + + private TecutlanTheSearingRiftEffect(final TecutlanTheSearingRiftEffect effect) { + super(effect); + } + + @Override + public TecutlanTheSearingRiftEffect copy() { + return new TecutlanTheSearingRiftEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + + Spell spell = game.getSpellOrLKIStack(getTargetPointer().getFirst(game, source)); + int mv = spell == null ? 0 : Math.max(0, spell.getManaValue()); + + DiscoverEffect.doDiscover(controller, mv, game, source); + return true; + } + +} diff --git a/Mage.Sets/src/mage/cards/b/BreakneckRider.java b/Mage.Sets/src/mage/cards/b/BreakneckRider.java index fbc0c3322e3..216c81bab3e 100644 --- a/Mage.Sets/src/mage/cards/b/BreakneckRider.java +++ b/Mage.Sets/src/mage/cards/b/BreakneckRider.java @@ -1,31 +1,54 @@ package mage.cards.b; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author fireshoes */ -public final class BreakneckRider extends CardImpl { +public final class BreakneckRider extends TransformingDoubleFacedCard { public BreakneckRider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); - this.subtype.add(SubType.HUMAN, SubType.SCOUT, SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SCOUT, SubType.WEREWOLF}, "{1}{R}{R}", + "Neck Breaker", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); - this.secondSideCardClazz = mage.cards.n.NeckBreaker.class; + // Breakneck Rider + this.getLeftHalfCard().setPT(3, 3); // At the beginning of each upkeep, if no spells were cast last turn, transform Breakneck Rider. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Neck Breaker + this.getRightHalfCard().setPT(4, 3); + + // Attacking creatures you control get +1/+0 and have trample. + Ability ability = new SimpleStaticAbility(new BoostControlledEffect( + 1, 0, Duration.WhileOnBattlefield, + StaticFilters.FILTER_ATTACKING_CREATURES + )); + ability.addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_ATTACKING_CREATURES + ).setText("and have trample")); + this.getRightHalfCard().addAbility(ability); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Neck Breaker. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private BreakneckRider(final BreakneckRider card) { diff --git a/Mage.Sets/src/mage/cards/b/BrineComber.java b/Mage.Sets/src/mage/cards/b/BrineComber.java index 084f01247f6..9bcbd692ed0 100644 --- a/Mage.Sets/src/mage/cards/b/BrineComber.java +++ b/Mage.Sets/src/mage/cards/b/BrineComber.java @@ -1,26 +1,28 @@ package mage.cards.b; -import mage.MageInt; +import mage.abilities.common.BecomesTargetAttachedTriggeredAbility; import mage.abilities.common.BecomesTargetSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.DisturbAbility; +import mage.abilities.keyword.EnchantAbility; import mage.abilities.meta.OrTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterSpell; import mage.filter.predicate.other.AuraSpellPredicate; import mage.game.permanent.token.SpiritWhiteToken; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class BrineComber extends CardImpl { +public final class BrineComber extends TransformingDoubleFacedCard { private static final FilterSpell filter = new FilterSpell("an Aura spell"); @@ -29,21 +31,40 @@ public final class BrineComber extends CardImpl { } public BrineComber(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{1}{W}{U}", + "Brinebound Gift", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "WU"); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.b.BrineboundGift.class; + // Brine Comber + this.getLeftHalfCard().setPT(1, 1); // Whenever Brine Comber enters the battlefield or becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying. - this.addAbility(new OrTriggeredAbility(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()), false, + this.getLeftHalfCard().addAbility(new OrTriggeredAbility(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()), false, "Whenever {this} enters or becomes the target of an Aura spell, ", new EntersBattlefieldTriggeredAbility(null), new BecomesTargetSourceTriggeredAbility(null, filter))); + + // Brinebound Gift + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + // Disturb {W}{U} - this.addAbility(new DisturbAbility(this, "{W}{U}")); + // needs to be added after enchant ability is set for target + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{W}{U}")); + + // Whenever Brinebound Gift enters the battlefield or enchanted creature becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying. + this.getRightHalfCard().addAbility(new OrTriggeredAbility(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()), false, + "Whenever {this} enters or enchanted creature becomes the target of an Aura spell, ", + new EntersBattlefieldTriggeredAbility(null), + new BecomesTargetAttachedTriggeredAbility(null, filter, SetTargetPointer.NONE, false))); + + // If Brinebound Gift would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private BrineComber(final BrineComber card) { diff --git a/Mage.Sets/src/mage/cards/b/BrineboundGift.java b/Mage.Sets/src/mage/cards/b/BrineboundGift.java deleted file mode 100644 index 254ed7f3601..00000000000 --- a/Mage.Sets/src/mage/cards/b/BrineboundGift.java +++ /dev/null @@ -1,64 +0,0 @@ -package mage.cards.b; - -import mage.abilities.common.BecomesTargetAttachedTriggeredAbility; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -import mage.abilities.meta.OrTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterSpell; -import mage.filter.predicate.other.AuraSpellPredicate; -import mage.game.permanent.token.SpiritWhiteToken; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BrineboundGift extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("an Aura spell"); - - static { - filter.add(AuraSpellPredicate.instance); - } - - public BrineboundGift(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setWhite(true); - this.color.setBlue(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Whenever Brinebound Gift enters the battlefield or enchanted creature becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying. - this.addAbility(new OrTriggeredAbility(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()), false, - "Whenever {this} enters or enchanted creature becomes the target of an Aura spell, ", - new EntersBattlefieldTriggeredAbility(null), - new BecomesTargetAttachedTriggeredAbility(null, filter, SetTargetPointer.NONE, false))); - - // If Brinebound Gift would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private BrineboundGift(final BrineboundGift card) { - super(card); - } - - @Override - public BrineboundGift copy() { - return new BrineboundGift(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BrutalCathar.java b/Mage.Sets/src/mage/cards/b/BrutalCathar.java index bf58c854a03..44ad7a76194 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalCathar.java +++ b/Mage.Sets/src/mage/cards/b/BrutalCathar.java @@ -1,12 +1,15 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.TransformsOrEntersTriggeredAbility; +import mage.abilities.costs.common.PayLifeCost; import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.NightboundAbility; +import mage.abilities.keyword.WardAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.target.common.TargetOpponentsCreaturePermanent; @@ -16,17 +19,18 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BrutalCathar extends CardImpl { +public final class BrutalCathar extends TransformingDoubleFacedCard { public BrutalCathar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER, SubType.WEREWOLF}, "{2}{W}", + "Moonrage Brute", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); + + + // Brutal Cathar + this.getLeftHalfCard().setPT(2, 2); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.m.MoonrageBrute.class; // When this creature enters the battlefield or transforms into Brutal Cathar, exile target creature an opponent controls until this creature leaves the battlefield. Ability ability = new TransformsOrEntersTriggeredAbility( @@ -34,10 +38,22 @@ public final class BrutalCathar extends CardImpl { .setText("exile target creature an opponent controls until this creature leaves the battlefield"), false ).setTriggerPhrase("When this creature enters or transforms into {this}, "); ability.addTarget(new TargetOpponentsCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Moonrage Brute + this.getRightHalfCard().setPT(3, 3); + + // First strike + this.getRightHalfCard().addAbility(FirstStrikeAbility.getInstance()); + + // Ward—Pay 3 life. + this.getRightHalfCard().addAbility(new WardAbility(new PayLifeCost(3), false)); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private BrutalCathar(final BrutalCathar card) { diff --git a/Mage.Sets/src/mage/cards/b/BumiKingOfThreeTrials.java b/Mage.Sets/src/mage/cards/b/BumiKingOfThreeTrials.java index 17b18557907..66ac62d7a24 100644 --- a/Mage.Sets/src/mage/cards/b/BumiKingOfThreeTrials.java +++ b/Mage.Sets/src/mage/cards/b/BumiKingOfThreeTrials.java @@ -60,7 +60,7 @@ class BumiKingOfThreeTrialsTriggeredAbility extends EntersBattlefieldTriggeredAb private static final DynamicValue xValue = new CardsInControllerGraveyardCount(new FilterCard(SubType.LESSON)); BumiKingOfThreeTrialsTriggeredAbility() { - super(new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + super(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3))); this.getModes().setChooseText("choose up to X, where X is the number of Lesson cards in your graveyard —"); this.getModes().setMinModes(0); this.addMode(new Mode(new ScryTargetEffect(3)).addTarget(new TargetPlayer())); diff --git a/Mage.Sets/src/mage/cards/b/BumiUnleashed.java b/Mage.Sets/src/mage/cards/b/BumiUnleashed.java index 663f06b4641..06938b8f27d 100644 --- a/Mage.Sets/src/mage/cards/b/BumiUnleashed.java +++ b/Mage.Sets/src/mage/cards/b/BumiUnleashed.java @@ -67,7 +67,7 @@ class BumiUnleashedEffect extends OneShotEffect { BumiUnleashedEffect() { super(Outcome.Benefit); - staticText = "After this main phase, there is an additional combat phase. Only land creatures can attack during that combat phase"; + staticText = "After this phase, there is an additional combat phase. Only land creatures can attack during that combat phase"; } private BumiUnleashedEffect(final BumiUnleashedEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/BumisFeastLecture.java b/Mage.Sets/src/mage/cards/b/BumisFeastLecture.java index f3850984bee..ef951b36622 100644 --- a/Mage.Sets/src/mage/cards/b/BumisFeastLecture.java +++ b/Mage.Sets/src/mage/cards/b/BumisFeastLecture.java @@ -35,7 +35,7 @@ public final class BumisFeastLecture extends CardImpl { // Create a Food token. Then earthbend X, where X is twice the number of Foods you control. this.getSpellAbility().addEffect(new CreateTokenEffect(new FoodToken())); - this.getSpellAbility().addEffect(new EarthbendTargetEffect(xValue).concatBy("Then")); + this.getSpellAbility().addEffect(new EarthbendTargetEffect(xValue, true).concatBy("Then")); this.getSpellAbility().addTarget(new TargetControlledLandPermanent()); this.getSpellAbility().addHint(hint); } diff --git a/Mage.Sets/src/mage/cards/b/BurlyBreaker.java b/Mage.Sets/src/mage/cards/b/BurlyBreaker.java index da7065a2329..d4d3f353148 100644 --- a/Mage.Sets/src/mage/cards/b/BurlyBreaker.java +++ b/Mage.Sets/src/mage/cards/b/BurlyBreaker.java @@ -1,11 +1,11 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.keyword.NightboundAbility; import mage.abilities.keyword.WardAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -14,22 +14,31 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BurlyBreaker extends CardImpl { +public final class BurlyBreaker extends TransformingDoubleFacedCard { public BurlyBreaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{G}{G}", + "Dire-Strain Demolisher", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.d.DireStrainDemolisher.class; + // Burly Breaker + this.getLeftHalfCard().setPT(6, 5); // Ward {1} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{1}"))); + this.getLeftHalfCard().addAbility(new WardAbility(new ManaCostsImpl<>("{1}"))); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Dire-Strain Demolisher + this.getRightHalfCard().setPT(8, 7); + + // Ward {3} + this.getRightHalfCard().addAbility(new WardAbility(new ManaCostsImpl<>("{3}"))); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private BurlyBreaker(final BurlyBreaker card) { diff --git a/Mage.Sets/src/mage/cards/b/BurningEarth.java b/Mage.Sets/src/mage/cards/b/BurningEarth.java index 36d30a2a340..7449ebdfc43 100644 --- a/Mage.Sets/src/mage/cards/b/BurningEarth.java +++ b/Mage.Sets/src/mage/cards/b/BurningEarth.java @@ -29,7 +29,7 @@ public final class BurningEarth extends CardImpl { // Whenever a player taps a nonbasic land for mana, Burning Earth deals 1 damage to that player. this.addAbility(new TapForManaAllTriggeredAbility( - new DamageTargetEffect(1, true, "that player"), + new DamageTargetEffect(1).withTargetDescription("that player"), filter, SetTargetPointer.PLAYER)); } diff --git a/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java b/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java index 9295e4ec8b0..aa615d6b308 100644 --- a/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java +++ b/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java @@ -2,7 +2,6 @@ package mage.cards.b; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; @@ -46,7 +45,8 @@ public final class BurningTreeShaman extends CardImpl { class BurningTreeShamanTriggeredAbility extends TriggeredAbilityImpl { BurningTreeShamanTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(StaticValue.get(1), true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player")); + setTriggerPhrase("Whenever a player activates an ability that isn't a mana ability, "); } private BurningTreeShamanTriggeredAbility(final BurningTreeShamanTriggeredAbility ability) { @@ -75,8 +75,4 @@ class BurningTreeShamanTriggeredAbility extends TriggeredAbilityImpl { return false; } - @Override - public String getRule() { - return "Whenever a player activates an ability that isn't a mana ability, {this} deals 1 damage to that player."; - } } diff --git a/Mage.Sets/src/mage/cards/c/CaptiveWeird.java b/Mage.Sets/src/mage/cards/c/CaptiveWeird.java index 80fd4e22171..c1bcfa2fb5c 100644 --- a/Mage.Sets/src/mage/cards/c/CaptiveWeird.java +++ b/Mage.Sets/src/mage/cards/c/CaptiveWeird.java @@ -1,14 +1,15 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import java.util.UUID; @@ -16,22 +17,33 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class CaptiveWeird extends CardImpl { +public final class CaptiveWeird extends TransformingDoubleFacedCard { public CaptiveWeird(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEIRD}, "{U}", + "Compleated Conjurer", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.WEIRD}, "UR"); - this.subtype.add(SubType.WEIRD); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.c.CompleatedConjurer.class; + // Captive Weird + this.getLeftHalfCard().setPT(1, 3); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // {3}{R/P}: Transform Captive Weird. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{R/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( + new TransformSourceEffect(), new ManaCostsImpl<>("{3}{R/P}") + )); + + // Compleated Conjurer + this.getRightHalfCard().setPT(3, 3); + + // When this creature transforms into Compleated Conjurer, exile the top card of your library. + // Until the end of your next turn, you may play that card. + this.getRightHalfCard().addAbility(new TransformIntoSourceTriggeredAbility( + new ExileTopXMayPlayUntilEffect(1, Duration.UntilEndOfYourNextTurn) + )); } private CaptiveWeird(final CaptiveWeird card) { diff --git a/Mage.Sets/src/mage/cards/c/CatapultCaptain.java b/Mage.Sets/src/mage/cards/c/CatapultCaptain.java deleted file mode 100644 index 59660863339..00000000000 --- a/Mage.Sets/src/mage/cards/c/CatapultCaptain.java +++ /dev/null @@ -1,53 +0,0 @@ -package mage.cards.c; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness; -import mage.abilities.effects.common.LoseLifeTargetEffect; -import mage.constants.SubType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.filter.StaticFilters; -import mage.target.common.TargetOpponent; - -/** - * - * @author weirddan455 - */ -public final class CatapultCaptain extends CardImpl { - - public CatapultCaptain(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ZOMBIE); - this.color.setBlack(true); - this.power = new MageInt(2); - this.toughness = new MageInt(6); - - // Back half of Catapult Fodder - this.nightCard = true; - - // {2}{B}, {T}, Sacrifice another creature: Target opponent loses life equal to the sacrificed creature's toughness. - Ability ability = new SimpleActivatedAbility(new LoseLifeTargetEffect(SacrificeCostCreaturesToughness.instance) - .setText("Target opponent loses life equal to the sacrificed creature's toughness"), new ManaCostsImpl<>("{2}{B}")); - ability.addCost(new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); - ability.addTarget(new TargetOpponent()); - this.addAbility(ability); - } - - private CatapultCaptain(final CatapultCaptain card) { - super(card); - } - - @Override - public CatapultCaptain copy() { - return new CatapultCaptain(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CatapultFodder.java b/Mage.Sets/src/mage/cards/c/CatapultFodder.java index 97882939d50..99cba995c07 100644 --- a/Mage.Sets/src/mage/cards/c/CatapultFodder.java +++ b/Mage.Sets/src/mage/cards/c/CatapultFodder.java @@ -1,29 +1,36 @@ package mage.cards.c; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness; +import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessGreaterThanPowerPredicate; +import mage.target.common.TargetOpponent; import java.util.UUID; /** * @author weirddan455 */ -public final class CatapultFodder extends CardImpl { +public final class CatapultFodder extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterControlledCreaturePermanent( "you control three or more creatures that each have toughness greater than their power" @@ -39,16 +46,27 @@ public final class CatapultFodder extends CardImpl { ); public CatapultFodder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ZOMBIE}, "{2}{B}", + "Catapult Captain", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ZOMBIE}, "B"); - this.subtype.add(SubType.ZOMBIE); - this.power = new MageInt(1); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.c.CatapultCaptain.class; + // Catapult Fodder + this.getLeftHalfCard().setPT(1, 5); // At the beginning of combat on your turn, if you control three or more creatures that each have toughness greater than their power, transform Catapult Fodder. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfCombatTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition)); + this.getLeftHalfCard().addAbility(new BeginningOfCombatTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition).addHint(hint)); + + // Catapult Captain + this.getRightHalfCard().setPT(2, 6); + + // {2}{B}, {T}, Sacrifice another creature: Target opponent loses life equal to the sacrificed creature's toughness. + Ability ability = new SimpleActivatedAbility(new LoseLifeTargetEffect(SacrificeCostCreaturesToughness.instance) + .setText("Target opponent loses life equal to the sacrificed creature's toughness"), new ManaCostsImpl<>("{2}{B}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); + ability.addTarget(new TargetOpponent()); + this.getRightHalfCard().addAbility(ability); } private CatapultFodder(final CatapultFodder card) { diff --git a/Mage.Sets/src/mage/cards/c/CecilDarkKnight.java b/Mage.Sets/src/mage/cards/c/CecilDarkKnight.java index f04cf84aa28..b7bc80602c7 100644 --- a/Mage.Sets/src/mage/cards/c/CecilDarkKnight.java +++ b/Mage.Sets/src/mage/cards/c/CecilDarkKnight.java @@ -1,7 +1,7 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DealsDamageSourceTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; @@ -9,13 +9,17 @@ import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.StaticFilters; import mage.game.Controllable; import mage.game.Game; import mage.players.Player; @@ -26,24 +30,21 @@ import java.util.UUID; /** * @author balazskristof */ -public final class CecilDarkKnight extends CardImpl { +public final class CecilDarkKnight extends TransformingDoubleFacedCard { public CecilDarkKnight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.KNIGHT}, "{B}", + "Cecil, Redeemed Paladin", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.KNIGHT}, "W"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - - this.secondSideCardClazz = mage.cards.c.CecilRedeemedPaladin.class; + // Cecil, Dark Knight + this.getLeftHalfCard().setPT(2, 3); // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); + this.getLeftHalfCard().addAbility(DeathtouchAbility.getInstance()); // Darkness -- Whenever Cecil deals damage, you lose that much life. Then if your life total is less than or equal to half your starting life total, untap Cecil and transform it. - this.addAbility(new TransformAbility()); Ability ability = new DealsDamageSourceTriggeredAbility(new LoseLifeSourceControllerEffect(SavedDamageValue.MUCH), false).withFlavorWord("Darkness"); ability.addEffect(new ConditionalOneShotEffect( new UntapSourceEffect(), @@ -51,7 +52,19 @@ public final class CecilDarkKnight extends CardImpl { ).addEffect( new TransformSourceEffect(true).concatBy("and") ).concatBy("Then")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Cecil, Redeemed Paladin + this.getRightHalfCard().setPT(4, 4); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Protect -- Whenever Cecil attacks, other attacking creatures gain indestructible until end of turn. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new GainAbilityAllEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_ATTACKING_CREATURES, true + )).withFlavorWord("Protect")); } private CecilDarkKnight(final CecilDarkKnight card) { diff --git a/Mage.Sets/src/mage/cards/c/CecilRedeemedPaladin.java b/Mage.Sets/src/mage/cards/c/CecilRedeemedPaladin.java deleted file mode 100644 index 2e6f4f4999c..00000000000 --- a/Mage.Sets/src/mage/cards/c/CecilRedeemedPaladin.java +++ /dev/null @@ -1,52 +0,0 @@ -package mage.cards.c; - -import java.util.UUID; -import mage.MageInt; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.StaticFilters; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; - -/** - * @author balazskristof - */ -public final class CecilRedeemedPaladin extends CardImpl { - - public CecilRedeemedPaladin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.color.setWhite(true); - this.nightCard = true; - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Protect -- Whenever Cecil attacks, other attacking creatures gain indestructible until end of turn. - this.addAbility(new AttacksTriggeredAbility(new GainAbilityAllEffect( - IndestructibleAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_ATTACKING_CREATURES, true - )).withFlavorWord("Protect")); - } - - private CecilRedeemedPaladin(final CecilRedeemedPaladin card) { - super(card); - } - - @Override - public CecilRedeemedPaladin copy() { - return new CecilRedeemedPaladin(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java b/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java index 9ec04a37b8b..54fd2fb2943 100644 --- a/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java +++ b/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java @@ -99,7 +99,7 @@ class CemeteryGatekeeperEffect extends OneShotEffect { class CemeteryGatekeeperTriggeredAbility extends TriggeredAbilityImpl { public CemeteryGatekeeperTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player")); setTriggerPhrase("Whenever a player plays a land or casts a spell, if it shares a card type with the exiled card, "); } diff --git a/Mage.Sets/src/mage/cards/c/ChaliceOfDeath.java b/Mage.Sets/src/mage/cards/c/ChaliceOfDeath.java deleted file mode 100644 index 7a3263e9c24..00000000000 --- a/Mage.Sets/src/mage/cards/c/ChaliceOfDeath.java +++ /dev/null @@ -1,41 +0,0 @@ - -package mage.cards.c; - -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.common.LoseLifeTargetEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Zone; -import mage.target.TargetPlayer; - -/** - * - * @author intimidatingant - */ -public final class ChaliceOfDeath extends CardImpl { - - public ChaliceOfDeath(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},""); - - // this card is the second face of double-faced card - this.nightCard = true; - - // {tap}: Target player loses 5 life. - Ability ability = new SimpleActivatedAbility(new LoseLifeTargetEffect(5), new TapSourceCost()); - ability.addTarget(new TargetPlayer()); - this.addAbility(ability); - } - - private ChaliceOfDeath(final ChaliceOfDeath card) { - super(card); - } - - @Override - public ChaliceOfDeath copy() { - return new ChaliceOfDeath(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java b/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java index f809074e503..4a0606729fe 100644 --- a/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java +++ b/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java @@ -6,32 +6,41 @@ import mage.abilities.condition.common.MoreThanStartingLifeTotalCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.TargetPlayer; import java.util.UUID; /** * @author intimidatingant */ -public final class ChaliceOfLife extends CardImpl { +public final class ChaliceOfLife extends TransformingDoubleFacedCard { public ChaliceOfLife(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{3}", + "Chalice of Death", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, ""); - this.secondSideCardClazz = mage.cards.c.ChaliceOfDeath.class; - this.addAbility(new TransformAbility()); - - // {tap}: You gain 1 life. Then if you have at least 10 life more than your starting life total, transform Chalice of Life. + // Chalice of Life + // {T}: You gain 1 life. Then if you have at least 10 life more than your starting life total, transform Chalice of Life. Ability ability = new SimpleActivatedAbility(new GainLifeEffect(1), new TapSourceCost()); ability.addEffect(new ConditionalOneShotEffect( new TransformSourceEffect(), MoreThanStartingLifeTotalCondition.TEN, "Then if you have at least 10 life more than your starting life total, transform {this}" )); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Chalice of Death + // {T}: Target player loses 5 life. + Ability deathAbility = new SimpleActivatedAbility(new LoseLifeTargetEffect(5), new TapSourceCost()); + deathAbility.addTarget(new TargetPlayer()); + this.getRightHalfCard().addAbility(deathAbility); } private ChaliceOfLife(final ChaliceOfLife card) { diff --git a/Mage.Sets/src/mage/cards/c/ChandraFireOfKaladesh.java b/Mage.Sets/src/mage/cards/c/ChandraFireOfKaladesh.java index cbe8871a1aa..2e98d2cdca8 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraFireOfKaladesh.java +++ b/Mage.Sets/src/mage/cards/c/ChandraFireOfKaladesh.java @@ -1,63 +1,79 @@ - package mage.cards.c; -import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceDealtDamageCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.command.emblems.ChandraRoaringFlameEmblem; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; import mage.watchers.common.DamageDoneWatcher; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; /** * @author LevelX2 */ -public final class ChandraFireOfKaladesh extends CardImpl { +public final class ChandraFireOfKaladesh extends TransformingDoubleFacedCard { private static final FilterSpell filter = new FilterSpell("a red spell"); - - static { - filter.add(new ColorPredicate(ObjectColor.RED)); - } - + static { filter.add(new ColorPredicate(ObjectColor.RED)); } private static final Condition condition = new SourceDealtDamageCondition(3); public ChandraFireOfKaladesh(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SHAMAN); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN}, "{1}{R}{R}", + "Chandra, Roaring Flame", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.CHANDRA}, "R"); - this.secondSideCardClazz = mage.cards.c.ChandraRoaringFlame.class; + // Chandra, Fire of Kaladesh + this.getLeftHalfCard().setPT(2, 2); // Whenever you cast a red spell, untap Chandra, Fire of Kaladesh. - this.addAbility(new SpellCastControllerTriggeredAbility(new UntapSourceEffect(), filter, false)); + this.getLeftHalfCard().addAbility(new SpellCastControllerTriggeredAbility(new UntapSourceEffect(), filter, false)); - // {T}: Chandra, Fire of Kaladesh deals 1 damage to target player. If Chandra has dealt 3 or more damage this turn, exile her, then return her to the battlefield transformed under her owner's control. - this.addAbility(new TransformAbility()); + // {T}: Chandra, Fire of Kaladesh deals 1 damage to target player or planeswalker. If Chandra has dealt 3 or more damage this turn, exile her, then return her to the battlefield transformed under her owner's control. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); ability.addEffect(new ConditionalOneShotEffect( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.SHE), condition )); ability.addTarget(new TargetPlayerOrPlaneswalker()); - this.addAbility(ability, new DamageDoneWatcher()); + ability.addWatcher(new DamageDoneWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // Chandra, Roaring Flame + this.getRightHalfCard().setStartingLoyalty(4); + + // +1: Chandra, Roaring Flame deals 2 damage to target player or planeswalker. + LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(2), 1); + loyaltyAbility.addTarget(new TargetPlayerOrPlaneswalker()); + this.getRightHalfCard().addAbility(loyaltyAbility); + + // -2: Chandra, Roaring Flame deals 2 damage to target creature. + loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(2), -2); + loyaltyAbility.addTarget(new TargetCreaturePermanent()); + this.getRightHalfCard().addAbility(loyaltyAbility); + + // -7: Chandra, Roaring Flame deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with "At the beginning of your upkeep, this emblem deals 3 damage to you." + this.getRightHalfCard().addAbility(new LoyaltyAbility(new ChandraRoaringFlameEmblemEffect(), -7)); } private ChandraFireOfKaladesh(final ChandraFireOfKaladesh card) { @@ -69,3 +85,31 @@ public final class ChandraFireOfKaladesh extends CardImpl { return new ChandraFireOfKaladesh(this); } } + +class ChandraRoaringFlameEmblemEffect extends OneShotEffect { + + ChandraRoaringFlameEmblemEffect() { + super(Outcome.Damage); + this.staticText = "{this} deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with \"At the beginning of your upkeep, this emblem deals 3 damage to you.\""; + } + + private ChandraRoaringFlameEmblemEffect(final ChandraRoaringFlameEmblemEffect effect) { super(effect); } + @Override public ChandraRoaringFlameEmblemEffect copy() { return new ChandraRoaringFlameEmblemEffect(this); } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + List opponentsEmblem = new ArrayList<>(); + for (UUID playerId : game.getOpponents(controller.getId())) { + Player opponent = game.getPlayer(playerId); + if (opponent != null && opponent.damage(6, source, game) > 0) { + opponentsEmblem.add(opponent); + } + } + for (Player opponent : opponentsEmblem) { + game.addEmblem(new ChandraRoaringFlameEmblem(), source.getSourceObject(game), opponent.getId()); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChandraHopesBeacon.java b/Mage.Sets/src/mage/cards/c/ChandraHopesBeacon.java index 1fb0d5e1482..ec1368360ce 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraHopesBeacon.java +++ b/Mage.Sets/src/mage/cards/c/ChandraHopesBeacon.java @@ -51,9 +51,8 @@ public class ChandraHopesBeacon extends CardImpl { this.addAbility(new LoyaltyAbility(new ChandraHopesBeaconEffect(), 1), new ChandraHopesBeaconWatcher()); //−X: Chandra, Hope’s Beacon deals X damage to each of up to two targets. - LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect( - GetXValue.instance, true, "each of up to two targets" - )); + LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(GetXValue.instance) + .withTargetDescription("each of up to two targets")); loyaltyAbility.addTarget(new TargetAnyTarget(0, 2)); this.addAbility(loyaltyAbility); } diff --git a/Mage.Sets/src/mage/cards/c/ChandraRoaringFlame.java b/Mage.Sets/src/mage/cards/c/ChandraRoaringFlame.java deleted file mode 100644 index 9759367aa57..00000000000 --- a/Mage.Sets/src/mage/cards/c/ChandraRoaringFlame.java +++ /dev/null @@ -1,96 +0,0 @@ -package mage.cards.c; - -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.game.Game; -import mage.game.command.emblems.ChandraRoaringFlameEmblem; -import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; -import mage.target.common.TargetPlayerOrPlaneswalker; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class ChandraRoaringFlame extends CardImpl { - - public ChandraRoaringFlame(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.CHANDRA); - this.color.setRed(true); - - this.nightCard = true; - - this.setStartingLoyalty(4); - - // +1: Chandra, Roaring Flame deals 2 damage to target player. - LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(2), 1); - loyaltyAbility.addTarget(new TargetPlayerOrPlaneswalker()); - this.addAbility(loyaltyAbility); - - //-2: Chandra, Roaring Flame deals 2 damage to target creature. - loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(2), -2); - loyaltyAbility.addTarget(new TargetCreaturePermanent()); - this.addAbility(loyaltyAbility); - - //-7: Chandra, Roaring Flame deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with "At the beginning of your upkeep, this emblem deals 3 damage to you." - this.addAbility(new LoyaltyAbility(new ChandraRoaringFlameEmblemEffect(), -7)); - } - - private ChandraRoaringFlame(final ChandraRoaringFlame card) { - super(card); - } - - @Override - public ChandraRoaringFlame copy() { - return new ChandraRoaringFlame(this); - } -} - -class ChandraRoaringFlameEmblemEffect extends OneShotEffect { - - ChandraRoaringFlameEmblemEffect() { - super(Outcome.Damage); - this.staticText = "{this} deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with \"At the beginning of your upkeep, this emblem deals 3 damage to you.\""; - } - - private ChandraRoaringFlameEmblemEffect(final ChandraRoaringFlameEmblemEffect effect) { - super(effect); - } - - @Override - public ChandraRoaringFlameEmblemEffect copy() { - return new ChandraRoaringFlameEmblemEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - List opponentsEmblem = new ArrayList<>(); - for (UUID playerId : game.getOpponents(controller.getId())) { - Player opponent = game.getPlayer(playerId); - if (opponent != null && opponent.damage(6, source, game) > 0) { - opponentsEmblem.add(opponent); - } - } - for (Player opponent : opponentsEmblem) { - game.addEmblem(new ChandraRoaringFlameEmblem(), source.getSourceObject(game), opponent.getId()); - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java b/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java index 1b145814642..96293d1cc59 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java +++ b/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java @@ -36,7 +36,7 @@ public final class ChandraTheFirebrand extends CardImpl { )); // -6: Chandra, the Firebrand deals 6 damage to each of up to six target creatures and/or players - LoyaltyAbility ability2 = new LoyaltyAbility(new DamageTargetEffect(6, true, "each of up to six targets"), -6); + LoyaltyAbility ability2 = new LoyaltyAbility(new DamageTargetEffect(6).withTargetDescription("each of up to six targets"), -6); ability2.addTarget(new TargetAnyTarget(0, 6)); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/c/ChapelShieldgeist.java b/Mage.Sets/src/mage/cards/c/ChapelShieldgeist.java deleted file mode 100644 index eb0d21c98ca..00000000000 --- a/Mage.Sets/src/mage/cards/c/ChapelShieldgeist.java +++ /dev/null @@ -1,61 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.WardAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ChapelShieldgeist extends CardImpl { - - public ChapelShieldgeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.color.setWhite(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // First strike - this.addAbility(FirstStrikeAbility.getInstance()); - - // Each creature you control has ward {1}. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - new WardAbility(new GenericManaCost(1)), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE - ).setText("each creature you control has ward {1}. " + - "(Whenever it becomes the target of a spell or ability an opponent controls, " + - "counter it unless that player pays 1.)"))); - - // If Chapel Shieldgeist would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private ChapelShieldgeist(final ChapelShieldgeist card) { - super(card); - } - - @Override - public ChapelShieldgeist copy() { - return new ChapelShieldgeist(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java b/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java index a6dd19da76b..85ca185e2b4 100644 --- a/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java +++ b/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java @@ -1,39 +1,63 @@ package mage.cards.c; -import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.DisturbAbility; import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.WardAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author TheElk801 */ -public final class ChaplainOfAlms extends CardImpl { +public final class ChaplainOfAlms extends TransformingDoubleFacedCard { public ChaplainOfAlms(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{W}", + "Chapel Shieldgeist", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.CLERIC}, "W"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.c.ChapelShieldgeist.class; + // Chaplain of Alms + this.getLeftHalfCard().setPT(1, 1); // First strike - this.addAbility(FirstStrikeAbility.getInstance()); + this.getLeftHalfCard().addAbility(FirstStrikeAbility.getInstance()); // Ward {1} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{1}"))); + this.getLeftHalfCard().addAbility(new WardAbility(new ManaCostsImpl<>("{1}"))); // Disturb {3}{W} - this.addAbility(new DisturbAbility(this, "{3}{W}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{3}{W}")); + + // Chapel Shieldgeist + this.getRightHalfCard().setPT(2, 1); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // First strike + this.getRightHalfCard().addAbility(FirstStrikeAbility.getInstance()); + + // Each creature you control has ward {1}. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new WardAbility(new GenericManaCost(1)), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("each creature you control has ward {1}. " + + "(Whenever it becomes the target of a spell or ability an opponent controls, counter it unless that player pays 1.)"))); + + // If Chapel Shieldgeist would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private ChaplainOfAlms(final ChaplainOfAlms card) { diff --git a/Mage.Sets/src/mage/cards/c/ChildOfThePack.java b/Mage.Sets/src/mage/cards/c/ChildOfThePack.java index ca2629315df..c1754ce6e31 100644 --- a/Mage.Sets/src/mage/cards/c/ChildOfThePack.java +++ b/Mage.Sets/src/mage/cards/c/ChildOfThePack.java @@ -1,13 +1,17 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.game.permanent.token.WolfToken; @@ -16,24 +20,38 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ChildOfThePack extends CardImpl { +public final class ChildOfThePack extends TransformingDoubleFacedCard { public ChildOfThePack(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{R}{G}", + "Savage Packmate", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "RG"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.s.SavagePackmate.class; + // Child of the Pack + this.getLeftHalfCard().setPT(2, 5); // {2}{R}{G}: Create a 2/2 green Wolf creature token. - this.addAbility(new SimpleActivatedAbility( + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility( new CreateTokenEffect(new WolfToken()), new ManaCostsImpl<>("{2}{R}{G}") )); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Savage Packmate + this.getRightHalfCard().setPT(5, 5); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Other creatures you control get +1/+0. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 0, Duration.WhileOnBattlefield, true + ))); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private ChildOfThePack(final ChildOfThePack card) { diff --git a/Mage.Sets/src/mage/cards/c/ChongAndLilyNomads.java b/Mage.Sets/src/mage/cards/c/ChongAndLilyNomads.java index 817564189f5..08e51199222 100644 --- a/Mage.Sets/src/mage/cards/c/ChongAndLilyNomads.java +++ b/Mage.Sets/src/mage/cards/c/ChongAndLilyNomads.java @@ -46,12 +46,12 @@ public final class ChongAndLilyNomads extends CardImpl { // * Put a lore counter on each of any number of target Sagas you control. Ability ability = new AttacksWithCreaturesTriggeredAbility( new AddCountersTargetEffect(CounterType.LORE.createInstance()), 1, filter - ); + ).setTriggerPhrase("Whenever one or more Bards you control attack, "); ability.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, ChongAndLilyNomadsValue.getFilter())); // * Creatures you control get +1/+0 until end of turn for each lore counter among Sagas you control. ability.addMode(new Mode(new BoostControlledEffect( - ChongAndLilyNomadsValue.instance, StaticValue.get(0), Duration.WhileOnBattlefield + ChongAndLilyNomadsValue.instance, StaticValue.get(0), Duration.EndOfTurn ))); this.addAbility(ability.addHint(ChongAndLilyNomadsValue.getHint())); } diff --git a/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java b/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java index d0d6472ed4e..cd0f5171507 100644 --- a/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java +++ b/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java @@ -1,28 +1,25 @@ - package mage.cards.c; -import java.util.UUID; - -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** * @author Loki */ -public final class ChosenOfMarkov extends CardImpl { +public final class ChosenOfMarkov extends TransformingDoubleFacedCard { + private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Vampire you control"); static { @@ -31,27 +28,28 @@ public final class ChosenOfMarkov extends CardImpl { } public ChosenOfMarkov(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); - this.subtype.add(SubType.HUMAN); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "{2}{B}", + "Markov's Servant", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "B"); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + // Chosen of Markov + this.getLeftHalfCard().setPT(2, 2); - this.secondSideCardClazz = mage.cards.m.MarkovsServant.class; - - // {tap}, Tap an untapped Vampire you control: Transform Chosen of Markov. - this.addAbility(new TransformAbility()); + // {T}, Tap an untapped Vampire you control: Transform Chosen of Markov. Ability ability = new SimpleActivatedAbility(new TransformSourceEffect(), new TapSourceCost()); ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Markov's Servant + this.getRightHalfCard().setPT(4, 4); } private ChosenOfMarkov(final ChosenOfMarkov card) { super(card); } - @Override - public ChosenOfMarkov copy() { + @Override public ChosenOfMarkov copy() { return new ChosenOfMarkov(this); } } diff --git a/Mage.Sets/src/mage/cards/c/Cindervines.java b/Mage.Sets/src/mage/cards/c/Cindervines.java index aa6108c9ea3..b6a1ea1e6aa 100644 --- a/Mage.Sets/src/mage/cards/c/Cindervines.java +++ b/Mage.Sets/src/mage/cards/c/Cindervines.java @@ -31,7 +31,7 @@ public final class Cindervines extends CardImpl { // Whenever an opponent casts a noncreature spell, Cindervines deals 1 damage to that player. this.addAbility(new SpellCastOpponentTriggeredAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that player"), + Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player"), StaticFilters.FILTER_SPELL_A_NON_CREATURE, false, SetTargetPointer.PLAYER )); diff --git a/Mage.Sets/src/mage/cards/c/CivilizedScholar.java b/Mage.Sets/src/mage/cards/c/CivilizedScholar.java index 9d9315204fe..a0c955d1e80 100644 --- a/Mage.Sets/src/mage/cards/c/CivilizedScholar.java +++ b/Mage.Sets/src/mage/cards/c/CivilizedScholar.java @@ -1,15 +1,20 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.AttackedThisTurnSourceCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -22,23 +27,33 @@ import java.util.UUID; /** * @author nantuko */ -public final class CivilizedScholar extends CardImpl { +public final class CivilizedScholar extends TransformingDoubleFacedCard { + + private static final Condition condition = new InvertCondition( + AttackedThisTurnSourceCondition.instance, "{this} didn't attack this turn" + ); public CivilizedScholar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ADVISOR); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ADVISOR}, "{2}{U}", + "Homicidal Brute", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.MUTANT}, "R"); - this.secondSideCardClazz = mage.cards.h.HomicidalBrute.class; + // Civilized Scholar + this.getLeftHalfCard().setPT(0, 1); - this.power = new MageInt(0); - this.toughness = new MageInt(1); - - // {tap}: Draw a card, then discard a card. If a creature card is discarded this way, untap Civilized Scholar, then transform it. + // {T}: Draw a card, then discard a card. If a creature card is discarded this way, untap Civilized Scholar, then transform it. Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost()); ability.addEffect(new CivilizedScholarEffect()); - this.addAbility(new TransformAbility()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Homicidal Brute + this.getRightHalfCard().setPT(5, 1); + + // At the beginning of your end step, if Homicidal Brute didn't attack this turn, tap Homicidal Brute, then transform it. + TriggeredAbility bruteAbility = new BeginningOfEndStepTriggeredAbility(new TapSourceEffect()); + bruteAbility.addEffect(new TransformSourceEffect().setText(", then transform it")); + this.getRightHalfCard().addAbility(bruteAbility.withInterveningIf(condition)); } private CivilizedScholar(final CivilizedScholar card) { @@ -51,7 +66,6 @@ public final class CivilizedScholar extends CardImpl { } } - class CivilizedScholarEffect extends OneShotEffect { CivilizedScholarEffect() { diff --git a/Mage.Sets/src/mage/cards/c/ClayFiredBricks.java b/Mage.Sets/src/mage/cards/c/ClayFiredBricks.java index 06cc8042fe6..7a5ca0af04b 100644 --- a/Mage.Sets/src/mage/cards/c/ClayFiredBricks.java +++ b/Mage.Sets/src/mage/cards/c/ClayFiredBricks.java @@ -2,13 +2,19 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.game.permanent.token.GnomeToken; import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -16,21 +22,33 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ClayFiredBricks extends CardImpl { +public final class ClayFiredBricks extends TransformingDoubleFacedCard { public ClayFiredBricks(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}"); - this.secondSideCardClazz = mage.cards.c.CosmiumKiln.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{W}", + "Cosmium Kiln", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "W"); + + // Clay-Fired Bricks // When Clay-Fired Bricks enters the battlefield, search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. You gain 2 life. Ability ability = new EntersBattlefieldTriggeredAbility( new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true) ); ability.addEffect(new GainLifeEffect(2)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Craft with artifact {5}{W}{W} - this.addAbility(new CraftAbility("{5}{W}{W}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{5}{W}{W}")); + + // Cosmium Kiln + + // When Cosmium Kiln enters the battlefield, create two 1/1 colorless Gnome artifact creature tokens. + this.getRightHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GnomeToken(), 2))); + + // Creatures you control get +1/+1. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); } private ClayFiredBricks(final ClayFiredBricks card) { diff --git a/Mage.Sets/src/mage/cards/c/CleverDistraction.java b/Mage.Sets/src/mage/cards/c/CleverDistraction.java deleted file mode 100644 index 751b419f195..00000000000 --- a/Mage.Sets/src/mage/cards/c/CleverDistraction.java +++ /dev/null @@ -1,68 +0,0 @@ -package mage.cards.c; - -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.TapTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class CleverDistraction extends CardImpl { - - private static final FilterPermanent filter - = new FilterCreaturePermanent("creature defending player controls"); - - static { - filter.add(DefendingPlayerControlsSourceAttackingPredicate.instance); - } - - public CleverDistraction(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setWhite(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature has "Whenever this creature attacks, tap target creature defending player controls." - Ability ability = new AttacksTriggeredAbility(new TapTargetEffect()) - .setTriggerPhrase("Whenever this creature attacks, "); - ability.addTarget(new TargetPermanent(filter)); - this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(ability, AttachmentType.AURA))); - - // If Clever Distracting would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private CleverDistraction(final CleverDistraction card) { - super(card); - } - - @Override - public CleverDistraction copy() { - return new CleverDistraction(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java b/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java index 8a18243df9c..c515b0799ed 100644 --- a/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java +++ b/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java @@ -1,54 +1,85 @@ package mage.cards.c; -import mage.MageInt; +import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SagaAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.common.DevotionCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.FightTargetSourceEffect; import mage.abilities.effects.common.discard.DiscardHandControllerEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.mana.BasicManaEffect; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class CliveIfritsDominant extends CardImpl { +public final class CliveIfritsDominant extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterCreaturePermanent("other target creature"); + private static final Condition condition = new SourceHasCounterCondition(CounterType.LORE, 3); public CliveIfritsDominant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE, SubType.WARRIOR}, "{4}{R}{R}", + "Ifrit, Warden of Inferno", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.DEMON}, "R"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.i.IfritWardenOfInferno.class; + // Clive, Ifrit's Dominant + this.getLeftHalfCard().setPT(5, 5); // When Clive enters, you may discard your hand, then draw cards equal to your devotion to red. Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardHandControllerEffect(), true); ability.addEffect(new DrawCardSourceControllerEffect(DevotionCount.R) .setText(", then draw cards equal to your devotion to red")); - this.addAbility(ability.addHint(DevotionCount.R.getHint())); + this.getLeftHalfCard().addAbility(ability.addHint(DevotionCount.R.getHint())); // {4}{R}{R}, {T}: Exile Clive, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); ability = new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{4}{R}{R}") ); ability.addCost(new TapSourceCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + + // Ifrit, Warden of Inferno + this.getRightHalfCard().setPT(9, 9); + + // Saga (chapters) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I -- Lunge -- Ifrit fights up to one other target creature. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, sagaChapterAbility -> { + sagaChapterAbility.addEffect(new FightTargetSourceEffect()); + sagaChapterAbility.addTarget(new TargetPermanent(0, 1, filter)); + sagaChapterAbility.withFlavorWord("Lunge"); + }); + + // II, III -- Brimstone -- Add {R}{R}{R}{R}. If Ifrit has three or more lore counters on it, exile it, then return it to the battlefield (front face up.) + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_III, sagaChapterAbility -> { + sagaChapterAbility.addEffect(new BasicManaEffect(Mana.RedMana(4))); + sagaChapterAbility.addEffect(new ConditionalOneShotEffect( + new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD), condition, + "If {this} has three or more lore counters on it, exile it, then return it to the battlefield. (front face up.)" + )); + sagaChapterAbility.withFlavorWord("Brimstone"); + }); + this.getRightHalfCard().addAbility(sagaAbility); } private CliveIfritsDominant(final CliveIfritsDominant card) { diff --git a/Mage.Sets/src/mage/cards/c/CloisteredYouth.java b/Mage.Sets/src/mage/cards/c/CloisteredYouth.java index def252da59e..bd8a283dccf 100644 --- a/Mage.Sets/src/mage/cards/c/CloisteredYouth.java +++ b/Mage.Sets/src/mage/cards/c/CloisteredYouth.java @@ -1,34 +1,38 @@ - package mage.cards.c; -import java.util.UUID; - -import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** * @author Loki */ -public final class CloisteredYouth extends CardImpl { +public final class CloisteredYouth extends TransformingDoubleFacedCard { public CloisteredYouth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); - this.subtype.add(SubType.HUMAN); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "{1}{W}", + "Unholy Fiend", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HORROR}, "B"); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - - this.secondSideCardClazz = mage.cards.u.UnholyFiend.class; + // Cloistered Youth + this.getLeftHalfCard().setPT(1, 1); // At the beginning of your upkeep, you may transform Cloistered Youth. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true)); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true)); + + // Unholy Fiend + this.getRightHalfCard().setPT(3, 3); + + // At the beginning of your end step, you lose 1 life. + this.getRightHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new LoseLifeSourceControllerEffect(1))); } private CloisteredYouth(final CloisteredYouth card) { diff --git a/Mage.Sets/src/mage/cards/c/Combust.java b/Mage.Sets/src/mage/cards/c/Combust.java index 7e0703f4087..7a4c5659917 100644 --- a/Mage.Sets/src/mage/cards/c/Combust.java +++ b/Mage.Sets/src/mage/cards/c/Combust.java @@ -2,7 +2,6 @@ package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -16,7 +15,8 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** * @@ -36,7 +36,7 @@ public final class Combust extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); // Combust deals 5 damage to target white or blue creature. The damage can't be prevented. - this.getSpellAbility().addEffect(new DamageTargetEffect(5, false)); + this.getSpellAbility().addEffect(new DamageTargetEffect(5).withCantBePrevented()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Combust can't be countered. diff --git a/Mage.Sets/src/mage/cards/c/CompleatedConjurer.java b/Mage.Sets/src/mage/cards/c/CompleatedConjurer.java deleted file mode 100644 index de01acadbb5..00000000000 --- a/Mage.Sets/src/mage/cards/c/CompleatedConjurer.java +++ /dev/null @@ -1,44 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class CompleatedConjurer extends CardImpl { - - public CompleatedConjurer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.WEIRD); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlue(true); - this.color.setRed(true); - this.nightCard = true; - - // When this creature transforms into Compleated Conjurer, exile the top card of your library. Until the end of your next turn, you may play that card. - this.addAbility(new TransformIntoSourceTriggeredAbility( - new ExileTopXMayPlayUntilEffect(1, Duration.UntilEndOfYourNextTurn) - )); - } - - private CompleatedConjurer(final CompleatedConjurer card) { - super(card); - } - - @Override - public CompleatedConjurer copy() { - return new CompleatedConjurer(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ConcealingCurtains.java b/Mage.Sets/src/mage/cards/c/ConcealingCurtains.java index ced78dc8f37..bb17274ce09 100644 --- a/Mage.Sets/src/mage/cards/c/ConcealingCurtains.java +++ b/Mage.Sets/src/mage/cards/c/ConcealingCurtains.java @@ -1,39 +1,58 @@ package mage.cards.c; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetOpponent; import java.util.UUID; /** * @author TheElk801 */ -public final class ConcealingCurtains extends CardImpl { +public final class ConcealingCurtains extends TransformingDoubleFacedCard { public ConcealingCurtains(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WALL}, "{B}", + "Revealing Eye", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.EYE, SubType.HORROR}, "B"); - this.subtype.add(SubType.WALL); - this.power = new MageInt(0); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.r.RevealingEye.class; + // Concealing Curtains + this.getLeftHalfCard().setPT(0, 4); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // {2}{B}: Transform Concealing Curtains. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}") )); + + // Revealing Eye + this.getRightHalfCard().setPT(3, 4); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility(false)); + + // When this creature transforms into Revealing Eye, target opponent reveals their hand. You may choose a nonland card from it. If you do, that player discards that card, then draws a card. + Ability ability = new TransformIntoSourceTriggeredAbility(new RevealingEyeEffect()); + ability.addTarget(new TargetOpponent()); + this.getRightHalfCard().addAbility(ability); } private ConcealingCurtains(final ConcealingCurtains card) { @@ -45,3 +64,43 @@ public final class ConcealingCurtains extends CardImpl { return new ConcealingCurtains(this); } } + +class RevealingEyeEffect extends OneShotEffect { + + RevealingEyeEffect() { + super(Outcome.Discard); + staticText = "target opponent reveals their hand. You may choose a nonland card from it. " + + "If you do, that player discards that card, then draws a card"; + } + + private RevealingEyeEffect(final RevealingEyeEffect effect) { + super(effect); + } + + @Override + public RevealingEyeEffect copy() { + return new RevealingEyeEffect(this); + } + + @Override + public boolean apply(mage.game.Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (controller == null || opponent == null) { + return false; + } + opponent.revealCards(source, opponent.getHand(), game); + if (opponent.getHand().count(StaticFilters.FILTER_CARD_NON_LAND, game) < 1) { + return true; + } + TargetCard target = new TargetCard(0, 1, Zone.HAND, StaticFilters.FILTER_CARD_NON_LAND); + controller.choose(outcome, opponent.getHand(), target, source, game); + mage.cards.Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return true; + } + opponent.discard(card, false, source, game); + opponent.drawCards(1, source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ConduitOfEmrakul.java b/Mage.Sets/src/mage/cards/c/ConduitOfEmrakul.java deleted file mode 100644 index ec2a8fc337e..00000000000 --- a/Mage.Sets/src/mage/cards/c/ConduitOfEmrakul.java +++ /dev/null @@ -1,49 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.Mana; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.delayed.AtTheBeginOfMainPhaseDelayedTriggeredAbility; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.mana.AddManaToManaPoolSourceControllerEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.TargetController; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class ConduitOfEmrakul extends CardImpl { - - public ConduitOfEmrakul(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(4); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Whenever Conduit of Emrakul attacks, add {C}{C} at the beginning of your next main phase this turn. - this.addAbility(new AttacksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( - new AtTheBeginOfMainPhaseDelayedTriggeredAbility( - new AddManaToManaPoolSourceControllerEffect(Mana.GenericMana(2)), false, - TargetController.YOU, AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN_THIS_TURN - ) - ).setText("add {C}{C} at the beginning of your next main phase this turn"), false)); - } - - private ConduitOfEmrakul(final ConduitOfEmrakul card) { - super(card); - } - - @Override - public ConduitOfEmrakul copy() { - return new ConduitOfEmrakul(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ConduitOfStorms.java b/Mage.Sets/src/mage/cards/c/ConduitOfStorms.java index 0fdf2d7098f..1e9ea59ceb0 100644 --- a/Mage.Sets/src/mage/cards/c/ConduitOfStorms.java +++ b/Mage.Sets/src/mage/cards/c/ConduitOfStorms.java @@ -1,6 +1,5 @@ package mage.cards.c; -import mage.MageInt; import mage.Mana; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -9,9 +8,8 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.mana.AddManaToManaPoolSourceControllerEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; @@ -21,19 +19,19 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class ConduitOfStorms extends CardImpl { +public final class ConduitOfStorms extends TransformingDoubleFacedCard { public ConduitOfStorms(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); - this.subtype.add(SubType.WEREWOLF); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(2); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF, SubType.HORROR}, "{2}{R}", + "Conduit of Emrakul", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.WEREWOLF}, ""); - this.secondSideCardClazz = mage.cards.c.ConduitOfEmrakul.class; + // Conduit of Storms + this.getLeftHalfCard().setPT(2, 3); // Whenever Conduit of Storms attacks, add {R} at the beginning of your next main phase this turn. - this.addAbility(new AttacksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfMainPhaseDelayedTriggeredAbility( new AddManaToManaPoolSourceControllerEffect(Mana.RedMana(1)), false, TargetController.YOU, AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN_THIS_TURN @@ -41,8 +39,18 @@ public final class ConduitOfStorms extends CardImpl { ).setText("add {R} at the beginning of your next main phase this turn"), false)); // {3}{R}{R}: Transform Conduit of Storms. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{R}{R}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{R}{R}"))); + + // Conduit of Emrakul + this.getRightHalfCard().setPT(5, 4); + + // Whenever Conduit of Emrakul attacks, add {C}{C} at the beginning of your next main phase this turn. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfMainPhaseDelayedTriggeredAbility( + new AddManaToManaPoolSourceControllerEffect(Mana.GenericMana(2)), false, + TargetController.YOU, AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN_THIS_TURN + ) + ).setText("add {C}{C} at the beginning of your next main phase this turn"), false)); } private ConduitOfStorms(final ConduitOfStorms card) { diff --git a/Mage.Sets/src/mage/cards/c/ConquerorsFoothold.java b/Mage.Sets/src/mage/cards/c/ConquerorsFoothold.java deleted file mode 100644 index aa342858ef5..00000000000 --- a/Mage.Sets/src/mage/cards/c/ConquerorsFoothold.java +++ /dev/null @@ -1,63 +0,0 @@ - -package mage.cards.c; - -import java.util.UUID; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.DrawDiscardControllerEffect; -import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; -import mage.abilities.mana.ColorlessManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Zone; -import mage.target.common.TargetCardInYourGraveyard; - -/** - * - * @author TheElk801 - */ -public final class ConquerorsFoothold extends CardImpl { - - public ConquerorsFoothold(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.nightCard = true; - - // {T}: Add {C}. - this.addAbility(new ColorlessManaAbility()); - - // {2}, {T}: Draw a card, then discard a card. - SimpleActivatedAbility ability = new SimpleActivatedAbility( - new DrawDiscardControllerEffect(), - new ManaCostsImpl<>("{2}")); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - - // {4}, {T}: Draw a card. - SimpleActivatedAbility ability2 = new SimpleActivatedAbility( - new DrawCardSourceControllerEffect(1), - new ManaCostsImpl<>("{4}")); - ability2.addCost(new TapSourceCost()); - this.addAbility(ability2); - - // {6}, {T}: Return target card from your graveyard to your hand. - SimpleActivatedAbility ability3 = new SimpleActivatedAbility( - new ReturnFromGraveyardToHandTargetEffect(), - new ManaCostsImpl<>("{6}")); - ability3.addCost(new TapSourceCost()); - ability3.addTarget(new TargetCardInYourGraveyard()); - this.addAbility(ability3); - } - - private ConquerorsFoothold(final ConquerorsFoothold card) { - super(card); - } - - @Override - public ConquerorsFoothold copy() { - return new ConquerorsFoothold(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ConquerorsGalleon.java b/Mage.Sets/src/mage/cards/c/ConquerorsGalleon.java index 7c8bcf607a3..dc788fa0b5a 100644 --- a/Mage.Sets/src/mage/cards/c/ConquerorsGalleon.java +++ b/Mage.Sets/src/mage/cards/c/ConquerorsGalleon.java @@ -1,48 +1,69 @@ package mage.cards.c; -import mage.MageInt; -import mage.constants.Pronoun; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.*; import mage.abilities.keyword.CrewAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Pronoun; import mage.constants.PutCards; import mage.constants.SubType; +import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; /** * @author TheElk801 */ -public final class ConquerorsGalleon extends CardImpl { +public final class ConquerorsGalleon extends TransformingDoubleFacedCard { public ConquerorsGalleon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "{4}", + "Conqueror's Foothold", + new CardType[]{CardType.LAND}, new SubType[]{}, ""); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(2); - this.toughness = new MageInt(10); + // Conqueror's Galleon + this.getLeftHalfCard().setPT(2, 10); - this.secondSideCardClazz = mage.cards.c.ConquerorsFoothold.class; - - // When Conqueror's Galleon attacks, exile it at the end of combat, then return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); - this.addAbility(new AttacksTriggeredAbility( + // When Conqueror's Galleon attacks, exile it at end of combat, then return it to the battlefield transformed under your control. + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility( new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility( new ExileAndReturnSourceEffect( PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.IT, true ) - )), false, "When {this} attacks, exile it at end of combat, " + - "then return it to the battlefield transformed under your control." + )), false, "When {this} attacks, exile it at end of combat, then return it to the battlefield transformed under your control." )); // Crew 4 - this.addAbility(new CrewAbility(4)); + this.getLeftHalfCard().addAbility(new CrewAbility(4)); + + + // Conqueror's Foothold + // {T}: Add {C}. + this.getRightHalfCard().addAbility(new ColorlessManaAbility()); + + // {2}, {T}: Draw a card, then discard a card. + SimpleActivatedAbility ability = new SimpleActivatedAbility(new DrawDiscardControllerEffect(), new ManaCostsImpl<>("{2}")); + ability.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability); + + // {4}, {T}: Draw a card. + SimpleActivatedAbility ability2 = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{4}")); + ability2.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability2); + + // {6}, {T}: Return target card from your graveyard to your hand. + SimpleActivatedAbility ability3 = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{6}")); + ability3.addCost(new TapSourceCost()); + ability3.addTarget(new TargetCardInYourGraveyard()); + this.getRightHalfCard().addAbility(ability3); } private ConquerorsGalleon(final ConquerorsGalleon card) { diff --git a/Mage.Sets/src/mage/cards/c/ConvictedKiller.java b/Mage.Sets/src/mage/cards/c/ConvictedKiller.java index ed0602e0025..e98aa4030a9 100644 --- a/Mage.Sets/src/mage/cards/c/ConvictedKiller.java +++ b/Mage.Sets/src/mage/cards/c/ConvictedKiller.java @@ -1,40 +1,38 @@ package mage.cards.c; -import java.util.UUID; - -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** * @author fireshoes */ -public final class ConvictedKiller extends CardImpl { +public final class ConvictedKiller extends TransformingDoubleFacedCard { public ConvictedKiller(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{R}", + "Branded Howler", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); - this.secondSideCardClazz = mage.cards.b.BrandedHowler.class; + // Convicted Killer + this.getLeftHalfCard().setPT(2, 2); // At the beginning of each upkeep, if no spells were cast last turn, transform Convicted Killer. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Branded Howler + this.getRightHalfCard().setPT(4, 4); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Branded Howler. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } - private ConvictedKiller(final ConvictedKiller card) { - super(card); - } - - @Override - public ConvictedKiller copy() { - return new ConvictedKiller(this); - } + private ConvictedKiller(final ConvictedKiller card) { super(card); } + @Override public ConvictedKiller copy() { return new ConvictedKiller(this); } } diff --git a/Mage.Sets/src/mage/cards/c/CopperTablet.java b/Mage.Sets/src/mage/cards/c/CopperTablet.java index 308d02063d0..240d72dc1ab 100644 --- a/Mage.Sets/src/mage/cards/c/CopperTablet.java +++ b/Mage.Sets/src/mage/cards/c/CopperTablet.java @@ -20,7 +20,7 @@ public final class CopperTablet extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); // At the beginning of each player's upkeep, Copper Tablet deals 1 damage to that player. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER, new DamageTargetEffect(1, true, "that player"), false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER, new DamageTargetEffect(1).withTargetDescription("that player"), false)); } private CopperTablet(final CopperTablet card) { diff --git a/Mage.Sets/src/mage/cards/c/CosmiumKiln.java b/Mage.Sets/src/mage/cards/c/CosmiumKiln.java deleted file mode 100644 index 08db82019b9..00000000000 --- a/Mage.Sets/src/mage/cards/c/CosmiumKiln.java +++ /dev/null @@ -1,41 +0,0 @@ -package mage.cards.c; - -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.game.permanent.token.GnomeToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class CosmiumKiln extends CardImpl { - - public CosmiumKiln(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.nightCard = true; - this.color.setWhite(true); - - // When Cosmium Kiln enters the battlefield, create two 1/1 colorless Gnome artifact creature tokens. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GnomeToken(), 2))); - - // Creatures you control get +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); - } - - private CosmiumKiln(final CosmiumKiln card) { - super(card); - } - - @Override - public CosmiumKiln copy() { - return new CosmiumKiln(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CovertCutpurse.java b/Mage.Sets/src/mage/cards/c/CovertCutpurse.java index c9372e1d538..3cd865e93c6 100644 --- a/Mage.Sets/src/mage/cards/c/CovertCutpurse.java +++ b/Mage.Sets/src/mage/cards/c/CovertCutpurse.java @@ -1,12 +1,13 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; @@ -20,40 +21,44 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class CovertCutpurse extends CardImpl { - - private static final FilterPermanent filter - = new FilterCreaturePermanent("creature you don't control that was dealt damage this turn"); +public final class CovertCutpurse extends TransformingDoubleFacedCard { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature you don't control that was dealt damage this turn"); static { filter.add(TargetController.NOT_YOU.getControllerPredicate()); filter.add(WasDealtDamageThisTurnPredicate.instance); } public CovertCutpurse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE}, "{2}{B}", + "Covetous Geist", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.ROGUE}, "B"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.c.CovetousGeist.class; + // Covert Cutpurse + this.getLeftHalfCard().setPT(2, 1); // When Covert Cutpurse enters the battlefield, destroy target creature you don't control that was dealt damage this turn. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Disturb {4}{B} - this.addAbility(new DisturbAbility(this, "{4}{B}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{4}{B}")); + + // Covetous Geist + this.getRightHalfCard().setPT(2, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Deathtouch + this.getRightHalfCard().addAbility(DeathtouchAbility.getInstance()); + + // If Covetous Geist would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } - private CovertCutpurse(final CovertCutpurse card) { - super(card); - } - - @Override - public CovertCutpurse copy() { - return new CovertCutpurse(this); - } + private CovertCutpurse(final CovertCutpurse card) { super(card); } + @Override public CovertCutpurse copy() { return new CovertCutpurse(this); } } diff --git a/Mage.Sets/src/mage/cards/c/CovetousCastaway.java b/Mage.Sets/src/mage/cards/c/CovetousCastaway.java index 1fd63048184..319d6b7d018 100644 --- a/Mage.Sets/src/mage/cards/c/CovetousCastaway.java +++ b/Mage.Sets/src/mage/cards/c/CovetousCastaway.java @@ -1,35 +1,53 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.common.DiesSourceTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.MillCardsControllerEffect; +import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; /** * @author TheElk801 */ -public final class CovetousCastaway extends CardImpl { +public final class CovetousCastaway extends TransformingDoubleFacedCard { public CovetousCastaway(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "{1}{U}", + "Ghostly Castigator", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U"); - this.subtype.add(SubType.HUMAN); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.g.GhostlyCastigator.class; + + // Covetous Castaway + this.getLeftHalfCard().setPT(1, 3); // When Covetous Castaway dies, mill three cards. - this.addAbility(new DiesSourceTriggeredAbility(new MillCardsControllerEffect(3))); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new MillCardsControllerEffect(3))); // Disturb {3}{U}{U} - this.addAbility(new DisturbAbility(this, "{3}{U}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{3}{U}{U}")); + + // Ghostly Castigator + this.getRightHalfCard().setPT(3, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // When Ghostly Castigator enters the battlefield, you may shuffle up to three target cards from your graveyard into your library. + EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ShuffleIntoLibraryTargetEffect(), true); + ability.addTarget(new TargetCardInYourGraveyard(0, 3)); + this.getRightHalfCard().addAbility(ability); + + // If Ghostly Castigator would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private CovetousCastaway(final CovetousCastaway card) { diff --git a/Mage.Sets/src/mage/cards/c/CovetousGeist.java b/Mage.Sets/src/mage/cards/c/CovetousGeist.java deleted file mode 100644 index 7dd65c1bb4f..00000000000 --- a/Mage.Sets/src/mage/cards/c/CovetousGeist.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class CovetousGeist extends CardImpl { - - public CovetousGeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); - - // If Covetous Geist would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private CovetousGeist(final CovetousGeist card) { - super(card); - } - - @Override - public CovetousGeist copy() { - return new CovetousGeist(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CrackedEarthTechnique.java b/Mage.Sets/src/mage/cards/c/CrackedEarthTechnique.java index 2230220930d..ffb223b38f0 100644 --- a/Mage.Sets/src/mage/cards/c/CrackedEarthTechnique.java +++ b/Mage.Sets/src/mage/cards/c/CrackedEarthTechnique.java @@ -22,10 +22,11 @@ public final class CrackedEarthTechnique extends CardImpl { this.subtype.add(SubType.LESSON); // Earthbend 3, then earthbend 3. You gain 3 life. - this.getSpellAbility().addEffect(new EarthbendTargetEffect(3)); - this.getSpellAbility().addEffect(new EarthbendTargetEffect(3) + this.getSpellAbility().addEffect(new EarthbendTargetEffect(3, false)); + this.getSpellAbility().addEffect(new EarthbendTargetEffect(3, false) + .concatBy(", then") .setTargetPointer(new SecondTargetPointer()) - .concatBy(", then")); + ); this.getSpellAbility().addTarget(new TargetControlledLandPermanent().withChooseHint("first target")); this.getSpellAbility().addTarget(new TargetControlledLandPermanent().withChooseHint("second target")); this.getSpellAbility().addEffect(new GainLifeEffect(3)); diff --git a/Mage.Sets/src/mage/cards/c/CradleOfVitality.java b/Mage.Sets/src/mage/cards/c/CradleOfVitality.java index 9cf5689a0f6..9fc3fdfb0d3 100644 --- a/Mage.Sets/src/mage/cards/c/CradleOfVitality.java +++ b/Mage.Sets/src/mage/cards/c/CradleOfVitality.java @@ -27,7 +27,7 @@ public final class CradleOfVitality extends CardImpl { new AddCountersTargetEffect(CounterType.P1P1.createInstance(), SavedGainedLifeValue.MANY) .setText("put a +1/+1 counter on target creature for each 1 life you gained"), new ManaCostsImpl<>("{1}{W}") - ), false, true); + ), false); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CragcrownPathway.java b/Mage.Sets/src/mage/cards/c/CragcrownPathway.java index 4834947b805..97926995e49 100644 --- a/Mage.Sets/src/mage/cards/c/CragcrownPathway.java +++ b/Mage.Sets/src/mage/cards/c/CragcrownPathway.java @@ -1,6 +1,5 @@ package mage.cards.c; -import mage.abilities.keyword.TransformAbility; import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.cards.CardSetInfo; @@ -27,7 +26,6 @@ public final class CragcrownPathway extends ModalDoubleFacedCard { // {T}: Add {R}. this.getLeftHalfCard().addAbility(new RedManaAbility()); - this.getLeftHalfCard().addAbility(new TransformAbility()); // 2. // Timbercrown Pathway diff --git a/Mage.Sets/src/mage/cards/c/CrashingWave.java b/Mage.Sets/src/mage/cards/c/CrashingWave.java new file mode 100644 index 00000000000..e3695a1bebb --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrashingWave.java @@ -0,0 +1,92 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetPermanentAmount; +import mage.target.targetadjustment.XTargetsCountAdjuster; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrashingWave extends CardImpl { + + public CrashingWave(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}{U}"); + + // As an additional cost to cast this spell, waterbend {X}. + this.getSpellAbility().addCost(new WaterbendCost("{X}")); + + // Tap up to X target creatures, then distribute three stun counters among tapped creatures your opponents control. + this.getSpellAbility().addEffect(new TapTargetEffect("tap up to X target creatures")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1)); + this.getSpellAbility().setTargetAdjuster(new XTargetsCountAdjuster()); + this.getSpellAbility().addEffect(new CrashingWaveEffect()); + } + + private CrashingWave(final CrashingWave card) { + super(card); + } + + @Override + public CrashingWave copy() { + return new CrashingWave(this); + } +} + +class CrashingWaveEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterOpponentsCreaturePermanent("tapped creatures your opponents control"); + + static { + filter.add(TappedPredicate.TAPPED); + } + + CrashingWaveEffect() { + super(Outcome.Benefit); + staticText = ", then distribute three stun counters among tapped creatures your opponents control"; + } + + private CrashingWaveEffect(final CrashingWaveEffect effect) { + super(effect); + } + + @Override + public CrashingWaveEffect copy() { + return new CrashingWaveEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || !game.getBattlefield().contains(filter, source.getControllerId(), source, game, 1)) { + return false; + } + TargetPermanentAmount target = new TargetPermanentAmount(3, 1, filter); + target.withNotTarget(true); + player.chooseTarget(outcome, target, source, game); + for (UUID targetId : target.getTargets()) { + Optional.ofNullable(targetId) + .map(game::getPermanent) + .ifPresent(permanent -> permanent.addCounters( + CounterType.STUN.createInstance(target.getTargetAmount(targetId)), source, game + )); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CryptolithFragment.java b/Mage.Sets/src/mage/cards/c/CryptolithFragment.java index ec264beae69..46c2288f17f 100644 --- a/Mage.Sets/src/mage/cards/c/CryptolithFragment.java +++ b/Mage.Sets/src/mage/cards/c/CryptolithFragment.java @@ -1,18 +1,22 @@ package mage.cards.c; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.LifeCompareCondition; import mage.abilities.effects.common.LoseLifeAllPlayersEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.constants.TargetController; import java.util.UUID; @@ -20,26 +24,39 @@ import java.util.UUID; /** * @author fireshoes */ -public final class CryptolithFragment extends CardImpl { +public final class CryptolithFragment extends TransformingDoubleFacedCard { private static final Condition condition = new LifeCompareCondition(TargetController.EACH_PLAYER, ComparisonType.OR_LESS, 10); public CryptolithFragment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); - - this.secondSideCardClazz = mage.cards.a.AuroraOfEmrakul.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{3}", + "Aurora of Emrakul", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.REFLECTION}, ""); + // Cryptolith Fragment // Cryptolith Fragment enters the battlefield tapped. - this.addAbility(new EntersBattlefieldTappedAbility()); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTappedAbility()); // {T}: Add one mana of any color. Each player loses 1 life. Ability anyColorManaAbility = new AnyColorManaAbility(); anyColorManaAbility.addEffect(new LoseLifeAllPlayersEffect(1)); - this.addAbility(anyColorManaAbility); + this.getLeftHalfCard().addAbility(anyColorManaAbility); // At the beginning of your upkeep, if each player has 10 or less life, transform Cryptolith Fragment. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition)); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition)); + + // Aurora of Emrakul + this.getRightHalfCard().setPT(1, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Deathtouch + this.getRightHalfCard().addAbility(DeathtouchAbility.getInstance()); + + // Whenever Aurora of Emrakul attacks, each opponent loses 3 life. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new LoseLifeOpponentsEffect(3), false)); } private CryptolithFragment(final CryptolithFragment card) { diff --git a/Mage.Sets/src/mage/cards/c/CrystalFragments.java b/Mage.Sets/src/mage/cards/c/CrystalFragments.java index 145a755ba55..8a84aefb02a 100644 --- a/Mage.Sets/src/mage/cards/c/CrystalFragments.java +++ b/Mage.Sets/src/mage/cards/c/CrystalFragments.java @@ -1,42 +1,65 @@ package mage.cards.c; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SagaAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.PreventAllDamageToAllEffect; +import mage.abilities.effects.common.TapAllEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EquipAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author TheElk801 */ -public final class CrystalFragments extends CardImpl { +public final class CrystalFragments extends TransformingDoubleFacedCard { public CrystalFragments(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{W}"); - - this.subtype.add(SubType.EQUIPMENT); - this.secondSideCardClazz = mage.cards.s.SummonAlexander.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "{W}", + "Summon: Alexander", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.CONSTRUCT}, "W"); + // Crystal Fragments // Equipped creature gets +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 1))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 1))); // {5}{W}{W}: Exile this Equipment, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{5}{W}{W}") )); // Equip {1} - this.addAbility(new EquipAbility(1)); + this.getLeftHalfCard().addAbility(new EquipAbility(1)); + + // Summon: Alexander + this.getRightHalfCard().setPT(4, 3); + + // Saga setup (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()).withShowSacText(true); + + // I, II -- Prevent all damage that would be dealt to creatures you control this turn. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + chapterAbility -> chapterAbility.addEffect(new PreventAllDamageToAllEffect( + Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED + ))); + + // III -- Tap all creatures your opponents control. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_III, + chapterAbility -> chapterAbility.addEffect(new TapAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES))); + + this.getRightHalfCard().addAbility(sagaAbility); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private CrystalFragments(final CrystalFragments card) { diff --git a/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java b/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java index b78941496aa..eeea1819109 100644 --- a/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java +++ b/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java @@ -1,21 +1,23 @@ package mage.cards.c; -import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.ProwessAbility; import mage.abilities.mana.ConditionalColorlessManaAbility; import mage.abilities.mana.builder.common.InstantOrSorcerySpellManaBuilder; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterInstantOrSorceryCard; @@ -24,25 +26,35 @@ import java.util.UUID; /** * @author fireshoes */ -public final class CuriousHomunculus extends CardImpl { +public final class CuriousHomunculus extends TransformingDoubleFacedCard { private static final Condition condition = new CardsInControllerGraveyardCondition(3, new FilterInstantOrSorceryCard("instant and/or sorcery cards")); private static final Hint hint = new ValueHint("Instant and sorcery cards in your graveyard", new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY)); + private static final FilterCard filter = new FilterInstantOrSorceryCard("Instant and sorcery spells"); public CuriousHomunculus(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); - this.subtype.add(SubType.HOMUNCULUS); - this.power = new MageInt(1); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HOMUNCULUS}, "{1}{U}", + "Voracious Reader", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.HOMUNCULUS}, ""); - this.secondSideCardClazz = mage.cards.v.VoraciousReader.class; + // Curious Homunculus + this.getLeftHalfCard().setPT(1, 1); // {T}: Add {C}. Spend this mana only to cast an instant or sorcery spell. - this.addAbility(new ConditionalColorlessManaAbility(new TapSourceCost(), 1, new InstantOrSorcerySpellManaBuilder())); + this.getLeftHalfCard().addAbility(new ConditionalColorlessManaAbility(new TapSourceCost(), 1, new InstantOrSorcerySpellManaBuilder())); // At the beginning of your upkeep, if there are three or more instant and/or sorcery cards in your graveyard, transform Curious Homunculus. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition).addHint(hint)); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition).addHint(hint)); + + // Voracious Reader + this.getRightHalfCard().setPT(3, 4); + + // Prowess + this.getRightHalfCard().addAbility(new ProwessAbility()); + + // Instant and sorcery spells you cast cost {1} less to cast. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); } private CuriousHomunculus(final CuriousHomunculus card) { diff --git a/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java b/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java index 1cbb930c7bd..13c506faebd 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java @@ -1,7 +1,6 @@ package mage.cards.c; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.AttachEffect; @@ -9,8 +8,11 @@ import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.EnchantAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.NightboundAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; @@ -23,24 +25,24 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class CurseOfLeeches extends CardImpl { +public final class CurseOfLeeches extends TransformingDoubleFacedCard { public CurseOfLeeches(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); - - this.subtype.add(SubType.AURA); - this.subtype.add(SubType.CURSE); - this.secondSideCardClazz = mage.cards.l.LeechingLurker.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA, SubType.CURSE}, "{2}{B}", + "Leeching Lurker", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.LEECH, SubType.HORROR}, "B"); + // Curse of Leeches // Enchant player TargetPlayer auraTarget = new TargetPlayer(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getLeftHalfCard().getSpellAbility().addTarget(auraTarget); + this.getLeftHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // As this permanent transforms into Curse of Leeches, attach it to a player. - this.addAbility(new SimpleStaticAbility(new CurseOfLeechesEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new CurseOfLeechesEffect())); // At the beginning of enchanted player's upkeep, they lose 1 life and you gain 1 life. ability = new BeginningOfUpkeepTriggeredAbility( @@ -48,10 +50,19 @@ public final class CurseOfLeeches extends CardImpl { false ); ability.addEffect(new GainLifeEffect(1).concatBy("and")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Leeching Lurker + this.getRightHalfCard().setPT(4, 4); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private CurseOfLeeches(final CurseOfLeeches card) { @@ -75,6 +86,11 @@ class CurseOfLeechesEffect extends ReplacementEffectImpl { super(effect); } + @Override + public CurseOfLeechesEffect copy() { + return new CurseOfLeechesEffect(this); + } + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); @@ -101,9 +117,4 @@ class CurseOfLeechesEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { return source.getSourceId().equals(event.getTargetId()); } - - @Override - public CurseOfLeechesEffect copy() { - return new CurseOfLeechesEffect(this); - } } diff --git a/Mage.Sets/src/mage/cards/c/CycleOfRenewal.java b/Mage.Sets/src/mage/cards/c/CycleOfRenewal.java index 29c8d2ae227..5b3d1d6ebb2 100644 --- a/Mage.Sets/src/mage/cards/c/CycleOfRenewal.java +++ b/Mage.Sets/src/mage/cards/c/CycleOfRenewal.java @@ -24,7 +24,7 @@ public final class CycleOfRenewal extends CardImpl { // Sacrifice a land. Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle. this.getSpellAbility().addEffect(new SacrificeControllerEffect(StaticFilters.FILTER_LAND, 1, "")); this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary( - 0, 2, StaticFilters.FILTER_CARD_BASIC_LAND + 0, 2, StaticFilters.FILTER_CARD_BASIC_LANDS ), true)); } diff --git a/Mage.Sets/src/mage/cards/c/CyclonusCybertronianFighter.java b/Mage.Sets/src/mage/cards/c/CyclonusCybertronianFighter.java deleted file mode 100644 index 1b21a9e9880..00000000000 --- a/Mage.Sets/src/mage/cards/c/CyclonusCybertronianFighter.java +++ /dev/null @@ -1,86 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.LivingMetalAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.TurnPhase; -import mage.game.Game; -import mage.game.turn.TurnMod; - -import java.util.UUID; - -/** - * @author mllagostera - */ -public final class CyclonusCybertronianFighter extends CardImpl { - - public CyclonusCybertronianFighter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setBlack(true); - this.color.setBlue(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever Cyclonus deals combat damage to a player, convert it. - // If you do, there is an additional beginning phase after this phase. - Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( - new CyclonusCybertronianFighterEffect(), - false - ); - this.addAbility(ability); - } - - private CyclonusCybertronianFighter(final CyclonusCybertronianFighter card) { - super(card); - } - - @Override - public CyclonusCybertronianFighter copy() { - return new CyclonusCybertronianFighter(this); - } -} - -class CyclonusCybertronianFighterEffect extends TransformSourceEffect { - - CyclonusCybertronianFighterEffect() { - super(); - staticText = "transform it. If you do, there is an additional beginning phase after this phase"; - } - - private CyclonusCybertronianFighterEffect(final CyclonusCybertronianFighterEffect effect) { - super(effect); - } - - @Override - public CyclonusCybertronianFighterEffect copy() { - return new CyclonusCybertronianFighterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - if (!super.apply(game, source)) { - return false; - } - TurnMod beginning = new TurnMod(game.getState().getActivePlayerId()).withExtraPhase(TurnPhase.BEGINNING); - game.getState().getTurnMods().add(beginning); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/c/CyclonusTheSaboteur.java b/Mage.Sets/src/mage/cards/c/CyclonusTheSaboteur.java index d5559695d3d..e54ff1cfdbf 100644 --- a/Mage.Sets/src/mage/cards/c/CyclonusTheSaboteur.java +++ b/Mage.Sets/src/mage/cards/c/CyclonusTheSaboteur.java @@ -1,74 +1,109 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.keyword.ConniveSourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.PowerPredicate; - -import java.util.UUID; - -/** - * @author mllagostera - */ -public final class CyclonusTheSaboteur extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent(); - - static { - filter.add(new PowerPredicate(ComparisonType.MORE_THAN,4)); - } - - private static final Condition condition = new SourceMatchesFilterCondition(filter); - - public CyclonusTheSaboteur(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{U}{B}"); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(2); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.c.CyclonusCybertronianFighter.class; - - // More Than Meets the Eye {5}{U}{B} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{5}{U}{B}")); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever Cyclonus deals combat damage to a player, it connives. - Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( - new ConniveSourceEffect("it"), - false, - true - ); - - // Then if Cyclonus's power is 5 or greater, convert it - ability.addEffect((new ConditionalOneShotEffect( - new TransformSourceEffect(), - condition, - "Then if {this}'s power is 5 or greater, convert it." - ))); - - this.addAbility(ability); - } - - private CyclonusTheSaboteur(final CyclonusTheSaboteur card) { - super(card); - } - - @Override - public CyclonusTheSaboteur copy() { - return new CyclonusTheSaboteur(this); - } -} +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LivingMetalAbility; +import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.game.turn.TurnMod; + +import java.util.UUID; + +/** + * @author mllagostera + */ +public final class CyclonusTheSaboteur extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterPermanent(); + static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN,4)); } + private static final Condition condition = new SourceMatchesFilterCondition(filter); + + public CyclonusTheSaboteur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{2}{U}{B}", + "Cyclonus, Cybertronian Fighter", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "UB"); + + // Cyclonus, the Saboteur + this.getLeftHalfCard().setPT(2, 5); + + // More Than Meets the Eye {5}{U}{B} + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{5}{U}{B}")); + + // Flying + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever Cyclonus deals combat damage to a player, it connives. Then if Cyclonus's power is 5 or greater, convert it. + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( + new ConniveSourceEffect("it"), false, true + ); + ability.addEffect(new ConditionalOneShotEffect( + new TransformSourceEffect(), condition, + "Then if {this}'s power is 5 or greater, convert it." + )); + this.getLeftHalfCard().addAbility(ability); + + // Cyclonus, Cybertronian Fighter + this.getRightHalfCard().setPT(5, 5); + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever Cyclonus deals combat damage to a player, transform it. If you do, there is an additional beginning phase after this phase. + Ability abilityBack = new DealsCombatDamageToAPlayerTriggeredAbility( + new CyclonusCybertronianFighterEffect(), + false + ); + this.getRightHalfCard().addAbility(abilityBack); + } + + private CyclonusTheSaboteur(final CyclonusTheSaboteur card) { + super(card); + } + + @Override + public CyclonusTheSaboteur copy() { + return new CyclonusTheSaboteur(this); + } +} + +class CyclonusCybertronianFighterEffect extends TransformSourceEffect { + + CyclonusCybertronianFighterEffect() { + super(); + staticText = "convert it. If you do, there is an additional beginning phase after this phase"; + } + + private CyclonusCybertronianFighterEffect(final CyclonusCybertronianFighterEffect effect) { + super(effect); + } + + @Override + public CyclonusCybertronianFighterEffect copy() { + return new CyclonusCybertronianFighterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (!super.apply(game, source)) { + return false; + } + TurnMod beginning = new TurnMod(game.getState().getActivePlayerId()).withExtraPhase(TurnPhase.BEGINNING); + game.getState().getTurnMods().add(beginning); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DaiLiAgents.java b/Mage.Sets/src/mage/cards/d/DaiLiAgents.java index fda6379c4cb..a5f62bd0d16 100644 --- a/Mage.Sets/src/mage/cards/d/DaiLiAgents.java +++ b/Mage.Sets/src/mage/cards/d/DaiLiAgents.java @@ -46,7 +46,7 @@ public final class DaiLiAgents extends CardImpl { this.toughness = new MageInt(4); // When this creature enters, earthbend 1, then earthbend 1. - Ability ability = new EntersBattlefieldTriggeredAbility(new EarthbendTargetEffect(1).setText("earhbend 1")); + Ability ability = new EntersBattlefieldTriggeredAbility(new EarthbendTargetEffect(1).setText("earthbend 1")); ability.addEffect(new EarthbendTargetEffect(1) .setTargetPointer(new SecondTargetPointer()) .concatBy(", then")); @@ -56,7 +56,7 @@ public final class DaiLiAgents extends CardImpl { // Whenever this creature attacks, each opponent loses X life and you gain X life, where X is the number of creatures you control with +1/+1 counters on them. ability = new AttacksTriggeredAbility(new LoseLifeOpponentsEffect(xValue).setText("each opponent loses X life")); - ability.addEffect(new GainLifeEffect(xValue).concatBy("and")); + ability.addEffect(new GainLifeEffect(xValue).setText("and you gain X life, where X is the number of creatures you control with +1/+1 counters on them")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DaringSleuth.java b/Mage.Sets/src/mage/cards/d/DaringSleuth.java index b6a2e57ab33..765a27080f0 100644 --- a/Mage.Sets/src/mage/cards/d/DaringSleuth.java +++ b/Mage.Sets/src/mage/cards/d/DaringSleuth.java @@ -1,11 +1,12 @@ package mage.cards.d; -import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SacrificePermanentTriggeredAbility; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.keyword.InvestigateEffect; +import mage.abilities.keyword.ProwessAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; @@ -15,21 +16,30 @@ import java.util.UUID; /** * @author fireshoes */ -public final class DaringSleuth extends CardImpl { +public final class DaringSleuth extends TransformingDoubleFacedCard { public DaringSleuth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(2); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE}, "{1}{U}", + "Bearer of Overwhelming Truths", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "U"); - this.secondSideCardClazz = mage.cards.b.BearerOfOverwhelmingTruths.class; + // Daring Sleuth + this.getLeftHalfCard().setPT(2, 1); // When you sacrifice a Clue, transform Daring Sleuth. - this.addAbility(new TransformAbility()); - this.addAbility(new SacrificePermanentTriggeredAbility(new TransformSourceEffect(), StaticFilters.FILTER_CONTROLLED_CLUE) - .setTriggerPhrase("When you sacrifice a Clue, ")); + this.getLeftHalfCard().addAbility(new SacrificePermanentTriggeredAbility( + new TransformSourceEffect(), StaticFilters.FILTER_CONTROLLED_CLUE + ).setTriggerPhrase("When you sacrifice a Clue, ")); + + // Bearer of Overwhelming Truths + this.getRightHalfCard().setPT(3, 2); + + // Prowess + this.getRightHalfCard().addAbility(new ProwessAbility()); + + // Whenever Bearer of Overwhelming Truths deals combat damage to a player, investigate. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new InvestigateEffect(), false)); } private DaringSleuth(final DaringSleuth card) { diff --git a/Mage.Sets/src/mage/cards/d/DarthVader.java b/Mage.Sets/src/mage/cards/d/DarthVader.java deleted file mode 100644 index df674cb3863..00000000000 --- a/Mage.Sets/src/mage/cards/d/DarthVader.java +++ /dev/null @@ -1,99 +0,0 @@ - -package mage.cards.d; - -import mage.MageInt; -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.dynamicvalue.common.CountersSourceCount; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.MenaceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.counters.CounterType; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; - -import java.util.Iterator; -import java.util.UUID; - -/** - * @author Styxo - */ -public final class DarthVader extends CardImpl { - - public DarthVader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SITH); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlack(true); - - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Whenever Darth Vader attacks, creatures defending player controls get -1/-1 until end of turn for each +1/+1 counter on Darth Vader. - this.addAbility(new AttacksTriggeredAbility(new UnboostCreaturesDefendingPlayerEffect(), false, null, SetTargetPointer.PLAYER)); - } - - private DarthVader(final DarthVader card) { - super(card); - } - - @Override - public DarthVader copy() { - return new DarthVader(this); - } -} - -class UnboostCreaturesDefendingPlayerEffect extends ContinuousEffectImpl { - - UnboostCreaturesDefendingPlayerEffect() { - super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.UnboostCreature); - staticText = "creatures defending player controls get -1/-1 until end of turn for each +1/+1 counter on Darth Vader"; - } - - private UnboostCreaturesDefendingPlayerEffect(final UnboostCreaturesDefendingPlayerEffect effect) { - super(effect); - } - - @Override - public UnboostCreaturesDefendingPlayerEffect copy() { - return new UnboostCreaturesDefendingPlayerEffect(this); - } - - @Override - public void init(Ability source, Game game) { - super.init(source, game); - if (getAffectedObjectsSet()) { - for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, getTargetPointer().getFirst(game, source), game)) { - affectedObjectList.add(new MageObjectReference(creature, game)); - } - } - } - - @Override - public boolean apply(Game game, Ability source) { - for (Iterator it = affectedObjectList.iterator(); it.hasNext(); ) { - Permanent permanent = it.next().getPermanent(game); - if (permanent != null) { - int unboostCount = -1 * new CountersSourceCount(CounterType.P1P1).calculate(game, source, this); - permanent.addPower(unboostCount); - permanent.addToughness(unboostCount); - } else { - it.remove(); - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DauntlessAvenger.java b/Mage.Sets/src/mage/cards/d/DauntlessAvenger.java deleted file mode 100644 index 8659565dace..00000000000 --- a/Mage.Sets/src/mage/cards/d/DauntlessAvenger.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.target.common.TargetCardInYourGraveyard; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DauntlessAvenger extends CardImpl { - - private static final FilterCard filter - = new FilterCreatureCard("creature card with mana value 2 or less from your graveyard"); - - static { - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3)); - } - - public DauntlessAvenger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.color.setWhite(true); - this.nightCard = true; - - // Whenever Dauntless Avenger attacks, return target creature card with mana value 2 or less from your graveyard to the battlefield tapped and attacking. - Ability ability = new AttacksTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(true, true)); - ability.addTarget(new TargetCardInYourGraveyard(filter)); - this.addAbility(ability); - } - - private DauntlessAvenger(final DauntlessAvenger card) { - super(card); - } - - @Override - public DauntlessAvenger copy() { - return new DauntlessAvenger(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java b/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java index 6d5c900626c..04275b5768e 100644 --- a/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java +++ b/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java @@ -31,9 +31,7 @@ public final class DavrielRogueShadowmage extends CardImpl { // At the beginning of each opponent's upkeep, if that player has one or fewer cards in hand, Davriel, Rogue Shadowmage deals 2 damage to them. this.addAbility(new BeginningOfUpkeepTriggeredAbility( TargetController.OPPONENT, - new DamageTargetEffect( - 2, true, "them", "{this}" - ), false + new DamageTargetEffect(2).withTargetDescription("them"), false ).withInterveningIf(condition)); // -1: Target player discards a card. diff --git a/Mage.Sets/src/mage/cards/d/DaybreakRanger.java b/Mage.Sets/src/mage/cards/d/DaybreakRanger.java index 7aa01edb49f..103813fc60f 100644 --- a/Mage.Sets/src/mage/cards/d/DaybreakRanger.java +++ b/Mage.Sets/src/mage/cards/d/DaybreakRanger.java @@ -1,46 +1,59 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.FightTargetSourceEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author North */ -public final class DaybreakRanger extends CardImpl { +public final class DaybreakRanger extends TransformingDoubleFacedCard { public DaybreakRanger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ARCHER); - this.subtype.add(SubType.RANGER); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ARCHER, SubType.RANGER, SubType.WEREWOLF}, "{2}{G}", + "Nightfall Predator", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.secondSideCardClazz = mage.cards.n.NightfallPredator.class; + // Daybreak Ranger + this.getLeftHalfCard().setPT(2, 2); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - - // {tap}: Daybreak Ranger deals 2 damage to target creature with flying. - Ability activatedAbility = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); - activatedAbility.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_FLYING)); - this.addAbility(activatedAbility); + // {T}: Daybreak Ranger deals 2 damage to target creature with flying. + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_FLYING)); + this.getLeftHalfCard().addAbility(ability); // At the beginning of each upkeep, if no spells were cast last turn, transform Daybreak Ranger. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Nightfall Predator + this.getRightHalfCard().setPT(4, 4); + + // {R}, {T}: Nightfall Predator fights target creature. + Ability ability2 = new SimpleActivatedAbility( + new FightTargetSourceEffect().setText("{this} fights target creature. (Each deals damage equal to its power to the other.)"), + new ManaCostsImpl<>("{R}") + ); + ability2.addCost(new TapSourceCost()); + ability2.addTarget(new TargetCreaturePermanent()); + this.getRightHalfCard().addAbility(ability2); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Nightfall Predator. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private DaybreakRanger(final DaybreakRanger card) { diff --git a/Mage.Sets/src/mage/cards/d/DazzlingTheaterPropRoom.java b/Mage.Sets/src/mage/cards/d/DazzlingTheaterPropRoom.java index c7d407fd916..46d4dc6c385 100644 --- a/Mage.Sets/src/mage/cards/d/DazzlingTheaterPropRoom.java +++ b/Mage.Sets/src/mage/cards/d/DazzlingTheaterPropRoom.java @@ -35,11 +35,11 @@ public final class DazzlingTheaterPropRoom extends RoomCard { // Dazzling Theater: Creature spells you cast have convoke. Ability left = new SimpleStaticAbility(new GainAbilityControlledSpellsEffect(new ConvokeAbility(), filter)); + this.getLeftHalfCard().addAbility(left); // Prop Room: Untap each creature you control during each other player's untap step. Ability right = new SimpleStaticAbility(new UntapAllDuringEachOtherPlayersUntapStepEffect(StaticFilters.FILTER_CONTROLLED_CREATURES)); - - this.addRoomAbilities(left, right); + this.getRightHalfCard().addAbility(right); } private DazzlingTheaterPropRoom(final DazzlingTheaterPropRoom card) { diff --git a/Mage.Sets/src/mage/cards/d/DeadlyDancer.java b/Mage.Sets/src/mage/cards/d/DeadlyDancer.java deleted file mode 100644 index a294a3a26ec..00000000000 --- a/Mage.Sets/src/mage/cards/d/DeadlyDancer.java +++ /dev/null @@ -1,61 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.mana.UntilEndOfTurnManaEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DeadlyDancer extends CardImpl { - - public DeadlyDancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.VAMPIRE); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setRed(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // When this creature transforms into Deadly Dancer, add {R}{R}. Until end of turn, you don't lose this mana as steps and phases end. - this.addAbility(new TransformIntoSourceTriggeredAbility(new UntilEndOfTurnManaEffect(Mana.RedMana(2)))); - - // {R}{R}: Deadly Dancer and another target creature each get +1/+0 until end of turn. - Ability ability = new SimpleActivatedAbility(new BoostSourceEffect( - 1, 0, Duration.EndOfTurn - ).setText("{this}"), new ManaCostsImpl<>("{R}{R}")); - ability.addEffect(new BoostTargetEffect(1, 0) - .setText("and another target creature each get +1/+0 until end of turn")); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); - this.addAbility(ability); - } - - private DeadlyDancer(final DeadlyDancer card) { - super(card); - } - - @Override - public DeadlyDancer copy() { - return new DeadlyDancer(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DeathbonnetHulk.java b/Mage.Sets/src/mage/cards/d/DeathbonnetHulk.java deleted file mode 100644 index a796956ec84..00000000000 --- a/Mage.Sets/src/mage/cards/d/DeathbonnetHulk.java +++ /dev/null @@ -1,93 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.counters.CounterType; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInGraveyard; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DeathbonnetHulk extends CardImpl { - - public DeathbonnetHulk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.FUNGUS); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setGreen(true); - this.nightCard = true; - - // At the beginning of your upkeep, you may exile a card from a graveyard. If a creature card was exiled this way, put a +1/+1 counter on Deathbonnet Hulk. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DeathbonnetHulkEffect())); - } - - private DeathbonnetHulk(final DeathbonnetHulk card) { - super(card); - } - - @Override - public DeathbonnetHulk copy() { - return new DeathbonnetHulk(this); - } -} - -class DeathbonnetHulkEffect extends OneShotEffect { - - DeathbonnetHulkEffect() { - super(Outcome.Benefit); - staticText = "you may exile a card from a graveyard. " + - "If a creature card was exiled this way, put a +1/+1 counter on {this}"; - } - - private DeathbonnetHulkEffect(final DeathbonnetHulkEffect effect) { - super(effect); - } - - @Override - public DeathbonnetHulkEffect copy() { - return new DeathbonnetHulkEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - TargetCard target = new TargetCardInGraveyard(0, 1); - target.withNotTarget(true); - player.choose(outcome, target, source, game); - Card card = game.getCard(target.getFirstTarget()); - if (card == null) { - return false; - } - boolean flag = card.isCreature(game); - player.moveCards(card, Zone.EXILED, source, game); - if (!flag) { - return true; - } - Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DeathbonnetSprout.java b/Mage.Sets/src/mage/cards/d/DeathbonnetSprout.java index a5ed010d194..77ae57a0c44 100644 --- a/Mage.Sets/src/mage/cards/d/DeathbonnetSprout.java +++ b/Mage.Sets/src/mage/cards/d/DeathbonnetSprout.java @@ -1,55 +1,66 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInGraveyard; import java.util.UUID; /** * @author TheElk801 */ -public final class DeathbonnetSprout extends CardImpl { +public final class DeathbonnetSprout extends TransformingDoubleFacedCard { - private static final Condition condition - = new CardsInControllerGraveyardCondition(3, StaticFilters.FILTER_CARD_CREATURE); + private static final Condition condition = new CardsInControllerGraveyardCondition(3, StaticFilters.FILTER_CARD_CREATURE); private static final Hint hint = new ValueHint( "Creature cards in your graveyard", new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE) ); public DeathbonnetSprout(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.FUNGUS}, "{G}", + "Deathbonnet Hulk", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.FUNGUS, SubType.HORROR}, "G"); - this.subtype.add(SubType.FUNGUS); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.d.DeathbonnetHulk.class; + // Deathbonnet Sprout + this.getLeftHalfCard().setPT(1, 1); // At the beginning of your upkeep, mill a card. Then if there are three or more creature cards in your graveyard, transform Deathbonnet Sprout. - this.addAbility(new TransformAbility()); - Ability ability = new BeginningOfUpkeepTriggeredAbility( - new MillCardsControllerEffect(1) - ); - ability.addEffect(new ConditionalOneShotEffect( - new TransformSourceEffect(), condition, - "Then if there are three or more creature cards in your graveyard, transform {this}" - )); - this.addAbility(ability.addHint(hint)); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new MillCardsControllerEffect(1)); + ability.addEffect(new ConditionalOneShotEffect(new TransformSourceEffect(), condition, + "Then if there are three or more creature cards in your graveyard, transform {this}")); + this.getLeftHalfCard().addAbility(ability.addHint(hint)); + + + // Deathbonnet Hulk + this.getRightHalfCard().setPT(3, 3); + + + // At the beginning of your upkeep, you may exile a card from a graveyard. If a creature card was exiled this way, put a +1/+1 counter on Deathbonnet Hulk. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new DeathbonnetHulkEffect())); } private DeathbonnetSprout(final DeathbonnetSprout card) { @@ -61,3 +72,44 @@ public final class DeathbonnetSprout extends CardImpl { return new DeathbonnetSprout(this); } } + +class DeathbonnetHulkEffect extends OneShotEffect { + DeathbonnetHulkEffect() { + super(Outcome.Benefit); + staticText = "you may exile a card from a graveyard. If a creature card was exiled this way, put a +1/+1 counter on {this}"; + } + + private DeathbonnetHulkEffect(final DeathbonnetHulkEffect effect) { + super(effect); + } + + @Override + public DeathbonnetHulkEffect copy() { + return new DeathbonnetHulkEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCard target = new TargetCardInGraveyard(0, 1); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + boolean creature = card.isCreature(game); + player.moveCards(card, Zone.EXILED, source, game); + if (!creature) { + return true; + } + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java b/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java index 0b89a031e26..1006315827d 100644 --- a/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java +++ b/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java @@ -1,9 +1,8 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.*; import mage.constants.CardType; @@ -19,21 +18,25 @@ import java.util.UUID; /** * @author Alvin */ -public final class DelverOfSecrets extends CardImpl { +public final class DelverOfSecrets extends TransformingDoubleFacedCard { public DelverOfSecrets(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{U}", + "Insectile Aberration", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.INSECT}, "U"); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - - this.secondSideCardClazz = mage.cards.i.InsectileAberration.class; + // Delver of Secrets + this.getLeftHalfCard().setPT(1, 1); // At the beginning of your upkeep, look at the top card of your library. You may reveal that card. If an instant or sorcery card is revealed this way, transform Delver of Secrets. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DelverOfSecretsEffect())); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new DelverOfSecretsEffect())); + + // Insectile Aberration + this.getRightHalfCard().setPT(3, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private DelverOfSecrets(final DelverOfSecrets card) { @@ -47,10 +50,9 @@ public final class DelverOfSecrets extends CardImpl { } class DelverOfSecretsEffect extends OneShotEffect { - - public DelverOfSecretsEffect() { + DelverOfSecretsEffect() { super(Outcome.Benefit); - this.staticText = "look at the top card of your library. You may reveal that card. " + + staticText = "look at the top card of your library. You may reveal that card. " + "If an instant or sorcery card is revealed this way, transform {this}"; } diff --git a/Mage.Sets/src/mage/cards/d/Demonfire.java b/Mage.Sets/src/mage/cards/d/Demonfire.java index fc9191b441c..d140c247695 100644 --- a/Mage.Sets/src/mage/cards/d/Demonfire.java +++ b/Mage.Sets/src/mage/cards/d/Demonfire.java @@ -41,7 +41,7 @@ public final class Demonfire extends CardImpl { // Hellbent - If you have no cards in hand, Demonfire can't be countered and the damage can't be prevented. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(GetXValue.instance, false), + new DamageTargetEffect(GetXValue.instance).withCantBePrevented(), HellbentCondition.instance, "
Hellbent — If you have no cards in hand, this spell can't be countered and the damage can't be prevented.")); // can't be countered diff --git a/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java b/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java index 55885247a4a..9d6652c5e49 100644 --- a/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java +++ b/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java @@ -1,44 +1,58 @@ package mage.cards.d; -import mage.MageInt; +import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CantBeTargetedCardsGraveyardsEffect; +import mage.abilities.effects.keyword.InvestigateEffect; import mage.abilities.keyword.DisturbAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.TargetController; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author LePwnerer */ -public final class DennickPiousApprentice extends CardImpl { +public final class DennickPiousApprentice extends TransformingDoubleFacedCard { public DennickPiousApprentice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER}, "{W}{U}", + "Dennick, Pious Apparition", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.SOLDIER}, "WU"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.d.DennickPiousApparition.class; + // Dennick, Pious Apprentice + this.getLeftHalfCard().setPT(2, 3); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // Cards in graveyards can't be the targets of spells or abilities. - this.addAbility(new SimpleStaticAbility(new CantBeTargetedCardsGraveyardsEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new CantBeTargetedCardsGraveyardsEffect())); // Disturb {2}{W}{U} - this.addAbility(new DisturbAbility(this, "{2}{W}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{2}{W}{U}")); + // Dennick, Pious Apparition + this.getRightHalfCard().setPT(3, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever one or more creature cards are put into graveyards from anywhere, investigate. This ability triggers only once each turn. + this.getRightHalfCard().addAbility(new PutCardIntoGraveFromAnywhereAllTriggeredAbility( + new InvestigateEffect(1), false, StaticFilters.FILTER_CARD_CREATURE, TargetController.ANY + ).setTriggersLimitEachTurn(1).setTriggerPhrase("Whenever one or more creature cards are put into graveyards from anywhere, ")); + + // If Dennick, Pious Apparition would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private DennickPiousApprentice(final DennickPiousApprentice card) { diff --git a/Mage.Sets/src/mage/cards/d/DepartedSoulkeeper.java b/Mage.Sets/src/mage/cards/d/DepartedSoulkeeper.java deleted file mode 100644 index 2503f1601ba..00000000000 --- a/Mage.Sets/src/mage/cards/d/DepartedSoulkeeper.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.common.CanBlockOnlyFlyingAbility; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DepartedSoulkeeper extends CardImpl { - - public DepartedSoulkeeper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(3); - this.toughness = new MageInt(1); - this.color.setWhite(true); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Departed Soulkeeper can block only creatures with flying. - this.addAbility(new CanBlockOnlyFlyingAbility()); - - // If Departed Soulkeeper would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private DepartedSoulkeeper(final DepartedSoulkeeper card) { - super(card); - } - - @Override - public DepartedSoulkeeper copy() { - return new DepartedSoulkeeper(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DepravedHarvester.java b/Mage.Sets/src/mage/cards/d/DepravedHarvester.java deleted file mode 100644 index 8a385930f39..00000000000 --- a/Mage.Sets/src/mage/cards/d/DepravedHarvester.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.keyword.LifelinkAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DepravedHarvester extends CardImpl { - - public DepravedHarvester(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.nightCard = true; - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - } - - private DepravedHarvester(final DepravedHarvester card) { - super(card); - } - - @Override - public DepravedHarvester copy() { - return new DepravedHarvester(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DesperateFarmer.java b/Mage.Sets/src/mage/cards/d/DesperateFarmer.java index a0aae4476de..0a111e8b0b9 100644 --- a/Mage.Sets/src/mage/cards/d/DesperateFarmer.java +++ b/Mage.Sets/src/mage/cards/d/DesperateFarmer.java @@ -1,12 +1,10 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; @@ -16,26 +14,30 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class DesperateFarmer extends CardImpl { +public final class DesperateFarmer extends TransformingDoubleFacedCard { public DesperateFarmer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{2}{B}", + "Depraved Harvester", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.KNIGHT}, "B"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.d.DepravedHarvester.class; + // Desperate Farmer + this.getLeftHalfCard().setPT(2, 2); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // When another creature you control dies, transform Desperate Farmer. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesCreatureTriggeredAbility( - new TransformSourceEffect(), false, - StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE + this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility( + new TransformSourceEffect(), false, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE ).setTriggerPhrase("When another creature you control dies, ")); + + // Depraved Harvester + this.getRightHalfCard().setPT(4, 3); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); } private DesperateFarmer(final DesperateFarmer card) { diff --git a/Mage.Sets/src/mage/cards/d/DesperatePlea.java b/Mage.Sets/src/mage/cards/d/DesperatePlea.java new file mode 100644 index 00000000000..9b826a29846 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DesperatePlea.java @@ -0,0 +1,84 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesPower; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DesperatePlea extends CardImpl { + + public DesperatePlea(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + this.subtype.add(SubType.LESSON); + + // As an additional cost to cast this spell, sacrifice a creature. + this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); + + // Choose one or both -- + this.getSpellAbility().getModes().setMinModes(1); + this.getSpellAbility().getModes().setMaxModes(2); + + // * Return target creature card from your graveyard to the battlefield if its power is less than or equal to the sacrificed creature's power. + this.getSpellAbility().addEffect(new DesperatePleaEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + + // * Destroy target creature. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect()).addTarget(new TargetCreaturePermanent())); + } + + private DesperatePlea(final DesperatePlea card) { + super(card); + } + + @Override + public DesperatePlea copy() { + return new DesperatePlea(this); + } +} + +class DesperatePleaEffect extends OneShotEffect { + + DesperatePleaEffect() { + super(Outcome.Benefit); + staticText = "return target creature card from your graveyard to the battlefield " + + "if its power is less than or equal to the sacrificed creature's power"; + } + + private DesperatePleaEffect(final DesperatePleaEffect effect) { + super(effect); + } + + @Override + public DesperatePleaEffect copy() { + return new DesperatePleaEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + return player != null && card != null + && card.getPower().getValue() <= SacrificeCostCreaturesPower.instance.calculate(game, source, this) + && player.moveCards(card, Zone.BATTLEFIELD, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java b/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java index e16068a08a7..76e8fdac5f8 100644 --- a/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java +++ b/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java @@ -1,14 +1,15 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.CanBlockOnlyFlyingAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SetTargetPointer; import mage.constants.SubType; @@ -21,19 +22,19 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class DevotedGrafkeeper extends CardImpl { +public final class DevotedGrafkeeper extends TransformingDoubleFacedCard { public DevotedGrafkeeper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{W}{U}", + "Departed Soulkeeper", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "WU"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.d.DepartedSoulkeeper.class; + // Devoted Grafkeeper + this.getLeftHalfCard().setPT(2, 1); // When Devoted Grafkeeper enters the battlefield, mill two cards. - this.addAbility(new EntersBattlefieldTriggeredAbility(new MillCardsControllerEffect(2))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new MillCardsControllerEffect(2))); // Whenever you cast a spell from your graveyard, tap target creature you don't control. Ability ability = new SpellCastControllerTriggeredAbility( @@ -41,10 +42,22 @@ public final class DevotedGrafkeeper extends CardImpl { false, SetTargetPointer.NONE, Zone.GRAVEYARD ); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Disturb {1}{W}{U} - this.addAbility(new DisturbAbility(this, "{1}{W}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{1}{W}{U}")); + + // Departed Soulkeeper + this.getRightHalfCard().setPT(3, 1); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Departed Soulkeeper can block only creatures with flying. + this.getRightHalfCard().addAbility(new CanBlockOnlyFlyingAbility()); + + // If Departed Soulkeeper would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private DevotedGrafkeeper(final DevotedGrafkeeper card) { diff --git a/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java b/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java index 1916be7d1ce..a3e0809935c 100644 --- a/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java +++ b/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java @@ -1,6 +1,5 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -14,10 +13,10 @@ import mage.abilities.effects.common.ExileAndReturnSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.game.permanent.token.WaylayToken; @@ -26,20 +25,18 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class DionBahamutsDominant extends CardImpl { +public final class DionBahamutsDominant extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterPermanent(SubType.KNIGHT, ""); public DionBahamutsDominant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE, SubType.KNIGHT}, "{3}{W}", + "Bahamut, Warden of Light", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.DRAGON}, "W"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.b.BahamutWardenOfLight.class; + // Dion, Bahamut's Dominant + this.getLeftHalfCard().setPT(3, 3); // Dragonfire Dive -- During your turn, Dion and other Knights you control have flying. Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( @@ -50,18 +47,47 @@ public final class DionBahamutsDominant extends CardImpl { new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filter), MyTurnCondition.instance, "and other Knights you control have flying" )); - this.addAbility(ability.withFlavorWord("Dragonfire Dive")); + this.getLeftHalfCard().addAbility(ability.withFlavorWord("Dragonfire Dive")); // When Dion enters, create a 2/2 white Knight creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WaylayToken()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WaylayToken()))); // {4}{W}{W}, {T}: Exile Dion, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - ability = new ActivateAsSorceryActivatedAbility( + Ability ability2 = new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{4}{W}{W}") ); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); + ability2.addCost(new TapSourceCost()); + this.getLeftHalfCard().addAbility(ability2); + + // Bahamut, Warden of Light + this.getRightHalfCard().setPT(5, 5); + + // (As this Saga enters and after your draw step, add a lore counter.) + mage.abilities.common.SagaAbility sagaAbility = new mage.abilities.common.SagaAbility(this.getRightHalfCard()); + + // I, II -- Wings of Light -- Put a +1/+1 counter on each other creature you control. Those creatures gain flying until end of turn. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, ability3 -> { + ability3.addEffect(new mage.abilities.effects.common.counter.AddCountersAllEffect( + CounterType.P1P1.createInstance(), mage.filter.StaticFilters.FILTER_OTHER_CONTROLLED_CREATURE + )); + ability3.addEffect(new mage.abilities.effects.common.continuous.GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn, + mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("Those creatures gain flying until end of turn")); + ability3.withFlavorWord("Wings of Light"); + }); + + // III -- Gigaflare -- Destroy target permanent. Exile Bahamut, then return it to the battlefield. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_III, ability4 -> { + ability4.addEffect(new mage.abilities.effects.common.DestroyTargetEffect()); + ability4.addEffect(new mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect()); + ability4.addTarget(new mage.target.TargetPermanent()); + ability4.withFlavorWord("Gigaflare"); + }); + this.getRightHalfCard().addAbility(sagaAbility); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private DionBahamutsDominant(final DionBahamutsDominant card) { diff --git a/Mage.Sets/src/mage/cards/d/DireBlunderbuss.java b/Mage.Sets/src/mage/cards/d/DireBlunderbuss.java deleted file mode 100644 index 3088dada74a..00000000000 --- a/Mage.Sets/src/mage/cards/d/DireBlunderbuss.java +++ /dev/null @@ -1,170 +0,0 @@ -package mage.cards.d; - -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.delayed.ReflexiveTriggeredAbility; -import mage.abilities.costs.Cost; -import mage.abilities.costs.SacrificeCost; -import mage.abilities.costs.UseAttachedCost; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.common.DamageWithPowerFromSourceToAnotherTargetEffect; -import mage.abilities.effects.common.DoWhenCostPaid; -import mage.abilities.effects.common.continuous.BoostEquippedEffect; -import mage.abilities.keyword.EquipAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterControlledArtifactPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.MageObjectReferencePredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTarget; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class DireBlunderbuss extends CardImpl { - - public DireBlunderbuss(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - this.nightCard = true; - - this.subtype.add(SubType.EQUIPMENT); - this.color.setRed(true); - - // Equipped creature gets +3/+0 and has "Whenever this creature attacks, you may sacrifice an artifact other than Dire Blunderbuss. When you do, this creature deals damage equal to its power to target creature" - Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 0)); - ability.addEffect(new DireBlunderbussGainAbilityEffect()); - this.addAbility(ability); - - // Equip {1} - this.addAbility(new EquipAbility(1, false)); - } - - private DireBlunderbuss(final DireBlunderbuss card) { - super(card); - } - - @Override - public DireBlunderbuss copy() { - return new DireBlunderbuss(this); - } -} - -class DireBlunderbussGainAbilityEffect extends ContinuousEffectImpl { - - DireBlunderbussGainAbilityEffect() { - super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); - staticText = "and has \"Whenever this creature attacks, you may sacrifice an artifact other than {this}. " - + "When you do, this creature deals damage equal to its power to target creature.\""; - } - - protected DireBlunderbussGainAbilityEffect(final DireBlunderbussGainAbilityEffect effect) { - super(effect); - } - - @Override - public DireBlunderbussGainAbilityEffect copy() { - return new DireBlunderbussGainAbilityEffect(this); - } - - @Override - public void init(Ability source, Game game) { - super.init(source, game); - if (getAffectedObjectsSet()) { - Permanent equipment = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (equipment != null && equipment.getAttachedTo() != null) { - this.setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game.getState().getZoneChangeCounter(equipment.getAttachedTo()))); - } - } - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = null; - if (getAffectedObjectsSet()) { - permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null) { - discard(); - return true; - } - } else { - Permanent equipment = game.getPermanent(source.getSourceId()); - if (equipment != null && equipment.getAttachedTo() != null) { - permanent = game.getPermanentOrLKIBattlefield(equipment.getAttachedTo()); - } - } - if (permanent == null) { - return true; - } - Ability ability = makeAbility(game, source); - ability.getEffects().setValue("attachedPermanent", game.getPermanent(source.getSourceId())); - permanent.addAbility(ability, source.getSourceId(), game); - return true; - } - - protected Ability makeAbility(Game game, Ability source) { - ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility( - new DamageWithPowerFromSourceToAnotherTargetEffect("this creature"), false - ); - reflexive.addTarget(new TargetCreaturePermanent()); - return new AttacksTriggeredAbility( - new DoWhenCostPaid( - reflexive, new DireBlunderbussSacrificeCost(source, game), - "Sacrifice an artifact other than the equipment?" - ), false - ); - } -} - -class DireBlunderbussSacrificeCost extends UseAttachedCost implements SacrificeCost { - - private final SacrificeTargetCost sacrificeCost; - - DireBlunderbussSacrificeCost(Ability source, Game game) { - super(); - this.setMageObjectReference(source, game); - FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent(); - filter.add(Predicates.not(new MageObjectReferencePredicate(this.mageObjectReference))); - this.sacrificeCost = new SacrificeTargetCost(filter); - } - - private DireBlunderbussSacrificeCost(final DireBlunderbussSacrificeCost cost) { - super(cost); - this.sacrificeCost = cost.sacrificeCost.copy(); - } - - @Override - public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return sacrificeCost.canPay(ability, source, controllerId, game); - } - - @Override - public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (mageObjectReference == null) { - return false; - } - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - return paid; - } - paid = sacrificeCost.pay(ability, game, source, controllerId, noMana, costToPay); - return paid; - } - - @Override - public DireBlunderbussSacrificeCost copy() { - return new DireBlunderbussSacrificeCost(this); - } - - @Override - public String getText() { - return "sacrifice an artifact other than " + this.name; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DireFlail.java b/Mage.Sets/src/mage/cards/d/DireFlail.java index 2224c630043..1b2412b1318 100644 --- a/Mage.Sets/src/mage/cards/d/DireFlail.java +++ b/Mage.Sets/src/mage/cards/d/DireFlail.java @@ -1,35 +1,59 @@ package mage.cards.d; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.SacrificeCost; +import mage.abilities.costs.UseAttachedCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.DamageWithPowerFromSourceToAnotherTargetEffect; +import mage.abilities.effects.common.DoWhenCostPaid; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.CraftAbility; import mage.abilities.keyword.EquipAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.MageObjectReferencePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** * @author Susucr */ -public final class DireFlail extends CardImpl { +public final class DireFlail extends TransformingDoubleFacedCard { public DireFlail(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{R}"); - this.secondSideCardClazz = mage.cards.d.DireBlunderbuss.class; - - this.subtype.add(SubType.EQUIPMENT); + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "{R}", + "Dire Blunderbuss", + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "R"); + // Dire Flail // Equipped creature gets +2/+0. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 0))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 0))); // Equip {1} - this.addAbility(new EquipAbility(1, false)); + this.getLeftHalfCard().addAbility(new EquipAbility(1, false)); // Craft with artifact {3}{R}{R} - this.addAbility(new CraftAbility("{3}{R}{R}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{3}{R}{R}")); + + // Dire Blunderbuss + + // Equipped creature gets +3/+0 and has "Whenever this creature attacks, you may sacrifice an artifact other than Dire Blunderbuss. When you do, this creature deals damage equal to its power to target creature" + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 0)); + ability.addEffect(new DireBlunderbussGainAbilityEffect()); + this.getRightHalfCard().addAbility(ability); + + // Equip {1} + this.getRightHalfCard().addAbility(new EquipAbility(1, false)); } private DireFlail(final DireFlail card) { @@ -41,3 +65,109 @@ public final class DireFlail extends CardImpl { return new DireFlail(this); } } + +class DireBlunderbussGainAbilityEffect extends ContinuousEffectImpl { + + DireBlunderbussGainAbilityEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "and has \"Whenever this creature attacks, you may sacrifice an artifact other than {this}. " + + "When you do, this creature deals damage equal to its power to target creature.\""; + } + + protected DireBlunderbussGainAbilityEffect(final DireBlunderbussGainAbilityEffect effect) { + super(effect); + } + + @Override + public DireBlunderbussGainAbilityEffect copy() { + return new DireBlunderbussGainAbilityEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + if (getAffectedObjectsSet()) { + Permanent equipment = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (equipment != null && equipment.getAttachedTo() != null) { + this.setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game.getState().getZoneChangeCounter(equipment.getAttachedTo()))); + } + } + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = null; + if (getAffectedObjectsSet()) { + permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + discard(); + return true; + } + } else { + Permanent equipment = game.getPermanent(source.getSourceId()); + if (equipment != null && equipment.getAttachedTo() != null) { + permanent = game.getPermanentOrLKIBattlefield(equipment.getAttachedTo()); + } + } + if (permanent == null) { + return true; + } + ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility( + new DamageWithPowerFromSourceToAnotherTargetEffect("this creature"), false + ); + reflexive.addTarget(new TargetCreaturePermanent()); + Ability grant = new mage.abilities.common.AttacksTriggeredAbility( + new DoWhenCostPaid( + reflexive, new DireBlunderbussSacrificeCost(source, game), + "Sacrifice an artifact other than the equipment?" + ), false + ); + permanent.addAbility(grant, source.getSourceId(), game); + return true; + } +} + +class DireBlunderbussSacrificeCost extends UseAttachedCost implements SacrificeCost { + + private final mage.abilities.costs.common.SacrificeTargetCost sacrificeCost; + private final mage.MageObjectReference mageObjectReference; + + DireBlunderbussSacrificeCost(Ability source, Game game) { + super(); + this.mageObjectReference = new mage.MageObjectReference(source.getSourceObject(game), game); + FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent(); + filter.add(Predicates.not(new MageObjectReferencePredicate(this.mageObjectReference))); + this.sacrificeCost = new mage.abilities.costs.common.SacrificeTargetCost(filter); + } + + private DireBlunderbussSacrificeCost(final DireBlunderbussSacrificeCost cost) { + super(cost); + this.sacrificeCost = cost.sacrificeCost.copy(); + this.mageObjectReference = cost.mageObjectReference; + } + + @Override + public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + return sacrificeCost.canPay(ability, source, controllerId, game); + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, mage.abilities.costs.Cost costToPay) { + Permanent equipment = game.getPermanent(source.getSourceId()); + if (equipment == null) { + return paid; + } + paid = sacrificeCost.pay(ability, game, source, controllerId, noMana, costToPay); + return paid; + } + + @Override + public DireBlunderbussSacrificeCost copy() { + return new DireBlunderbussSacrificeCost(this); + } + + @Override + public String getText() { + return "sacrifice an artifact other than " + this.name; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DireStrainDemolisher.java b/Mage.Sets/src/mage/cards/d/DireStrainDemolisher.java deleted file mode 100644 index abb57f23514..00000000000 --- a/Mage.Sets/src/mage/cards/d/DireStrainDemolisher.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.keyword.WardAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DireStrainDemolisher extends CardImpl { - - public DireStrainDemolisher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(8); - this.toughness = new MageInt(7); - this.color.setGreen(true); - this.nightCard = true; - - // Ward {3} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{3}"))); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private DireStrainDemolisher(final DireStrainDemolisher card) { - super(card); - } - - @Override - public DireStrainDemolisher copy() { - return new DireStrainDemolisher(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DistractingGeist.java b/Mage.Sets/src/mage/cards/d/DistractingGeist.java index 6d46c46ca82..8baef404c8a 100644 --- a/Mage.Sets/src/mage/cards/d/DistractingGeist.java +++ b/Mage.Sets/src/mage/cards/d/DistractingGeist.java @@ -1,49 +1,67 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.EnchantAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.AttachmentType; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class DistractingGeist extends CardImpl { +public final class DistractingGeist extends TransformingDoubleFacedCard { - private static final FilterPermanent filter - = new FilterCreaturePermanent("creature defending player controls"); + private static final FilterPermanent filter = new FilterCreaturePermanent("creature defending player controls"); static { filter.add(DefendingPlayerControlsSourceAttackingPredicate.instance); } public DistractingGeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{2}{W}", + "Clever Distraction", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "W"); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.c.CleverDistraction.class; + // Distracting Geist + this.getLeftHalfCard().setPT(2, 1); // Whenever Distracting Geist attacks, tap target creature defending player controls. Ability ability = new AttacksTriggeredAbility(new TapTargetEffect()); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Disturb {4}{W} - this.addAbility(new DisturbAbility(this, "{4}{W}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{4}{W}")); + + // Clever Distraction + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new mage.abilities.effects.common.AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + + // Enchanted creature has "Whenever this creature attacks, tap target creature defending player controls." + Ability ability2 = new AttacksTriggeredAbility(new TapTargetEffect()).setTriggerPhrase("Whenever this creature attacks, "); + ability2.addTarget(new TargetPermanent(filter)); + this.getRightHalfCard().addAbility(new mage.abilities.common.SimpleStaticAbility(new mage.abilities.effects.common.continuous.GainAbilityAttachedEffect(ability2, AttachmentType.AURA))); + + // If Clever Distracting would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private DistractingGeist(final DistractingGeist card) { diff --git a/Mage.Sets/src/mage/cards/d/DollmakersShopPorcelainGallery.java b/Mage.Sets/src/mage/cards/d/DollmakersShopPorcelainGallery.java index 2ca7b73a5cc..1566406118a 100644 --- a/Mage.Sets/src/mage/cards/d/DollmakersShopPorcelainGallery.java +++ b/Mage.Sets/src/mage/cards/d/DollmakersShopPorcelainGallery.java @@ -34,13 +34,14 @@ public final class DollmakersShopPorcelainGallery extends RoomCard { // Dollmaker's Shop: Whenever one or more non-Toy creatures you control attack a player, create a 1/1 white Toy artifact creature token. Ability left = new AttacksPlayerWithCreaturesTriggeredAbility(new CreateTokenEffect(new ToyToken()), filter, SetTargetPointer.NONE); + this.getLeftHalfCard().addAbility(left); // Porcelain Gallery: Creatures you control have base power and toughness each equal to the number of creatures you control. Ability right = new SimpleStaticAbility(new SetBasePowerToughnessAllEffect( CreaturesYouControlCount.PLURAL, Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES ).setText("Creatures you control have base power and toughness each equal to the number of creatures you control")); - - this.addRoomAbilities(left, right.addHint(new ValueHint("Creatures you control", CreaturesYouControlCount.PLURAL))); + right.addHint(new ValueHint("Creatures you control", CreaturesYouControlCount.PLURAL)); + this.getRightHalfCard().addAbility(right); } private DollmakersShopPorcelainGallery (final DollmakersShopPorcelainGallery card) { diff --git a/Mage.Sets/src/mage/cards/d/DormantGrove.java b/Mage.Sets/src/mage/cards/d/DormantGrove.java index 3db92560395..17988a2eea7 100644 --- a/Mage.Sets/src/mage/cards/d/DormantGrove.java +++ b/Mage.Sets/src/mage/cards/d/DormantGrove.java @@ -1,47 +1,58 @@ package mage.cards.d; -import java.util.UUID; - import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** * * @author weirddan455 */ -public final class DormantGrove extends CardImpl { +public final class DormantGrove extends TransformingDoubleFacedCard { public DormantGrove(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); - - this.secondSideCardClazz = mage.cards.g.GnarledGrovestrider.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{3}{G}", + "Gnarled Grovestrider", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.TREEFOLK}, "G"); + // Dormant Grove // At the beginning of combat on your turn, put a +1/+1 counter on target creature you control. // Then if that creature has toughness 6 or greater, transform Dormant Grove. - this.addAbility(new TransformAbility()); - - Ability ability = new BeginningOfCombatTriggeredAbility( - new AddCountersTargetEffect(CounterType.P1P1.createInstance()) - ); + Ability ability = new BeginningOfCombatTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); ability.addEffect(new ConditionalOneShotEffect( new TransformSourceEffect(), DormatGroveCondition.instance, "Then if that creature has toughness 6 or greater, transform {this}" )); ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Gnarled Grovestrider + this.getRightHalfCard().setPT(3, 6); + + // Vigilance + this.getRightHalfCard().addAbility(mage.abilities.keyword.VigilanceAbility.getInstance()); + + // Other creatures you control have vigilance. + this.getRightHalfCard().addAbility(new mage.abilities.common.SimpleStaticAbility(new mage.abilities.effects.common.continuous.GainAbilityControlledEffect( + mage.abilities.keyword.VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, + mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES, true + ))); } private DormantGrove(final DormantGrove card) { diff --git a/Mage.Sets/src/mage/cards/d/DorotheaVengefulVictim.java b/Mage.Sets/src/mage/cards/d/DorotheaVengefulVictim.java index eb57714d748..dd2319d0ce4 100644 --- a/Mage.Sets/src/mage/cards/d/DorotheaVengefulVictim.java +++ b/Mage.Sets/src/mage/cards/d/DorotheaVengefulVictim.java @@ -1,45 +1,63 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.DisturbAbility; +import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class DorotheaVengefulVictim extends CardImpl { +public final class DorotheaVengefulVictim extends TransformingDoubleFacedCard { public DorotheaVengefulVictim(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{W}{U}", + "Dorothea's Retribution", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "WU"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.d.DorotheasRetribution.class; + // Dorothea, Vengeful Victim + this.getLeftHalfCard().setPT(4, 4); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // When Dorothea, Vengeful Victim attacks or blocks, sacrifice it at end of combat. - this.addAbility(new AttacksOrBlocksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + this.getLeftHalfCard().addAbility(new AttacksOrBlocksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( new AtTheEndOfCombatDelayedTriggeredAbility(new SacrificeSourceEffect()) ).setText("sacrifice it at end of combat"), false)); // Disturb {1}{W}{U} - this.addAbility(new DisturbAbility(this, "{1}{W}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{1}{W}{U}")); + + // Dorothea's Retribution + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + + // Enchanted creature has "Whenever this creature attacks, create a 4/4 white Spirit creature token with flying that's tapped and attacking. Sacrifice that token at end of combat." + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + new mage.abilities.common.AttacksTriggeredAbility(new DorotheasRetributionEffect()).setTriggerPhrase("Whenever this creature attacks, "), + AttachmentType.AURA + ))); + + // If Dorothea's Retribution would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private DorotheaVengefulVictim(final DorotheaVengefulVictim card) { @@ -51,3 +69,32 @@ public final class DorotheaVengefulVictim extends CardImpl { return new DorotheaVengefulVictim(this); } } + +class DorotheasRetributionEffect extends mage.abilities.effects.OneShotEffect { + + DorotheasRetributionEffect() { + super(Outcome.Benefit); + staticText = "create a 4/4 white Spirit creature token with flying that's tapped and attacking. Sacrifice that token at end of combat"; + } + + private DorotheasRetributionEffect(final DorotheasRetributionEffect effect) { + super(effect); + } + + @Override + public DorotheasRetributionEffect copy() { + return new DorotheasRetributionEffect(this); + } + + @Override + public boolean apply(mage.game.Game game, mage.abilities.Ability source) { + mage.game.permanent.token.Token token = new mage.game.permanent.token.DorotheasRetributionSpiritToken(); + token.putOntoBattlefield(1, game, source, source.getControllerId(), true, true); + game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility( + new mage.abilities.effects.common.SacrificeTargetEffect() + .setTargetPointer(new mage.target.targetpointer.FixedTargets(token, game)) + .setText("sacrifice that token") + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DorotheasRetribution.java b/Mage.Sets/src/mage/cards/d/DorotheasRetribution.java deleted file mode 100644 index 688994337d7..00000000000 --- a/Mage.Sets/src/mage/cards/d/DorotheasRetribution.java +++ /dev/null @@ -1,96 +0,0 @@ -package mage.cards.d; - -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.SacrificeTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.game.Game; -import mage.game.permanent.token.DorotheasRetributionSpiritToken; -import mage.game.permanent.token.Token; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTargets; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DorotheasRetribution extends CardImpl { - - public DorotheasRetribution(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setWhite(true); - this.color.setBlue(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature has "Whenever this creature attacks, create a 4/4 white Spirit creature token with flying that's tapped and attacking. Sacrifice that token at end of combat." - this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( - new AttacksTriggeredAbility(new DorotheasRetributionEffect()) - .setTriggerPhrase("Whenever this creature attacks, "), - AttachmentType.AURA - ))); - - // If Dorothea's Retribution would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private DorotheasRetribution(final DorotheasRetribution card) { - super(card); - } - - @Override - public DorotheasRetribution copy() { - return new DorotheasRetribution(this); - } -} - -class DorotheasRetributionEffect extends OneShotEffect { - - DorotheasRetributionEffect() { - super(Outcome.Benefit); - staticText = "create a 4/4 white Spirit creature token with flying " + - "that's tapped and attacking. Sacrifice that token at end of combat"; - } - - private DorotheasRetributionEffect(final DorotheasRetributionEffect effect) { - super(effect); - } - - @Override - public DorotheasRetributionEffect copy() { - return new DorotheasRetributionEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Token token = new DorotheasRetributionSpiritToken(); - token.putOntoBattlefield(1, game, source, source.getControllerId(), true, true); - game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility( - new SacrificeTargetEffect() - .setTargetPointer(new FixedTargets(token, game)) - .setText("sacrifice that token") - ), source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DowsingDagger.java b/Mage.Sets/src/mage/cards/d/DowsingDagger.java index a5b02e21193..e1325e4438f 100644 --- a/Mage.Sets/src/mage/cards/d/DowsingDagger.java +++ b/Mage.Sets/src/mage/cards/d/DowsingDagger.java @@ -1,18 +1,14 @@ - package mage.cards.d; import mage.abilities.Ability; import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.CreateTokenTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EquipAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -24,29 +20,32 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class DowsingDagger extends CardImpl { +public final class DowsingDagger extends TransformingDoubleFacedCard { public DowsingDagger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - - this.subtype.add(SubType.EQUIPMENT); - - this.secondSideCardClazz = mage.cards.l.LostVale.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "{2}", + "Lost Vale", + new CardType[]{CardType.LAND}, new SubType[]{}, ""); + // Dowsing Dagger // When Dowsing Dagger enters the battlefield, target opponent creates two 0/2 green Plant creature tokens with defender. Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenTargetEffect(new DefenderPlantToken(), 2), false); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Equipped creature gets +2/+1. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 1))); + this.getLeftHalfCard().addAbility(new mage.abilities.common.SimpleStaticAbility(new BoostEquippedEffect(2, 1))); // Whenever equipped creature deals combat damage to a player, you may transform Dowsing Dagger. - this.addAbility(new TransformAbility()); - this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new TransformSourceEffect(), "equipped", true)); + this.getLeftHalfCard().addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new TransformSourceEffect(), "equipped", true)); // Equip 2 - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), false)); + this.getLeftHalfCard().addAbility(new EquipAbility(Outcome.AddAbility, new mage.abilities.costs.mana.GenericManaCost(2), false)); + + // Lost Vale + // T: Add three mana of any one color. + this.getRightHalfCard().addAbility(new mage.abilities.mana.SimpleManaAbility(new mage.abilities.effects.mana.AddManaOfAnyColorEffect(3), new mage.abilities.costs.common.TapSourceCost())); } private DowsingDagger(final DowsingDagger card) { diff --git a/Mage.Sets/src/mage/cards/d/DowsingDevice.java b/Mage.Sets/src/mage/cards/d/DowsingDevice.java index d6e3c299bbe..a8dcf8c9663 100644 --- a/Mage.Sets/src/mage/cards/d/DowsingDevice.java +++ b/Mage.Sets/src/mage/cards/d/DowsingDevice.java @@ -10,11 +10,11 @@ import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.hint.common.ArtifactYouControlHint; import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.common.TargetControlledCreaturePermanent; @@ -23,18 +23,20 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class DowsingDevice extends CardImpl { +public final class DowsingDevice extends TransformingDoubleFacedCard { private static final Condition condition = new PermanentsOnTheBattlefieldCondition( StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, ComparisonType.MORE_THAN, 3 ); public DowsingDevice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{R}"); - this.secondSideCardClazz = mage.cards.g.GeodeGrotto.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{R}", + "Geode Grotto", + new CardType[]{CardType.LAND}, new SubType[]{SubType.CAVE}, ""); + // Dowsing Device // Whenever Dowsing Device or another artifact you control enters, up to one target creature you control gets +1/+0 and gains haste until end of turn. Then transform Dowsing Device if you control four or more artifacts. - this.addAbility(new TransformAbility()); Ability ability = new EntersBattlefieldThisOrAnotherTriggeredAbility( new BoostTargetEffect(1, 0) .setText("up to one target creature you control gets +1/+0"), @@ -43,11 +45,24 @@ public final class DowsingDevice extends CardImpl { ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance()) .setText("and gains haste until end of turn")); ability.addEffect(new ConditionalOneShotEffect( - new TransformSourceEffect(), condition, "Then " + - "transform {this} if you control four or more artifacts" + new TransformSourceEffect(), condition, "Then transform {this} if you control four or more artifacts" )); ability.addTarget(new TargetControlledCreaturePermanent(0, 1)); - this.addAbility(ability.addHint(ArtifactYouControlHint.instance)); + this.getLeftHalfCard().addAbility(ability.addHint(ArtifactYouControlHint.instance)); + + // Geode Grotto + // {T}: Add {R}. + this.getRightHalfCard().addAbility(new mage.abilities.mana.RedManaAbility()); + + // {2}{R}, {T}: Until end of turn, target creature gains haste and gets +X/+0, where X is the number of artifacts you control. Activate only as a sorcery. + Ability ability2 = new mage.abilities.common.ActivateAsSorceryActivatedAbility(new GainAbilityTargetEffect(HasteAbility.getInstance()) + .setText("Until end of turn, target creature gains haste"), new mage.abilities.costs.mana.ManaCostsImpl<>("{2}{R}")); + ability2.addCost(new mage.abilities.costs.common.TapSourceCost()); + ability2.addEffect(new mage.abilities.effects.common.continuous.BoostTargetEffect( + mage.abilities.dynamicvalue.common.ArtifactYouControlCount.instance, mage.abilities.dynamicvalue.common.StaticValue.get(0) + ).setText("and gets +X/+0, where X is the number of artifacts you control")); + ability2.addTarget(new mage.target.common.TargetCreaturePermanent()); + this.getRightHalfCard().addAbility(ability2.addHint(ArtifactYouControlHint.instance)); } private DowsingDevice(final DowsingDevice card) { diff --git a/Mage.Sets/src/mage/cards/d/DraugrNecromancer.java b/Mage.Sets/src/mage/cards/d/DraugrNecromancer.java index 59db469c383..4d30803171c 100644 --- a/Mage.Sets/src/mage/cards/d/DraugrNecromancer.java +++ b/Mage.Sets/src/mage/cards/d/DraugrNecromancer.java @@ -182,8 +182,8 @@ class DraugrNecromancerSpendAnyManaEffect extends AsThoughEffectImpl implements cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); } else if (card instanceof CardWithSpellOption) { cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); - } else if (card instanceof ModalDoubleFacedCard) { - cardState = game.getLastKnownInformationCard(((ModalDoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); + } else if (card instanceof DoubleFacedCard) { + cardState = game.getLastKnownInformationCard(((DoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); } else { cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); } diff --git a/Mage.Sets/src/mage/cards/d/DrogskolArmaments.java b/Mage.Sets/src/mage/cards/d/DrogskolArmaments.java deleted file mode 100644 index dd67d25ed9d..00000000000 --- a/Mage.Sets/src/mage/cards/d/DrogskolArmaments.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.d; - -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.continuous.BoostEnchantedEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DrogskolArmaments extends CardImpl { - - public DrogskolArmaments(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setWhite(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature gets +2/+2. - this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(2, 2))); - - // If Drogskol Armaments would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private DrogskolArmaments(final DrogskolArmaments card) { - super(card); - } - - @Override - public DrogskolArmaments copy() { - return new DrogskolArmaments(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java b/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java index c83c5ccffe5..5ff5195f54b 100644 --- a/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java +++ b/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java @@ -1,31 +1,52 @@ package mage.cards.d; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.EnchantAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class DrogskolInfantry extends CardImpl { +public final class DrogskolInfantry extends TransformingDoubleFacedCard { public DrogskolInfantry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.SOLDIER}, "{1}{W}", + "Drogskol Armaments", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "W"); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.d.DrogskolArmaments.class; + // Drogskol Infantry + this.getLeftHalfCard().setPT(2, 2); + + + // Drogskol Armaments + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); // Disturb {3}{W} - this.addAbility(new DisturbAbility(this, "{3}{W}")); + // needs to be added after enchant ability to set correct target + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{3}{W}")); + + // Enchanted creature gets +2/+2. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(2, 2))); + + // If Drogskol Armaments would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private DrogskolInfantry(final DrogskolInfantry card) { diff --git a/Mage.Sets/src/mage/cards/d/DuelistsFlame.java b/Mage.Sets/src/mage/cards/d/DuelistsFlame.java index 01eae7cd35d..83c3d6b6475 100644 --- a/Mage.Sets/src/mage/cards/d/DuelistsFlame.java +++ b/Mage.Sets/src/mage/cards/d/DuelistsFlame.java @@ -42,7 +42,7 @@ public final class DuelistsFlame extends CardImpl { // Until end of turn, target blocked creature you control gets +X/+0 and gains trample and "Whenever this creature deals combat damage to a player, look at that many cards from the top of your library. Exile up to one nonland card from among them and put the rest on the bottom of your library in a random order. You may cast the exiled card without paying its mana cost." this.getSpellAbility().addEffect(new BoostTargetEffect(GetXValue.instance, StaticValue.get(0)) .setText("until end of turn, target blocked creature you control gets +X/+0")); - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()).setText("and has trample")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()).setText("and gains trample")); this.getSpellAbility().addEffect(new GainAbilityTargetEffect( new DealsCombatDamageToAPlayerTriggeredAbility(new DuelistsFlameEffect()) ).setText("and \"Whenever this creature deals combat damage to a player, " + diff --git a/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java b/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java index 695fb926a45..7ae652dd555 100644 --- a/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java +++ b/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java @@ -1,45 +1,54 @@ package mage.cards.d; -import java.util.UUID; - -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.PutCards; import mage.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** * @author fireshoes */ -public final class DuskwatchRecruiter extends CardImpl { +public final class DuskwatchRecruiter extends TransformingDoubleFacedCard { public DuskwatchRecruiter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WARRIOR); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WARRIOR, SubType.WEREWOLF}, "{1}{G}", + "Krallenhorde Howler", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.secondSideCardClazz = mage.cards.k.KrallenhordeHowler.class; + // Duskwatch Recruiter + this.getLeftHalfCard().setPT(2, 2); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - - // {2}{G}: Look at the top three cards of your library. You may reveal a creature card from among them and put it into your hand. - // Put the rest on the bottom of your library in any order. - this.addAbility(new SimpleActivatedAbility( + // {2}{G}: Look at the top three cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in any order. + Ability ability = new SimpleActivatedAbility( new LookLibraryAndPickControllerEffect(3, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_ANY), - new ManaCostsImpl<>("{2}{G}"))); + new ManaCostsImpl<>("{2}{G}") + ); + this.getLeftHalfCard().addAbility(ability); // At the beginning of each upkeep, if no spells were cast last turn, transform Duskwatch Recruiter. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Krallenhorde Howler + this.getRightHalfCard().setPT(3, 3); + + // Creature spells you cast cost {1} less to cast. + this.getRightHalfCard().addAbility(new mage.abilities.common.SimpleStaticAbility( + new mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect(new mage.filter.common.FilterCreatureCard("creature spells"), 1) + )); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Krallenhorde Howler. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private DuskwatchRecruiter(final DuskwatchRecruiter card) { diff --git a/Mage.Sets/src/mage/cards/d/DutifulKnowledgeSeeker.java b/Mage.Sets/src/mage/cards/d/DutifulKnowledgeSeeker.java new file mode 100644 index 00000000000..8921f751bf4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DutifulKnowledgeSeeker.java @@ -0,0 +1,51 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.PutIntoLibraryOneOrMoreTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DutifulKnowledgeSeeker extends CardImpl { + + public DutifulKnowledgeSeeker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.FOX); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever one or more cards are put into a library from anywhere, put a +1/+1 counter on this creature. + this.addAbility(new PutIntoLibraryOneOrMoreTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + )); + + // {3}: Put target card from a graveyard on the bottom of its owner's library. + Ability ability = new SimpleActivatedAbility(new PutOnLibraryTargetEffect(false), new GenericManaCost(3)); + ability.addTarget(new TargetCardInGraveyard()); + this.addAbility(ability); + } + + private DutifulKnowledgeSeeker(final DutifulKnowledgeSeeker card) { + super(card); + } + + @Override + public DutifulKnowledgeSeeker copy() { + return new DutifulKnowledgeSeeker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java b/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java index 6cafeb67f3c..bcdfce26d32 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java @@ -42,7 +42,7 @@ public final class DwarvenSeaClan extends CardImpl { // {tap}: Choose target attacking or blocking creature whose controller controls an Island. Dwarven Sea Clan deals 2 damage to that creature at end of combat. Activate this ability only before the end of combat step. Ability ability = new ActivateIfConditionActivatedAbility( new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility( - new DamageTargetEffect(2, true, "that creature") + new DamageTargetEffect(2).withTargetDescription("that creature") )).setText("Choose target attacking or blocking creature whose controller controls an Island. " + "{this} deals 2 damage to that creature at end of combat."), new TapSourceCost(), BeforeEndCombatCondition.getInstance() diff --git a/Mage.Sets/src/mage/cards/e/EarthKingdomGeneral.java b/Mage.Sets/src/mage/cards/e/EarthKingdomGeneral.java index c497d0e1b5b..72f9f07455d 100644 --- a/Mage.Sets/src/mage/cards/e/EarthKingdomGeneral.java +++ b/Mage.Sets/src/mage/cards/e/EarthKingdomGeneral.java @@ -23,7 +23,7 @@ import java.util.UUID; */ public final class EarthKingdomGeneral extends CardImpl { - private static final DynamicValue xValue = new EffectKeyValue("countersAdded", "that many"); + private static final DynamicValue xValue = new EffectKeyValue("countersAdded", "that much"); public EarthKingdomGeneral(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); diff --git a/Mage.Sets/src/mage/cards/e/EcstaticAwakener.java b/Mage.Sets/src/mage/cards/e/EcstaticAwakener.java index 6002799d4a1..e1162a2a6a1 100644 --- a/Mage.Sets/src/mage/cards/e/EcstaticAwakener.java +++ b/Mage.Sets/src/mage/cards/e/EcstaticAwakener.java @@ -1,45 +1,45 @@ package mage.cards.e; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class EcstaticAwakener extends CardImpl { +public final class EcstaticAwakener extends TransformingDoubleFacedCard { public EcstaticAwakener(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{B}", + "Awoken Demon", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEMON}, "B" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.a.AwokenDemon.class; + // Ecstatic Awakener + this.getLeftHalfCard().setPT(1, 1); // {2}{B}, Sacrifice another creature: Draw a card, then transform Ecstatic Awakener. Activate only once each turn. - this.addAbility(new TransformAbility()); Ability ability = new LimitedTimesPerTurnActivatedAbility( Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{B}") ); ability.addEffect(new TransformSourceEffect().concatBy(", then")); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Awoken Demon + this.getRightHalfCard().setPT(4, 4); } private EcstaticAwakener(final EcstaticAwakener card) { diff --git a/Mage.Sets/src/mage/cards/e/EddieBrock.java b/Mage.Sets/src/mage/cards/e/EddieBrock.java index cc84afc2c29..feb1f69ff93 100644 --- a/Mage.Sets/src/mage/cards/e/EddieBrock.java +++ b/Mage.Sets/src/mage/cards/e/EddieBrock.java @@ -47,7 +47,7 @@ public final class EddieBrock extends ModalDoubleFacedCard { "Venom, Lethal Protector", new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SYMBIOTE, SubType.HERO, SubType.VILLAIN}, "{3}{B}{R}{G}" ); - this.getLeftHalfCard().setPT(5, 5); + this.getLeftHalfCard().setPT(3, 3); this.getRightHalfCard().setPT(5, 5); // When Eddie Brock enters, return target creature card with mana value 1 or less from your graveyard to the battlefield. diff --git a/Mage.Sets/src/mage/cards/e/EdgarCharmedGroom.java b/Mage.Sets/src/mage/cards/e/EdgarCharmedGroom.java index 8016a66a7f4..704a9315a79 100644 --- a/Mage.Sets/src/mage/cards/e/EdgarCharmedGroom.java +++ b/Mage.Sets/src/mage/cards/e/EdgarCharmedGroom.java @@ -1,19 +1,27 @@ package mage.cards.e; -import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.RemoveAllCountersSourceEffect; +import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; +import mage.game.permanent.token.EdgarMarkovsCoffinVampireToken; import mage.players.Player; import java.util.UUID; @@ -21,28 +29,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class EdgarCharmedGroom extends CardImpl { +public final class EdgarCharmedGroom extends TransformingDoubleFacedCard { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.VAMPIRE, "Vampires"); + private static final Condition condition = new SourceHasCounterCondition(CounterType.BLOODLINE, 3); public EdgarCharmedGroom(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.NOBLE}, "{2}{W}{B}", + "Edgar Markov's Coffin", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "WB" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.NOBLE); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.e.EdgarMarkovsCoffin.class; + // Edgar, Charmed Groom + this.getLeftHalfCard().setPT(4, 4); // Other Vampires you control get +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect( 1, 1, Duration.WhileOnBattlefield, filter, true ))); // When Edgar, Charmed Groom dies, return it to the battlefield transformed under its owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesSourceTriggeredAbility(new EdgarCharmedGroomEffect())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new EdgarCharmedGroomEffect())); + + // Edgar Markov's Coffin + + // At the beginning of your upkeep, create a 1/1 white and black Vampire creature token with lifelink and put a bloodline counter on Edgar Markov's Coffin. Then if there are three or more bloodline counters on it, remove those counters and transform it. + Ability ability = new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new EdgarMarkovsCoffinVampireToken())); + ability.addEffect(new AddCountersSourceEffect(CounterType.BLOODLINE.createInstance()).concatBy("and")); + ability.addEffect(new ConditionalOneShotEffect( + new RemoveAllCountersSourceEffect(CounterType.BLOODLINE), condition, + "Then if there are three or more bloodline counters on it, remove those counters and transform it" + ).addEffect(new TransformSourceEffect())); + this.getRightHalfCard().addAbility(ability); } private EdgarCharmedGroom(final EdgarCharmedGroom card) { diff --git a/Mage.Sets/src/mage/cards/e/EdgarMarkovsCoffin.java b/Mage.Sets/src/mage/cards/e/EdgarMarkovsCoffin.java deleted file mode 100644 index 36ac4be28bd..00000000000 --- a/Mage.Sets/src/mage/cards/e/EdgarMarkovsCoffin.java +++ /dev/null @@ -1,54 +0,0 @@ -package mage.cards.e; - -import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.SourceHasCounterCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.RemoveAllCountersSourceEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; -import mage.counters.CounterType; -import mage.game.permanent.token.EdgarMarkovsCoffinVampireToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class EdgarMarkovsCoffin extends CardImpl { - - private static final Condition condition = new SourceHasCounterCondition(CounterType.BLOODLINE, 3); - - public EdgarMarkovsCoffin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.color.setWhite(true); - this.color.setBlack(true); - this.nightCard = true; - - // At the beginning of your upkeep, create a 1/1 white and black Vampire creature token with lifelink and put a bloodline counter on Edgar Markov's Coffin. Then if there are three or more bloodline counters on it, remove those counters and transform it. - Ability ability = new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new EdgarMarkovsCoffinVampireToken())); - ability.addEffect(new AddCountersSourceEffect(CounterType.BLOODLINE.createInstance()).concatBy("and")); - ability.addEffect(new ConditionalOneShotEffect( - new RemoveAllCountersSourceEffect(CounterType.BLOODLINE), condition, - "Then if there are three or more bloodline counters on it, remove those counters and transform it" - ).addEffect(new TransformSourceEffect())); - this.addAbility(ability); - } - - private EdgarMarkovsCoffin(final EdgarMarkovsCoffin card) { - super(card); - } - - @Override - public EdgarMarkovsCoffin copy() { - return new EdgarMarkovsCoffin(this); - } -} diff --git a/Mage.Sets/src/mage/cards/e/EidolonOfTheGreatRevel.java b/Mage.Sets/src/mage/cards/e/EidolonOfTheGreatRevel.java index 66b05b103db..6ba0665ca81 100644 --- a/Mage.Sets/src/mage/cards/e/EidolonOfTheGreatRevel.java +++ b/Mage.Sets/src/mage/cards/e/EidolonOfTheGreatRevel.java @@ -49,7 +49,7 @@ class EidolonOfTheGreatRevelTriggeredAbility extends TriggeredAbilityImpl { public EidolonOfTheGreatRevelTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player")); } diff --git a/Mage.Sets/src/mage/cards/e/EirduCarrierOfDawn.java b/Mage.Sets/src/mage/cards/e/EirduCarrierOfDawn.java index 65606b79efd..9c25983040b 100644 --- a/Mage.Sets/src/mage/cards/e/EirduCarrierOfDawn.java +++ b/Mage.Sets/src/mage/cards/e/EirduCarrierOfDawn.java @@ -1,21 +1,24 @@ package mage.cards.e; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; import mage.abilities.keyword.ConvokeAbility; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.PersistAbility; import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.StaticFilters; import mage.filter.common.FilterNonlandCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; @@ -25,7 +28,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class EirduCarrierOfDawn extends CardImpl { +public final class EirduCarrierOfDawn extends TransformingDoubleFacedCard { private static final FilterNonlandCard filter = new FilterNonlandCard("creature spells you cast"); @@ -35,29 +38,45 @@ public final class EirduCarrierOfDawn extends CardImpl { } public EirduCarrierOfDawn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL, SubType.GOD}, "{3}{W}{W}", + "Isilu, Carrier of Twilight", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL, SubType.GOD}, "B" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELEMENTAL); - this.subtype.add(SubType.GOD); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.i.IsiluCarrierOfTwilight.class; + // Eirdu, Carrier of Dawn + this.getLeftHalfCard().setPT(5, 5); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // Creature spells you cast have convoke. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledSpellsEffect(new ConvokeAbility(), filter))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledSpellsEffect(new ConvokeAbility(), filter))); // At the beginning of your first main phase, you may pay {B}. If you do, transform Eirdu. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfFirstMainTriggeredAbility( - new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{B}")) - )); + Ability ability = new BeginningOfFirstMainTriggeredAbility(new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{B}"))); + this.getLeftHalfCard().addAbility(ability); + + // Isilu, Carrier of Twilight + this.getRightHalfCard().setPT(5, 5); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Each other nontoken creature you control has persist. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + new PersistAbility(), Duration.WhileControlled, + StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN, true + ).setText("each other nontoken creature you control has persist"))); + + // At the beginning of your first main phase, you may pay {W}. If you do, transform Isilu. + this.getRightHalfCard().addAbility(new BeginningOfFirstMainTriggeredAbility(new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{W}")))); } private EirduCarrierOfDawn(final EirduCarrierOfDawn card) { diff --git a/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java b/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java index 8612d8b1dfa..23af1fe5d14 100644 --- a/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java +++ b/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java @@ -1,20 +1,22 @@ package mage.cards.e; import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EquipAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.IntimidateAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.GameEvent; import java.util.Optional; import java.util.UUID; @@ -22,28 +24,43 @@ import java.util.UUID; /** * @author BetaSteward */ -public final class ElbrusTheBindingBlade extends CardImpl { +public final class ElbrusTheBindingBlade extends TransformingDoubleFacedCard { public ElbrusTheBindingBlade(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{7}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.EQUIPMENT); - - this.secondSideCardClazz = mage.cards.w.WithengarUnbound.class; - this.addAbility(new TransformAbility()); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "{7}", + "Withengar Unbound", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEMON}, "B" + ); + // Elbrus, the Binding Blade // Equipped creature gets +1/+0. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 0))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 0))); // When equipped creature deals combat damage to a player, unattach Elbrus, the Binding Blade, then transform it. Ability ability = new DealsDamageToAPlayerAttachedTriggeredAbility( new ElbrusTheBindingBladeEffect(), "equipped", false ); ability.addEffect(new TransformSourceEffect(true).concatBy(", then")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Equip {1} - this.addAbility(new EquipAbility(1, false)); + this.getLeftHalfCard().addAbility(new EquipAbility(1, false)); + + // Withengar Unbound + this.getRightHalfCard().setPT(13, 13); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Intimidate + this.getRightHalfCard().addAbility(IntimidateAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Whenever a player loses the game, put thirteen +1/+1 counters on Withengar Unbound. + this.getRightHalfCard().addAbility(new WithengarUnboundTriggeredAbility()); } private ElbrusTheBindingBlade(final ElbrusTheBindingBlade card) { @@ -59,7 +76,7 @@ public final class ElbrusTheBindingBlade extends CardImpl { class ElbrusTheBindingBladeEffect extends OneShotEffect { ElbrusTheBindingBladeEffect() { super(Outcome.BecomeCreature); - staticText = "unattach {this}, then transform it"; + staticText = "unattach {this}"; } private ElbrusTheBindingBladeEffect(final ElbrusTheBindingBladeEffect effect) { @@ -77,3 +94,30 @@ class ElbrusTheBindingBladeEffect extends OneShotEffect { return new ElbrusTheBindingBladeEffect(this); } } + +class WithengarUnboundTriggeredAbility extends TriggeredAbilityImpl { + + WithengarUnboundTriggeredAbility() { + super(Zone.BATTLEFIELD, new mage.abilities.effects.common.counter.AddCountersSourceEffect(CounterType.P1P1.createInstance(13)), false); + setTriggerPhrase("Whenever a player loses the game, "); + } + + private WithengarUnboundTriggeredAbility(final WithengarUnboundTriggeredAbility ability) { + super(ability); + } + + @Override + public WithengarUnboundTriggeredAbility copy() { + return new WithengarUnboundTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LOST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElectroAssaultingBattery.java b/Mage.Sets/src/mage/cards/e/ElectroAssaultingBattery.java index 27e33673fd2..d802d3cc68d 100644 --- a/Mage.Sets/src/mage/cards/e/ElectroAssaultingBattery.java +++ b/Mage.Sets/src/mage/cards/e/ElectroAssaultingBattery.java @@ -63,7 +63,7 @@ class ElectroAssaultingBatteryEffect extends OneShotEffect { ElectroAssaultingBatteryEffect() { super(Outcome.Damage); - staticText = "you may pay x. When you do, he deals X damage to target player"; + staticText = "you may pay {X}. When you do, he deals X damage to target player"; } private ElectroAssaultingBatteryEffect(final ElectroAssaultingBatteryEffect effect) { @@ -92,4 +92,4 @@ class ElectroAssaultingBatteryEffect extends OneShotEffect { } return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/e/EleshNorn.java b/Mage.Sets/src/mage/cards/e/EleshNorn.java index e1fe1dce1a4..c8898eda722 100644 --- a/Mage.Sets/src/mage/cards/e/EleshNorn.java +++ b/Mage.Sets/src/mage/cards/e/EleshNorn.java @@ -1,65 +1,104 @@ package mage.cards.e; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SagaAbility; import mage.abilities.common.SourceDealsDamageToYouTriggeredAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.IncubateEffect; +import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetControlledPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class EleshNorn extends CardImpl { +public final class EleshNorn extends TransformingDoubleFacedCard { private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("other creatures"); + private static final FilterPermanent argentFilter = new FilterPermanent("other permanents except for artifacts, lands, and Phyrexians"); static { filter.add(AnotherPredicate.instance); + argentFilter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); + argentFilter.add(Predicates.not(CardType.LAND.getPredicate())); + argentFilter.add(Predicates.not(SubType.PHYREXIAN.getPredicate())); + argentFilter.add(AnotherPredicate.instance); } public EleshNorn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.PRAETOR}, "{2}{W}{W}", + "The Argent Etchings", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "W" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.PRAETOR); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.t.TheArgentEtchings.class; + // Elesh Norn + this.getLeftHalfCard().setPT(3, 5); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // Whenever a source an opponent controls deals damage to you or a permanent you control, that source's controller loses 2 life unless they pay {1}. - this.addAbility(new SourceDealsDamageToYouTriggeredAbility(new EleshNornEffect(), StaticFilters.FILTER_PERMANENT, false)); + this.getLeftHalfCard().addAbility(new SourceDealsDamageToYouTriggeredAbility(new EleshNornEffect(), StaticFilters.FILTER_PERMANENT, false)); // {2}{W}, Sacrifice three other creatures: Exile Elesh Norn, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); Ability ability = new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{2}{W}") ); ability.addCost(new SacrificeTargetCost(3, filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // The Argent Etchings + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I -- Incubate 2 five times, then transform all Incubator tokens you control. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, new TheArgentEtchingsEffect()); + + // II -- Creatures you control get +1/+1 and gain double strike until end of turn. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_II, + new BoostControlledEffect(1, 1, Duration.EndOfTurn) + .setText("creatures you control get +1/+1"), + new GainAbilityControlledEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("and gain double strike until end of turn") + ); + + // III -- Destroy all other permanents except for artifacts, lands, and Phyrexians. Exile The Argent Etchings, then return it to the battlefield. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_III, + new DestroyAllEffect(argentFilter), + new ExileSourceAndReturnFaceUpEffect() + ); + this.getRightHalfCard().addAbility(sagaAbility); } private EleshNorn(final EleshNorn card) { @@ -103,3 +142,39 @@ class EleshNornEffect extends OneShotEffect { return player.loseLife(2, game, source, false) > 0; } } + +class TheArgentEtchingsEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.INCUBATOR); + + static { + filter.add(TokenPredicate.TRUE); + } + + TheArgentEtchingsEffect() { + super(Outcome.Benefit); + staticText = "incubate 2 five times, then transform all Incubator tokens you control"; + } + + private TheArgentEtchingsEffect(final TheArgentEtchingsEffect effect) { + super(effect); + } + + @Override + public TheArgentEtchingsEffect copy() { + return new TheArgentEtchingsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (int i = 0; i < 5; i++) { + IncubateEffect.doIncubate(2, game, source); + } + for (Permanent permanent : game.getBattlefield().getActivePermanents( + filter, source.getControllerId(), source, game + )) { + permanent.transform(source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElusiveTormentor.java b/Mage.Sets/src/mage/cards/e/ElusiveTormentor.java index 7081587e355..3ba1e539a3a 100644 --- a/Mage.Sets/src/mage/cards/e/ElusiveTormentor.java +++ b/Mage.Sets/src/mage/cards/e/ElusiveTormentor.java @@ -1,40 +1,66 @@ - package mage.cards.e; -import java.util.UUID; - -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.abilities.effects.common.combat.CantBlockSourceEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.SuperType; + +import java.util.UUID; /** * @author fireshoes */ -public final class ElusiveTormentor extends CardImpl { +public final class ElusiveTormentor extends TransformingDoubleFacedCard { public ElusiveTormentor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(4); - this.toughness = new MageInt(4); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.WIZARD}, "{2}{B}{B}", + "Insidious Mist", + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL}, "U" + ); - this.secondSideCardClazz = mage.cards.i.InsidiousMist.class; + // Elusive Tormentor + this.getLeftHalfCard().setPT(4, 4); // {1}, Discard a card: Transform Elusive Tormentor. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new TransformSourceEffect(), new GenericManaCost(1)); ability.addCost(new DiscardCardCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + + // Insidious Mist + this.getRightHalfCard().setPT(0, 1); + + // Hexproof + this.getRightHalfCard().addAbility(HexproofAbility.getInstance()); + + // Indestructible + this.getRightHalfCard().addAbility(IndestructibleAbility.getInstance()); + + // Insidious Mist can't block and can't be blocked. + Ability staticAbility = new SimpleStaticAbility(new CantBlockSourceEffect(Duration.WhileOnBattlefield)); + staticAbility.addEffect(new CantBeBlockedSourceEffect().setText("and can't be blocked")); + this.getRightHalfCard().addAbility(staticAbility); + + // Whenever Insidious Mist attacks and isn't blocked, you may pay {2}{B}. If you do, transform it. + this.getRightHalfCard().addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new DoIfCostPaid( + new TransformSourceEffect().setText("transform it"), new ManaCostsImpl<>("{2}{B}"), "Pay {2}{B} to transform?" + ))); } private ElusiveTormentor(final ElusiveTormentor card) { diff --git a/Mage.Sets/src/mage/cards/e/EmetSelchUnsundered.java b/Mage.Sets/src/mage/cards/e/EmetSelchUnsundered.java index c2f8e872ee5..6d688e4d04e 100644 --- a/Mage.Sets/src/mage/cards/e/EmetSelchUnsundered.java +++ b/Mage.Sets/src/mage/cards/e/EmetSelchUnsundered.java @@ -1,48 +1,66 @@ package mage.cards.e; -import java.util.UUID; -import mage.MageInt; -import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveyardCondition; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalAsThoughEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.abilities.keyword.VigilanceAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; /** * @author balazskristof */ -public final class EmetSelchUnsundered extends CardImpl { +public final class EmetSelchUnsundered extends TransformingDoubleFacedCard { public EmetSelchUnsundered(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELDER); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(2); - this.toughness = new MageInt(4); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDER, SubType.WIZARD}, "{1}{U}{B}", + "Hades, Sorcerer of Eld", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR}, "" + ); - this.secondSideCardClazz = mage.cards.h.HadesSorcererOfEld.class; + // Emet-Selch, Unsundered + this.getLeftHalfCard().setPT(2, 4); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // Whenever Emet-Selch enters or attacks, draw a card, then discard a card. - this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DrawDiscardControllerEffect(1, 1))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DrawDiscardControllerEffect(1, 1))); // At the beginning of your upkeep, if there are fourteen or more cards in your graveyard, you may transform Emet-Selch. - this.addAbility(new BeginningOfUpkeepTriggeredAbility( + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility( new TransformSourceEffect(), true - ).withInterveningIf(new CardsInControllerGraveyardCondition(14))); - this.addAbility(new TransformAbility()); + ).withInterveningIf(new CardsInControllerGraveyardCondition(14))); // assumption: condition counts all cards + + // Hades, Sorcerer of Eld + this.getRightHalfCard().setPT(6, 6); + this.getRightHalfCard().getColor().setBlue(true); + this.getRightHalfCard().getColor().setBlack(true); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Echo of the Lost -- During your turn, you may play cards from your graveyard. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( + PlayFromGraveyardControllerEffect.playCards(), MyTurnCondition.instance + ).setText("during your turn, you may play cards from your graveyard")).withFlavorWord("Echo of the Lost")); + + // If a card or token would be put into your graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(true, true))); } private EmetSelchUnsundered(final EmetSelchUnsundered card) { diff --git a/Mage.Sets/src/mage/cards/e/Emptiness.java b/Mage.Sets/src/mage/cards/e/Emptiness.java index 747a3495a2f..f84c4bca8cd 100644 --- a/Mage.Sets/src/mage/cards/e/Emptiness.java +++ b/Mage.Sets/src/mage/cards/e/Emptiness.java @@ -48,7 +48,7 @@ public final class Emptiness extends CardImpl { this.addAbility(ability); // When this creature enters, if {B}{B} was spent to cast it, put three -1/-1 counters on up to one target creature. - ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.M1M1.createInstance(2))) + ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.M1M1.createInstance(3))) .withInterveningIf(TwoOfManaColorSpentCondition.BLACK); ability.addTarget(new TargetCreaturePermanent(0, 1)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/e/EnduringAngel.java b/Mage.Sets/src/mage/cards/e/EnduringAngel.java index cb4b85471a4..379bbc3b553 100644 --- a/Mage.Sets/src/mage/cards/e/EnduringAngel.java +++ b/Mage.Sets/src/mage/cards/e/EnduringAngel.java @@ -1,20 +1,19 @@ package mage.cards.e; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.ControllerLifeCount; import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -25,28 +24,48 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class EnduringAngel extends CardImpl { +public final class EnduringAngel extends TransformingDoubleFacedCard { public EnduringAngel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}{W}"); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "{2}{W}{W}{W}", + "Angelic Enforcer", + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "W" + ); - this.subtype.add(SubType.ANGEL); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.a.AngelicEnforcer.class; + // Enduring Angel + this.getLeftHalfCard().setPT(3, 3); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Double strike - this.addAbility(DoubleStrikeAbility.getInstance()); + this.getLeftHalfCard().addAbility(DoubleStrikeAbility.getInstance()); // You have hexproof. - this.addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance()))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance()))); // If your life total would be reduced to 0 or less, instead transform Enduring Angel and your life total becomes 3. Then if Enduring Angel didn't transform this way, you lose the game. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleStaticAbility(new EnduringAngelEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new EnduringAngelEffect())); + + // Angelic Enforcer + this.getRightHalfCard().setPT(0, 0); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // You have hexproof. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance()))); + + // Angelic Enforcer's power and toughness are each equal to your life total. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect( + ControllerLifeCount.instance + ).setText("{this}'s power and toughness are each equal to your life total"))); + + // Whenever Angelic Enforcer attacks, double your life total. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new GainLifeEffect( + ControllerLifeCount.instance + ).setText("double your life total"))); } private EnduringAngel(final EnduringAngel card) { diff --git a/Mage.Sets/src/mage/cards/e/EraOfEnlightenment.java b/Mage.Sets/src/mage/cards/e/EraOfEnlightenment.java index d7a5761a94e..a6c4a031f53 100644 --- a/Mage.Sets/src/mage/cards/e/EraOfEnlightenment.java +++ b/Mage.Sets/src/mage/cards/e/EraOfEnlightenment.java @@ -4,40 +4,46 @@ import mage.abilities.common.SagaAbility; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.keyword.ScryEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SagaChapter; import mage.constants.SubType; +import mage.constants.SuperType; import java.util.UUID; /** * @author TheElk801 */ -public final class EraOfEnlightenment extends CardImpl { +public final class EraOfEnlightenment extends TransformingDoubleFacedCard { public EraOfEnlightenment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{W}", + "Hand of Enlightenment", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.MONK}, "W" + ); - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.h.HandOfEnlightenment.class; - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + // Era of Enlightenment + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I — Scry 2. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new ScryEffect(2)); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_I, new ScryEffect(2)); // II — You gain 2 life. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new GainLifeEffect(2)); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new GainLifeEffect(2)); // III — Exile this Saga, then return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility); + // Hand of Enlightenment + this.getRightHalfCard().setPT(2, 2); + + // First strike + this.getRightHalfCard().addAbility(FirstStrikeAbility.getInstance()); } private EraOfEnlightenment(final EraOfEnlightenment card) { diff --git a/Mage.Sets/src/mage/cards/e/EsperOrigins.java b/Mage.Sets/src/mage/cards/e/EsperOrigins.java index 92025c053fb..e8c10f40d11 100644 --- a/Mage.Sets/src/mage/cards/e/EsperOrigins.java +++ b/Mage.Sets/src/mage/cards/e/EsperOrigins.java @@ -1,21 +1,27 @@ package mage.cards.e; +import mage.Mana; import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; import mage.abilities.condition.common.CastFromGraveyardSourceCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.keyword.SurveilEffect; +import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.keyword.FlashbackAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.cards.CardsImpl; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.counters.CounterType; import mage.counters.Counters; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.stack.Spell; import mage.players.Player; @@ -25,20 +31,48 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class EsperOrigins extends CardImpl { +public final class EsperOrigins extends TransformingDoubleFacedCard { public EsperOrigins(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); - this.secondSideCardClazz = mage.cards.s.SummonEsperMaduin.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.SORCERY}, new SubType[]{}, "{1}{G}", + "Summon: Esper Maduin", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.ELEMENTAL}, "G" + ); + // Esper Origins // Surveil 2. You gain 2 life. If this spell was cast from a graveyard, exile it, then put it onto the battlefield transformed under its owner's control with a finality counter on it. - this.getSpellAbility().addEffect(new SurveilEffect(2, false)); - this.getSpellAbility().addEffect(new GainLifeEffect(2)); - this.getSpellAbility().addEffect(new EsperOriginsEffect()); - this.addAbility(new TransformAbility()); + this.getLeftHalfCard().getSpellAbility().addEffect(new SurveilEffect(2, false)); + this.getLeftHalfCard().getSpellAbility().addEffect(new GainLifeEffect(2)); + this.getLeftHalfCard().getSpellAbility().addEffect(new EsperOriginsEffect()); // Flashback {3}{G} - this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{3}{G}"))); + this.getLeftHalfCard().addAbility(new FlashbackAbility(this.getLeftHalfCard(), new ManaCostsImpl<>("{3}{G}"))); + + // Summon: Esper Maduin + this.getRightHalfCard().setPT(4, 4); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I -- Reveal the top card of your library. If it's a permanent card, put it into your hand. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, new SummonEsperMaduinEffect()); + + // II -- Add {G}{G}. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_II, new BasicManaEffect(Mana.GreenMana(2))); + + // III -- Other creatures you control get +2/+2 and gain trample until end of turn. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_III, + new BoostControlledEffect( + 2, 2, Duration.EndOfTurn, true + ).setText("other creatures you control get +2/+2"), + new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, true + ).setText("and gain trample until end of turn") + ); + this.getRightHalfCard().addAbility(sagaAbility.withShowSacText(true)); } private EsperOrigins(final EsperOrigins card) { @@ -89,3 +123,37 @@ class EsperOriginsEffect extends OneShotEffect { return true; } } + +class SummonEsperMaduinEffect extends OneShotEffect { + + SummonEsperMaduinEffect() { + super(Outcome.Benefit); + staticText = "reveal the top card of your library. If it's a permanent card, put it into your hand"; + } + + private SummonEsperMaduinEffect(final SummonEsperMaduinEffect effect) { + super(effect); + } + + @Override + public SummonEsperMaduinEffect copy() { + return new SummonEsperMaduinEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + player.revealCards(source, new CardsImpl(card), game); + if (card.isPermanent(game)) { + player.moveCards(card, Zone.HAND, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java b/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java index 8330ea611f9..27d2adc26d8 100644 --- a/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java +++ b/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java @@ -1,16 +1,17 @@ package mage.cards.e; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.IndestructibleAbility; import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.TransformAbility; import mage.cards.*; import mage.constants.*; +import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; @@ -21,27 +22,40 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class EtaliPrimalConqueror extends CardImpl { +public final class EtaliPrimalConqueror extends TransformingDoubleFacedCard { public EtaliPrimalConqueror(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDER, SubType.DINOSAUR}, "{5}{R}{R}", + "Etali, Primal Sickness", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.ELDER, SubType.DINOSAUR}, "RG" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELDER); - this.subtype.add(SubType.DINOSAUR); - this.power = new MageInt(7); - this.toughness = new MageInt(7); - this.secondSideCardClazz = mage.cards.e.EtaliPrimalSickness.class; + // Etali, Primal Conqueror + this.getLeftHalfCard().setPT(7, 7); // Trample - this.addAbility(TrampleAbility.getInstance()); + this.getLeftHalfCard().addAbility(TrampleAbility.getInstance()); // When Etali, Primal Conqueror enters the battlefield, each player exiles cards from the top of their library until they exile a nonland card. You may cast any number of spells from among the nonland cards exiled this way without paying their mana costs. - this.addAbility(new EntersBattlefieldTriggeredAbility(new EtaliPrimalConquerorEffect())); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new EtaliPrimalConquerorEffect())); // {9}{G/P}: Transform Etali. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{9}{G/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{9}{G/P}"))); + + // Etali, Primal Sickness + this.getRightHalfCard().setPT(11, 11); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Indestructible + this.getRightHalfCard().addAbility(IndestructibleAbility.getInstance()); + + // Whenever Etali, Primal Sickness deals combat damage to a player, they get that many poison counters. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new EtaliPrimalSicknessEffect(), false, true + )); } private EtaliPrimalConqueror(final EtaliPrimalConqueror card) { @@ -97,3 +111,27 @@ class EtaliPrimalConquerorEffect extends OneShotEffect { return true; } } + +class EtaliPrimalSicknessEffect extends OneShotEffect { + + EtaliPrimalSicknessEffect() { + super(Outcome.Benefit); + staticText = "they get that many poison counters"; + } + + private EtaliPrimalSicknessEffect(final EtaliPrimalSicknessEffect effect) { + super(effect); + } + + @Override + public EtaliPrimalSicknessEffect copy() { + return new EtaliPrimalSicknessEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + int damage = (Integer) getValue("damage"); + return player != null && player.addCounters(CounterType.POISON.createInstance(damage), source.getControllerId(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EtaliPrimalSickness.java b/Mage.Sets/src/mage/cards/e/EtaliPrimalSickness.java deleted file mode 100644 index bc9f2c0fdaa..00000000000 --- a/Mage.Sets/src/mage/cards/e/EtaliPrimalSickness.java +++ /dev/null @@ -1,83 +0,0 @@ -package mage.cards.e; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.counters.CounterType; -import mage.game.Game; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class EtaliPrimalSickness extends CardImpl { - - public EtaliPrimalSickness(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.ELDER); - this.subtype.add(SubType.DINOSAUR); - this.power = new MageInt(11); - this.toughness = new MageInt(11); - this.color.setRed(true); - this.color.setGreen(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Indestructible - this.addAbility(IndestructibleAbility.getInstance()); - - // Whenever Etali, Primal Sickness deals combat damage to a player, they get that many poison counters. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new EtaliPrimalSicknessEffect(), false, true - )); - } - - private EtaliPrimalSickness(final EtaliPrimalSickness card) { - super(card); - } - - @Override - public EtaliPrimalSickness copy() { - return new EtaliPrimalSickness(this); - } -} - -class EtaliPrimalSicknessEffect extends OneShotEffect { - - EtaliPrimalSicknessEffect() { - super(Outcome.Benefit); - staticText = "they get that many poison counters"; - } - - private EtaliPrimalSicknessEffect(final EtaliPrimalSicknessEffect effect) { - super(effect); - } - - @Override - public EtaliPrimalSicknessEffect copy() { - return new EtaliPrimalSicknessEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - int damage = (Integer) getValue("damage"); - return player.addCounters(CounterType.POISON.createInstance(damage), source.getControllerId(), source, game); - } -} diff --git a/Mage.Sets/src/mage/cards/e/EvelynTheCovetous.java b/Mage.Sets/src/mage/cards/e/EvelynTheCovetous.java index 5f098d88de5..bb54bf9003e 100644 --- a/Mage.Sets/src/mage/cards/e/EvelynTheCovetous.java +++ b/Mage.Sets/src/mage/cards/e/EvelynTheCovetous.java @@ -174,8 +174,8 @@ class EvelynTheCovetousManaEffect extends AsThoughEffectImpl implements AsThough && EvelynTheCovetousWatcher.checkExile(affectedControllerId, card, game, 0); } CardState cardState; - if (card instanceof ModalDoubleFacedCard) { - cardState = game.getLastKnownInformationCard(((ModalDoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); + if (card instanceof DoubleFacedCard) { + cardState = game.getLastKnownInformationCard(((DoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); } else { cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); } diff --git a/Mage.Sets/src/mage/cards/e/ExdeathVoidWarlock.java b/Mage.Sets/src/mage/cards/e/ExdeathVoidWarlock.java index 4a941ceec6a..0c378675dfb 100644 --- a/Mage.Sets/src/mage/cards/e/ExdeathVoidWarlock.java +++ b/Mage.Sets/src/mage/cards/e/ExdeathVoidWarlock.java @@ -1,18 +1,20 @@ package mage.cards.e; -import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; @@ -23,31 +25,40 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ExdeathVoidWarlock extends CardImpl { +public final class ExdeathVoidWarlock extends TransformingDoubleFacedCard { private static final Condition condition = new CardsInControllerGraveyardCondition(6, StaticFilters.FILTER_CARD_PERMANENTS); private static final Hint hint = new ValueHint( "Permanent cards in your graveyard", new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_PERMANENT) ); + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_PERMANENTS); public ExdeathVoidWarlock(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{G}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.WARLOCK}, "{1}{B}{G}", + "Neo Exdeath, Dimension's End", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.AVATAR}, "BG" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.WARLOCK); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.n.NeoExdeathDimensionsEnd.class; + // Exdeath, Void Warlock + this.getLeftHalfCard().setPT(3, 3); // When Exdeath enters, you gain 3 life. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3))); // At the beginning of your end step, if there are six or more permanent cards in your graveyard, transform Exdeath. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) .withInterveningIf(condition).addHint(hint)); + + // Neo Exdeath, Dimension's End + this.getRightHalfCard().setPT(0, 3); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Neo Exdeath's power is equal to the number of permanent cards in your graveyard. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new SetBasePowerSourceEffect(xValue))); } private ExdeathVoidWarlock(final ExdeathVoidWarlock card) { diff --git a/Mage.Sets/src/mage/cards/e/ExplosiveWelcome.java b/Mage.Sets/src/mage/cards/e/ExplosiveWelcome.java index 34d261a336d..fd5faf51be3 100644 --- a/Mage.Sets/src/mage/cards/e/ExplosiveWelcome.java +++ b/Mage.Sets/src/mage/cards/e/ExplosiveWelcome.java @@ -20,7 +20,7 @@ import java.util.UUID; */ public final class ExplosiveWelcome extends CardImpl { - private static final FilterPermanentOrPlayer filter = new FilterAnyTarget(); + private static final FilterPermanentOrPlayer filter = new FilterAnyTarget("any other target"); static { filter.getPermanentFilter().add(new AnotherTargetPredicate(2)); diff --git a/Mage.Sets/src/mage/cards/e/ExtricatorOfFlesh.java b/Mage.Sets/src/mage/cards/e/ExtricatorOfFlesh.java deleted file mode 100644 index 1d9019bd1c1..00000000000 --- a/Mage.Sets/src/mage/cards/e/ExtricatorOfFlesh.java +++ /dev/null @@ -1,67 +0,0 @@ -package mage.cards.e; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; -import mage.game.permanent.token.EldraziHorrorToken; - -/** - * - * @author LevelX2 - */ -public final class ExtricatorOfFlesh extends CardImpl { - - private static final FilterControlledCreaturePermanent filterNonEldrazi = new FilterControlledCreaturePermanent("non-Eldrazi creature"); - private static final FilterControlledPermanent filterEldrazi = new FilterControlledPermanent(SubType.ELDRAZI, "Eldrazi"); - - static { - filterNonEldrazi.add(Predicates.not(SubType.ELDRAZI.getPredicate())); - } - - public ExtricatorOfFlesh(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Eldrazi you control have vigilance - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, filterEldrazi))); - - // {2}, {T}, Sacrifice a non-Eldrazi creature: Create a 3/2 colorless Eldrazi Horror creature token. - Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new EldraziHorrorToken()), new GenericManaCost(2)); - ability.addCost(new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(filterNonEldrazi)); - this.addAbility(ability); - } - - private ExtricatorOfFlesh(final ExtricatorOfFlesh card) { - super(card); - } - - @Override - public ExtricatorOfFlesh copy() { - return new ExtricatorOfFlesh(this); - } -} diff --git a/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java b/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java index e52dc72a2a3..d58ae932069 100644 --- a/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java +++ b/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java @@ -1,21 +1,29 @@ package mage.cards.e; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.VigilanceAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.AbilityWord; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.permanent.token.EldraziHorrorToken; @@ -24,33 +32,49 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class ExtricatorOfSin extends CardImpl { +public final class ExtricatorOfSin extends TransformingDoubleFacedCard { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another permanent"); + private static final FilterControlledCreaturePermanent filterNonEldrazi = new FilterControlledCreaturePermanent("non-Eldrazi creature"); + private static final FilterControlledPermanent filterEldrazi = new FilterControlledPermanent(SubType.ELDRAZI, "Eldrazi"); static { filter.add(AnotherPredicate.instance); + filterNonEldrazi.add(Predicates.not(SubType.ELDRAZI.getPredicate())); } public ExtricatorOfSin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(0); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{2}{W}", + "Extricator Of Flesh", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.HORROR}, "" + ); - this.secondSideCardClazz = mage.cards.e.ExtricatorOfFlesh.class; + // Extricator of Sin + this.getLeftHalfCard().setPT(0, 3); // When Extricator of Sin enters the battlefield, you may sacrifice another permanent. If you do, create a 3/2 colorless Eldrazi Horror creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new EldraziHorrorToken()), + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new EldraziHorrorToken()), new SacrificeTargetCost(filter)), false)); - // Delirium — At the beginning of your upkeep, if there are four or more card types among cards in your graveyard, transform Extricator of Sin. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()) + // Delirium — At the beginning of your upkeep, if there are four or more card types among cards in your graveyard, transform Extricator of Sin. + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()) .withInterveningIf(DeliriumCondition.instance) .setAbilityWord(AbilityWord.DELIRIUM) .addHint(CardTypesInGraveyardCount.YOU.getHint())); + + // Extricator Of Flesh + this.getRightHalfCard().setPT(3, 5); + + // Eldrazi you control have vigilance + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, filterEldrazi))); + + // {2}, {T}, Sacrifice a non-Eldrazi creature: Create a 3/2 colorless Eldrazi Horror creature token. + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new EldraziHorrorToken()), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(filterNonEldrazi)); + this.getRightHalfCard().addAbility(ability); } private ExtricatorOfSin(final ExtricatorOfSin card) { diff --git a/Mage.Sets/src/mage/cards/e/EyeOfOjerTaq.java b/Mage.Sets/src/mage/cards/e/EyeOfOjerTaq.java index 775a3ded557..ccb404fca3e 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfOjerTaq.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfOjerTaq.java @@ -1,39 +1,69 @@ package mage.cards.e; -import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.CraftAbility; import mage.abilities.mana.AnyColorManaAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.TargetController; +import mage.cards.TransformingDoubleFacedCard; +import mage.choices.Choice; +import mage.choices.ChoiceCardType; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.ExileZone; import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.common.TargetCardInGraveyardBattlefieldOrStack; +import mage.util.CardUtil; + +import java.util.*; +import java.util.stream.Collectors; /** - * * @author jeffwadsworth */ -public class EyeOfOjerTaq extends CardImpl { +public final class EyeOfOjerTaq extends TransformingDoubleFacedCard { public EyeOfOjerTaq(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); - - this.secondSideCardClazz = mage.cards.a.ApexObservatory.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{3}", + "Apex Observatory", + new SuperType[]{}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "" + ); + // Eye of Ojer Taq // {T}: Add one mana of any color. - this.addAbility(new AnyColorManaAbility()); + this.getLeftHalfCard().addAbility(new AnyColorManaAbility()); - // Craft with two that share a card type {6} ({6}, Exile this artifact, Exile the two from among other permanents you control - // and/or cards from your graveyard: Return this card transformed under its owner’s control. Craft only as a sorcery.) - this.addAbility(new CraftAbility( + // Craft with two that share a card type {6} ({6}, Exile this artifact, Exile the two from among other permanents you control and/or cards from your graveyard: Return this card transformed under its owner's control. Craft only as a sorcery.) + this.getLeftHalfCard().addAbility(new CraftAbility( "{6}", "two that share a card type", new EyeOfOjerTaqTarget() )); + + // Apex Observatory + + // This artifact enters tapped. As it enters, choose a card type shared among two exiled cards used to craft it. + EntersBattlefieldEffect entersEffect = new EntersBattlefieldEffect(new TapSourceEffect(true) + .setText("{this} enters tapped")); + entersEffect.addEffect(new ChooseCardTypeEffect() + .concatBy("As it enters,")); + Ability observatoryAbility = new SimpleStaticAbility(entersEffect); + this.getRightHalfCard().addAbility(observatoryAbility); + + // The next spell you cast this turn of the chosen type can be cast without paying its mana cost. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new ApexObservatoryEffect(), new TapSourceCost())); } private EyeOfOjerTaq(final EyeOfOjerTaq card) { @@ -44,20 +74,16 @@ public class EyeOfOjerTaq extends CardImpl { public EyeOfOjerTaq copy() { return new EyeOfOjerTaq(this); } - } class EyeOfOjerTaqTarget extends TargetCardInGraveyardBattlefieldOrStack { - private static final FilterCard filterCard - = new FilterCard(); - private static final FilterControlledPermanent filterPermanent - = new FilterControlledPermanent(); + private static final FilterCard filterCard = new FilterCard(); + private static final FilterControlledPermanent filterPermanent = new FilterControlledPermanent(); static { filterCard.add(TargetController.YOU.getOwnerPredicate()); filterPermanent.add(AnotherPredicate.instance); - } EyeOfOjerTaqTarget() { @@ -81,22 +107,190 @@ class EyeOfOjerTaqTarget extends TargetCardInGraveyardBattlefieldOrStack { Card cardObject = game.getCard(id); return cardObject != null && this.getTargets() - .stream() - .map(game::getCard) - .noneMatch(c -> sharesCardtype(cardObject, c, game)); + .stream() + .map(game::getCard) + .noneMatch(c -> sharesCardtype(cardObject, c, game)); } - + public static boolean sharesCardtype(Card card1, Card card2, Game game) { if (card1.getId().equals(card2.getId())) { return false; } - // this should be returned true, but the invert works. - // if you note the code logic issue, please speak up. for (CardType type : card1.getCardType(game)) { if (card2.getCardType(game).contains(type)) { - return false; + return false; // see comment in original code } } return true; } } + +class ChooseCardTypeEffect extends OneShotEffect { + + public ChooseCardTypeEffect() { + super(Outcome.Neutral); + staticText = "choose a card type shared among two exiled cards used to craft it."; + } + + protected ChooseCardTypeEffect(final ChooseCardTypeEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); + List exiledCardsCardType = new ArrayList<>(); + if (mageObject == null) { + mageObject = game.getObject(source); + } + if (controller != null && mageObject != null) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source, game.getState().getZoneChangeCounter(mageObject.getId()) - 1)); + if (exileZone == null) { + return false; + } + for (Card card : exileZone.getCards(game)) { + exiledCardsCardType.addAll(card.getCardType(game)); + } + Choice cardTypeChoice = new ChoiceCardType(); + cardTypeChoice.getChoices().clear(); + cardTypeChoice.getChoices().addAll(exiledCardsCardType.stream().map(CardType::toString).collect(Collectors.toList())); + Map cardTypeCounts = new HashMap<>(); + for (String cardType : cardTypeChoice.getChoices()) { + cardTypeCounts.put(cardType, 0); + } + for (Card c : exileZone.getCards(game)) { + for (CardType cardType : c.getCardType(game)) { + if (cardTypeCounts.containsKey(cardType.toString())) { + cardTypeCounts.put(cardType.toString(), cardTypeCounts.get(cardType.toString()) + 1); + } + } + } + List sharedCardTypes = new ArrayList<>(); + int numExiledCards = exileZone.getCards(game).size(); + for (Map.Entry entry : cardTypeCounts.entrySet()) { + if (entry.getValue() == numExiledCards) { + sharedCardTypes.add(entry.getKey()); + } + } + if (sharedCardTypes.isEmpty()) { + game.informPlayers(mageObject.getIdName() + " No exiled cards shared a type in exile, so nothing is done."); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("No exiled cards have the same card type."), game); + } + return false; + } + cardTypeChoice.getChoices().retainAll(sharedCardTypes); + if (controller.choose(Outcome.Benefit, cardTypeChoice, game)) { + if (!game.isSimulation()) { + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + cardTypeChoice.getChoice()); + } + game.getState().setValue("ApexObservatoryType_" + source.getSourceId().toString(), cardTypeChoice.getChoice()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen card type: " + cardTypeChoice.getChoice()), game); + } + return true; + } + } + return false; + } + + @Override + public ChooseCardTypeEffect copy() { + return new ChooseCardTypeEffect(this); + } +} + +class ApexObservatoryEffect extends OneShotEffect { + + ApexObservatoryEffect() { + super(Outcome.Benefit); + staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost."; + } + + private ApexObservatoryEffect(final ApexObservatoryEffect effect) { + super(effect); + } + + @Override + public ApexObservatoryEffect copy() { + return new ApexObservatoryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + String chosenCardType = (String) game.getState().getValue("ApexObservatoryType_" + source.getSourceId().toString()); + if (chosenCardType == null) { + return false; + } + game.addEffect(new ApexObservatoryCastWithoutManaEffect(chosenCardType, source.getControllerId()), source); + return true; + } +} + +class ApexObservatoryCastWithoutManaEffect extends CostModificationEffectImpl { + + private final String chosenCardType; + private final UUID playerId; + private boolean used = false; + + ApexObservatoryCastWithoutManaEffect(String chosenCardType, UUID playerId) { + super(Duration.EndOfTurn, Outcome.Benefit, CostModificationType.SET_COST); + this.chosenCardType = chosenCardType; + this.playerId = playerId; + staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost"; + } + + private ApexObservatoryCastWithoutManaEffect(final ApexObservatoryCastWithoutManaEffect effect) { + super(effect); + this.chosenCardType = effect.chosenCardType; + this.playerId = effect.playerId; + this.used = effect.used; + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + Player controller = game.getPlayer(playerId); + if (controller != null) { + MageObject spell = abilityToModify.getSourceObject(game); + if (spell != null && !game.isSimulation()) { + String message = "Cast " + spell.getIdName() + " without paying its mana cost?"; + if (controller.chooseUse(Outcome.Benefit, message, source, game)) { + abilityToModify.getManaCostsToPay().clear(); + used = true; + } + } + } + return true; + } + + @Override + public boolean isInactive(Ability source, Game game) { + return used || super.isInactive(source, game); + } + + @Override + public boolean applies(Ability ability, Ability source, Game game) { + if (used) { + return false; + } + if (!ability.isControlledBy(playerId)) { + return false; + } + if (!(ability instanceof SpellAbility)) { + return false; + } + MageObject object = game.getObject(ability.getSourceId()); + return object != null && object.getCardType(game).stream() + .anyMatch(cardType -> cardType.toString().equals(chosenCardType)); + } + + @Override + public ApexObservatoryCastWithoutManaEffect copy() { + return new ApexObservatoryCastWithoutManaEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EzurisPredation.java b/Mage.Sets/src/mage/cards/e/EzurisPredation.java index dec66cf05f3..a478c3ce212 100644 --- a/Mage.Sets/src/mage/cards/e/EzurisPredation.java +++ b/Mage.Sets/src/mage/cards/e/EzurisPredation.java @@ -92,7 +92,7 @@ class EzurisPredationEffect extends OneShotEffect { Permanent opponentCreature = creaturesOfOpponents.iterator().next(); creaturesOfOpponents.remove(opponentCreature); // can be multiple tokens, so must be used custom BATCH_FIGHT event - token.fight(opponentCreature, source, game, false); + token.fightWithExcess(opponentCreature, source, game, false); morSet.add(new MageObjectReference(token, game)); morSet.add(new MageObjectReference(opponentCreature, game)); game.informPlayers(token.getLogName() + " fights " + opponentCreature.getLogName()); diff --git a/Mage.Sets/src/mage/cards/f/FaithboundJudge.java b/Mage.Sets/src/mage/cards/f/FaithboundJudge.java index 0098ae14971..1519ccd30ca 100644 --- a/Mage.Sets/src/mage/cards/f/FaithboundJudge.java +++ b/Mage.Sets/src/mage/cards/f/FaithboundJudge.java @@ -1,67 +1,83 @@ package mage.cards.f; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.keyword.*; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Duration; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPlayer; +import java.util.Optional; import java.util.UUID; /** * @author TheElk801 */ -public final class FaithboundJudge extends CardImpl { +public final class FaithboundJudge extends TransformingDoubleFacedCard { private static final Condition condition1 = new SourceHasCounterCondition(CounterType.JUDGMENT, ComparisonType.OR_LESS, 2); private static final Condition condition2 = new SourceHasCounterCondition(CounterType.JUDGMENT, 3); public FaithboundJudge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.SOLDIER}, "{1}{W}{W}", + "Sinner's Judgment", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA, SubType.CURSE}, "W"); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.s.SinnersJudgment.class; + this.getLeftHalfCard().setPT(4, 4); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // At the beginning of your upkeep, if Faithbound Judge has two or fewer judgment counters on it, put a judgment counter on it. - this.addAbility(new BeginningOfUpkeepTriggeredAbility( + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility( new AddCountersSourceEffect(CounterType.JUDGMENT.createInstance()) .setText("put a judgment counter on it"), false ).withInterveningIf(condition1)); // As long as Faithbound Judge has three or more judgment counters on it, it can attack as though it didn't have defender. - this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.WhileOnBattlefield), condition2 ).setText("as long as {this} has three or more judgment counters on it, " + "it can attack as though it didn't have defender"))); - // Disturb {5}{W}{W} - this.addAbility(new DisturbAbility(this, "{5}{W}{W}")); + // Sinner's Judgement + + // Enchant player + TargetPlayer auraTarget = new TargetPlayer(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + + // Faithbound Judge - Disturb {5}{W}{W} + // needs target from right half spell ability + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{5}{W}{W}")); + + // At the beginning of your upkeep, put a judgment counter on Sinner's Judgment. Then if there are three or more judgment counters on it, enchanted player loses the game. + Ability ability = new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.JUDGMENT.createInstance())); + ability.addEffect(new SinnersJudgmentEffect()); + this.getRightHalfCard().addAbility(ability); + + // If Sinner's Judgment would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private FaithboundJudge(final FaithboundJudge card) { @@ -73,3 +89,34 @@ public final class FaithboundJudge extends CardImpl { return new FaithboundJudge(this); } } + +class SinnersJudgmentEffect extends OneShotEffect { + + SinnersJudgmentEffect() { + super(Outcome.Benefit); + staticText = "Then if there are three or more judgment counters on it, enchanted player loses the game"; + } + + private SinnersJudgmentEffect(final SinnersJudgmentEffect effect) { + super(effect); + } + + @Override + public SinnersJudgmentEffect copy() { + return new SinnersJudgmentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .filter(permanent -> permanent.getCounters(game).getCount(CounterType.JUDGMENT) >= 3) + .map(Permanent::getAttachedTo) + .map(game::getPlayer) + .filter(player -> { + player.lost(game); + return true; + }) + .isPresent(); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FalkenrathPerforator.java b/Mage.Sets/src/mage/cards/f/FalkenrathPerforator.java index dde1b9eb370..94171df03cb 100644 --- a/Mage.Sets/src/mage/cards/f/FalkenrathPerforator.java +++ b/Mage.Sets/src/mage/cards/f/FalkenrathPerforator.java @@ -24,9 +24,8 @@ public final class FalkenrathPerforator extends CardImpl { this.toughness = new MageInt(1); // Whenever Falkenrath Perforator attacks, it deals 1 damage to defending player. - this.addAbility(new AttacksTriggeredAbility(new DamageTargetEffect( - 1, true, "defending player", "it" - ), false, null, SetTargetPointer.PLAYER)); + this.addAbility(new AttacksTriggeredAbility(new DamageTargetEffect(1) + .withTargetDescription("defending player"), false, null, SetTargetPointer.PLAYER)); } private FalkenrathPerforator(final FalkenrathPerforator card) { diff --git a/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java b/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java index 499d0a3a875..c59f26d3d0c 100644 --- a/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java +++ b/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java @@ -21,7 +21,8 @@ public final class FallOfTheTitans extends CardImpl { // Fall of the Titans deals X damage to each of up to two target creatures and/or players. this.getSpellAbility().addTarget(new TargetAnyTarget(0, 2)); - this.getSpellAbility().addEffect(new DamageTargetEffect(GetXValue.instance, true, "each of up to two targets")); + this.getSpellAbility().addEffect(new DamageTargetEffect(GetXValue.instance) + .withTargetDescription("each of up to two targets")); // Surge {X}{R} addAbility(new SurgeAbility(this, "{X}{R}")); diff --git a/Mage.Sets/src/mage/cards/f/FangRokusCompanion.java b/Mage.Sets/src/mage/cards/f/FangRokusCompanion.java new file mode 100644 index 00000000000..3773b60100a --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FangRokusCompanion.java @@ -0,0 +1,130 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FangRokusCompanion extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("another target legendary creature you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(TargetController.YOU.getControllerPredicate()); + } + + public FangRokusCompanion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Fang attacks, another target legendary creature you control gets +X/+0 until end of turn, where X is Fang's power. + Ability ability = new AttacksTriggeredAbility(new BoostTargetEffect( + SourcePermanentPowerValue.NOT_NEGATIVE, StaticValue.get(0) + )); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // When Fang dies, if he wasn't a Spirit, return this card to the battlefield under your control. He's a Spirit in addition to his other types. + this.addAbility(new FangRokusCompanionTriggeredAbility()); + } + + private FangRokusCompanion(final FangRokusCompanion card) { + super(card); + } + + @Override + public FangRokusCompanion copy() { + return new FangRokusCompanion(this); + } +} + +class FangRokusCompanionTriggeredAbility extends DiesSourceTriggeredAbility { + + FangRokusCompanionTriggeredAbility() { + super(new FangRokusCompanionReturnEffect()); + } + + private FangRokusCompanionTriggeredAbility(final FangRokusCompanionTriggeredAbility ability) { + super(ability); + } + + @Override + public FangRokusCompanionTriggeredAbility copy() { + return new FangRokusCompanionTriggeredAbility(this); + } + + @Override + public boolean checkInterveningIfClause(Game game) { + return CardUtil + .getEffectValueFromAbility(this, "permanentLeftBattlefield", Permanent.class) + .filter(permanent -> !permanent.hasSubtype(SubType.SPIRIT, game)) + .isPresent(); + } +} + +class FangRokusCompanionReturnEffect extends OneShotEffect { + + FangRokusCompanionReturnEffect() { + super(Outcome.Benefit); + staticText = "if he wasn't a Spirit, return this card to the battlefield under your control. " + + "He's a Spirit in addition to his other types."; + } + + private FangRokusCompanionReturnEffect(final FangRokusCompanionReturnEffect effect) { + super(effect); + } + + @Override + public FangRokusCompanionReturnEffect copy() { + return new FangRokusCompanionReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(source.getSourceId()); + if (player == null || card == null) { + return false; + } + game.addEffect(new AddCardSubTypeTargetEffect(SubType.SPIRIT, Duration.Custom) + .setTargetPointer(new FixedTarget(new MageObjectReference(card, game, 1))), source); + return player.moveCards( + card, Zone.BATTLEFIELD, source, game, true, + false, true, null + ); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FateUnraveler.java b/Mage.Sets/src/mage/cards/f/FateUnraveler.java index 991456c01c9..f278bc05a14 100644 --- a/Mage.Sets/src/mage/cards/f/FateUnraveler.java +++ b/Mage.Sets/src/mage/cards/f/FateUnraveler.java @@ -24,7 +24,7 @@ public final class FateUnraveler extends CardImpl { this.toughness = new MageInt(4); // Whenever an opponent draws a card, Fate Unraveler deals 1 damage to that player. - this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1, true, "that player"), false, true)); + this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that player"), false, true)); } private FateUnraveler(final FateUnraveler card) { diff --git a/Mage.Sets/src/mage/cards/f/FatedClash.java b/Mage.Sets/src/mage/cards/f/FatedClash.java index 4d582e3651c..ebfd5bd0388 100644 --- a/Mage.Sets/src/mage/cards/f/FatedClash.java +++ b/Mage.Sets/src/mage/cards/f/FatedClash.java @@ -33,7 +33,7 @@ public final class FatedClash extends CardImpl { // You may cast this spell as though it had flash if a creature is attacking and a creature is blocking. this.addAbility(new CastAsThoughItHadFlashIfConditionAbility( condition, "you may cast this spell as though it had flash " + - "if a creature is attacking and a creature is blocking" + "if a creature is attacking and a creature is blocking." )); // Target creature you control and target creature an opponent controls each gain indestructible until end of turn. Then destroy all creatures. diff --git a/Mage.Sets/src/mage/cards/f/FatefulEnd.java b/Mage.Sets/src/mage/cards/f/FatefulEnd.java index 4890a8f8415..cb22c7c62ad 100644 --- a/Mage.Sets/src/mage/cards/f/FatefulEnd.java +++ b/Mage.Sets/src/mage/cards/f/FatefulEnd.java @@ -18,7 +18,7 @@ public final class FatefulEnd extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Fateful End deals 3 damage to any target. Scry 1. - this.getSpellAbility().addEffect(new DamageTargetEffect(3, true, "any target")); + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addEffect(new ScryEffect(1, false)); } diff --git a/Mage.Sets/src/mage/cards/f/FieryAnnihilation.java b/Mage.Sets/src/mage/cards/f/FieryAnnihilation.java index 2196e4d6699..157c2ec53b7 100644 --- a/Mage.Sets/src/mage/cards/f/FieryAnnihilation.java +++ b/Mage.Sets/src/mage/cards/f/FieryAnnihilation.java @@ -36,14 +36,12 @@ public final class FieryAnnihilation extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Fiery Annihilation deals 5 damage to target creature. Exile up to one target Equipment attached to that creature. If that creature would die this turn, exile it instead. - this.getSpellAbility().addEffect(new DamageTargetEffect( - 5, true, "target creature" - )); + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new ExileTargetEffect() .setTargetPointer(new SecondTargetPointer()) .setText("exile up to one target Equipment attached to that creature")); this.getSpellAbility().addEffect(new ExileTargetIfDiesEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter)); } diff --git a/Mage.Sets/src/mage/cards/f/FireLordOzai.java b/Mage.Sets/src/mage/cards/f/FireLordOzai.java new file mode 100644 index 00000000000..d161173dff6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireLordOzai.java @@ -0,0 +1,197 @@ +package mage.cards.f; + +import mage.MageIdentifier; +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetSacrifice; +import mage.target.targetpointer.FixedTargets; +import mage.watchers.Watcher; + +import java.util.*; + +/** + * @author TheElk801 + */ +public final class FireLordOzai extends CardImpl { + + public FireLordOzai(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever Fire Lord Ozai attacks, you may sacrifice another creature. If you do, add an amount of {R} equal to the sacrificed creature's power. Until end of combat, you don't lose this mana as steps end. + this.addAbility(new AttacksTriggeredAbility(new FireLordOzaiSacrificeEffect())); + + // {6}: Exile the top card of each opponent's library. Until end of turn, you may play one of those cards without paying its mana cost. + this.addAbility(new SimpleActivatedAbility(new FireLordOzaiCastEffect(), new GenericManaCost(6)) + .setIdentifier(MageIdentifier.FireLordOzaiAlternateCast), new FireLordOzaiWatcher()); + } + + private FireLordOzai(final FireLordOzai card) { + super(card); + } + + @Override + public FireLordOzai copy() { + return new FireLordOzai(this); + } +} + +class FireLordOzaiSacrificeEffect extends OneShotEffect { + + FireLordOzaiSacrificeEffect() { + super(Outcome.Benefit); + staticText = "you may sacrifice another creature. If you do, add an amount of {R} " + + "equal to the sacrificed creature's power. Until end of combat, you don't lose this mana as steps end"; + } + + private FireLordOzaiSacrificeEffect(final FireLordOzaiSacrificeEffect effect) { + super(effect); + } + + @Override + public FireLordOzaiSacrificeEffect copy() { + return new FireLordOzaiSacrificeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetSacrifice target = new TargetSacrifice(0, 1, StaticFilters.FILTER_ANOTHER_CREATURE); + player.choose(Outcome.Sacrifice, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null || !permanent.sacrifice(source, game)) { + return false; + } + int power = permanent.getPower().getValue(); + if (power > 0) { + player.getManaPool().addMana(Mana.RedMana(power), game, source, Duration.EndOfCombat); + } + return true; + } +} + +class FireLordOzaiCastEffect extends OneShotEffect { + + FireLordOzaiCastEffect() { + super(Outcome.Benefit); + staticText = "exile the top card of each opponent's library. Until end of turn, " + + "you may play one of those cards without paying its mana cost"; + } + + private FireLordOzaiCastEffect(final FireLordOzaiCastEffect effect) { + super(effect); + } + + @Override + public FireLordOzaiCastEffect copy() { + return new FireLordOzaiCastEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Cards cards = new CardsImpl(); + for (UUID playerId : game.getOpponents(source.getControllerId())) { + Optional.ofNullable(playerId) + .map(game::getPlayer) + .map(Player::getLibrary) + .map(library -> library.getFromTop(game)) + .ifPresent(cards::add); + } + if (cards.isEmpty()) { + return false; + } + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.moveCards(cards, Zone.EXILED, source, game); + FireLordOzaiWatcher.storeCardInfo(cards, game, source); + return true; + } +} + +class FireLordOzaiWatcher extends Watcher { + + private static final class FireLordOzaiCondition implements Condition { + + private final UUID token; + + FireLordOzaiCondition(UUID token) { + this.token = token; + } + + @Override + public boolean apply(Game game, Ability source) { + return !game + .getState() + .getWatcher(FireLordOzaiWatcher.class) + .usedTokens + .contains(token); + } + } + + private final Set usedTokens = new HashSet<>(); + private final Map> tokenMap = new HashMap<>(); + + FireLordOzaiWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + switch (event.getType()) { + case SPELL_CAST: + case LAND_PLAYED: + if (event.hasApprovingIdentifier(MageIdentifier.FireLordOzaiAlternateCast)) { + Optional.ofNullable(tokenMap.get(event.getPlayerId())) + .map(map -> map.get(event.getTargetId())) + .ifPresent(usedTokens::add); + } + } + } + + @Override + public void reset() { + super.reset(); + usedTokens.clear(); + tokenMap.clear(); + } + + static void storeCardInfo(Cards cards, Game game, Ability source) { + FireLordOzaiWatcher watcher = game.getState().getWatcher(FireLordOzaiWatcher.class); + UUID token = UUID.randomUUID(); + watcher.tokenMap.computeIfAbsent(source.getControllerId(), x -> new HashMap<>()); + for (UUID cardId : cards) { + watcher.tokenMap.get(source.getControllerId()).put(cardId, token); + } + game.addEffect(new ConditionalAsThoughEffect(new PlayFromNotOwnHandZoneTargetEffect( + Zone.ALL, TargetController.YOU, Duration.EndOfTurn, true, false + ), new FireLordOzaiCondition(token)).setTargetPointer(new FixedTargets(cards, game)), source); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FireNationCadets.java b/Mage.Sets/src/mage/cards/f/FireNationCadets.java index 8b5a49df213..99fac01ed27 100644 --- a/Mage.Sets/src/mage/cards/f/FireNationCadets.java +++ b/Mage.Sets/src/mage/cards/f/FireNationCadets.java @@ -38,7 +38,7 @@ public final class FireNationCadets extends CardImpl { // {2}: This creature gets +1/+0 until end of turn. this.addAbility(new SimpleActivatedAbility( - new BoostSourceEffect(2, 0, Duration.EndOfTurn), new GenericManaCost(2) + new BoostSourceEffect(1, 0, Duration.EndOfTurn), new GenericManaCost(2) )); } diff --git a/Mage.Sets/src/mage/cards/f/FireNationSalvagers.java b/Mage.Sets/src/mage/cards/f/FireNationSalvagers.java new file mode 100644 index 00000000000..7ed0ca54ac0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireNationSalvagers.java @@ -0,0 +1,77 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.OneOrMoreCombatDamagePlayerTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.CounterAnyPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInGraveyard; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FireNationSalvagers extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("creatures you control with counters on them"); + private static final FilterCard filter2 = new FilterCard("creature or Vehicle card from that player's graveyard"); + + static { + filter.add(CounterAnyPredicate.instance); + filter2.add(Predicates.or( + CardType.CREATURE.getPredicate(), + SubType.VEHICLE.getPredicate() + )); + } + + public FireNationSalvagers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Menace + this.addAbility(new MenaceAbility()); + + // When this creature enters, put a +1/+1 counter on target creature or Vehicle you control. + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_CREATURE_OR_VEHICLE)); + this.addAbility(ability); + + // Whenever one or more creatures you control with counters on them deal combat damage to a player, put target creature or Vehicle card from that player's graveyard onto the battlefield under your control. + ability = new OneOrMoreCombatDamagePlayerTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), SetTargetPointer.PLAYER, filter, false + ); + ability.addTarget(new TargetCardInGraveyard(filter2)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true)); + this.addAbility(ability); + } + + private FireNationSalvagers(final FireNationSalvagers card) { + super(card); + } + + @Override + public FireNationSalvagers copy() { + return new FireNationSalvagers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FireNationTurret.java b/Mage.Sets/src/mage/cards/f/FireNationTurret.java index be67f432b7c..5e66014bf20 100644 --- a/Mage.Sets/src/mage/cards/f/FireNationTurret.java +++ b/Mage.Sets/src/mage/cards/f/FireNationTurret.java @@ -44,6 +44,7 @@ public final class FireNationTurret extends CardImpl { ability = new SimpleActivatedAbility( new DamageTargetEffect(50, "it"), new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(50)) + .setText("remove fifty charge counters from {this}") ); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/f/FlamebladeAngel.java b/Mage.Sets/src/mage/cards/f/FlamebladeAngel.java index 2f7bc7c0015..be67527a492 100644 --- a/Mage.Sets/src/mage/cards/f/FlamebladeAngel.java +++ b/Mage.Sets/src/mage/cards/f/FlamebladeAngel.java @@ -28,7 +28,7 @@ public final class FlamebladeAngel extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Whenever a source an opponent controls deals damage to you or a permanent you control, you may have Flameblade Angel deal 1 damage to that source's controller. - Effect effect = new DamageTargetEffect(1, true, "that source's controller"); + Effect effect = new DamageTargetEffect(1).withTargetDescription("that source's controller"); this.addAbility(new SourceDealsDamageToYouTriggeredAbility(effect, StaticFilters.FILTER_PERMANENT, true)); } diff --git a/Mage.Sets/src/mage/cards/f/FlameheartWerewolf.java b/Mage.Sets/src/mage/cards/f/FlameheartWerewolf.java index a1666e46be1..4da8cf33502 100644 --- a/Mage.Sets/src/mage/cards/f/FlameheartWerewolf.java +++ b/Mage.Sets/src/mage/cards/f/FlameheartWerewolf.java @@ -27,7 +27,7 @@ public final class FlameheartWerewolf extends CardImpl { this.nightCard = true; // Whenever Flameheart Werewolf blocks or becomes blocked by a creature, Flameheart Werewolf deals 2 damage to that creature. - this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(2, true, "that creature"))); + this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(2).withTargetDescription("that creature"))); // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Flameheart Werewolf. this.addAbility(new WerewolfBackTriggeredAbility()); diff --git a/Mage.Sets/src/mage/cards/f/FlamesOfTheBloodHand.java b/Mage.Sets/src/mage/cards/f/FlamesOfTheBloodHand.java index ef55c8f7de0..8f03422d378 100644 --- a/Mage.Sets/src/mage/cards/f/FlamesOfTheBloodHand.java +++ b/Mage.Sets/src/mage/cards/f/FlamesOfTheBloodHand.java @@ -24,7 +24,7 @@ public final class FlamesOfTheBloodHand extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Flames of the Blood Hand deals 4 damage to target player. The damage can't be prevented. - this.getSpellAbility().addEffect(new DamageTargetEffect(4, false)); + this.getSpellAbility().addEffect(new DamageTargetEffect(4).withCantBePrevented()); // If that player would gain life this turn, that player gains no life instead. this.getSpellAbility().addEffect(new FlamesOfTheBloodHandReplacementEffect()); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); diff --git a/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java b/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java index ee7cedd0b5a..2a3bfa4abb9 100644 --- a/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java +++ b/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java @@ -6,7 +6,6 @@ import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileSpellEffect; @@ -73,7 +72,8 @@ public final class FlamescrollCelebrant extends ModalDoubleFacedCard { class FlamescrollCelebrantTriggeredAbility extends TriggeredAbilityImpl { FlamescrollCelebrantTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(StaticValue.get(1), true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player")); + setTriggerPhrase("Whenever an opponent activates an ability that isn't a mana ability, "); } private FlamescrollCelebrantTriggeredAbility(final FlamescrollCelebrantTriggeredAbility ability) { @@ -103,11 +103,6 @@ class FlamescrollCelebrantTriggeredAbility extends TriggeredAbilityImpl { return true; } - @Override - public String getRule() { - return "Whenever an opponent activates an ability that isn't a mana ability, " + - "{this} deals 1 damage to that player."; - } } class RevelInSilenceEffect extends ContinuousRuleModifyingEffectImpl { diff --git a/Mage.Sets/src/mage/cards/f/FlashPhotography.java b/Mage.Sets/src/mage/cards/f/FlashPhotography.java index 871cf8e8514..c3fbb6955bb 100644 --- a/Mage.Sets/src/mage/cards/f/FlashPhotography.java +++ b/Mage.Sets/src/mage/cards/f/FlashPhotography.java @@ -26,7 +26,7 @@ public final class FlashPhotography extends CardImpl { // You may cast this spell as though it had flash if it targets a permanent you control. this.addAbility(new CastAsThoughItHadFlashIfConditionAbility( - condition, "you may cast this spell as though it had flash if it targets a permanent you control" + condition, "you may cast this spell as though it had flash if it targets a permanent you control." )); // Create a token that's a copy of target permanent. diff --git a/Mage.Sets/src/mage/cards/f/FlexibleWaterbender.java b/Mage.Sets/src/mage/cards/f/FlexibleWaterbender.java index c315c30d5e6..5ccc0816900 100644 --- a/Mage.Sets/src/mage/cards/f/FlexibleWaterbender.java +++ b/Mage.Sets/src/mage/cards/f/FlexibleWaterbender.java @@ -32,7 +32,7 @@ public final class FlexibleWaterbender extends CardImpl { // Waterbend {3}: This creature has base power and toughness 5/2 until end of turn. this.addAbility(new SimpleActivatedAbility( - new SetBasePowerToughnessSourceEffect(3, 2, Duration.EndOfTurn), new WaterbendCost(3) + new SetBasePowerToughnessSourceEffect(5, 2, Duration.EndOfTurn), new WaterbendCost(3) )); } diff --git a/Mage.Sets/src/mage/cards/f/FoggySwampVisions.java b/Mage.Sets/src/mage/cards/f/FoggySwampVisions.java new file mode 100644 index 00000000000..f1ad9b03694 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FoggySwampVisions.java @@ -0,0 +1,94 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; +import mage.target.targetadjustment.XManaValueTargetAdjuster; +import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FoggySwampVisions extends CardImpl { + + public FoggySwampVisions(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); + + // As an additional cost to cast this spell, waterbend {X}. + this.getSpellAbility().addCost(new WaterbendCost("{X}")); + + // Exile X target creature cards from graveyards. For each creature card exiled this way, create a token that's a copy of it. At the beginning of your next end step, sacrifice those tokens. + this.getSpellAbility().addEffect(new FoggySwampVisionsEffect()); + this.getSpellAbility().addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURES)); + this.getSpellAbility().setTargetAdjuster(new XManaValueTargetAdjuster()); + } + + private FoggySwampVisions(final FoggySwampVisions card) { + super(card); + } + + @Override + public FoggySwampVisions copy() { + return new FoggySwampVisions(this); + } +} + +class FoggySwampVisionsEffect extends OneShotEffect { + + FoggySwampVisionsEffect() { + super(Outcome.Benefit); + staticText = "exile X target creature cards from graveyards. For each creature card exiled this way, " + + "create a token that's a copy of it. At the beginning of your next end step, sacrifice those tokens."; + } + + private FoggySwampVisionsEffect(final FoggySwampVisionsEffect effect) { + super(effect); + } + + @Override + public FoggySwampVisionsEffect copy() { + return new FoggySwampVisionsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source)); + if (player == null || cards.isEmpty()) { + return false; + } + player.moveCards(cards, Zone.EXILED, source, game); + cards.retainZone(Zone.EXILED, game); + Set permanents = new HashSet<>(); + for (Card card : cards.getCards(game)) { + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); + effect.setTargetPointer(new FixedTarget(card, game)); + effect.apply(game, source); + permanents.addAll(effect.getAddedPermanents()); + } + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new SacrificeTargetEffect("sacrifice those tokens") + .setTargetPointer(new FixedTargets(permanents, game)), + TargetController.YOU + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/Fumble.java b/Mage.Sets/src/mage/cards/f/Fumble.java index b0ddcaa6973..8fbdb8b027e 100644 --- a/Mage.Sets/src/mage/cards/f/Fumble.java +++ b/Mage.Sets/src/mage/cards/f/Fumble.java @@ -97,7 +97,7 @@ class FumbleEffect extends OneShotEffect { effect.setTargetPointer(new FixedTarget(attachment, game)); game.addEffect(effect, source); if (newCreature != null) { - attachment.attachTo(newCreature.getId(), source, game); + newCreature.addAttachment(attachment.getId(), source, game); } } } diff --git a/Mage.Sets/src/mage/cards/f/FuneralRoomAwakeningHall.java b/Mage.Sets/src/mage/cards/f/FuneralRoomAwakeningHall.java index b85c3d4b205..a10d8b8f31e 100644 --- a/Mage.Sets/src/mage/cards/f/FuneralRoomAwakeningHall.java +++ b/Mage.Sets/src/mage/cards/f/FuneralRoomAwakeningHall.java @@ -30,13 +30,13 @@ public final class FuneralRoomAwakeningHall extends RoomCard { StaticFilters.FILTER_CONTROLLED_A_CREATURE ); left.addEffect(new GainLifeEffect(1).concatBy("and")); + this.getLeftHalfCard().addAbility(left); // Awakening Hall: When you unlock this door, return all creature cards from your graveyard to the battlefield. Ability right = new UnlockThisDoorTriggeredAbility( new ReturnFromYourGraveyardToBattlefieldAllEffect(StaticFilters.FILTER_CARD_CREATURES), false, false ); - - this.addRoomAbilities(left, right); + this.getRightHalfCard().addAbility(right); } private FuneralRoomAwakeningHall(final FuneralRoomAwakeningHall card) { diff --git a/Mage.Sets/src/mage/cards/f/FuriousReprisal.java b/Mage.Sets/src/mage/cards/f/FuriousReprisal.java index 4f99b3d599f..1ead08841c9 100644 --- a/Mage.Sets/src/mage/cards/f/FuriousReprisal.java +++ b/Mage.Sets/src/mage/cards/f/FuriousReprisal.java @@ -18,7 +18,7 @@ public final class FuriousReprisal extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); // Furious Reprisal deals 2 damage to each of two target creatures and/or players. - this.getSpellAbility().addEffect(new DamageTargetEffect(2, true, "each of two targets")); + this.getSpellAbility().addEffect(new DamageTargetEffect(2).withTargetDescription("each of two targets")); this.getSpellAbility().addTarget(new TargetAnyTarget(2, 2)); } diff --git a/Mage.Sets/src/mage/cards/f/FurnaceScamp.java b/Mage.Sets/src/mage/cards/f/FurnaceScamp.java index 3eabea17458..fd55df86f03 100644 --- a/Mage.Sets/src/mage/cards/f/FurnaceScamp.java +++ b/Mage.Sets/src/mage/cards/f/FurnaceScamp.java @@ -28,7 +28,7 @@ public final class FurnaceScamp extends CardImpl { // Whenever Furnace Scamp deals combat damage to a player, you may sacrifice it. If you do, Furnace Scamp deals 3 damage to that player. Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DoIfCostPaid( - new DamageTargetEffect(3, true, "that player"), new SacrificeSourceCost() + new DamageTargetEffect(3).withTargetDescription("that player"), new SacrificeSourceCost() ), false, true); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/Galedrifter.java b/Mage.Sets/src/mage/cards/g/Galedrifter.java index c76b1198447..e8ac03ad82b 100644 --- a/Mage.Sets/src/mage/cards/g/Galedrifter.java +++ b/Mage.Sets/src/mage/cards/g/Galedrifter.java @@ -1,11 +1,9 @@ package mage.cards.g; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.keyword.DisturbAbility; import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -14,21 +12,29 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class Galedrifter extends CardImpl { +public final class Galedrifter extends TransformingDoubleFacedCard { public Galedrifter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HIPPOGRIFF}, "{3}{U}", + "Waildrifter", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HIPPOGRIFF, SubType.SPIRIT}, "U"); - this.subtype.add(SubType.HIPPOGRIFF); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.w.Waildrifter.class; + this.getLeftHalfCard().setPT(3, 2); + this.getRightHalfCard().setPT(2, 2); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Disturb {4}{U} - this.addAbility(new DisturbAbility(this, "{4}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{4}{U}")); + + // Waildrifter + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // If Waildrifter would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private Galedrifter(final Galedrifter card) { diff --git a/Mage.Sets/src/mage/cards/g/GavelOfTheRighteous.java b/Mage.Sets/src/mage/cards/g/GavelOfTheRighteous.java index bbe616ea942..00e03c24ce8 100644 --- a/Mage.Sets/src/mage/cards/g/GavelOfTheRighteous.java +++ b/Mage.Sets/src/mage/cards/g/GavelOfTheRighteous.java @@ -1,7 +1,6 @@ package mage.cards.g; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.OrCost; @@ -14,9 +13,13 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.EquipAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.Counter; import mage.counters.CounterType; import mage.game.Game; @@ -57,7 +60,7 @@ public final class GavelOfTheRighteous extends CardImpl { Outcome.BoostCreature, new OrCost( "Pay {3} or remove a counter from {this}", - new GenericManaCost(3), new RemoveCountersSourceCost() + new GenericManaCost(3), new RemoveCountersSourceCost(1) ), false )); diff --git a/Mage.Sets/src/mage/cards/g/GenerousSoul.java b/Mage.Sets/src/mage/cards/g/GenerousSoul.java deleted file mode 100644 index d0d85e6ad79..00000000000 --- a/Mage.Sets/src/mage/cards/g/GenerousSoul.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -public final class GenerousSoul extends CardImpl { - - public GenerousSoul(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setWhite(true); - - // This is the back half of Beloved Beggar - this.nightCard = true; - - this.addAbility(FlyingAbility.getInstance()); - this.addAbility(VigilanceAbility.getInstance()); - - // If Generous Soul would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private GenerousSoul(final GenerousSoul card) { - super(card); - } - - @Override - public GenerousSoul copy() { - return new GenerousSoul(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GeodeGrotto.java b/Mage.Sets/src/mage/cards/g/GeodeGrotto.java deleted file mode 100644 index 9bcf1d2c4c3..00000000000 --- a/Mage.Sets/src/mage/cards/g/GeodeGrotto.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.g; - -import mage.abilities.Ability; -import mage.abilities.common.ActivateAsSorceryActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.hint.common.ArtifactYouControlHint; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.mana.RedManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class GeodeGrotto extends CardImpl { - - public GeodeGrotto(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.subtype.add(SubType.CAVE); - this.nightCard = true; - - // {T}: Add {R}. - this.addAbility(new RedManaAbility()); - - // {2}{R}, {T}: Until end of turn, target creature gains haste and gets +X/+0, where X is the number of artifacts you control. Activate only as a sorcery. - Ability ability = new ActivateAsSorceryActivatedAbility(new GainAbilityTargetEffect(HasteAbility.getInstance()) - .setText("Until end of turn, target creature gains haste"), new ManaCostsImpl<>("{2}{R}")); - ability.addCost(new TapSourceCost()); - ability.addEffect(new BoostTargetEffect( - ArtifactYouControlCount.instance, StaticValue.get(0) - ).setText("and gets +X/+0, where X is the number of artifacts you control")); - ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability.addHint(ArtifactYouControlHint.instance)); - } - - private GeodeGrotto(final GeodeGrotto card) { - super(card); - } - - @Override - public GeodeGrotto copy() { - return new GeodeGrotto(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GhostlyCastigator.java b/Mage.Sets/src/mage/cards/g/GhostlyCastigator.java deleted file mode 100644 index bb9f5f62e56..00000000000 --- a/Mage.Sets/src/mage/cards/g/GhostlyCastigator.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.target.common.TargetCardInYourGraveyard; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class GhostlyCastigator extends CardImpl { - - public GhostlyCastigator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // When Ghostly Castigator enters the battlefield, you may shuffle up to three target cards from your graveyard into your library. - Ability ability = new EntersBattlefieldTriggeredAbility(new ShuffleIntoLibraryTargetEffect(), true); - ability.addTarget(new TargetCardInYourGraveyard(0, 3)); - this.addAbility(ability); - - // If Ghostly Castigator would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private GhostlyCastigator(final GhostlyCastigator card) { - super(card); - } - - @Override - public GhostlyCastigator copy() { - return new GhostlyCastigator(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GibberingFiend.java b/Mage.Sets/src/mage/cards/g/GibberingFiend.java index 0fe87e51653..e119ecfb373 100644 --- a/Mage.Sets/src/mage/cards/g/GibberingFiend.java +++ b/Mage.Sets/src/mage/cards/g/GibberingFiend.java @@ -35,7 +35,7 @@ public final class GibberingFiend extends CardImpl { // Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, // Gibbering Fiend deals 1 damage to that player. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.OPPONENT, new DamageTargetEffect(1, true, "that player"), false + TargetController.OPPONENT, new DamageTargetEffect(1).withTargetDescription("that player"), false ).withInterveningIf(DeliriumCondition.instance).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } diff --git a/Mage.Sets/src/mage/cards/g/GitaxianMindstinger.java b/Mage.Sets/src/mage/cards/g/GitaxianMindstinger.java deleted file mode 100644 index dbd1fe8fcbb..00000000000 --- a/Mage.Sets/src/mage/cards/g/GitaxianMindstinger.java +++ /dev/null @@ -1,45 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.common.DealsCombatDamageToAPlayerOrBattleTriggeredAbility; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.keyword.DeathtouchAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class GitaxianMindstinger extends CardImpl { - - public GitaxianMindstinger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlue(true); - this.color.setBlack(true); - this.nightCard = true; - - // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); - - // Whenever Gitaxian Mindstinger deals combat damage to a player or battle, draw a card. - this.addAbility(new DealsCombatDamageToAPlayerOrBattleTriggeredAbility(new DrawCardSourceControllerEffect(1),false)); - } - - private GitaxianMindstinger(final GitaxianMindstinger card) { - super(card); - } - - @Override - public GitaxianMindstinger copy() { - return new GitaxianMindstinger(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GnarledGrovestrider.java b/Mage.Sets/src/mage/cards/g/GnarledGrovestrider.java deleted file mode 100644 index ad4fced764d..00000000000 --- a/Mage.Sets/src/mage/cards/g/GnarledGrovestrider.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * - * @author weirddan455 - */ -public class GnarledGrovestrider extends CardImpl { - - public GnarledGrovestrider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.TREEFOLK); - this.color.setGreen(true); - - // Back half of Dormant Grove - this.nightCard = true; - - this.power = new MageInt(3); - this.toughness = new MageInt(6); - - this.addAbility(VigilanceAbility.getInstance()); - - // Other creatures you control have vigilance. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURES, true - ))); - } - - private GnarledGrovestrider(final GnarledGrovestrider card) { - super(card); - } - - @Override - public GnarledGrovestrider copy() { - return new GnarledGrovestrider(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GwenomRemorseless.java b/Mage.Sets/src/mage/cards/g/GwenomRemorseless.java index dc637d370e3..a6b24fab20e 100644 --- a/Mage.Sets/src/mage/cards/g/GwenomRemorseless.java +++ b/Mage.Sets/src/mage/cards/g/GwenomRemorseless.java @@ -46,7 +46,7 @@ public final class GwenomRemorseless extends CardImpl { // Whenever Gwenom attacks, until end of turn you may look at the top card of your library any time and you may play cards from the top of your library. If you cast a spell this way, pay life equal to its mana value rather than pay its mana cost. ContinuousEffect libraryAnyTimeEffect = new LookAtTopCardOfLibraryAnyTimeEffect(Duration.EndOfTurn); - libraryAnyTimeEffect.setText("until end of turn you may look at the top card of your library any time"); + libraryAnyTimeEffect.setText("until end of turn, you may look at the top card of your library any time"); libraryAnyTimeEffect.concatBy(" "); AsThoughEffectImpl playCardEffect = new GwenomRemorselessPlayTopCardEffect(); playCardEffect.concatBy("and"); diff --git a/Mage.Sets/src/mage/cards/h/HadesSorcererOfEld.java b/Mage.Sets/src/mage/cards/h/HadesSorcererOfEld.java deleted file mode 100644 index 270bb430e07..00000000000 --- a/Mage.Sets/src/mage/cards/h/HadesSorcererOfEld.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.MyTurnCondition; -import mage.abilities.decorator.ConditionalAsThoughEffect; -import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect; -import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; -import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; - -import java.util.UUID; - -/** - * @author balazskristof - */ -public final class HadesSorcererOfEld extends CardImpl { - - public HadesSorcererOfEld(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AVATAR); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - - this.color.setBlue(true); - this.color.setBlack(true); - this.nightCard = true; - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - - // Echo of the Lost -- During your turn you may play cards from your graveyard. - this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( - PlayFromGraveyardControllerEffect.playCards(), MyTurnCondition.instance - ).setText("during your turn, you may play cards from your graveyard")).withFlavorWord("Echo of the Lost")); - - // If a card or token would be put into your graveyard from anywhere, exile it instead. - this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(true, true))); - } - - private HadesSorcererOfEld(final HadesSorcererOfEld card) { - super(card); - } - - @Override - public HadesSorcererOfEld copy() { - return new HadesSorcererOfEld(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HamaTheBloodbender.java b/Mage.Sets/src/mage/cards/h/HamaTheBloodbender.java new file mode 100644 index 00000000000..034e8a07f6e --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HamaTheBloodbender.java @@ -0,0 +1,152 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.CostsImpl; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.MillCardsTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInGraveyard; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HamaTheBloodbender extends CardImpl { + + public HamaTheBloodbender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U/B}{U/B}{U/B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARLOCK); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Hama enters, target opponent mills three cards. Exile up to one noncreature, nonland card from that player's graveyard. For as long as you control Hama, you may cast the exiled card during your turn by waterbending {X} rather than paying its mana cost, where X is its mana value. + Ability ability = new EntersBattlefieldTriggeredAbility(new MillCardsTargetEffect(3)); + ability.addEffect(new HamaTheBloodbenderExileEffect()); + this.addAbility(ability); + } + + private HamaTheBloodbender(final HamaTheBloodbender card) { + super(card); + } + + @Override + public HamaTheBloodbender copy() { + return new HamaTheBloodbender(this); + } +} + +class HamaTheBloodbenderExileEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("noncreature, nonland card"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + filter.add(Predicates.not(CardType.LAND.getPredicate())); + } + + HamaTheBloodbenderExileEffect() { + super(Outcome.Benefit); + staticText = "Exile up to one noncreature, nonland card from that player's graveyard. " + + "For as long as you control {this}, you may cast the exiled card during your turn " + + "by waterbending {X} rather than paying its mana cost, where X is its mana value."; + } + + private HamaTheBloodbenderExileEffect(final HamaTheBloodbenderExileEffect effect) { + super(effect); + } + + @Override + public HamaTheBloodbenderExileEffect copy() { + return new HamaTheBloodbenderExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || opponent == null) { + return false; + } + TargetCard target = new TargetCardInGraveyard(0, 1, filter, true); + controller.choose(Outcome.PlayForFree, opponent.getGraveyard(), target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + controller.moveCardsToExile( + card, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + if (source.getSourcePermanentIfItStillExists(game) != null) { + game.addEffect(new HamaTheBloodbenderCastEffect(card, game), source); + } + return true; + } +} + +class HamaTheBloodbenderCastEffect extends AsThoughEffectImpl { + + HamaTheBloodbenderCastEffect(Card card, Game game) { + super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.WhileControlled, Outcome.AIDontUseIt); + this.setTargetPointer(new FixedTarget(card, game)); + } + + private HamaTheBloodbenderCastEffect(final HamaTheBloodbenderCastEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public HamaTheBloodbenderCastEffect copy() { + return new HamaTheBloodbenderCastEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (!game.isActivePlayer(affectedControllerId) || !source.isControlledBy(affectedControllerId)) { + return false; + } + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (card == null) { + discard(); + return false; + } + if (!card.getId().equals(objectId)) { + return false; + } + Player player = game.getPlayer(affectedControllerId); + if (player == null) { + return false; + } + Costs newCosts = new CostsImpl<>(); + newCosts.add(new WaterbendCost(card.getManaValue())); + newCosts.addAll(card.getSpellAbility().getCosts()); + player.setCastSourceIdWithAlternateMana(card.getId(), null, newCosts); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HandOfEnlightenment.java b/Mage.Sets/src/mage/cards/h/HandOfEnlightenment.java deleted file mode 100644 index bd13b8a3582..00000000000 --- a/Mage.Sets/src/mage/cards/h/HandOfEnlightenment.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class HandOfEnlightenment extends CardImpl { - - public HandOfEnlightenment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.MONK); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setWhite(true); - this.nightCard = true; - - // First strike - this.addAbility(FirstStrikeAbility.getInstance()); - } - - private HandOfEnlightenment(final HandOfEnlightenment card) { - super(card); - } - - @Override - public HandOfEnlightenment copy() { - return new HandOfEnlightenment(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HarshMentor.java b/Mage.Sets/src/mage/cards/h/HarshMentor.java index 281c340514d..1c5332d40e4 100644 --- a/Mage.Sets/src/mage/cards/h/HarshMentor.java +++ b/Mage.Sets/src/mage/cards/h/HarshMentor.java @@ -2,7 +2,6 @@ package mage.cards.h; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.Card; @@ -48,7 +47,8 @@ public final class HarshMentor extends CardImpl { class HarshMentorTriggeredAbility extends TriggeredAbilityImpl { HarshMentorTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(StaticValue.get(2), true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player")); + setTriggerPhrase("Whenever an opponent activates an ability of an artifact, creature, or land on the battlefield, if it isn't a mana ability, "); } private HarshMentorTriggeredAbility(final HarshMentorTriggeredAbility ability) { @@ -82,8 +82,4 @@ class HarshMentorTriggeredAbility extends TriggeredAbilityImpl { return false; } - @Override - public String getRule() { - return "Whenever an opponent activates an ability of an artifact, creature, or land on the battlefield, if it isn't a mana ability, {this} deals 2 damage to that player."; - } } diff --git a/Mage.Sets/src/mage/cards/h/HeiBaiForestGuardian.java b/Mage.Sets/src/mage/cards/h/HeiBaiForestGuardian.java new file mode 100644 index 00000000000..ab99c0180bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HeiBaiForestGuardian.java @@ -0,0 +1,115 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledEnchantmentPermanent; +import mage.game.Game; +import mage.game.permanent.token.SpiritWorldToken; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HeiBaiForestGuardian extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledEnchantmentPermanent(); + + static { + filter.add(SuperType.LEGENDARY.getPredicate()); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Legendary enchantments you control", xValue); + + public HeiBaiForestGuardian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BEAR); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Hei Bai enters, reveal cards from the top of your library until you reveal a Shrine card. You may put that card onto the battlefield. Then shuffle. + this.addAbility(new EntersBattlefieldTriggeredAbility(new HeiBaiForestGuardianEffect())); + + // {W}{U}{B}{R}{G}, {T}: For each legendary enchantment you control, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures." + Ability ability = new SimpleActivatedAbility( + new CreateTokenEffect(new SpiritWorldToken(), xValue) + .setText("for each legendary enchantment you control, create a 1/1 colorless Spirit creature " + + "token with \"This token can't block or be blocked by non-Spirit creatures.\""), + new ManaCostsImpl<>("{W}{U}{B}{R}{G}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability.addHint(hint)); + } + + private HeiBaiForestGuardian(final HeiBaiForestGuardian card) { + super(card); + } + + @Override + public HeiBaiForestGuardian copy() { + return new HeiBaiForestGuardian(this); + } +} + +class HeiBaiForestGuardianEffect extends OneShotEffect { + + HeiBaiForestGuardianEffect() { + super(Outcome.Benefit); + staticText = "reveal cards from the top of your library until you reveal a Shrine card. " + + "You may put that card onto the battlefield. Then shuffle."; + } + + private HeiBaiForestGuardianEffect(final HeiBaiForestGuardianEffect effect) { + super(effect); + } + + @Override + public HeiBaiForestGuardianEffect copy() { + return new HeiBaiForestGuardianEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + Card card = getCard(player, cards, game, source); + player.revealCards(source, cards, game); + if (card != null && player.chooseUse( + Outcome.PutCardInPlay, "Put " + card.getName() + " onto the battlefield?", source, game + )) { + player.moveCards(card, Zone.BATTLEFIELD, source, game); + } + player.shuffleLibrary(source, game); + return true; + } + + private static Card getCard(Player player, Cards cards, Game game, Ability source) { + for (Card card : player.getLibrary().getCards(game)) { + cards.add(card); + if (card.hasSubtype(SubType.SHRINE, game)) { + return card; + } + } + return null; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HellfireMongrel.java b/Mage.Sets/src/mage/cards/h/HellfireMongrel.java index 527669c7bd4..97ae001b9d0 100644 --- a/Mage.Sets/src/mage/cards/h/HellfireMongrel.java +++ b/Mage.Sets/src/mage/cards/h/HellfireMongrel.java @@ -33,7 +33,7 @@ public final class HellfireMongrel extends CardImpl { // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Hellfire Mongrel deals 2 damage to that player. this.addAbility(new BeginningOfUpkeepTriggeredAbility( TargetController.OPPONENT, - new DamageTargetEffect(2, true, "that player"), + new DamageTargetEffect(2).withTargetDescription("that player"), false ).withInterveningIf(condition)); } diff --git a/Mage.Sets/src/mage/cards/h/HermiticHerbalist.java b/Mage.Sets/src/mage/cards/h/HermiticHerbalist.java new file mode 100644 index 00000000000..88a1a4689aa --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HermiticHerbalist.java @@ -0,0 +1,53 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.mana.ConditionalAnyColorManaAbility; +import mage.abilities.mana.conditional.ConditionalSpellManaBuilder; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HermiticHerbalist extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("Lesson spells"); + + static { + filter.add(SubType.LESSON.getPredicate()); + } + + public HermiticHerbalist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + + // {T}: Add two mana in any combination of colors. Spend this mana only to cast Lesson spells. + this.addAbility(new ConditionalAnyColorManaAbility( + new TapSourceCost(), 2, new ConditionalSpellManaBuilder(filter), false + )); + } + + private HermiticHerbalist(final HermiticHerbalist card) { + super(card); + } + + @Override + public HermiticHerbalist copy() { + return new HermiticHerbalist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HinterlandLogger.java b/Mage.Sets/src/mage/cards/h/HinterlandLogger.java index 51df4a09630..ffd994ac6ab 100644 --- a/Mage.Sets/src/mage/cards/h/HinterlandLogger.java +++ b/Mage.Sets/src/mage/cards/h/HinterlandLogger.java @@ -1,10 +1,10 @@ package mage.cards.h; -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,20 +13,29 @@ import java.util.UUID; /** * @author fireshoes */ -public final class HinterlandLogger extends CardImpl { +public final class HinterlandLogger extends TransformingDoubleFacedCard { public HinterlandLogger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{1}{G}", + "Timber Shredder", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.secondSideCardClazz = mage.cards.t.TimberShredder.class; + this.getLeftHalfCard().setPT(2, 1); + this.getRightHalfCard().setPT(4, 2); // At the beginning of each upkeep, if no spells were cast last turn, transform Hinterland Logger. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Timber Shredder + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Timber Shredder. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); + + } private HinterlandLogger(final HinterlandLogger card) { diff --git a/Mage.Sets/src/mage/cards/h/HogMonkeyRampage.java b/Mage.Sets/src/mage/cards/h/HogMonkeyRampage.java new file mode 100644 index 00000000000..a42a9636017 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HogMonkeyRampage.java @@ -0,0 +1,67 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.FightTargetsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HogMonkeyRampage extends CardImpl { + + public HogMonkeyRampage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R/G}"); + + // Choose target creature you control and target creature an opponent controls. Put a +1/+1 counter on the creature you control if it has power 4 or greater. Then those creatures fight each other. + this.getSpellAbility().addEffect(new HogMonkeyRampageEffect()); + this.getSpellAbility().addEffect(new FightTargetsEffect().setText("Then those creatures fight each other")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); + } + + private HogMonkeyRampage(final HogMonkeyRampage card) { + super(card); + } + + @Override + public HogMonkeyRampage copy() { + return new HogMonkeyRampage(this); + } +} + +class HogMonkeyRampageEffect extends OneShotEffect { + + HogMonkeyRampageEffect() { + super(Outcome.Benefit); + staticText = "choose target creature you control and target creature an opponent controls. " + + "Put a +1/+1 counter on the creature you control if it has power 4 or greater"; + } + + private HogMonkeyRampageEffect(final HogMonkeyRampageEffect effect) { + super(effect); + } + + @Override + public HogMonkeyRampageEffect copy() { + return new HogMonkeyRampageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + return permanent != null + && permanent.getPower().getValue() >= 4 + && permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HollowhengeHuntmaster.java b/Mage.Sets/src/mage/cards/h/HollowhengeHuntmaster.java deleted file mode 100644 index efe1f2b1abb..00000000000 --- a/Mage.Sets/src/mage/cards/h/HollowhengeHuntmaster.java +++ /dev/null @@ -1,63 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.AddCountersAllEffect; -import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.NightboundAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.counters.CounterType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class HollowhengeHuntmaster extends CardImpl { - - public HollowhengeHuntmaster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.color.setGreen(true); - this.nightCard = true; - - // Hexproof - this.addAbility(HexproofAbility.getInstance()); - - // Other permanents you control have hexproof. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - HexproofAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENTS, true - ))); - - // At the beginning of combat on your turn, put two +1/+1 counters on each creature you control. - this.addAbility(new BeginningOfCombatTriggeredAbility( - new AddCountersAllEffect( - CounterType.P1P1.createInstance(2), - StaticFilters.FILTER_CONTROLLED_CREATURE - ) - )); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private HollowhengeHuntmaster(final HollowhengeHuntmaster card) { - super(card); - } - - @Override - public HollowhengeHuntmaster copy() { - return new HollowhengeHuntmaster(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HonestWork.java b/Mage.Sets/src/mage/cards/h/HonestWork.java new file mode 100644 index 00000000000..3d79617209b --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HonestWork.java @@ -0,0 +1,153 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.TapEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HonestWork extends CardImpl { + + public HonestWork(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature an opponent controls + TargetPermanent auraTarget = new TargetOpponentsCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget)); + + // When this Aura enters, tap enchanted creature and remove all counters from it. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()); + ability.addEffect(new HonestWorkCountersEffect()); + this.addAbility(ability); + + // Enchanted creature loses all abilities and is a Citizen with base power and toughness 1/1 and "{T}: Add {C}" named Humble Merchant. + this.addAbility(new SimpleStaticAbility(new HonestWorkAbilityEffect())); + } + + private HonestWork(final HonestWork card) { + super(card); + } + + @Override + public HonestWork copy() { + return new HonestWork(this); + } +} + +class HonestWorkCountersEffect extends OneShotEffect { + + HonestWorkCountersEffect() { + super(Outcome.Benefit); + staticText = "and remove all counters from it"; + } + + private HonestWorkCountersEffect(final HonestWorkCountersEffect effect) { + super(effect); + } + + @Override + public HonestWorkCountersEffect copy() { + return new HonestWorkCountersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return Optional + .ofNullable((Permanent) getValue("permanentEnteredBattlefield")) + .map(Permanent::getAttachedTo) + .map(game::getPermanent) + .filter(permanent -> permanent.removeAllCounters(source, game) > 0) + .isPresent(); + } +} + +class HonestWorkAbilityEffect extends ContinuousEffectImpl { + + HonestWorkAbilityEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "enchanted creature loses all abilities and is a Citizen " + + "with base power and toughness 1/1 and \"{T}: Add {C}\" named Humble Merchant."; + } + + private HonestWorkAbilityEffect(final HonestWorkAbilityEffect effect) { + super(effect); + } + + @Override + public HonestWorkAbilityEffect copy() { + return new HonestWorkAbilityEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .map(Permanent::getAttachedTo) + .map(game::getPermanent) + .orElse(null); + if (permanent == null) { + return false; + } + switch (layer) { + case TextChangingEffects_3: + permanent.setName("Humble Merchant"); + return true; + case TypeChangingEffects_4: + permanent.removeAllCreatureTypes(); + permanent.addSubType(game, SubType.CITIZEN); + return true; + case AbilityAddingRemovingEffects_6: + permanent.removeAllAbilities(source.getSourceId(), game); + permanent.addAbility(new ColorlessManaAbility(), source.getSourceId(), game); + return true; + case PTChangingEffects_7: + if (sublayer != SubLayer.SetPT_7b) { + return false; + } + permanent.getPower().setModifiedBaseValue(1); + permanent.getToughness().setModifiedBaseValue(1); + return true; + default: + return false; + } + } + + @Override + public boolean hasLayer(Layer layer) { + switch (layer) { + case TextChangingEffects_3: + case TypeChangingEffects_4: + case AbilityAddingRemovingEffects_6: + case PTChangingEffects_7: + return true; + default: + return false; + } + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HookHauntDrifter.java b/Mage.Sets/src/mage/cards/h/HookHauntDrifter.java deleted file mode 100644 index b63a9bb5b09..00000000000 --- a/Mage.Sets/src/mage/cards/h/HookHauntDrifter.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class HookHauntDrifter extends CardImpl { - - public HookHauntDrifter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(1); - this.toughness = new MageInt(2); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // If Hook-Haunt Drifter would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private HookHauntDrifter(final HookHauntDrifter card) { - super(card); - } - - @Override - public HookHauntDrifter copy() { - return new HookHauntDrifter(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HuntmasterOfTheFells.java b/Mage.Sets/src/mage/cards/h/HuntmasterOfTheFells.java index 5994fd49068..ca890cf5573 100644 --- a/Mage.Sets/src/mage/cards/h/HuntmasterOfTheFells.java +++ b/Mage.Sets/src/mage/cards/h/HuntmasterOfTheFells.java @@ -1,43 +1,64 @@ package mage.cards.h; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.common.TransformsOrEntersTriggeredAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.WolfToken; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponentOrPlaneswalker; +import mage.target.targetpointer.EachTargetPointer; +import java.util.Set; import java.util.UUID; /** * @author BetaSteward */ -public final class HuntmasterOfTheFells extends CardImpl { +public final class HuntmasterOfTheFells extends TransformingDoubleFacedCard { public HuntmasterOfTheFells(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{R}{G}", + "Ravager of the Fells", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "RG" + ); - this.secondSideCardClazz = mage.cards.r.RavagerOfTheFells.class; - - this.power = new MageInt(2); - this.toughness = new MageInt(2); + this.getLeftHalfCard().setPT(2, 2); + this.getRightHalfCard().setPT(4, 4); // Whenever this creature enters the battlefield or transforms into Huntmaster of the Fells, create a 2/2 green Wolf creature token and you gain 2 life. Ability ability = new TransformsOrEntersTriggeredAbility(new CreateTokenEffect(new WolfToken()), false); ability.addEffect(new GainLifeEffect(2).concatBy("and")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the beginning of each upkeep, if no spells were cast last turn, transform Huntmaster of the Fells. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + + // Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. + Ability ravagerAbility = new TransformIntoSourceTriggeredAbility( + new RavagerOfTheFellsEffect(), false, true + ); + ravagerAbility.addTarget(new TargetOpponentOrPlaneswalker()); + ravagerAbility.addTarget(new RavagerOfTheFellsTarget()); + this.getRightHalfCard().addAbility(ravagerAbility); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private HuntmasterOfTheFells(final HuntmasterOfTheFells card) { @@ -49,3 +70,70 @@ public final class HuntmasterOfTheFells extends CardImpl { return new HuntmasterOfTheFells(this); } } + +class RavagerOfTheFellsEffect extends OneShotEffect { + + RavagerOfTheFellsEffect() { + super(Outcome.Damage); + this.setTargetPointer(new EachTargetPointer()); + staticText = "it deals 2 damage to target opponent or planeswalker and 2 damage " + + "to up to one target creature that player or that planeswalker's controller controls."; + } + + private RavagerOfTheFellsEffect(final RavagerOfTheFellsEffect effect) { + super(effect); + } + + @Override + public RavagerOfTheFellsEffect copy() { + return new RavagerOfTheFellsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID targetId : getTargetPointer().getTargets(game, source)) { + game.damagePlayerOrPermanent( + targetId, 2, source.getSourceId(), source, + game, false, true + ); + } + return true; + } + +} + +class RavagerOfTheFellsTarget extends TargetPermanent { + + RavagerOfTheFellsTarget() { + super(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE); + } + + private RavagerOfTheFellsTarget(final RavagerOfTheFellsTarget target) { + super(target); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); + + Player needPlayer = game.getPlayerOrPlaneswalkerController(source.getFirstTarget()); + if (needPlayer == null) { + // playable or not selected - use any + } else { + // filter by controller + possibleTargets.removeIf(id -> { + Permanent permanent = game.getPermanent(id); + return permanent == null + || permanent.getId().equals(source.getFirstTarget()) + || !permanent.isControlledBy(needPlayer.getId()); + }); + } + + return possibleTargets; + } + + @Override + public RavagerOfTheFellsTarget copy() { + return new RavagerOfTheFellsTarget(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IchneumonDruid.java b/Mage.Sets/src/mage/cards/i/IchneumonDruid.java index 174558742a7..7f17695d748 100644 --- a/Mage.Sets/src/mage/cards/i/IchneumonDruid.java +++ b/Mage.Sets/src/mage/cards/i/IchneumonDruid.java @@ -1,11 +1,7 @@ package mage.cards.i; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; @@ -20,6 +16,10 @@ import mage.game.stack.Spell; import mage.target.targetpointer.FixedTarget; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** * * @author L_J @@ -50,7 +50,8 @@ public final class IchneumonDruid extends CardImpl { class IchneumonDruidAbility extends TriggeredAbilityImpl { IchneumonDruidAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(StaticValue.get(4), false, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(4).withTargetDescription("that player")); + setTriggerPhrase("Whenever an opponent casts an instant spell other than the first instant spell that player casts each turn, "); } private IchneumonDruidAbility(final IchneumonDruidAbility ability) { @@ -84,10 +85,6 @@ class IchneumonDruidAbility extends TriggeredAbilityImpl { return false; } - @Override - public String getRule() { - return "Whenever an opponent casts an instant spell other than the first instant spell that player casts each turn, {this} deals 4 damage to that player."; - } } class IchneumonDruidWatcher extends Watcher { diff --git a/Mage.Sets/src/mage/cards/i/IfritWardenOfInferno.java b/Mage.Sets/src/mage/cards/i/IfritWardenOfInferno.java deleted file mode 100644 index 25f9b3ccc9f..00000000000 --- a/Mage.Sets/src/mage/cards/i/IfritWardenOfInferno.java +++ /dev/null @@ -1,72 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -import mage.Mana; -import mage.abilities.common.SagaAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.SourceHasCounterCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.ExileAndReturnSourceEffect; -import mage.abilities.effects.common.FightTargetSourceEffect; -import mage.abilities.effects.mana.BasicManaEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class IfritWardenOfInferno extends CardImpl { - - private static final FilterPermanent filter = new FilterCreaturePermanent("other target creature"); - private static final Condition condition = new SourceHasCounterCondition(CounterType.LORE, 3); - - public IfritWardenOfInferno(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.DEMON); - this.power = new MageInt(9); - this.toughness = new MageInt(9); - this.nightCard = true; - this.color.setRed(true); - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I -- Lunge -- Ifrit fights up to one other target creature. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, ability -> { - ability.addEffect(new FightTargetSourceEffect()); - ability.addTarget(new TargetPermanent(0, 1, filter)); - ability.withFlavorWord("Lunge"); - }); - - // II, III -- Brimstone -- Add {R}{R}{R}{R}. If Ifrit has three or more lore counters on it, exile it, then return it to the battlefield - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_III, ability -> { - ability.addEffect(new BasicManaEffect(Mana.RedMana(4))); - ability.addEffect(new ConditionalOneShotEffect( - new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD), condition, - "If {this} has three or more lore counters on it, exile it, " + - "then return it to the battlefield (front face up.)." - )); - ability.withFlavorWord("Brimstone"); - }); - this.addAbility(sagaAbility); - } - - private IfritWardenOfInferno(final IfritWardenOfInferno card) { - super(card); - } - - @Override - public IfritWardenOfInferno copy() { - return new IfritWardenOfInferno(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/ImmolationShaman.java b/Mage.Sets/src/mage/cards/i/ImmolationShaman.java index 785653ee816..c78eb4351d7 100644 --- a/Mage.Sets/src/mage/cards/i/ImmolationShaman.java +++ b/Mage.Sets/src/mage/cards/i/ImmolationShaman.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; @@ -67,7 +66,7 @@ public final class ImmolationShaman extends CardImpl { class ImmolationShamanTriggeredAbility extends TriggeredAbilityImpl { ImmolationShamanTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(StaticValue.get(1), true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player")); setTriggerPhrase("Whenever an opponent activates an ability of an artifact, creature, or land that isn't a mana ability, "); } diff --git a/Mage.Sets/src/mage/cards/i/ImperialMoth.java b/Mage.Sets/src/mage/cards/i/ImperialMoth.java deleted file mode 100644 index c3d40b92497..00000000000 --- a/Mage.Sets/src/mage/cards/i/ImperialMoth.java +++ /dev/null @@ -1,38 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ImperialMoth extends CardImpl { - - public ImperialMoth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.INSECT); - this.power = new MageInt(2); - this.toughness = new MageInt(4); - this.color.setWhite(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private ImperialMoth(final ImperialMoth card) { - super(card); - } - - @Override - public ImperialMoth copy() { - return new ImperialMoth(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/InfectiousCurse.java b/Mage.Sets/src/mage/cards/i/InfectiousCurse.java deleted file mode 100644 index 8df074292f5..00000000000 --- a/Mage.Sets/src/mage/cards/i/InfectiousCurse.java +++ /dev/null @@ -1,115 +0,0 @@ -package mage.cards.i; - -import mage.abilities.Ability; -import mage.abilities.SpellAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.LoseLifeTargetEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; -import mage.abilities.keyword.EnchantAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.target.TargetPlayer; -import mage.util.CardUtil; - -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -/** - * @author halljared - */ -public final class InfectiousCurse extends CardImpl { - - public InfectiousCurse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - this.subtype.add(SubType.AURA, SubType.CURSE); - this.color.setBlack(true); - - this.nightCard = true; - - // Enchant player - TargetPlayer auraTarget = new TargetPlayer(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.Damage)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Spells you cast that target enchanted player cost {1} less to cast. - this.addAbility(new SimpleStaticAbility(new InfectiousCurseCostReductionEffect())); - - // At the beginning of enchanted player's upkeep, that player loses 1 life and you gain 1 life. - Ability ability = new BeginningOfUpkeepTriggeredAbility( - TargetController.ENCHANTED, new LoseLifeTargetEffect(1).setText("that player loses 1 life"), - false - ); - ability.addEffect(new GainLifeEffect(1).concatBy("and")); - this.addAbility(ability); - } - - private InfectiousCurse(final InfectiousCurse card) { - super(card); - } - - @Override - public InfectiousCurse copy() { - return new InfectiousCurse(this); - } -} - -class InfectiousCurseCostReductionEffect extends CostModificationEffectImpl { - - InfectiousCurseCostReductionEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); - this.staticText = "Spells you cast that target enchanted player cost {1} less to cast"; - } - - private InfectiousCurseCostReductionEffect(InfectiousCurseCostReductionEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - CardUtil.reduceCost(abilityToModify, 1); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (!(abilityToModify instanceof SpellAbility)) { - return false; - } - - if (!source.isControlledBy(abilityToModify.getControllerId())) { - return false; - } - - Permanent enchantment = game.getPermanent(source.getSourceId()); - if (enchantment == null || enchantment.getAttachedTo() == null) { - return false; - } - - Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId()); - Set allTargets; - if (spell != null) { - // real cast - allTargets = CardUtil.getAllSelectedTargets(abilityToModify, game); - } else { - // playable - allTargets = CardUtil.getAllPossibleTargets(abilityToModify, game); - } - - // try to reduce all the time (if it possible to target) - return allTargets.stream().anyMatch(target -> Objects.equals(target, enchantment.getAttachedTo())); - } - - @Override - public InfectiousCurseCostReductionEffect copy() { - return new InfectiousCurseCostReductionEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/InfernoElemental.java b/Mage.Sets/src/mage/cards/i/InfernoElemental.java index 1ba8734e94d..51de7e5c9ee 100644 --- a/Mage.Sets/src/mage/cards/i/InfernoElemental.java +++ b/Mage.Sets/src/mage/cards/i/InfernoElemental.java @@ -23,7 +23,8 @@ public final class InfernoElemental extends CardImpl { this.toughness = new MageInt(4); // Whenever Inferno Elemental blocks or becomes blocked by a creature, Inferno Elemental deals 3 damage to that creature. - this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(3, true, "that creature"))); + this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility( + new DamageTargetEffect(3).withTargetDescription("that creature"))); } private InfernoElemental(final InfernoElemental card) { diff --git a/Mage.Sets/src/mage/cards/i/InsectileAberration.java b/Mage.Sets/src/mage/cards/i/InsectileAberration.java deleted file mode 100644 index e946630432c..00000000000 --- a/Mage.Sets/src/mage/cards/i/InsectileAberration.java +++ /dev/null @@ -1,43 +0,0 @@ - -package mage.cards.i; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author Alvin - */ -public final class InsectileAberration extends CardImpl { - - public InsectileAberration(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.INSECT); - - this.color.setBlue(true); - - // this card is the second face of double-faced card Delver of Secrets - this.nightCard = true; - - this.power = new MageInt(3); - this.toughness = new MageInt(2); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private InsectileAberration(final InsectileAberration card) { - super(card); - } - - @Override - public InsectileAberration copy() { - return new InsectileAberration(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/InsidiousMist.java b/Mage.Sets/src/mage/cards/i/InsidiousMist.java deleted file mode 100644 index 25546fc0589..00000000000 --- a/Mage.Sets/src/mage/cards/i/InsidiousMist.java +++ /dev/null @@ -1,62 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; -import mage.abilities.effects.common.combat.CantBlockSourceEffect; -import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class InsidiousMist extends CardImpl { - - public InsidiousMist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.ELEMENTAL); - this.power = new MageInt(0); - this.toughness = new MageInt(1); - this.color.setBlue(true); - - this.nightCard = true; - - // Hexproof - this.addAbility(HexproofAbility.getInstance()); - - // Indestructible - this.addAbility(IndestructibleAbility.getInstance()); - - // Insideous Mist can't block and can't be blocked. - Ability ability = new SimpleStaticAbility(new CantBlockSourceEffect(Duration.WhileOnBattlefield)); - ability.addEffect(new CantBeBlockedSourceEffect().setText("and can't be blocked")); - this.addAbility(ability); - - // Whenever Insideous Mist attacks and isn't blocked, you may pay {2}{B}. If you do, transform it. - this.addAbility(new TransformAbility()); - this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new DoIfCostPaid(new TransformSourceEffect() - .setText("transform it"), new ManaCostsImpl<>("{2}{B}"), "Pay {2}{B} to transform?"))); - } - - private InsidiousMist(final InsidiousMist card) { - super(card); - } - - @Override - public InsidiousMist copy() { - return new InsidiousMist(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfBelenon.java b/Mage.Sets/src/mage/cards/i/InvasionOfBelenon.java index 717ac38bdc8..797ae3caef3 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfBelenon.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfBelenon.java @@ -2,10 +2,13 @@ package mage.cards.i; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.CreateTokenEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.game.permanent.token.KnightWhiteBlueToken; @@ -14,20 +17,27 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfBelenon extends CardImpl { +public final class InvasionOfBelenon extends TransformingDoubleFacedCard { public InvasionOfBelenon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{W}", + "Belenon War Anthem", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "W"); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.b.BelenonWarAnthem.class; + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Belenon enters the battlefield, create a 2/2 white and blue Knight creature token with vigilance. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightWhiteBlueToken()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightWhiteBlueToken()))); + + // Belenon War Anthem + + // Creatures you control get +1/+1. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); + } private InvasionOfBelenon(final InvasionOfBelenon card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfPyrulea.java b/Mage.Sets/src/mage/cards/i/InvasionOfPyrulea.java index beeee35bd4f..0c7368ae308 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfPyrulea.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfPyrulea.java @@ -67,7 +67,7 @@ class InvasionOfPyruleaEffect extends OneShotEffect { player.scry(3, source, game); Card card = player.getLibrary().getFromTop(game); player.revealCards(source, new CardsImpl(card), game); - if (card != null && (card.isLand(game) || card instanceof ModalDoubleFacedCard || card.getSecondCardFace() != null)) { + if (card != null && (card.isLand(game) || card instanceof DoubleFacedCard || card.getSecondCardFace() != null)) { player.drawCards(1, source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfRegatha.java b/Mage.Sets/src/mage/cards/i/InvasionOfRegatha.java index f6068787a4b..4f7ff4dda05 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfRegatha.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfRegatha.java @@ -23,7 +23,7 @@ import java.util.UUID; public final class InvasionOfRegatha extends CardImpl { private static final FilterPermanentOrPlayer filter = new FilterPermanentOrPlayer( - "another target permanent or player", + "another target battle or opponent", new FilterBattlePermanent(), new FilterOpponent() ); diff --git a/Mage.Sets/src/mage/cards/i/IrohDragonOfTheWest.java b/Mage.Sets/src/mage/cards/i/IrohDragonOfTheWest.java index d18ed8d6e99..90c7a212d26 100644 --- a/Mage.Sets/src/mage/cards/i/IrohDragonOfTheWest.java +++ b/Mage.Sets/src/mage/cards/i/IrohDragonOfTheWest.java @@ -1,23 +1,23 @@ package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.FirebendingAbility; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.MentorAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.CounterAnyPredicate; +import java.util.UUID; + /** - * * @author anonymous */ public final class IrohDragonOfTheWest extends CardImpl { @@ -30,7 +30,7 @@ public final class IrohDragonOfTheWest extends CardImpl { public IrohDragonOfTheWest(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.NOBLE); @@ -45,7 +45,9 @@ public final class IrohDragonOfTheWest extends CardImpl { this.addAbility(new MentorAbility()); // At the beginning of combat on your turn, each creature you control with a counter on it gains firebending 2 until end of turn. - this.addAbility(new BeginningOfCombatTriggeredAbility(new GainAbilityControlledEffect(new FirebendingAbility(2), Duration.EndOfTurn, filter))); + this.addAbility(new BeginningOfCombatTriggeredAbility(new GainAbilityControlledEffect( + new FirebendingAbility(2), Duration.EndOfTurn, filter + ).setText("each creature you control with a counter on it gains firebending 2 until end of turn"))); } private IrohDragonOfTheWest(final IrohDragonOfTheWest card) { diff --git a/Mage.Sets/src/mage/cards/i/IrohGrandLotus.java b/Mage.Sets/src/mage/cards/i/IrohGrandLotus.java index e96799fb099..7f07b6d407c 100644 --- a/Mage.Sets/src/mage/cards/i/IrohGrandLotus.java +++ b/Mage.Sets/src/mage/cards/i/IrohGrandLotus.java @@ -13,6 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.Predicates; import mage.game.Game; import mage.players.Player; @@ -59,6 +60,10 @@ class IrohGrandLotusEffect extends ContinuousEffectImpl { private static final FilterCard filterLesson = new FilterCard(SubType.LESSON); private final boolean isLesson; + static { + filterNonLesson.add(Predicates.not(SubType.LESSON.getPredicate())); + } + IrohGrandLotusEffect(boolean isLesson) { super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); this.isLesson = isLesson; diff --git a/Mage.Sets/src/mage/cards/i/IrohTeaMaster.java b/Mage.Sets/src/mage/cards/i/IrohTeaMaster.java new file mode 100644 index 00000000000..d153c830fa7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IrohTeaMaster.java @@ -0,0 +1,148 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.AllyToken; +import mage.game.permanent.token.FoodToken; +import mage.game.permanent.token.Token; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.EachTargetPointer; +import mage.target.targetpointer.FixedTarget; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IrohTeaMaster extends CardImpl { + + public IrohTeaMaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Iroh enters, create a Food token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken()))); + + // At the beginning of combat on your turn, you may have target opponent gain control of target permanent you control. When you do, create a 1/1 white Ally creature token. Put a +1/+1 counter on that token for each permanent you own that your opponents control. + Ability ability = new BeginningOfCombatTriggeredAbility(new IrohTeaMasterControlEffect(), true); + ability.addTarget(new TargetOpponent()); + ability.addTarget(new TargetControlledPermanent()); + this.addAbility(ability.addHint(IrohTeaMasterTokenEffect.getHint())); + } + + private IrohTeaMaster(final IrohTeaMaster card) { + super(card); + } + + @Override + public IrohTeaMaster copy() { + return new IrohTeaMaster(this); + } +} + +class IrohTeaMasterControlEffect extends OneShotEffect { + + IrohTeaMasterControlEffect() { + super(Outcome.Benefit); + staticText = "have target opponent gain control of target permanent you control. " + + "When you do, create a 1/1 white Ally creature token. " + + "Put a +1/+1 counter on that token for each permanent you own that your opponents control"; + this.setTargetPointer(new EachTargetPointer()); + } + + private IrohTeaMasterControlEffect(final IrohTeaMasterControlEffect effect) { + super(effect); + } + + @Override + public IrohTeaMasterControlEffect copy() { + return new IrohTeaMasterControlEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + Permanent permanent = game.getPermanent(getTargetPointer().getTargets(game, source).get(0)); + if (player == null || permanent == null) { + return false; + } + game.addEffect(new GainControlTargetEffect(Duration.Custom, true, player.getId()) + .setTargetPointer(new FixedTarget(permanent, game)), source); + game.fireReflexiveTriggeredAbility(new ReflexiveTriggeredAbility(new IrohTeaMasterTokenEffect(), false), source); + return true; + } +} + +class IrohTeaMasterTokenEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(TargetController.YOU.getOwnerPredicate()); + filter.add(TargetController.OPPONENT.getControllerPredicate()); + } + + private static final Hint hint = new ValueHint( + "Permanents you own that your opponents control", new PermanentsOnBattlefieldCount(filter) + ); + + public static Hint getHint() { + return hint; + } + + IrohTeaMasterTokenEffect() { + super(Outcome.Benefit); + staticText = "create a 1/1 white Ally creature token. Put a +1/+1 counter " + + "on that token for each permanent you own that your opponents control"; + } + + private IrohTeaMasterTokenEffect(final IrohTeaMasterTokenEffect effect) { + super(effect); + } + + @Override + public IrohTeaMasterTokenEffect copy() { + return new IrohTeaMasterTokenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Token token = new AllyToken(); + token.putOntoBattlefield(1, game, source); + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game); + if (count < 1) { + return true; + } + for (UUID tokenId : token.getLastAddedTokenIds()) { + Optional.ofNullable(tokenId) + .map(game::getPermanent) + .ifPresent(permanent -> permanent.addCounters(CounterType.P1P1.createInstance(count), source, game)); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/IrohsDemonstration.java b/Mage.Sets/src/mage/cards/i/IrohsDemonstration.java index b9c39d21f6c..4af1b269bab 100644 --- a/Mage.Sets/src/mage/cards/i/IrohsDemonstration.java +++ b/Mage.Sets/src/mage/cards/i/IrohsDemonstration.java @@ -24,7 +24,8 @@ public final class IrohsDemonstration extends CardImpl { // Choose one -- // * Iroh's Demonstration deals 1 damage to each creature your opponents control. - this.getSpellAbility().addEffect(new DamageAllEffect(1, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + this.getSpellAbility().addEffect(new DamageAllEffect(1, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE) + .setText("{this} deals 1 damage to each creature your opponents control")); // * Iroh's Demonstration deals 4 damage to target creature. this.getSpellAbility().addMode(new Mode(new DamageTargetEffect(4)).addTarget(new TargetCreaturePermanent())); diff --git a/Mage.Sets/src/mage/cards/i/IronSpiderStarkUpgrade.java b/Mage.Sets/src/mage/cards/i/IronSpiderStarkUpgrade.java index 1b97e9734d0..98205ee3a57 100644 --- a/Mage.Sets/src/mage/cards/i/IronSpiderStarkUpgrade.java +++ b/Mage.Sets/src/mage/cards/i/IronSpiderStarkUpgrade.java @@ -29,11 +29,14 @@ import java.util.UUID; public final class IronSpiderStarkUpgrade extends CardImpl { private static final FilterPermanent filter - = new FilterControlledPermanent("creature and/or Vehicle you control"); + = new FilterControlledPermanent("artifact creature and/or Vehicle you control"); static { filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), + Predicates.and( + CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate() + ), SubType.VEHICLE.getPredicate() )); } @@ -59,7 +62,7 @@ public final class IronSpiderStarkUpgrade extends CardImpl { Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(2)); ability.addCost(new RemoveCounterCost(new TargetPermanent( 1, 2, StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT - ), CounterType.P1P1, 2).setText("remove two +1/+1 counters from among creatures you control")); + ), CounterType.P1P1, 2).setText("remove two +1/+1 counters from among artifacts you control")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java b/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java index 6cbc709eefb..554e8c77c3b 100644 --- a/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java +++ b/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java @@ -28,7 +28,7 @@ public final class IshiIshiAkkiCrackshot extends CardImpl { // Whenever an opponent casts a Spirit or Arcane spell, Ishi-Ishi, Akki Crackshot deals 2 damage to that player. this.addAbility(new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, - new DamageTargetEffect(2, true, "that player"), + new DamageTargetEffect(2).withTargetDescription("that player"), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false, SetTargetPointer.PLAYER)); } diff --git a/Mage.Sets/src/mage/cards/i/IsiluCarrierOfTwilight.java b/Mage.Sets/src/mage/cards/i/IsiluCarrierOfTwilight.java deleted file mode 100644 index 54e585d92c9..00000000000 --- a/Mage.Sets/src/mage/cards/i/IsiluCarrierOfTwilight.java +++ /dev/null @@ -1,65 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.PersistAbility; -import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class IsiluCarrierOfTwilight extends CardImpl { - - public IsiluCarrierOfTwilight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELEMENTAL); - this.subtype.add(SubType.GOD); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Each other nontoken creature you control has persist. - this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( - new PersistAbility(), Duration.WhileControlled, - StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN, true - ).setText("each other nontoken creature you control has persist"))); - - // At the beginning of your first main phase, you may pay {W}. If you do, transform Isilu. - this.addAbility(new BeginningOfFirstMainTriggeredAbility( - new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{W}")) - )); - } - - private IsiluCarrierOfTwilight(final IsiluCarrierOfTwilight card) { - super(card); - } - - @Override - public IsiluCarrierOfTwilight copy() { - return new IsiluCarrierOfTwilight(this); - } -} diff --git a/Mage.Sets/src/mage/cards/j/JaggedLightning.java b/Mage.Sets/src/mage/cards/j/JaggedLightning.java index 0da793f9011..5a818c25a6a 100644 --- a/Mage.Sets/src/mage/cards/j/JaggedLightning.java +++ b/Mage.Sets/src/mage/cards/j/JaggedLightning.java @@ -17,7 +17,7 @@ public final class JaggedLightning extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); // Jagged Lightning deals 3 damage to each of two target creatures. - this.getSpellAbility().addEffect(new DamageTargetEffect(3, true, "each of two target creatures")); + this.getSpellAbility().addEffect(new DamageTargetEffect(3).withTargetDescription("each of two target creatures")); this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); } diff --git a/Mage.Sets/src/mage/cards/j/JasmineDragonTeaShop.java b/Mage.Sets/src/mage/cards/j/JasmineDragonTeaShop.java new file mode 100644 index 00000000000..22aa700ce8f --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JasmineDragonTeaShop.java @@ -0,0 +1,83 @@ +package mage.cards.j; + +import mage.ConditionalMana; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.ConditionalAnyColorManaAbility; +import mage.abilities.mana.builder.ConditionalManaBuilder; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JasmineDragonTeaShop extends CardImpl { + + public JasmineDragonTeaShop(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add one mana of any color. Spend this mana only to cast an Ally spell or activate an ability of an Ally source. + this.addAbility(new ConditionalAnyColorManaAbility(1, new JasmineDragonTeaShopManaBuilder())); + + // {5}, {T}: Create a 1/1 white Ally creature token. + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new AllyToken()), new GenericManaCost(5)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private JasmineDragonTeaShop(final JasmineDragonTeaShop card) { + super(card); + } + + @Override + public JasmineDragonTeaShop copy() { + return new JasmineDragonTeaShop(this); + } +} + +class JasmineDragonTeaShopManaBuilder extends ConditionalManaBuilder { + + @Override + public ConditionalMana build(Object... options) { + return new JasmineDragonTeaShopConditionalMana(this.mana); + } + + @Override + public String getRule() { + return "Spend this mana only to cast an Ally spell or activate an ability of an Ally source"; + } +} + +class JasmineDragonTeaShopConditionalMana extends ConditionalMana { + + JasmineDragonTeaShopConditionalMana(Mana mana) { + super(mana); + addCondition(JasmineDragonTeaShopCondition.instance); + } +} + +enum JasmineDragonTeaShopCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + MageObject object = game.getObject(source); + return object != null && object.hasSubtype(SubType.ALLY, game) && !source.isActivated(); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JeskaiRevelation.java b/Mage.Sets/src/mage/cards/j/JeskaiRevelation.java index 4a0b4d6f52b..71f62bc2e88 100644 --- a/Mage.Sets/src/mage/cards/j/JeskaiRevelation.java +++ b/Mage.Sets/src/mage/cards/j/JeskaiRevelation.java @@ -22,9 +22,7 @@ public final class JeskaiRevelation extends CardImpl { // Return target spell or permanent to its owner's hand. Jeskai Revelation deals 4 damage to any target. Create two 1/1 white Monk creature tokens with prowess. Draw two cards. You gain 4 life. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetSpellOrPermanent()); - this.getSpellAbility().addEffect(new DamageTargetEffect( - 4, true, "any target" - ).setTargetPointer(new SecondTargetPointer())); + this.getSpellAbility().addEffect(new DamageTargetEffect(4).setTargetPointer(new SecondTargetPointer())); this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addEffect(new CreateTokenEffect(new MonasteryMentorToken(), 2)); this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); diff --git a/Mage.Sets/src/mage/cards/j/JestersScepter.java b/Mage.Sets/src/mage/cards/j/JestersScepter.java index bb34acdfccd..482244ee81e 100644 --- a/Mage.Sets/src/mage/cards/j/JestersScepter.java +++ b/Mage.Sets/src/mage/cards/j/JestersScepter.java @@ -165,9 +165,9 @@ class JestersScepterCost extends CostImpl { if (card instanceof SplitCard) { game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((SplitCard) card).getLeftHalfCard().getName()); game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((SplitCard) card).getRightHalfCard().getName()); - } else if (card instanceof ModalDoubleFacedCard) { - game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((ModalDoubleFacedCard) card).getLeftHalfCard().getName()); - game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((ModalDoubleFacedCard) card).getRightHalfCard().getName()); + } else if (card instanceof DoubleFacedCard) { + game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((DoubleFacedCard) card).getLeftHalfCard().getName()); + game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((DoubleFacedCard) card).getRightHalfCard().getName()); } else { game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", card.getName()); } diff --git a/Mage.Sets/src/mage/cards/j/JetFreedomFighter.java b/Mage.Sets/src/mage/cards/j/JetFreedomFighter.java index 51d031ae5c7..d1427af3158 100644 --- a/Mage.Sets/src/mage/cards/j/JetFreedomFighter.java +++ b/Mage.Sets/src/mage/cards/j/JetFreedomFighter.java @@ -35,7 +35,9 @@ public final class JetFreedomFighter extends CardImpl { // When Jet enters, he deals damage equal to the number of creatures you control to target creature an opponent controls. Ability ability = new EntersBattlefieldTriggeredAbility( - new DamageTargetEffect(CreaturesYouControlCount.PLURAL, "he") + new DamageTargetEffect(CreaturesYouControlCount.PLURAL) + .setText("he deals damage equal to the number of creatures " + + "you control to target creature an opponent controls") ); ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/k/KappaCannoneer.java b/Mage.Sets/src/mage/cards/k/KappaCannoneer.java index a2c29c94268..5094609202b 100644 --- a/Mage.Sets/src/mage/cards/k/KappaCannoneer.java +++ b/Mage.Sets/src/mage/cards/k/KappaCannoneer.java @@ -43,7 +43,7 @@ public final class KappaCannoneer extends CardImpl { StaticFilters.FILTER_PERMANENT_ARTIFACT, false, true ); ability.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn) - .setText("and it can't be blocked this turn")); + .setText("It can't be blocked this turn")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KataraSeekingRevenge.java b/Mage.Sets/src/mage/cards/k/KataraSeekingRevenge.java new file mode 100644 index 00000000000..62559da7617 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KataraSeekingRevenge.java @@ -0,0 +1,68 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.condition.common.WaterbendedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.keyword.WaterbendAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KataraSeekingRevenge extends CardImpl { + + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(new FilterCard(SubType.LESSON)); + + public KataraSeekingRevenge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U/B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // As an additional cost to cast this spell, you may waterbend {2}. + this.addAbility(new WaterbendAbility(2)); + + // When Katara enters, draw a card, then discard a card unless her additional cost was paid. + Ability ability = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)); + ability.addEffect(new ConditionalOneShotEffect( + null, new DiscardControllerEffect(1), WaterbendedCondition.instance, + ", then discard a card unless her additional cost was paid" + )); + this.addAbility(ability); + + // Katara gets +1/+1 for each Lesson card in your graveyard. + this.addAbility(new SimpleStaticAbility( + new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield) + ).addHint(LessonsInGraveCondition.getHint())); + } + + private KataraSeekingRevenge(final KataraSeekingRevenge card) { + super(card); + } + + @Override + public KataraSeekingRevenge copy() { + return new KataraSeekingRevenge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java b/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java index 35f78ab4521..d637cb6b178 100644 --- a/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java +++ b/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java @@ -9,6 +9,7 @@ import mage.abilities.costs.common.WaterbendCost; import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessAllEffect; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; @@ -49,6 +50,7 @@ public final class KataraWaterTribesHope extends CardImpl { GetXValue.instance, GetXValue.instance, Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES ), new WaterbendCost("{X}"), MyTurnCondition.instance); + ability.addEffect(new InfoEffect("X can't be 0")); CardUtil.castStream(ability.getCosts(), VariableManaCost.class).forEach(cost -> cost.setMinX(1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KatarasReversal.java b/Mage.Sets/src/mage/cards/k/KatarasReversal.java new file mode 100644 index 00000000000..93af60adaa7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KatarasReversal.java @@ -0,0 +1,47 @@ +package mage.cards.k; + +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; +import mage.target.TargetStackObject; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KatarasReversal extends CardImpl { + + public KatarasReversal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); + + // Counter up to four target spells and/or abilities. + this.getSpellAbility().addEffect(new CounterTargetEffect() + .setText("counter up to four target spells and/or abilities")); + this.getSpellAbility().addTarget(new TargetStackObject( + 0, 4, StaticFilters.FILTER_SPELL_OR_ABILITY + )); + + // Untap up to four target artifacts and/or creatures. + this.getSpellAbility().addEffect(new UntapTargetEffect() + .setTargetPointer(new SecondTargetPointer()) + .setText("
Untap up to four target artifacts and/or creatures")); + this.getSpellAbility().addTarget(new TargetPermanent( + 0, 4, StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE + )); + } + + private KatarasReversal(final KatarasReversal card) { + super(card); + } + + @Override + public KatarasReversal copy() { + return new KatarasReversal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KederektParasite.java b/Mage.Sets/src/mage/cards/k/KederektParasite.java index 8242a79a6c7..e5c279bd776 100644 --- a/Mage.Sets/src/mage/cards/k/KederektParasite.java +++ b/Mage.Sets/src/mage/cards/k/KederektParasite.java @@ -1,4 +1,3 @@ - package mage.cards.k; import java.util.UUID; @@ -17,7 +16,6 @@ import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.target.targetpointer.FixedTarget; /** @@ -56,7 +54,7 @@ class KederektParasiteTriggeredAbility extends TriggeredAbilityImpl { } KederektParasiteTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "opponent"), true); + super(Zone.BATTLEFIELD, new DamageTargetEffect(1), true); } private KederektParasiteTriggeredAbility(final KederektParasiteTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/k/KessigForgemaster.java b/Mage.Sets/src/mage/cards/k/KessigForgemaster.java index 77c073320d1..9ac344d5b16 100644 --- a/Mage.Sets/src/mage/cards/k/KessigForgemaster.java +++ b/Mage.Sets/src/mage/cards/k/KessigForgemaster.java @@ -27,7 +27,7 @@ public final class KessigForgemaster extends CardImpl { this.secondSideCardClazz = mage.cards.f.FlameheartWerewolf.class; // Whenever Kessig Forgemaster blocks or becomes blocked by a creature, Kessig Forgemaster deals 1 damage to that creature. - this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1, true, "that creature"))); + this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that creature"))); // At the beginning of each upkeep, if no spells were cast last turn, transform Kessig Forgemaster. this.addAbility(new TransformAbility()); diff --git a/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java b/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java index 32b51409d80..fdfc2100202 100644 --- a/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java +++ b/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java @@ -30,13 +30,11 @@ import java.util.UUID; */ public final class KnollspineInvocation extends CardImpl { - protected static final FilterCard filter = new FilterCard("a card with mana value X"); - public KnollspineInvocation(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{R}"); // {X}, Discard a card with mana value X: This enchantment deals X damage to any target. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(GetXValue.instance, true), new ManaCostsImpl<>("{X}")); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(GetXValue.instance), new ManaCostsImpl<>("{X}")); ability.addCost(new KnollspineInvocationDiscardCost()); ability.addTarget(new TargetAnyTarget()); ability.setCostAdjuster(KnollspineInvocationAdjuster.instance); diff --git a/Mage.Sets/src/mage/cards/k/KohTheFaceStealer.java b/Mage.Sets/src/mage/cards/k/KohTheFaceStealer.java new file mode 100644 index 00000000000..b40faff1f23 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KohTheFaceStealer.java @@ -0,0 +1,167 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInExile; +import mage.util.CardUtil; + +import java.util.HashSet; +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KohTheFaceStealer extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("another nontoken creature"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(TokenPredicate.FALSE); + } + + public KohTheFaceStealer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SHAPESHIFTER); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // When Koh enters, exile up to one other target creature. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect()); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + this.addAbility(ability); + + // Whenever another nontoken creature dies, you may exile it. + this.addAbility(new DiesCreatureTriggeredAbility( + new ExileTargetForSourceEffect().withTargetDescription("it"), true, filter, true + )); + + // Pay 1 life: Choose a creature card exiled with Koh. + this.addAbility(new SimpleActivatedAbility(new KohTheFaceStealerChooseEffect(), new PayLifeCost(1))); + + // Koh has all activated and triggered abilities of the last chosen card. + this.addAbility(new SimpleStaticAbility(new KohTheFaceStealerAbilityEffect())); + } + + private KohTheFaceStealer(final KohTheFaceStealer card) { + super(card); + } + + @Override + public KohTheFaceStealer copy() { + return new KohTheFaceStealer(this); + } +} + +class KohTheFaceStealerChooseEffect extends OneShotEffect { + + KohTheFaceStealerChooseEffect() { + super(Outcome.Benefit); + staticText = "choose a creature card exiled with {this}"; + } + + private KohTheFaceStealerChooseEffect(final KohTheFaceStealerChooseEffect effect) { + super(effect); + } + + @Override + public KohTheFaceStealerChooseEffect copy() { + return new KohTheFaceStealerChooseEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (player == null || permanent == null) { + return false; + } + UUID exileId = CardUtil.getExileZoneId(game, source); + if (Optional + .ofNullable(game.getExile().getExileZone(exileId)) + .filter(HashSet::isEmpty) + .isPresent()) { + return false; + } + TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD_CREATURE, exileId); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + game.getState().setValue( + CardUtil.getObjectZoneString( + "chosenCard", permanent.getId(), game, + permanent.getZoneChangeCounter(game), false + ), + new MageObjectReference(card, game) + ); + permanent.addInfo("chosen card", CardUtil.addToolTipMarkTags("Chosen Card " + card.getIdName()), game); + return true; + } +} + +class KohTheFaceStealerAbilityEffect extends ContinuousEffectImpl { + + KohTheFaceStealerAbilityEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.Benefit); + staticText = "{this} has all activated and triggered abilities of the last chosen card"; + } + + private KohTheFaceStealerAbilityEffect(final KohTheFaceStealerAbilityEffect effect) { + super(effect); + } + + @Override + public KohTheFaceStealerAbilityEffect copy() { + return new KohTheFaceStealerAbilityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + Card card = Optional + .ofNullable(CardUtil.getCardZoneString("chosenCard", source.getSourceId(), game, false)) + .map(game.getState()::getValue) + .map(MageObjectReference.class::cast) + .map(mor -> mor.getCard(game)) + .orElse(null); + if (permanent == null || card == null) { + return false; + } + for (Ability ability : card.getAbilities(game)) { + if (ability.isActivatedAbility() || ability.isTriggeredAbility()) { + permanent.addAbility(ability, source.getSourceId(), game, true); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KolaghanAspirant.java b/Mage.Sets/src/mage/cards/k/KolaghanAspirant.java index c0fb8e3cf9c..aeac9a73ecd 100644 --- a/Mage.Sets/src/mage/cards/k/KolaghanAspirant.java +++ b/Mage.Sets/src/mage/cards/k/KolaghanAspirant.java @@ -24,7 +24,7 @@ public final class KolaghanAspirant extends CardImpl { this.toughness = new MageInt(1); // Whenever Kolaghan Aspirant becomes blocked by a creature, Kolaghan Aspirant deals 1 damage to that creature. - this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new DamageTargetEffect(1, true, "that creature"), false)); + this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that creature"), false)); } private KolaghanAspirant(final KolaghanAspirant card) { diff --git a/Mage.Sets/src/mage/cards/k/KrallenhordeHowler.java b/Mage.Sets/src/mage/cards/k/KrallenhordeHowler.java deleted file mode 100644 index c57d2e864bb..00000000000 --- a/Mage.Sets/src/mage/cards/k/KrallenhordeHowler.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.k; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class KrallenhordeHowler extends CardImpl { - - private static final FilterCard FILTER = new FilterCreatureCard("creature spells"); - - public KrallenhordeHowler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Creature spells you cast cost {1} less to cast. - this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(FILTER, 1))); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Krallenhorde Howler. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private KrallenhordeHowler(final KrallenhordeHowler card) { - super(card); - } - - @Override - public KrallenhordeHowler copy() { - return new KrallenhordeHowler(this); - } -} diff --git a/Mage.Sets/src/mage/cards/k/KratosStoicFather.java b/Mage.Sets/src/mage/cards/k/KratosStoicFather.java index edd10bbbf1b..ede9a3f28c0 100644 --- a/Mage.Sets/src/mage/cards/k/KratosStoicFather.java +++ b/Mage.Sets/src/mage/cards/k/KratosStoicFather.java @@ -48,7 +48,7 @@ public final class KratosStoicFather extends CardImpl { // At the beginning of your end step, put a number of +1/+1 counters on target creature equal to the number of experience counters you have. Ability ability = new BeginningOfEndStepTriggeredAbility( new AddCountersTargetEffect(CounterType.P1P1.createInstance(), xValue) - .setText(" put a number of +1/+1 counters on target creature " + + .setText("put a number of +1/+1 counters on target creature " + "equal to the number of experience counters you have") ); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/k/KutzilsFlanker.java b/Mage.Sets/src/mage/cards/k/KutzilsFlanker.java index 79ecf0f0963..f9f53fe1a50 100644 --- a/Mage.Sets/src/mage/cards/k/KutzilsFlanker.java +++ b/Mage.Sets/src/mage/cards/k/KutzilsFlanker.java @@ -10,24 +10,18 @@ import mage.abilities.effects.common.ExileGraveyardAllTargetPlayerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.keyword.FlashAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; import mage.target.TargetPlayer; -import mage.util.CardUtil; -import mage.watchers.Watcher; +import mage.watchers.common.CreatureLeftBattlefieldWatcher; -import java.util.HashMap; -import java.util.Map; import java.util.UUID; /** @@ -52,8 +46,8 @@ public final class KutzilsFlanker extends CardImpl { new AddCountersSourceEffect(CounterType.P1P1.createInstance(), KutzilsFlankerValue.instance, true) .setText("put a +1/+1 counter on {this} for each creature that left the battlefield under your control this turn") ); - ability.addHint(new ValueHint("Number of creatures that left", KutzilsFlankerValue.instance)); - ability.addWatcher(new KutzilsFlankerWatcher()); + ability.addHint(KutzilsFlankerValue.getHint()); + ability.addWatcher(new CreatureLeftBattlefieldWatcher()); // * You gain 2 life and scry 2. ability.addMode(new Mode( @@ -82,10 +76,15 @@ public final class KutzilsFlanker extends CardImpl { enum KutzilsFlankerValue implements DynamicValue { instance; + private static final Hint hint = new ValueHint("Number of creatures that left", KutzilsFlankerValue.instance); + + public static Hint getHint() { + return hint; + } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return KutzilsFlankerWatcher.getNumberCreatureLeft(sourceAbility.getControllerId(), game); + return CreatureLeftBattlefieldWatcher.getNumberCreatureLeft(sourceAbility.getControllerId(), game); } @Override @@ -103,37 +102,3 @@ enum KutzilsFlankerValue implements DynamicValue { return ""; } } - - -class KutzilsFlankerWatcher extends Watcher { - - // player -> number of creatures that left the battlefield under that player's control this turn - private final Map mapCreaturesLeft = new HashMap<>(); - - KutzilsFlankerWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() != GameEvent.EventType.ZONE_CHANGE) { - return; - } - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() != Zone.BATTLEFIELD || !zEvent.getTarget().isCreature(game)) { - return; - } - mapCreaturesLeft.compute(zEvent.getTarget().getControllerId(), CardUtil::setOrIncrementValue); - } - - @Override - public void reset() { - super.reset(); - mapCreaturesLeft.clear(); - } - - public static int getNumberCreatureLeft(UUID playerId, Game game) { - KutzilsFlankerWatcher watcher = game.getState().getWatcher(KutzilsFlankerWatcher.class); - return watcher == null ? 0 : watcher.mapCreaturesLeft.getOrDefault(playerId, 0); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LambholtButcher.java b/Mage.Sets/src/mage/cards/l/LambholtButcher.java deleted file mode 100644 index 7e168fbffb3..00000000000 --- a/Mage.Sets/src/mage/cards/l/LambholtButcher.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.l; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class LambholtButcher extends CardImpl { - - public LambholtButcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Lambholt Butcher. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private LambholtButcher(final LambholtButcher card) { - super(card); - } - - @Override - public LambholtButcher copy() { - return new LambholtButcher(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LambholtPacifist.java b/Mage.Sets/src/mage/cards/l/LambholtPacifist.java index 36969373dc5..ab4f81c39fa 100644 --- a/Mage.Sets/src/mage/cards/l/LambholtPacifist.java +++ b/Mage.Sets/src/mage/cards/l/LambholtPacifist.java @@ -1,7 +1,7 @@ package mage.cards.l; -import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; @@ -9,9 +9,8 @@ import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalRestrictionEffect; import mage.abilities.effects.common.combat.CantAttackSourceEffect; import mage.abilities.hint.common.FerociousHint; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; @@ -21,29 +20,32 @@ import java.util.UUID; /** * @author fireshoes */ -public final class LambholtPacifist extends CardImpl { +public final class LambholtPacifist extends TransformingDoubleFacedCard { private static final Condition condition = new InvertCondition(FerociousCondition.instance); public LambholtPacifist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SHAMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN, SubType.WEREWOLF}, "{1}{G}", + "Lambholt Butcher", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.secondSideCardClazz = mage.cards.l.LambholtButcher.class; + this.getLeftHalfCard().setPT(3, 3); + this.getRightHalfCard().setPT(4, 4); // Lambholt Pacifist can't attack unless you control a creature with power 4 or greater. - this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( new CantAttackSourceEffect(Duration.WhileOnBattlefield), condition, "{this} can't attack unless you control a creature with power 4 or greater" )).addHint(FerociousHint.instance)); // At the beginning of each upkeep, if no spells were cast last turn, transform Lambholt Pacifist. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Lambholt Butcher + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Lambholt Butcher. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private LambholtPacifist(final LambholtPacifist card) { diff --git a/Mage.Sets/src/mage/cards/l/LavabornMuse.java b/Mage.Sets/src/mage/cards/l/LavabornMuse.java index e63bccc138b..7c215610f31 100644 --- a/Mage.Sets/src/mage/cards/l/LavabornMuse.java +++ b/Mage.Sets/src/mage/cards/l/LavabornMuse.java @@ -30,7 +30,7 @@ public final class LavabornMuse extends CardImpl { // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Lavaborn Muse deals 3 damage to that player. this.addAbility(new BeginningOfUpkeepTriggeredAbility( TargetController.OPPONENT, - new DamageTargetEffect(3, true, "that player"), + new DamageTargetEffect(3).withTargetDescription("that player"), false ).withInterveningIf(condition)); } diff --git a/Mage.Sets/src/mage/cards/l/LeechingLurker.java b/Mage.Sets/src/mage/cards/l/LeechingLurker.java deleted file mode 100644 index 1fc7474793a..00000000000 --- a/Mage.Sets/src/mage/cards/l/LeechingLurker.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.l; - -import mage.MageInt; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.NightboundAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class LeechingLurker extends CardImpl { - - public LeechingLurker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.LEECH); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private LeechingLurker(final LeechingLurker card) { - super(card); - } - - @Override - public LeechingLurker copy() { - return new LeechingLurker(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LightningSurge.java b/Mage.Sets/src/mage/cards/l/LightningSurge.java index 517f07f2347..4affdc01001 100644 --- a/Mage.Sets/src/mage/cards/l/LightningSurge.java +++ b/Mage.Sets/src/mage/cards/l/LightningSurge.java @@ -25,7 +25,7 @@ public final class LightningSurge extends CardImpl { // Lightning Surge deals 4 damage to any target. // Threshold - If seven or more cards are in your graveyard, instead Lightning Surge deals 6 damage to that creature or player and the damage can't be prevented. Effect effect = new ConditionalOneShotEffect( - new DamageTargetEffect(6, false), new DamageTargetEffect(4), + new DamageTargetEffect(6).withCantBePrevented(), new DamageTargetEffect(4), ThresholdCondition.instance, "{this} deals 4 damage to any target.
" + AbilityWord.THRESHOLD.formatWord() + "If seven or more cards are in your graveyard, " + "instead {this} deals 6 damage to that permanent or player and the damage can't be prevented" diff --git a/Mage.Sets/src/mage/cards/l/LikenessOfTheSeeker.java b/Mage.Sets/src/mage/cards/l/LikenessOfTheSeeker.java deleted file mode 100644 index a2fa4b8c3b0..00000000000 --- a/Mage.Sets/src/mage/cards/l/LikenessOfTheSeeker.java +++ /dev/null @@ -1,40 +0,0 @@ -package mage.cards.l; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; -import mage.abilities.effects.common.UntapLandsEffect; -import mage.constants.SubType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; - -/** - * - * @author weirddan455 - */ -public final class LikenessOfTheSeeker extends CardImpl { - - public LikenessOfTheSeeker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.MONK); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setGreen(true); - this.nightCard = true; - - // Whenever Likeness of the Seeker becomes blocked, untap up to three lands you control. - this.addAbility(new BecomesBlockedSourceTriggeredAbility(new UntapLandsEffect(3, true, true), false)); - } - - private LikenessOfTheSeeker(final LikenessOfTheSeeker card) { - super(card); - } - - @Override - public LikenessOfTheSeeker copy() { - return new LikenessOfTheSeeker(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LordOfLineage.java b/Mage.Sets/src/mage/cards/l/LordOfLineage.java deleted file mode 100644 index 3480656c2d1..00000000000 --- a/Mage.Sets/src/mage/cards/l/LordOfLineage.java +++ /dev/null @@ -1,57 +0,0 @@ -package mage.cards.l; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.game.permanent.token.VampireToken; - -/** - * - * @author Loki - */ -public final class LordOfLineage extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.VAMPIRE, "Vampire creatures"); - - public LordOfLineage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.VAMPIRE); - - this.color.setBlack(true); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - - // this card is the second face of double-faced card Bloodline Keeper - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Other Vampire creatures you control get +2/+2. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, filter, true))); - - // {T}: Create a 2/2 black Vampire creature token with flying. - this.addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new VampireToken()), new TapSourceCost())); - } - - private LordOfLineage(final LordOfLineage card) { - super(card); - } - - @Override - public LordOfLineage copy() { - return new LordOfLineage(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LostVale.java b/Mage.Sets/src/mage/cards/l/LostVale.java deleted file mode 100644 index 2936d1430ff..00000000000 --- a/Mage.Sets/src/mage/cards/l/LostVale.java +++ /dev/null @@ -1,34 +0,0 @@ -package mage.cards.l; - -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.mana.AddManaOfAnyColorEffect; -import mage.abilities.mana.SimpleManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class LostVale extends CardImpl { - - public LostVale(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.nightCard = true; - - // T: Add three mana of any one color. - this.addAbility(new SimpleManaAbility(new AddManaOfAnyColorEffect(3), new TapSourceCost())); - } - - private LostVale(final LostVale card) { - super(card); - } - - @Override - public LostVale copy() { - return new LostVale(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LunarchInquisitors.java b/Mage.Sets/src/mage/cards/l/LunarchInquisitors.java deleted file mode 100644 index 191be943d48..00000000000 --- a/Mage.Sets/src/mage/cards/l/LunarchInquisitors.java +++ /dev/null @@ -1,46 +0,0 @@ -package mage.cards.l; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class LunarchInquisitors extends CardImpl { - - public LunarchInquisitors(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setWhite(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // When this creature transforms into Lunarch Inquisitors, you may exile another target creature until Lunarch Inquisitors leaves the battlefield. - Ability ability = new TransformIntoSourceTriggeredAbility(new ExileUntilSourceLeavesEffect(), true); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); - this.addAbility(ability); - } - - private LunarchInquisitors(final LunarchInquisitors card) { - super(card); - } - - @Override - public LunarchInquisitors copy() { - return new LunarchInquisitors(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/Manabarbs.java b/Mage.Sets/src/mage/cards/m/Manabarbs.java index 2ce7acb564f..d267a2cbd21 100644 --- a/Mage.Sets/src/mage/cards/m/Manabarbs.java +++ b/Mage.Sets/src/mage/cards/m/Manabarbs.java @@ -22,7 +22,7 @@ public final class Manabarbs extends CardImpl { // Whenever a player taps a land for mana, Manabarbs deals 1 damage to that player. this.addAbility(new TapForManaAllTriggeredAbility( - new DamageTargetEffect(1, true, "that player"), + new DamageTargetEffect(1).withTargetDescription("that player"), new FilterLandPermanent("a player taps a land"), SetTargetPointer.PLAYER)); } diff --git a/Mage.Sets/src/mage/cards/m/MarkovsServant.java b/Mage.Sets/src/mage/cards/m/MarkovsServant.java deleted file mode 100644 index 81a62c53563..00000000000 --- a/Mage.Sets/src/mage/cards/m/MarkovsServant.java +++ /dev/null @@ -1,36 +0,0 @@ - -package mage.cards.m; - -import java.util.UUID; -import mage.MageInt; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author Loki - */ -public final class MarkovsServant extends CardImpl { - - public MarkovsServant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},null); - this.subtype.add(SubType.VAMPIRE); - this.color.setBlack(true); - - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.nightCard = true; - } - - private MarkovsServant(final MarkovsServant card) { - super(card); - } - - @Override - public MarkovsServant copy() { - return new MarkovsServant(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java b/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java index b4d4df12080..4c33ac837a6 100644 --- a/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java +++ b/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java @@ -24,7 +24,7 @@ public final class MaskOfIntolerance extends CardImpl { // At the beginning of each player's upkeep, if there are four or more basic land types among lands that player controls, Mask of Intolerance deals 3 damage to that player. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.EACH_PLAYER, new DamageTargetEffect(3, true, "that player"), false + TargetController.EACH_PLAYER, new DamageTargetEffect(3).withTargetDescription("that player"), false ).withInterveningIf(MaskOfIntoleranceCondition.instance).addHint(DomainHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/m/Megrim.java b/Mage.Sets/src/mage/cards/m/Megrim.java index 4f2d3aec0ca..a258655a852 100644 --- a/Mage.Sets/src/mage/cards/m/Megrim.java +++ b/Mage.Sets/src/mage/cards/m/Megrim.java @@ -19,7 +19,7 @@ public final class Megrim extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}"); // Whenever an opponent discards a card, Megrim deals 2 damage to that player. - this.addAbility(new DiscardsACardOpponentTriggeredAbility(new DamageTargetEffect(2, true, "that player"), false, SetTargetPointer.PLAYER)); + this.addAbility(new DiscardsACardOpponentTriggeredAbility(new DamageTargetEffect(2).withTargetDescription("that player"), false, SetTargetPointer.PLAYER)); } private Megrim(final Megrim card) { diff --git a/Mage.Sets/src/mage/cards/m/MilesMorales.java b/Mage.Sets/src/mage/cards/m/MilesMorales.java index 6069cffefeb..3e0f040fb29 100644 --- a/Mage.Sets/src/mage/cards/m/MilesMorales.java +++ b/Mage.Sets/src/mage/cards/m/MilesMorales.java @@ -60,7 +60,7 @@ public final class MilesMorales extends ModalDoubleFacedCard { // When Miles Morales enters, put a +1/+1 counter on each of up to two target creatures. Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); ability.addTarget(new TargetCreaturePermanent(0, 2)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {3}{R}{G}{W}: Transform Miles Morales. Activate only as a sorcery. this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/m/MisterNegative.java b/Mage.Sets/src/mage/cards/m/MisterNegative.java index 47f035eccda..01f556e6c58 100644 --- a/Mage.Sets/src/mage/cards/m/MisterNegative.java +++ b/Mage.Sets/src/mage/cards/m/MisterNegative.java @@ -59,7 +59,7 @@ class MisterNegativeEffect extends OneShotEffect { MisterNegativeEffect() { super(Outcome.Neutral); - staticText = "When {this} enters, you may exchange your life total with target opponent. If you lose life this way, draw that many cards."; + staticText = "you may exchange life totals with target opponent. If you lose life this way, draw that many cards."; } protected MisterNegativeEffect(final MisterNegativeEffect effect) { @@ -82,6 +82,7 @@ class MisterNegativeEffect extends OneShotEffect { controller.exchangeLife(player, source, game); int lifeChange = startingLife - controller.getLife(); if (lifeChange > 0) { + game.processAction(); controller.drawCards(lifeChange, source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/m/MomosHeist.java b/Mage.Sets/src/mage/cards/m/MomosHeist.java new file mode 100644 index 00000000000..aeef02004db --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MomosHeist.java @@ -0,0 +1,46 @@ +package mage.cards.m; + +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetArtifactPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MomosHeist extends CardImpl { + + public MomosHeist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Gain control of target artifact. Untap it. It gains haste. At the beginning of the next end step, sacrifice it. + this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.Custom)); + this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap it")); + this.getSpellAbility().addTarget(new TargetArtifactPermanent()); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.Custom + ).setText("It gains haste")); + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeTargetEffect("sacrifice it")), true + )); + } + + private MomosHeist(final MomosHeist card) { + super(card); + } + + @Override + public MomosHeist copy() { + return new MomosHeist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MoonrageBrute.java b/Mage.Sets/src/mage/cards/m/MoonrageBrute.java deleted file mode 100644 index 1b9ed12ce72..00000000000 --- a/Mage.Sets/src/mage/cards/m/MoonrageBrute.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.abilities.costs.common.PayLifeCost; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.keyword.WardAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class MoonrageBrute extends CardImpl { - - public MoonrageBrute(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setRed(true); - this.nightCard = true; - - // First strike - this.addAbility(FirstStrikeAbility.getInstance()); - - // Ward—Pay 3 life. - this.addAbility(new WardAbility(new PayLifeCost(3), false)); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private MoonrageBrute(final MoonrageBrute card) { - super(card); - } - - @Override - public MoonrageBrute copy() { - return new MoonrageBrute(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/Mournwillow.java b/Mage.Sets/src/mage/cards/m/Mournwillow.java index e6bdde9bae8..bc5c5b3630e 100644 --- a/Mage.Sets/src/mage/cards/m/Mournwillow.java +++ b/Mage.Sets/src/mage/cards/m/Mournwillow.java @@ -1,20 +1,16 @@ package mage.cards.m; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; -import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.combat.CantBlockAllEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; import java.util.UUID; @@ -23,6 +19,11 @@ import java.util.UUID; */ public final class Mournwillow extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with power 2 or less"); + static { + filter.add(new PowerPredicate(ComparisonType.OR_LESS, 2)); + } + public Mournwillow(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{G}"); this.subtype.add(SubType.PLANT); @@ -35,7 +36,7 @@ public final class Mournwillow extends CardImpl { // Delirium — When Mournwillow enters the battlefield, if there are four or more card types among cards in your graveyard, // creatures with power 2 or less can't block this turn. - this.addAbility(new EntersBattlefieldTriggeredAbility(new MournwillowEffect()) + this.addAbility(new EntersBattlefieldTriggeredAbility(new CantBlockAllEffect(filter, Duration.EndOfTurn)) .withInterveningIf(DeliriumCondition.instance) .setAbilityWord(AbilityWord.DELIRIUM) .addHint(CardTypesInGraveyardCount.YOU.getHint())); @@ -50,30 +51,3 @@ public final class Mournwillow extends CardImpl { return new Mournwillow(this); } } - -class MournwillowEffect extends RestrictionEffect { - - MournwillowEffect() { - super(Duration.EndOfTurn); - staticText = "creatures with power 2 or less can't block this turn"; - } - - private MournwillowEffect(final MournwillowEffect effect) { - super(effect); - } - - @Override - public MournwillowEffect copy() { - return new MournwillowEffect(this); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - return permanent.getPower().getValue() <= 2; - } - - @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MycosynthLattice.java b/Mage.Sets/src/mage/cards/m/MycosynthLattice.java index cbefd32b853..7f14adf8639 100644 --- a/Mage.Sets/src/mage/cards/m/MycosynthLattice.java +++ b/Mage.Sets/src/mage/cards/m/MycosynthLattice.java @@ -134,10 +134,10 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl { affectedCards.forEach(card -> { game.getState().getCreateMageObjectAttribute(card, game).getColor().setColor(colorless); - // mdf cards - if (card instanceof ModalDoubleFacedCard) { - ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); - ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard(); + // df cards + if (card instanceof DoubleFacedCard) { + DoubleFacedCardHalf leftHalfCard = ((DoubleFacedCard) card).getLeftHalfCard(); + DoubleFacedCardHalf rightHalfCard = ((DoubleFacedCard) card).getRightHalfCard(); game.getState().getCreateMageObjectAttribute(leftHalfCard, game).getColor().setColor(colorless); game.getState().getCreateMageObjectAttribute(rightHalfCard, game).getColor().setColor(colorless); } @@ -151,6 +151,7 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl { } // double faces cards + // TODO: can remove after tdfc rework if (card.getSecondCardFace() != null) { game.getState().getCreateMageObjectAttribute(card, game).getColor().setColor(colorless); } diff --git a/Mage.Sets/src/mage/cards/n/NeckBreaker.java b/Mage.Sets/src/mage/cards/n/NeckBreaker.java deleted file mode 100644 index 96ced371e3f..00000000000 --- a/Mage.Sets/src/mage/cards/n/NeckBreaker.java +++ /dev/null @@ -1,57 +0,0 @@ -package mage.cards.n; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class NeckBreaker extends CardImpl { - - public NeckBreaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Attacking creatures you control get +1/+0 and have trample. - Ability ability = new SimpleStaticAbility(new BoostControlledEffect( - 1, 0, Duration.WhileOnBattlefield, - StaticFilters.FILTER_ATTACKING_CREATURES - )); - ability.addEffect(new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_ATTACKING_CREATURES - ).setText("and have trample")); - this.addAbility(ability); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Neck Breaker. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private NeckBreaker(final NeckBreaker card) { - super(card); - } - - @Override - public NeckBreaker copy() { - return new NeckBreaker(this); - } -} diff --git a/Mage.Sets/src/mage/cards/n/NekusarTheMindrazer.java b/Mage.Sets/src/mage/cards/n/NekusarTheMindrazer.java index 43c1a721efd..e565a69b724 100644 --- a/Mage.Sets/src/mage/cards/n/NekusarTheMindrazer.java +++ b/Mage.Sets/src/mage/cards/n/NekusarTheMindrazer.java @@ -33,7 +33,7 @@ public final class NekusarTheMindrazer extends CardImpl { false)); // Whenever an opponent draws a card, Nekusar, the Mindrazer deals 1 damage to that player. - this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1, true, "that player"), false, true)); + this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that player"), false, true)); } private NekusarTheMindrazer(final NekusarTheMindrazer card) { diff --git a/Mage.Sets/src/mage/cards/n/NeoExdeathDimensionsEnd.java b/Mage.Sets/src/mage/cards/n/NeoExdeathDimensionsEnd.java deleted file mode 100644 index d2602d2d66b..00000000000 --- a/Mage.Sets/src/mage/cards/n/NeoExdeathDimensionsEnd.java +++ /dev/null @@ -1,52 +0,0 @@ -package mage.cards.n; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; -import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class NeoExdeathDimensionsEnd extends CardImpl { - - private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_PERMANENTS); - - public NeoExdeathDimensionsEnd(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.AVATAR); - this.power = new MageInt(0); - this.toughness = new MageInt(3); - this.nightCard = true; - this.color.setBlack(true); - this.color.setGreen(true); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Neo Exdeath's power is equal to the number of permanent cards in your graveyard. - this.addAbility(new SimpleStaticAbility(new SetBasePowerSourceEffect(xValue))); - } - - private NeoExdeathDimensionsEnd(final NeoExdeathDimensionsEnd card) { - super(card); - } - - @Override - public NeoExdeathDimensionsEnd copy() { - return new NeoExdeathDimensionsEnd(this); - } -} diff --git a/Mage.Sets/src/mage/cards/n/NightfallPredator.java b/Mage.Sets/src/mage/cards/n/NightfallPredator.java deleted file mode 100644 index 275b43fe3cb..00000000000 --- a/Mage.Sets/src/mage/cards/n/NightfallPredator.java +++ /dev/null @@ -1,57 +0,0 @@ -package mage.cards.n; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.FightTargetSourceEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author North - */ -public final class NightfallPredator extends CardImpl { - - public NightfallPredator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - - this.color.setGreen(true); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - // this card is the second face of double-faced card - this.nightCard = true; - - // {R}, {tap}: Nightfall Predator fights target creature. - Ability activatedAbility = new SimpleActivatedAbility( - new FightTargetSourceEffect().setText( - "{this} fights target creature. " + - "(Each deals damage equal to its power to the other.)"), - new ManaCostsImpl<>("{R}") - ); - activatedAbility.addCost(new TapSourceCost()); - activatedAbility.addTarget(new TargetCreaturePermanent()); - this.addAbility(activatedAbility); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Nightfall Predator. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private NightfallPredator(final NightfallPredator card) { - super(card); - } - - @Override - public NightfallPredator copy() { - return new NightfallPredator(this); - } -} diff --git a/Mage.Sets/src/mage/cards/n/NylaShirshuSleuth.java b/Mage.Sets/src/mage/cards/n/NylaShirshuSleuth.java new file mode 100644 index 00000000000..9b293cc893c --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NylaShirshuSleuth.java @@ -0,0 +1,134 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.token.ClueArtifactToken; +import mage.players.Player; +import mage.target.common.TargetCardInExile; +import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NylaShirshuSleuth extends CardImpl { + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.CLUE, "you control no Clues"), ComparisonType.EQUAL_TO, 0 + ); + private static final Hint hint = new ValueHint( + "Clues you control", new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.CLUE)) + ); + private static final FilterCard filter = new FilterCard("card exiled with this permanent"); + + static { + filter.add(NylaShirshuSleuthPredicate.instance); + } + + public NylaShirshuSleuth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MOLE); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // When Nyla enters, exile up to one target creature card from your graveyard. If you do, you lose X life and create X Clue tokens, where X is that card's mana value. + Ability ability = new EntersBattlefieldTriggeredAbility(new NylaShirshuSleuthEffect()); + ability.addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(ability); + + // At the beginning of your end step, if you control no Clues, return target card exiled with Nyla to its owner's hand. + ability = new BeginningOfEndStepTriggeredAbility(new ReturnToHandTargetEffect() + .setText("return target card exiled with {this} to its owner's hand")) + .withInterveningIf(condition) + .addHint(hint); + ability.addTarget(new TargetCardInExile(filter)); + this.addAbility(ability); + } + + private NylaShirshuSleuth(final NylaShirshuSleuth card) { + super(card); + } + + @Override + public NylaShirshuSleuth copy() { + return new NylaShirshuSleuth(this); + } +} + +enum NylaShirshuSleuthPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return Optional + .ofNullable(input) + .map(ObjectSourcePlayer::getSource) + .map(source -> CardUtil.getExileZoneId(game, source)) + .map(game.getState().getExile()::getExileZone) + .filter(exile -> exile.contains(input.getObject().getId())) + .isPresent(); + } +} + +class NylaShirshuSleuthEffect extends OneShotEffect { + + NylaShirshuSleuthEffect() { + super(Outcome.Benefit); + staticText = "exile up to one target creature card from your graveyard. " + + "If you do, you lose X life and create X Clue tokens, where X is that card's mana value"; + } + + private NylaShirshuSleuthEffect(final NylaShirshuSleuthEffect effect) { + super(effect); + } + + @Override + public NylaShirshuSleuthEffect copy() { + return new NylaShirshuSleuthEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (player == null || card == null) { + return false; + } + int mv = card.getManaValue(); + player.moveCardsToExile( + card, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + if (mv > 0) { + player.loseLife(mv, game, source, false); + new ClueArtifactToken().putOntoBattlefield(mv, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java b/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java index 09a51a27ee6..7cf043ecee2 100644 --- a/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java +++ b/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java @@ -28,9 +28,8 @@ public final class ObNixilisTheHateTwisted extends CardImpl { this.setStartingLoyalty(5); // Whenever an opponent draws a card, Ob Nixilis, the Hate-Twisted deals 1 damage to that player. - this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect( - 1, true, "that player" - ), false, true)); + this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1) + .withTargetDescription("that player"), false, true)); // -2: Destroy target creature. Its controller draws two cards. Ability ability = new LoyaltyAbility(new DestroyTargetEffect(), -2); diff --git a/Mage.Sets/src/mage/cards/o/ObsessivePursuit.java b/Mage.Sets/src/mage/cards/o/ObsessivePursuit.java new file mode 100644 index 00000000000..39fa5c31463 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObsessivePursuit.java @@ -0,0 +1,74 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.PermanentsSacrificedThisTurnCount; +import mage.abilities.effects.common.AddContinuousEffectToGame; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.meta.OrTriggeredAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.token.ClueArtifactToken; +import mage.target.common.TargetAttackingCreature; +import mage.watchers.common.PermanentsSacrificedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ObsessivePursuit extends CardImpl { + + public ObsessivePursuit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + + // When this enchantment enters and at the beginning of your upkeep, you lose 1 life and create a Clue token. + Ability ability = new OrTriggeredAbility( + Zone.BATTLEFIELD, new LoseLifeSourceControllerEffect(1), + new EntersBattlefieldTriggeredAbility(null), new BeginningOfUpkeepTriggeredAbility(null) + ).setTriggerPhrase("When {this} enters and at the beginning of your upkeep, "); + ability.addEffect(new CreateTokenEffect(new ClueArtifactToken()).concatBy("and")); + this.addAbility(ability); + + // Whenever you attack, put X +1/+1 counters on target attacking creature, where X is the number of permanents you've sacrificed this turn. If X is three or greater, that creature gains lifelink until end of turn. + ability = new AttacksWithCreaturesTriggeredAbility(new AddCountersTargetEffect( + CounterType.P1P1.createInstance(), PermanentsSacrificedThisTurnCount.YOU + ), 1).addHint(PermanentsSacrificedThisTurnCount.YOU.getHint()); + ability.addEffect(new ConditionalOneShotEffect( + new AddContinuousEffectToGame(new GainAbilityTargetEffect(LifelinkAbility.getInstance())), + ObsessivePursuitCondition.instance, "If X is three or greater, that creature gains lifelink until end of turn" + )); + ability.addTarget(new TargetAttackingCreature()); + this.addAbility(ability, new PermanentsSacrificedWatcher()); + } + + private ObsessivePursuit(final ObsessivePursuit card) { + super(card); + } + + @Override + public ObsessivePursuit copy() { + return new ObsessivePursuit(this); + } +} + +enum ObsessivePursuitCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return PermanentsSacrificedThisTurnCount.YOU.calculate(game, source, null) >= 3; + } +} diff --git a/Mage.Sets/src/mage/cards/o/OptimusPrimeAutobotLeader.java b/Mage.Sets/src/mage/cards/o/OptimusPrimeAutobotLeader.java deleted file mode 100644 index a3d53cfe4dc..00000000000 --- a/Mage.Sets/src/mage/cards/o/OptimusPrimeAutobotLeader.java +++ /dev/null @@ -1,130 +0,0 @@ -package mage.cards.o; - -import mage.MageInt; -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.effects.keyword.BolsterEffect; -import mage.abilities.keyword.LivingMetalAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; - -import java.util.UUID; - -/** - * @author xenohedron - */ -public final class OptimusPrimeAutobotLeader extends CardImpl { - - public OptimusPrimeAutobotLeader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(6); - this.toughness = new MageInt(8); - this.color.setWhite(true); - this.color.setBlue(true); - this.color.setRed(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Whenever you attack, bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert Optimus Prime. - this.addAbility(new AttacksWithCreaturesTriggeredAbility(new BolsterEffect(2) - .withAdditionalEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance())) - .withAdditionalEffect(new OptimusPrimeAutobotLeaderEffect()) - .setText("bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert {this}"), - 1)); - - // Transform Ability - this.addAbility(new TransformAbility()); - } - - private OptimusPrimeAutobotLeader(final OptimusPrimeAutobotLeader card) { - super(card); - } - - @Override - public OptimusPrimeAutobotLeader copy() { - return new OptimusPrimeAutobotLeader(this); - } -} - -class OptimusPrimeAutobotLeaderEffect extends OneShotEffect { - - OptimusPrimeAutobotLeaderEffect() { - super(Outcome.Transform); - } - - private OptimusPrimeAutobotLeaderEffect(final OptimusPrimeAutobotLeaderEffect effect) { - super(effect); - } - - @Override - public OptimusPrimeAutobotLeaderEffect copy() { - return new OptimusPrimeAutobotLeaderEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (creature == null) { - return false; - } - game.addDelayedTriggeredAbility(new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(new MageObjectReference(creature, game)), source); - return true; - } - -} - -class OptimusPrimeAutobotLeaderDelayedTriggeredAbility extends DelayedTriggeredAbility { - - private final MageObjectReference mor; - - OptimusPrimeAutobotLeaderDelayedTriggeredAbility(MageObjectReference mor) { - super(new TransformSourceEffect().setText("convert {this}"), Duration.EndOfTurn); - this.mor = mor; - setTriggerPhrase("When that creature deals combat damage to a player this turn, "); - } - - private OptimusPrimeAutobotLeaderDelayedTriggeredAbility(final OptimusPrimeAutobotLeaderDelayedTriggeredAbility ability) { - super(ability); - this.mor = ability.mor; - } - - @Override - public OptimusPrimeAutobotLeaderDelayedTriggeredAbility copy() { - return new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (((DamagedPlayerEvent) event).isCombatDamage()) { - Permanent permanent = game.getPermanent(event.getSourceId()); - return mor.refersTo(permanent, game); - } - return false; - } - -} diff --git a/Mage.Sets/src/mage/cards/o/OptimusPrimeHero.java b/Mage.Sets/src/mage/cards/o/OptimusPrimeHero.java index 833b7d03404..11a4d5db80c 100644 --- a/Mage.Sets/src/mage/cards/o/OptimusPrimeHero.java +++ b/Mage.Sets/src/mage/cards/o/OptimusPrimeHero.java @@ -1,7 +1,13 @@ package mage.cards.o; -import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.LivingMetalAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -9,10 +15,14 @@ import mage.abilities.effects.keyword.BolsterEffect; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.cards.TransformingDoubleFacedCardHalf; import mage.constants.*; import mage.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; import mage.players.Player; import java.util.UUID; @@ -20,25 +30,40 @@ import java.util.UUID; /** * @author jbureau88 */ -public final class OptimusPrimeHero extends CardImpl { +public final class OptimusPrimeHero extends TransformingDoubleFacedCard { public OptimusPrimeHero(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{U}{R}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{3}{U}{R}{W}", + "Optimus Prime, Autobot Leader", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "WUR"); - this.addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(4); - this.toughness = new MageInt(8); - this.secondSideCardClazz = mage.cards.o.OptimusPrimeAutobotLeader.class; + this.getLeftHalfCard().setPT(4, 8); + this.getRightHalfCard().setPT(6, 8); // More Than Meets the Eye {2}{U}{R}{W} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{U}{R}{W}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{U}{R}{W}")); // At the beginning of each end step, bolster 1. - this.addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.ANY, new BolsterEffect(1), false)); + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.ANY, new BolsterEffect(1), false)); // When Optimus Prime dies, return it to the battlefield converted under its owner’s control. - this.addAbility(new DiesSourceTriggeredAbility(new OptimusPrimeHeroEffect())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new OptimusPrimeHeroEffect())); + + // Optimus Prime, Autobot Leader + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Whenever you attack, bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert Optimus Prime. + this.getRightHalfCard().addAbility(new AttacksWithCreaturesTriggeredAbility(new BolsterEffect(2) + .withAdditionalEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance())) + .withAdditionalEffect(new OptimusPrimeAutobotLeaderEffect()) + .setText("bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert {this}"), + 1)); } private OptimusPrimeHero(final OptimusPrimeHero card) { @@ -70,11 +95,81 @@ class OptimusPrimeHeroEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Card card = game.getCard(source.getSourceId()); - if (card == null || controller == null) { + Card card = source.getSourceCardIfItStillExists(game); + if (controller == null || card == null) { return false; } - game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - return controller.moveCards(card, Zone.BATTLEFIELD, source, game); + if (game.getState().getZone(source.getSourceId()) != Zone.GRAVEYARD) { + return true; + } + Card backSide = ((TransformingDoubleFacedCardHalf) card).getOtherSide(); + if (backSide == null) { + return true; + } + game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + backSide.getId(), true); + controller.moveCards(backSide, Zone.BATTLEFIELD, source, game); + return true; + } +} + +class OptimusPrimeAutobotLeaderEffect extends OneShotEffect { + + OptimusPrimeAutobotLeaderEffect() { + super(Outcome.Transform); + } + + private OptimusPrimeAutobotLeaderEffect(final OptimusPrimeAutobotLeaderEffect effect) { + super(effect); + } + + @Override + public OptimusPrimeAutobotLeaderEffect copy() { + return new OptimusPrimeAutobotLeaderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (creature == null) { + return false; + } + game.addDelayedTriggeredAbility(new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(new MageObjectReference(creature, game)), source); + return true; + } + +} + +class OptimusPrimeAutobotLeaderDelayedTriggeredAbility extends DelayedTriggeredAbility { + + private final MageObjectReference mor; + + OptimusPrimeAutobotLeaderDelayedTriggeredAbility(MageObjectReference mor) { + super(new TransformSourceEffect().setText("convert {this}"), Duration.EndOfTurn); + this.mor = mor; + setTriggerPhrase("When that creature deals combat damage to a player this turn, "); + } + + private OptimusPrimeAutobotLeaderDelayedTriggeredAbility(final OptimusPrimeAutobotLeaderDelayedTriggeredAbility ability) { + super(ability); + this.mor = ability.mor; + } + + @Override + public OptimusPrimeAutobotLeaderDelayedTriggeredAbility copy() { + return new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (((DamagedPlayerEvent) event).isCombatDamage()) { + Permanent permanent = game.getPermanent(event.getSourceId()); + return mor.refersTo(permanent, game); + } + return false; } } diff --git a/Mage.Sets/src/mage/cards/o/OrneryGoblin.java b/Mage.Sets/src/mage/cards/o/OrneryGoblin.java index 5c78ad12729..418e73e97db 100644 --- a/Mage.Sets/src/mage/cards/o/OrneryGoblin.java +++ b/Mage.Sets/src/mage/cards/o/OrneryGoblin.java @@ -24,7 +24,7 @@ public final class OrneryGoblin extends CardImpl { this.toughness = new MageInt(1); // Whenever Ornery Goblin blocks or becomes blocked by a creature, Ornery Goblin deals 1 damage to that creature. - this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1, true, "that creature"))); + this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that creature"))); } private OrneryGoblin(final OrneryGoblin card) { diff --git a/Mage.Sets/src/mage/cards/o/OstrichHorse.java b/Mage.Sets/src/mage/cards/o/OstrichHorse.java index 4c4131db6f5..5ed227bafca 100644 --- a/Mage.Sets/src/mage/cards/o/OstrichHorse.java +++ b/Mage.Sets/src/mage/cards/o/OstrichHorse.java @@ -29,7 +29,7 @@ public final class OstrichHorse extends CardImpl { // When this creature enters, mill three cards. You may put a land card from among them into your hand. If you don't, put a +1/+1 counter on this creature. this.addAbility(new EntersBattlefieldTriggeredAbility(new MillThenPutInHandEffect( 3, StaticFilters.FILTER_CARD_LAND, new AddCountersSourceEffect(CounterType.P1P1.createInstance()) - ))); + ).withTextOptions("them"))); } private OstrichHorse(final OstrichHorse card) { diff --git a/Mage.Sets/src/mage/cards/o/Overabundance.java b/Mage.Sets/src/mage/cards/o/Overabundance.java index 94b7b809584..ea68ec6f634 100644 --- a/Mage.Sets/src/mage/cards/o/Overabundance.java +++ b/Mage.Sets/src/mage/cards/o/Overabundance.java @@ -30,7 +30,7 @@ public final class Overabundance extends CardImpl { )); this.addAbility(new TapForManaAllTriggeredAbility( - new DamageTargetEffect(1, true, "that player"), + new DamageTargetEffect(1).withTargetDescription("that player"), new FilterLandPermanent("a player taps a land"), SetTargetPointer.PLAYER )); diff --git a/Mage.Sets/src/mage/cards/p/PaintersServant.java b/Mage.Sets/src/mage/cards/p/PaintersServant.java index bdffc476a83..4c47d77655f 100644 --- a/Mage.Sets/src/mage/cards/p/PaintersServant.java +++ b/Mage.Sets/src/mage/cards/p/PaintersServant.java @@ -107,10 +107,10 @@ class PaintersServantEffect extends ContinuousEffectImpl { affectedCards.forEach(card -> { game.getState().getCreateMageObjectAttribute(card, game).getColor().addColor(color); - // mdf cards - if (card instanceof ModalDoubleFacedCard) { - ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); - ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard(); + // df cards + if (card instanceof DoubleFacedCard) { + DoubleFacedCardHalf leftHalfCard = ((DoubleFacedCard) card).getLeftHalfCard(); + DoubleFacedCardHalf rightHalfCard = ((DoubleFacedCard) card).getRightHalfCard(); game.getState().getCreateMageObjectAttribute(leftHalfCard, game).getColor().addColor(color); game.getState().getCreateMageObjectAttribute(rightHalfCard, game).getColor().addColor(color); } @@ -124,6 +124,7 @@ class PaintersServantEffect extends ContinuousEffectImpl { } // double faces cards + // TODO: can remove after tdfc rework if (card.getSecondCardFace() != null) { game.getState().getCreateMageObjectAttribute(card.getSecondCardFace(), game).getColor().addColor(color); } diff --git a/Mage.Sets/src/mage/cards/p/PaupersCage.java b/Mage.Sets/src/mage/cards/p/PaupersCage.java index 2c976f03dca..757ffb2fbea 100644 --- a/Mage.Sets/src/mage/cards/p/PaupersCage.java +++ b/Mage.Sets/src/mage/cards/p/PaupersCage.java @@ -24,7 +24,7 @@ public final class PaupersCage extends CardImpl { // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Paupers' Cage deals 2 damage to that player. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.OPPONENT, new DamageTargetEffect(2, true, "that player"), false + TargetController.OPPONENT, new DamageTargetEffect(2).withTargetDescription("that player"), false ).withInterveningIf(condition)); } diff --git a/Mage.Sets/src/mage/cards/p/PerfectedForm.java b/Mage.Sets/src/mage/cards/p/PerfectedForm.java deleted file mode 100644 index 64232ed2ee7..00000000000 --- a/Mage.Sets/src/mage/cards/p/PerfectedForm.java +++ /dev/null @@ -1,41 +0,0 @@ - -package mage.cards.p; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class PerfectedForm extends CardImpl { - - public PerfectedForm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.INSECT); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(5); - this.toughness = new MageInt(4); - this.color.setBlue(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private PerfectedForm(final PerfectedForm card) { - super(card); - } - - @Override - public PerfectedForm copy() { - return new PerfectedForm(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PersistentNightmare.java b/Mage.Sets/src/mage/cards/p/PersistentNightmare.java deleted file mode 100644 index d1825f3f44b..00000000000 --- a/Mage.Sets/src/mage/cards/p/PersistentNightmare.java +++ /dev/null @@ -1,46 +0,0 @@ -package mage.cards.p; - -import mage.MageInt; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandSourceEffect; -import mage.abilities.keyword.SkulkAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class PersistentNightmare extends CardImpl { - - public PersistentNightmare(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.NIGHTMARE); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.color.setBlue(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Skulk - this.addAbility(new SkulkAbility()); - - // When Persistent Nightmare deals combat damage to a player, return it to its owner's hand. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new ReturnToHandSourceEffect(), false - ).setTriggerPhrase("When {this} deals combat damage to a player, ")); - } - - private PersistentNightmare(final PersistentNightmare card) { - super(card); - } - - @Override - public PersistentNightmare copy() { - return new PersistentNightmare(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PhoenixFleetAirship.java b/Mage.Sets/src/mage/cards/p/PhoenixFleetAirship.java index 564c6c5556c..7c6ca6aea08 100644 --- a/Mage.Sets/src/mage/cards/p/PhoenixFleetAirship.java +++ b/Mage.Sets/src/mage/cards/p/PhoenixFleetAirship.java @@ -12,7 +12,6 @@ import mage.abilities.effects.CreateTokenCopySourceEffect; import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.hint.common.PermanentsSacrificedThisTurnHint; import mage.abilities.keyword.CrewAbility; import mage.abilities.keyword.FlyingAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; @@ -59,7 +58,7 @@ public final class PhoenixFleetAirship extends CardImpl { // At the beginning of your end step, if you sacrificed a permanent this turn, create a token that's a copy of this Vehicle. this.addAbility(new BeginningOfEndStepTriggeredAbility(new CreateTokenCopySourceEffect()) .withInterveningIf(PhoenixFleetAirshipCondition.instance) - .addHint(PermanentsSacrificedThisTurnHint.instance), new PermanentsSacrificedWatcher()); + .addHint(PermanentsSacrificedThisTurnCount.YOU.getHint()), new PermanentsSacrificedWatcher()); // As long as you control eight or more permanents named Phoenix Fleet Airship, this Vehicle is an artifact creature. this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( @@ -87,7 +86,7 @@ enum PhoenixFleetAirshipCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - return PermanentsSacrificedThisTurnCount.instance.calculate(game, source, null) > 0; + return PermanentsSacrificedThisTurnCount.YOU.calculate(game, source, null) > 0; } @Override diff --git a/Mage.Sets/src/mage/cards/p/PinpointAvalanche.java b/Mage.Sets/src/mage/cards/p/PinpointAvalanche.java index ab81e6a79d4..83e9d3ed0b4 100644 --- a/Mage.Sets/src/mage/cards/p/PinpointAvalanche.java +++ b/Mage.Sets/src/mage/cards/p/PinpointAvalanche.java @@ -18,7 +18,7 @@ public final class PinpointAvalanche extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R}{R}"); // Pinpoint Avalanche deals 4 damage to target creature. The damage can't be prevented. - this.getSpellAbility().addEffect(new DamageTargetEffect(4, false)); + this.getSpellAbility().addEffect(new DamageTargetEffect(4).withCantBePrevented()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/p/PlatedKilnbeast.java b/Mage.Sets/src/mage/cards/p/PlatedKilnbeast.java deleted file mode 100644 index f0cd80d8980..00000000000 --- a/Mage.Sets/src/mage/cards/p/PlatedKilnbeast.java +++ /dev/null @@ -1,40 +0,0 @@ -package mage.cards.p; - -import mage.MageInt; -import mage.abilities.keyword.MenaceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class PlatedKilnbeast extends CardImpl { - - public PlatedKilnbeast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.BEAST); - this.power = new MageInt(7); - this.toughness = new MageInt(5); - this.color.setRed(true); - this.color.setGreen(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - } - - private PlatedKilnbeast(final PlatedKilnbeast card) { - super(card); - } - - @Override - public PlatedKilnbeast copy() { - return new PlatedKilnbeast(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PrickleFaeries.java b/Mage.Sets/src/mage/cards/p/PrickleFaeries.java index 525b6089461..331dcf20681 100644 --- a/Mage.Sets/src/mage/cards/p/PrickleFaeries.java +++ b/Mage.Sets/src/mage/cards/p/PrickleFaeries.java @@ -34,7 +34,7 @@ public final class PrickleFaeries extends CardImpl { // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Prickle Faeries deals 2 damage to them. this.addAbility(new BeginningOfUpkeepTriggeredAbility( Zone.BATTLEFIELD, TargetController.OPPONENT, - new DamageTargetEffect(2, true, "them"), false + new DamageTargetEffect(2).withTargetDescription("them"), false ).withInterveningIf(condition)); } diff --git a/Mage.Sets/src/mage/cards/p/PrincessYue.java b/Mage.Sets/src/mage/cards/p/PrincessYue.java new file mode 100644 index 00000000000..1ae70920647 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PrincessYue.java @@ -0,0 +1,165 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PrincessYue extends CardImpl { + + public PrincessYue(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Princess Yue dies, if she was a nonland creature, return this card to the battlefield tapped under your control. She's a land named Moon. She gains "{T}: Add {C}." + this.addAbility(new PrincessYueTriggeredAbility()); + + // {T}: Scry 2. + this.addAbility(new SimpleActivatedAbility(new ScryEffect(2), new TapSourceCost())); + } + + private PrincessYue(final PrincessYue card) { + super(card); + } + + @Override + public PrincessYue copy() { + return new PrincessYue(this); + } +} + +class PrincessYueTriggeredAbility extends DiesSourceTriggeredAbility { + + PrincessYueTriggeredAbility() { + super(new PrincessYueReturnEffect()); + } + + private PrincessYueTriggeredAbility(final PrincessYueTriggeredAbility ability) { + super(ability); + } + + @Override + public PrincessYueTriggeredAbility copy() { + return new PrincessYueTriggeredAbility(this); + } + + @Override + public boolean checkInterveningIfClause(Game game) { + return CardUtil + .getEffectValueFromAbility(this, "permanentLeftBattlefield", Permanent.class) + .filter(permanent -> !permanent.isLand(game) && permanent.isCreature(game)) + .isPresent(); + } +} + +class PrincessYueReturnEffect extends OneShotEffect { + + PrincessYueReturnEffect() { + super(Outcome.Benefit); + staticText = "if she was a nonland creature, return this card to the battlefield tapped " + + "under your control. She's a land named Moon. She gains \"{T}: Add {C}.\""; + } + + private PrincessYueReturnEffect(final PrincessYueReturnEffect effect) { + super(effect); + } + + @Override + public PrincessYueReturnEffect copy() { + return new PrincessYueReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(source.getSourceId()); + if (player == null || card == null) { + return false; + } + game.addEffect(new PrincessYueTypeEffect() + .setTargetPointer(new FixedTarget(new MageObjectReference(card, game, 1))), source); + return player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, true, null); + } +} + +class PrincessYueTypeEffect extends ContinuousEffectImpl { + + PrincessYueTypeEffect() { + super(Duration.Custom, Outcome.Benefit); + } + + private PrincessYueTypeEffect(final PrincessYueTypeEffect effect) { + super(effect); + } + + @Override + public PrincessYueTypeEffect copy() { + return new PrincessYueTypeEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + discard(); + return false; + } + switch (layer) { + case TextChangingEffects_3: + permanent.setName("Moon"); + return true; + case TypeChangingEffects_4: + permanent.removeAllCardTypes(game); + permanent.addCardType(game, CardType.LAND); + return true; + case AbilityAddingRemovingEffects_6: + permanent.addAbility(new ColorlessManaAbility(), source.getSourceId(), game); + return true; + default: + return false; + } + } + + @Override + public boolean hasLayer(Layer layer) { + switch (layer) { + case TextChangingEffects_3: + case TypeChangingEffects_4: + case AbilityAddingRemovingEffects_6: + return true; + default: + return false; + } + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PrisonBreak.java b/Mage.Sets/src/mage/cards/p/PrisonBreak.java index 3ac0e4aacef..f4786cd2ec3 100644 --- a/Mage.Sets/src/mage/cards/p/PrisonBreak.java +++ b/Mage.Sets/src/mage/cards/p/PrisonBreak.java @@ -19,8 +19,8 @@ public final class PrisonBreak extends CardImpl { public PrisonBreak(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); - // Return target creature card from your graveyard to the battlefield with a +1/+1 counter on it. - this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(CounterType.P1P1.createInstance())); + // Return target creature card from your graveyard to the battlefield with an additional +1/+1 counter on it. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(true, CounterType.P1P1.createInstance())); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // Mayhem {3}{B} diff --git a/Mage.Sets/src/mage/cards/p/PyrostaticPillar.java b/Mage.Sets/src/mage/cards/p/PyrostaticPillar.java index 1d4a2db8358..f099429192d 100644 --- a/Mage.Sets/src/mage/cards/p/PyrostaticPillar.java +++ b/Mage.Sets/src/mage/cards/p/PyrostaticPillar.java @@ -42,7 +42,7 @@ class PyrostaticPillarTriggeredAbility extends TriggeredAbilityImpl { public PyrostaticPillarTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player")); } @@ -76,4 +76,4 @@ class PyrostaticPillarTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever a player casts a spell with mana value 3 or less, {this} deals 2 damage to that player."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/q/QuenchableFire.java b/Mage.Sets/src/mage/cards/q/QuenchableFire.java index 0b555526ce7..fac069deee6 100644 --- a/Mage.Sets/src/mage/cards/q/QuenchableFire.java +++ b/Mage.Sets/src/mage/cards/q/QuenchableFire.java @@ -24,7 +24,7 @@ public final class QuenchableFire extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(3)); // It deals an additional 3 damage to that player or planeswalker at the beginning of your next upkeep step unless that player or that planeswalker’s controller pays {U} before that step. this.getSpellAbility().addEffect(new UnlessPaysDelayedEffect(new ManaCostsImpl<>("{U}"), - new DamageTargetEffect(3, true, "that player or that planeswalker's controller"), PhaseStep.UPKEEP, false, + new DamageTargetEffect(3).withTargetDescription("that player or that planeswalker's controller"), PhaseStep.UPKEEP, false, "It deals an additional 3 damage to that player or planeswalker at the beginning of your next upkeep step unless that player or that planeswalker's controller pays {U} before that step.")); } diff --git a/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java b/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java index 131cab77f3d..d3e630d8ca4 100644 --- a/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java +++ b/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java @@ -43,8 +43,9 @@ public final class RampagingFerocidon extends CardImpl { this.addAbility(new SimpleStaticAbility(new CantGainLifeAllEffect())); // Whenever another creature enters the battlefield, Rampaging Ferocidon deals 1 damage to that creature's controller. - this.addAbility(new EntersBattlefieldAllTriggeredAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that creature's controller"), filter, false, SetTargetPointer.PLAYER)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, + new DamageTargetEffect(1).withTargetDescription("that creature's controller"), + filter, false, SetTargetPointer.PLAYER)); } private RampagingFerocidon(final RampagingFerocidon card) { diff --git a/Mage.Sets/src/mage/cards/r/RavagerOfTheFells.java b/Mage.Sets/src/mage/cards/r/RavagerOfTheFells.java deleted file mode 100644 index ed4bd054210..00000000000 --- a/Mage.Sets/src/mage/cards/r/RavagerOfTheFells.java +++ /dev/null @@ -1,131 +0,0 @@ -package mage.cards.r; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetPermanent; -import mage.target.common.TargetOpponentOrPlaneswalker; -import mage.target.targetpointer.EachTargetPointer; - -import java.util.Set; -import java.util.UUID; - -/** - * @author BetaSteward - */ -public final class RavagerOfTheFells extends CardImpl { - - public RavagerOfTheFells(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setRed(true); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.addAbility(TrampleAbility.getInstance()); - - // Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. - Ability ability = new TransformIntoSourceTriggeredAbility( - new RavagerOfTheFellsEffect(), false, true - ); - ability.addTarget(new TargetOpponentOrPlaneswalker()); - ability.addTarget(new RavagerOfTheFellsTarget()); - this.addAbility(ability); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private RavagerOfTheFells(final RavagerOfTheFells card) { - super(card); - } - - @Override - public RavagerOfTheFells copy() { - return new RavagerOfTheFells(this); - } -} - -class RavagerOfTheFellsEffect extends OneShotEffect { - - RavagerOfTheFellsEffect() { - super(Outcome.Damage); - this.setTargetPointer(new EachTargetPointer()); - staticText = "it deals 2 damage to target opponent or planeswalker and 2 damage " + - "to up to one target creature that player or that planeswalker's controller controls."; - } - - private RavagerOfTheFellsEffect(final RavagerOfTheFellsEffect effect) { - super(effect); - } - - @Override - public RavagerOfTheFellsEffect copy() { - return new RavagerOfTheFellsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - for (UUID targetId : getTargetPointer().getTargets(game, source)) { - game.damagePlayerOrPermanent( - targetId, 2, source.getSourceId(), source, - game, false, true - ); - } - return true; - } - -} - -class RavagerOfTheFellsTarget extends TargetPermanent { - - RavagerOfTheFellsTarget() { - super(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE); - } - - private RavagerOfTheFellsTarget(final RavagerOfTheFellsTarget target) { - super(target); - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { - Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); - - Player needPlayer = game.getPlayerOrPlaneswalkerController(source.getFirstTarget()); - if (needPlayer == null) { - // playable or not selected - use any - } else { - // filter by controller - possibleTargets.removeIf(id -> { - Permanent permanent = game.getPermanent(id); - return permanent == null - || permanent.getId().equals(source.getFirstTarget()) - || !permanent.isControlledBy(needPlayer.getId()); - }); - } - - return possibleTargets; - } - - @Override - public RavagerOfTheFellsTarget copy() { - return new RavagerOfTheFellsTarget(this); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RazorPendulum.java b/Mage.Sets/src/mage/cards/r/RazorPendulum.java index 6a0e1d0d6b0..e891923fc6d 100644 --- a/Mage.Sets/src/mage/cards/r/RazorPendulum.java +++ b/Mage.Sets/src/mage/cards/r/RazorPendulum.java @@ -25,7 +25,7 @@ public final class RazorPendulum extends CardImpl { // At the beginning of each player’s end step, if that player has 5 or less life, Razor Pendulum deals 2 damage to that player. this.addAbility(new BeginningOfEndStepTriggeredAbility( TargetController.EACH_PLAYER, - new DamageTargetEffect(2, true, "that player"), + new DamageTargetEffect(2).withTargetDescription("that player"), false, condition )); } diff --git a/Mage.Sets/src/mage/cards/r/RazorkinNeedlehead.java b/Mage.Sets/src/mage/cards/r/RazorkinNeedlehead.java index 42eeff23e9d..20271b68b2e 100644 --- a/Mage.Sets/src/mage/cards/r/RazorkinNeedlehead.java +++ b/Mage.Sets/src/mage/cards/r/RazorkinNeedlehead.java @@ -35,9 +35,9 @@ public final class RazorkinNeedlehead extends CardImpl { ))); // Whenever an opponent draws a card, Razorkin Needlehead deals 1 damage to them. - this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect( - 1, true, "them" - ), false, true)); + this.addAbility(new DrawCardOpponentTriggeredAbility( + new DamageTargetEffect(1).withTargetDescription("them"), + false, true)); } private RazorkinNeedlehead(final RazorkinNeedlehead card) { diff --git a/Mage.Sets/src/mage/cards/r/RecklessBlaze.java b/Mage.Sets/src/mage/cards/r/RecklessBlaze.java new file mode 100644 index 00000000000..69ba0f2c90d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RecklessBlaze.java @@ -0,0 +1,115 @@ +package mage.cards.r; + +import mage.MageObjectReference; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RecklessBlaze extends CardImpl { + + public RecklessBlaze(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); + + this.subtype.add(SubType.LESSON); + + // Reckless Blaze deals 5 damage to each creature. Whenever a creature you control dealt damage this way dies this turn, add {R}. + this.getSpellAbility().addEffect(new RecklessBlazeEffect()); + } + + private RecklessBlaze(final RecklessBlaze card) { + super(card); + } + + @Override + public RecklessBlaze copy() { + return new RecklessBlaze(this); + } +} + +class RecklessBlazeEffect extends OneShotEffect { + + RecklessBlazeEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 5 damage to each creature. " + + "Whenever a creature you control dealt damage this way dies this turn, add {R}"; + } + + private RecklessBlazeEffect(final RecklessBlazeEffect effect) { + super(effect); + } + + @Override + public RecklessBlazeEffect copy() { + return new RecklessBlazeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Set morSet = new HashSet<>(); + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game + )) { + if (permanent.damage(5, source, game) > 0) { + morSet.add(new MageObjectReference(permanent, game)); + } + } + game.addDelayedTriggeredAbility(new RecklessBlazeTriggeredAbility(morSet), source); + return true; + } +} + +class RecklessBlazeTriggeredAbility extends DelayedTriggeredAbility { + + private final Set morSet = new HashSet<>(); + + RecklessBlazeTriggeredAbility(Set morSet) { + super(new BasicManaEffect(Mana.RedMana(1)), Duration.EndOfTurn, false, false); + this.morSet.addAll(morSet); + this.setTriggerPhrase("Whenever a creature you control dealt damage this way dies this turn, "); + } + + private RecklessBlazeTriggeredAbility(final RecklessBlazeTriggeredAbility ability) { + super(ability); + this.morSet.addAll(ability.morSet); + } + + @Override + public RecklessBlazeTriggeredAbility copy() { + return new RecklessBlazeTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.isDiesEvent() + && zEvent.getTarget() != null + && morSet.stream().anyMatch(mor -> mor.refersTo(zEvent.getTarget(), game)) + && zEvent.getTarget().isControlledBy(getControllerId()) + && zEvent.getTarget().isCreature(game); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RevealingEye.java b/Mage.Sets/src/mage/cards/r/RevealingEye.java deleted file mode 100644 index 284c7eee69b..00000000000 --- a/Mage.Sets/src/mage/cards/r/RevealingEye.java +++ /dev/null @@ -1,96 +0,0 @@ -package mage.cards.r; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.MenaceAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInHand; -import mage.target.common.TargetOpponent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class RevealingEye extends CardImpl { - - public RevealingEye(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.EYE); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility(false)); - - // When this creature transforms into Revealing Eye, target opponent reveals their hand. You may choose a nonland card from it. If you do, that player discards that card, then draws a card. - Ability ability = new TransformIntoSourceTriggeredAbility(new RevealingEyeEffect()); - ability.addTarget(new TargetOpponent()); - this.addAbility(ability); - } - - private RevealingEye(final RevealingEye card) { - super(card); - } - - @Override - public RevealingEye copy() { - return new RevealingEye(this); - } -} - -class RevealingEyeEffect extends OneShotEffect { - - RevealingEyeEffect() { - super(Outcome.Discard); - staticText = "target opponent reveals their hand. You may choose a nonland card from it. " + - "If you do, that player discards that card, then draws a card"; - } - - private RevealingEyeEffect(final RevealingEyeEffect effect) { - super(effect); - } - - @Override - public RevealingEyeEffect copy() { - return new RevealingEyeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Player opponent = game.getPlayer(source.getFirstTarget()); - if (controller == null || opponent == null) { - return false; - } - opponent.revealCards(source, opponent.getHand(), game); - if (opponent.getHand().count(StaticFilters.FILTER_CARD_NON_LAND, game) < 1) { - return true; - } - TargetCard target = new TargetCard(0, 1, Zone.HAND, StaticFilters.FILTER_CARD_NON_LAND); - controller.choose(outcome, opponent.getHand(), target, source, game); - Card card = game.getCard(target.getFirstTarget()); - if (card == null) { - return true; - } - opponent.discard(card, false, source, game); - opponent.drawCards(1, source, game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RhinosRampage.java b/Mage.Sets/src/mage/cards/r/RhinosRampage.java index 8ed68d09334..19280c56afc 100644 --- a/Mage.Sets/src/mage/cards/r/RhinosRampage.java +++ b/Mage.Sets/src/mage/cards/r/RhinosRampage.java @@ -4,50 +4,41 @@ import mage.abilities.Ability; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.FightTargetsEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Outcome; -import mage.constants.TargetController; import mage.filter.FilterPermanent; import mage.filter.common.FilterArtifactPermanent; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; +import mage.target.targetpointer.EachTargetPointer; +import java.util.List; +import java.util.Objects; import java.util.UUID; +import java.util.stream.Collectors; /** - * * @author Jmlundeen */ public final class RhinosRampage extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("creature an opponent controls"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public RhinosRampage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R/G}"); - // Target creature you control gets +1/+0 until end of turn. It fights target creature an opponent controls. When excess damage is dealt to the creature an opponent controls this way, destroy up to one target noncreature artifact with mana value 3 or less. this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0)); - this.getSpellAbility().addEffect(new FightTargetsEffect() - .setText("It fights target creature an opponent controls")); this.getSpellAbility().addEffect(new RhinosRampageEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetPermanent(filter)); - + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); } private RhinosRampage(final RhinosRampage card) { @@ -62,10 +53,18 @@ public final class RhinosRampage extends CardImpl { class RhinosRampageEffect extends OneShotEffect { + private static final FilterPermanent filter = new FilterArtifactPermanent("noncreature artifact with mana value 3 or less"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, 3)); + } + RhinosRampageEffect() { super(Outcome.BoostCreature); - staticText = "When excess damage is dealt to the creature an opponent controls this way, destroy up to one target noncreature " + - "artifact with mana value 3 or less"; + staticText = "it fights target creature an opponent controls. When excess damage is dealt to the creature " + + "an opponent controls this way, destroy up to one target noncreature artifact with mana value 3 or less."; + this.setTargetPointer(new EachTargetPointer()); } protected RhinosRampageEffect(final RhinosRampageEffect effect) { @@ -79,14 +78,20 @@ class RhinosRampageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanentOrLKIBattlefield(source.getTargets().get(1).getFirstTarget()); - if (permanent == null || permanent.getDamage() <= permanent.getToughness().getBaseValue()) { + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (permanents.size() < 2) { return false; } - FilterPermanent filter = new FilterArtifactPermanent("noncreature artifact with mana value 3 or less"); - filter.add(Predicates.not(CardType.CREATURE.getPredicate())); - filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, 3)); - + int excess = permanents.get(0).fightWithExcess(permanents.get(1), source, game, true); + if (excess < 1) { + return true; + } ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new DestroyTargetEffect(), false); ability.addTarget(new TargetPermanent(0, 1, filter)); game.fireReflexiveTriggeredAbility(ability, source); diff --git a/Mage.Sets/src/mage/cards/r/Rockalanche.java b/Mage.Sets/src/mage/cards/r/Rockalanche.java index ef35c89bfce..a4843ce6bbd 100644 --- a/Mage.Sets/src/mage/cards/r/Rockalanche.java +++ b/Mage.Sets/src/mage/cards/r/Rockalanche.java @@ -32,7 +32,7 @@ public final class Rockalanche extends CardImpl { this.subtype.add(SubType.LESSON); // Earthbend X, where X is the number of Forests you control. - this.getSpellAbility().addEffect(new EarthbendTargetEffect(xValue)); + this.getSpellAbility().addEffect(new EarthbendTargetEffect(xValue, true)); this.getSpellAbility().addTarget(new TargetControlledLandPermanent()); this.getSpellAbility().addHint(hint); diff --git a/Mage.Sets/src/mage/cards/r/RoilingVortex.java b/Mage.Sets/src/mage/cards/r/RoilingVortex.java index 3f64b096d95..e35c3e043aa 100644 --- a/Mage.Sets/src/mage/cards/r/RoilingVortex.java +++ b/Mage.Sets/src/mage/cards/r/RoilingVortex.java @@ -32,15 +32,15 @@ public final class RoilingVortex extends CardImpl { // At the beginning of each player's upkeep, Roiling Vortex deals 1 damage to them. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.EACH_PLAYER, new DamageTargetEffect(1, true, "them"), + TargetController.EACH_PLAYER, new DamageTargetEffect(1).withTargetDescription("them"), false )); // Whenever a player casts a spell, if no mana was spent to cast that spell, Roiling Vortex deals 5 damage to that player. - this.addAbility(new SpellCastAllTriggeredAbility(new DamageTargetEffect( - 5, true, "that player", - "if no mana was spent to cast that spell, {this}" - ), filter, false, SetTargetPointer.PLAYER)); + this.addAbility(new SpellCastAllTriggeredAbility( + new DamageTargetEffect(5) + .setText("if no mana was spent to cast that spell, {this} deals 5 damage to that player"), + filter, false, SetTargetPointer.PLAYER)); // {R}: Your opponents can't gain life this turn. this.addAbility(new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/r/RuinousWaterbending.java b/Mage.Sets/src/mage/cards/r/RuinousWaterbending.java new file mode 100644 index 00000000000..59794334c6b --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RuinousWaterbending.java @@ -0,0 +1,87 @@ +package mage.cards.r; + +import mage.MageObject; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.condition.common.WaterbendedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.keyword.WaterbendAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RuinousWaterbending extends CardImpl { + + public RuinousWaterbending(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); + + this.subtype.add(SubType.LESSON); + + // As an additional cost to cast this spell, you may waterbend {4}. + this.addAbility(new WaterbendAbility(4)); + + // All creatures get -2/-2 until end of turn. If this spell's additional cost was paid, whenever a creature dies this turn, you gain 1 life. + this.getSpellAbility().addEffect(new BoostAllEffect(-2, -2, Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new CreateDelayedTriggeredAbilityEffect(new RuinousWaterbendingAbility()), + WaterbendedCondition.instance, "If this spell's additional cost was paid, " + + "whenever a creature dies this turn, you gain 1 life" + )); + } + + private RuinousWaterbending(final RuinousWaterbending card) { + super(card); + } + + @Override + public RuinousWaterbending copy() { + return new RuinousWaterbending(this); + } +} + +class RuinousWaterbendingAbility extends DelayedTriggeredAbility { + + RuinousWaterbendingAbility() { + super(new GainLifeEffect(1), Duration.EndOfTurn, false); + setLeavesTheBattlefieldTrigger(true); + setTriggerPhrase("Whenever a creature dies this turn, "); + } + + private RuinousWaterbendingAbility(final RuinousWaterbendingAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.isDiesEvent() && zEvent.getTarget().isCreature(game); + } + + @Override + public RuinousWaterbendingAbility copy() { + return new RuinousWaterbendingAbility(this); + } + + @Override + public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) { + return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SaltRoadPackbeast.java b/Mage.Sets/src/mage/cards/s/SaltRoadPackbeast.java index 4abb51be552..5d04c5a6172 100644 --- a/Mage.Sets/src/mage/cards/s/SaltRoadPackbeast.java +++ b/Mage.Sets/src/mage/cards/s/SaltRoadPackbeast.java @@ -7,8 +7,10 @@ import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; import mage.abilities.hint.common.CreaturesYouControlHint; +import mage.abilities.keyword.AffinityAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AffinityType; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; @@ -27,10 +29,8 @@ public final class SaltRoadPackbeast extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(3); - // This spell costs {1} less to cast for each creature you control. - this.addAbility(new SimpleStaticAbility( - Zone.ALL, new SpellCostReductionForEachSourceEffect(1, CreaturesYouControlCount.SINGULAR) - ).addHint(CreaturesYouControlHint.instance)); + // Affinity for creatures + this.addAbility(new AffinityAbility(AffinityType.CREATURES)); // When this creature enters, draw a card. this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfTheSun.java b/Mage.Sets/src/mage/cards/s/SanctumOfTheSun.java deleted file mode 100644 index e83c6d87bb0..00000000000 --- a/Mage.Sets/src/mage/cards/s/SanctumOfTheSun.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.s; - -import java.util.UUID; -import mage.Mana; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.dynamicvalue.common.ControllerLifeCount; -import mage.abilities.mana.DynamicManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; - -/** - * - * @author LevelX2 - */ -public final class SanctumOfTheSun extends CardImpl { - - public SanctumOfTheSun(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - - this.nightCard = true; - - // (Transforms from Azor's Gateway.) - - // {T}: Add X mana of any one color, where X is your life total. - this.addAbility(new DynamicManaAbility(new Mana(0, 0, 0, 0, 0, 0, 1, 0), ControllerLifeCount.instance, new TapSourceCost(), - "Add X mana of any one color, where X is your life total", true)); - - } - - private SanctumOfTheSun(final SanctumOfTheSun card) { - super(card); - } - - @Override - public SanctumOfTheSun copy() { - return new SanctumOfTheSun(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SandbenderScavengers.java b/Mage.Sets/src/mage/cards/s/SandbenderScavengers.java new file mode 100644 index 00000000000..6dd8e0abd56 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SandbenderScavengers.java @@ -0,0 +1,105 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SandbenderScavengers extends CardImpl { + + public SandbenderScavengers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever you sacrifice another permanent, put a +1/+1 counter on this creature. + this.addAbility(new SacrificePermanentTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), StaticFilters.FILTER_ANOTHER_PERMANENT + )); + + // When this creature dies, you may exile it. When you do, return target creature card with mana value less than or equal to this creature's power from your graveyard to the battlefield. + this.addAbility(new DiesSourceTriggeredAbility(new SandbenderScavengersEffect())); + } + + private SandbenderScavengers(final SandbenderScavengers card) { + super(card); + } + + @Override + public SandbenderScavengers copy() { + return new SandbenderScavengers(this); + } +} + +class SandbenderScavengersEffect extends OneShotEffect { + + SandbenderScavengersEffect() { + super(Outcome.Benefit); + staticText = "you may exile it. When you do, return target creature card with mana value " + + "less than or equal to this creature's power from your graveyard to the battlefield."; + } + + private SandbenderScavengersEffect(final SandbenderScavengersEffect effect) { + super(effect); + } + + @Override + public SandbenderScavengersEffect copy() { + return new SandbenderScavengersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = Optional + .ofNullable(source.getSourceObject(game)) + .filter(Card.class::isInstance) + .map(Card.class::cast) + .filter(c -> c.getZoneChangeCounter(game) != source.getStackMomentSourceZCC() + 1) + .orElse(null); + if (player == null || card == null || !player.chooseUse( + Outcome.Exile, "Exile " + card.getName() + '?', source, game + )) { + return false; + } + player.moveCards(card, Zone.EXILED, source, game); + int mv = Optional + .ofNullable((Permanent) getValue("permanentLeftBattlefield")) + .map(MageObject::getPower) + .map(MageInt::getValue) + .orElse(0); + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false); + FilterCard filter = new FilterCreatureCard("creature card with mana value " + mv + " or less"); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, mv + 1)); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SavagePackmate.java b/Mage.Sets/src/mage/cards/s/SavagePackmate.java deleted file mode 100644 index f60351ab25a..00000000000 --- a/Mage.Sets/src/mage/cards/s/SavagePackmate.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SavagePackmate extends CardImpl { - - public SavagePackmate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setRed(true); - this.color.setGreen(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Other creatures you control get +1/+0. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( - 1, 0, Duration.WhileOnBattlefield, true - ))); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private SavagePackmate(final SavagePackmate card) { - super(card); - } - - @Override - public SavagePackmate copy() { - return new SavagePackmate(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java b/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java index 408833a25e4..b250229b7e1 100644 --- a/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java +++ b/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java @@ -37,7 +37,7 @@ public final class ScabClanBerserker extends CardImpl { // Whenever an opponent casts a noncreature spell, if Scab-Clan Berserker is renowned, Scab-Clan Berserker deals 2 damage to that player. this.addAbility(new SpellCastOpponentTriggeredAbility( Zone.BATTLEFIELD, - new DamageTargetEffect(2, true, "that player"), + new DamageTargetEffect(2).withTargetDescription("that player"), StaticFilters.FILTER_SPELL_A_NON_CREATURE, false, SetTargetPointer.PLAYER ).withInterveningIf(RenownedSourceCondition.THIS)); } diff --git a/Mage.Sets/src/mage/cards/s/Scald.java b/Mage.Sets/src/mage/cards/s/Scald.java index 48f66774b62..fcad2a81c3e 100644 --- a/Mage.Sets/src/mage/cards/s/Scald.java +++ b/Mage.Sets/src/mage/cards/s/Scald.java @@ -29,7 +29,7 @@ public final class Scald extends CardImpl { // Whenever a player taps an Island for mana, Scald deals 1 damage to that player. this.addAbility(new TapForManaAllTriggeredAbility( - new DamageTargetEffect(1, true, "that player"), + new DamageTargetEffect(1).withTargetDescription("that player"), filter, SetTargetPointer.PLAYER)); } diff --git a/Mage.Sets/src/mage/cards/s/ScaldingViper.java b/Mage.Sets/src/mage/cards/s/ScaldingViper.java index f0e17f5f7fc..7006ac38719 100644 --- a/Mage.Sets/src/mage/cards/s/ScaldingViper.java +++ b/Mage.Sets/src/mage/cards/s/ScaldingViper.java @@ -34,7 +34,7 @@ public final class ScaldingViper extends AdventureCard { // Whenever an opponent casts a spell with mana value 3 or less, Scalding Viper deals 1 damage to that player. this.addAbility(new SpellCastOpponentTriggeredAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that player"), + Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player"), filter, false, SetTargetPointer.PLAYER )); diff --git a/Mage.Sets/src/mage/cards/s/ScarringMemories.java b/Mage.Sets/src/mage/cards/s/ScarringMemories.java index 1c6058d0283..4ffccfad733 100644 --- a/Mage.Sets/src/mage/cards/s/ScarringMemories.java +++ b/Mage.Sets/src/mage/cards/s/ScarringMemories.java @@ -41,7 +41,7 @@ public final class ScarringMemories extends CardImpl { // You may cast this spell as though it had flash if you control an attacking legendary creature. this.addAbility(new CastAsThoughItHadFlashIfConditionAbility( - condition, "you may cast this spell as though it had flash if you control an attacking legendary creature" + condition, "you may cast this spell as though it had flash if you control an attacking legendary creature." )); // Target opponent sacrifices a creature of their choice, discards a card, and loses 3 life. diff --git a/Mage.Sets/src/mage/cards/s/SearchForDagger.java b/Mage.Sets/src/mage/cards/s/SearchForDagger.java index 07812507446..1e7aa9d87d5 100644 --- a/Mage.Sets/src/mage/cards/s/SearchForDagger.java +++ b/Mage.Sets/src/mage/cards/s/SearchForDagger.java @@ -21,7 +21,7 @@ import java.util.UUID; public final class SearchForDagger extends CardImpl { private static final FilterCard filter = new FilterCreatureCard("a legendary creature card"); - private static final FilterPermanent filter2 = new FilterPermanent("you commander"); + private static final FilterPermanent filter2 = new FilterPermanent("your commander"); static { filter.add(SuperType.LEGENDARY.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/s/SearingBlood.java b/Mage.Sets/src/mage/cards/s/SearingBlood.java index dde6c05bf80..91fcf8785da 100644 --- a/Mage.Sets/src/mage/cards/s/SearingBlood.java +++ b/Mage.Sets/src/mage/cards/s/SearingBlood.java @@ -23,7 +23,7 @@ public final class SearingBlood extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect( new WhenTargetDiesDelayedTriggeredAbility( - new DamageTargetEffect(3, true, "the creature's controller"), + new DamageTargetEffect(3).withTargetDescription("the creature's controller"), SetTargetPointer.PLAYER ) )); diff --git a/Mage.Sets/src/mage/cards/s/SeasonedCathar.java b/Mage.Sets/src/mage/cards/s/SeasonedCathar.java deleted file mode 100644 index 57397897f3d..00000000000 --- a/Mage.Sets/src/mage/cards/s/SeasonedCathar.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.keyword.LifelinkAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SeasonedCathar extends CardImpl { - - public SeasonedCathar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setWhite(true); - this.nightCard = true; - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - } - - private SeasonedCathar(final SeasonedCathar card) { - super(card); - } - - @Override - public SeasonedCathar copy() { - return new SeasonedCathar(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SentinelTower.java b/Mage.Sets/src/mage/cards/s/SentinelTower.java index 3526e28c1ea..9609bb3b846 100644 --- a/Mage.Sets/src/mage/cards/s/SentinelTower.java +++ b/Mage.Sets/src/mage/cards/s/SentinelTower.java @@ -5,7 +5,7 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SpellCastAllTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.hint.ValueHint; @@ -50,7 +50,7 @@ class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility { private String damageInfo; SentinelTowerTriggeredAbility() { - super(new DamageTargetEffect(0), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false); + super(new DamageTargetEffect(SavedDamageValue.MUCH), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false); this.addTarget(new TargetAnyTarget()); this.addHint(new ValueHint("There were cast instant and sorcery this turn", SentinelTowerSpellsCastValue.instance)); this.damageInfo = null; @@ -87,12 +87,7 @@ class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility { } } damageInfo = " (" + damageToDeal + " damage)"; - for (Effect effect : this.getEffects()) { - if (effect instanceof DamageTargetEffect) { - ((DamageTargetEffect) effect).setAmount(StaticValue.get(damageToDeal)); - return true; - } - } + this.getEffects().setValue("damage", damageToDeal); } return false; } @@ -166,4 +161,4 @@ enum SentinelTowerSpellsCastValue implements DynamicValue { public String getMessage() { return "There was an instant or sorcery spell in this turn"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/ShadowInTheWarp.java b/Mage.Sets/src/mage/cards/s/ShadowInTheWarp.java index 2670cc3f137..8c4feb6466d 100644 --- a/Mage.Sets/src/mage/cards/s/ShadowInTheWarp.java +++ b/Mage.Sets/src/mage/cards/s/ShadowInTheWarp.java @@ -14,7 +14,6 @@ import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.game.Controllable; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; @@ -22,6 +21,7 @@ import mage.players.Player; import mage.target.targetpointer.FixedTarget; import mage.watchers.Watcher; import mage.watchers.common.SpellsCastWatcher; + import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -108,8 +108,8 @@ class FirstCastCreatureSpellPredicate implements ObjectSourcePlayerPredicate permanent.getCounters(game).getCount(CounterType.JUDGMENT) >= 3) - .map(Permanent::getAttachedTo) - .map(game::getPlayer) - .filter(player -> { - player.lost(game); - return true; - }) - .isPresent(); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SkewerSlinger.java b/Mage.Sets/src/mage/cards/s/SkewerSlinger.java index d529cd33c42..d391f503266 100644 --- a/Mage.Sets/src/mage/cards/s/SkewerSlinger.java +++ b/Mage.Sets/src/mage/cards/s/SkewerSlinger.java @@ -30,7 +30,7 @@ public final class SkewerSlinger extends CardImpl { // Whenever Skewer Slinger blocks or becomes blocked by a creature, Skewer Slinger deals 1 damage to that creature. this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility( - new DamageTargetEffect(1, true, "that creature") + new DamageTargetEffect(1).withTargetDescription("that creature") )); } diff --git a/Mage.Sets/src/mage/cards/s/SokkaAndSuki.java b/Mage.Sets/src/mage/cards/s/SokkaAndSuki.java new file mode 100644 index 00000000000..bab01efc152 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SokkaAndSuki.java @@ -0,0 +1,85 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.AllyToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SokkaAndSuki extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.ALLY, "Ally"); + + public SokkaAndSuki(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever Sokka and Suki or another Ally you control enters, attach up to one target Equipment you control to that creature. + Ability ability = new EntersBattlefieldThisOrAnotherTriggeredAbility( + new SokkaAndSukiEffect(), filter, false, true + ); + ability.addTarget(new TargetPermanent( + 0, 1, StaticFilters.FILTER_CONTROLLED_PERMANENT_EQUIPMENT + )); + this.addAbility(ability); + + // Whenever an Equipment you control enters, create a 1/1 white Ally creature token. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new CreateTokenEffect(new AllyToken()), StaticFilters.FILTER_CONTROLLED_PERMANENT_EQUIPMENT + )); + } + + private SokkaAndSuki(final SokkaAndSuki card) { + super(card); + } + + @Override + public SokkaAndSuki copy() { + return new SokkaAndSuki(this); + } +} + +class SokkaAndSukiEffect extends OneShotEffect { + + SokkaAndSukiEffect() { + super(Outcome.Benefit); + staticText = "attach up to one target Equipment you control to that creature"; + } + + private SokkaAndSukiEffect(final SokkaAndSukiEffect effect) { + super(effect); + } + + @Override + public SokkaAndSukiEffect copy() { + return new SokkaAndSukiEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = (Permanent) getValue("permanentEnteringBattlefield"); + Permanent equipment = game.getPermanent(getTargetPointer().getFirst(game, source)); + return creature != null && equipment != null && creature.addAttachment(equipment.getId(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SokkaSwordmaster.java b/Mage.Sets/src/mage/cards/s/SokkaSwordmaster.java new file mode 100644 index 00000000000..ef87f0e83d3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SokkaSwordmaster.java @@ -0,0 +1,97 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SokkaSwordmaster extends CardImpl { + + public SokkaSwordmaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Equipment spells you cast cost {1} less to cast for each Ally you control. + this.addAbility(new SimpleStaticAbility(new SokkaSwordmasterEffect()).addHint(AffinityType.ALLIES.getHint())); + + // At the beginning of combat on your turn, attach up to one target Equipment you control to Sokka. + Ability ability = new BeginningOfCombatTriggeredAbility( + new AttachEffect(Outcome.BoostCreature, "attach up to one target Equipment you control to {this}" + )); + ability.addTarget(new TargetPermanent( + 0, 1, StaticFilters.FILTER_CONTROLLED_PERMANENT_EQUIPMENT + )); + this.addAbility(ability); + } + + private SokkaSwordmaster(final SokkaSwordmaster card) { + super(card); + } + + @Override + public SokkaSwordmaster copy() { + return new SokkaSwordmaster(this); + } +} + +class SokkaSwordmasterEffect extends CostModificationEffectImpl { + + SokkaSwordmasterEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "Equipment spells you cast cost {1} less to cast for each Ally you control"; + } + + private SokkaSwordmasterEffect(final SokkaSwordmasterEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + CardUtil.reduceCost(abilityToModify, game.getBattlefield().count(AffinityType.ALLIES.getFilter(), source.getControllerId(), source, game)); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return Optional + .ofNullable(abilityToModify) + .filter(SpellAbility.class::isInstance) + .filter(spellAbility -> spellAbility.isControlledBy(source.getControllerId())) + .map(SpellAbility.class::cast) + .map(spellAbility -> spellAbility.getCharacteristics(game)) + .filter(card -> card.hasSubtype(SubType.EQUIPMENT, game)) + .isPresent(); + } + + @Override + public SokkaSwordmasterEffect copy() { + return new SokkaSwordmasterEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/s/SomberwaldVigilante.java b/Mage.Sets/src/mage/cards/s/SomberwaldVigilante.java index 7f8e196f6cd..ca31507c3e7 100644 --- a/Mage.Sets/src/mage/cards/s/SomberwaldVigilante.java +++ b/Mage.Sets/src/mage/cards/s/SomberwaldVigilante.java @@ -25,7 +25,7 @@ public final class SomberwaldVigilante extends CardImpl { this.toughness = new MageInt(1); // Whenever Somberwald Vigilante becomes blocked by a creature, Somberwald Vigilante deals 1 damage to that creature. - this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new DamageTargetEffect(1, true, "that creature"), false)); + this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that creature"), false)); } private SomberwaldVigilante(final SomberwaldVigilante card) { diff --git a/Mage.Sets/src/mage/cards/s/SozinsComet.java b/Mage.Sets/src/mage/cards/s/SozinsComet.java index 5bcfeb3608a..c318072ab96 100644 --- a/Mage.Sets/src/mage/cards/s/SozinsComet.java +++ b/Mage.Sets/src/mage/cards/s/SozinsComet.java @@ -22,7 +22,7 @@ public final class SozinsComet extends CardImpl { // Each creature you control gains firebending 5 until end of turn. this.getSpellAbility().addEffect(new GainAbilityControlledEffect( new FirebendingAbility(5), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE - )); + ).setText("each creature you control gains firebending 5 until end of turn")); // Foretell {2}{R} this.addAbility(new ForetellAbility(this, "{2}{R}")); diff --git a/Mage.Sets/src/mage/cards/s/SpectralBinding.java b/Mage.Sets/src/mage/cards/s/SpectralBinding.java deleted file mode 100644 index 89d2a0f443a..00000000000 --- a/Mage.Sets/src/mage/cards/s/SpectralBinding.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.s; - -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.continuous.BoostEnchantedEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SpectralBinding extends CardImpl { - - public SpectralBinding(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setBlue(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature gets -2/-0. - this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(-2, 0))); - - // If Spectral Binding would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private SpectralBinding(final SpectralBinding card) { - super(card); - } - - @Override - public SpectralBinding copy() { - return new SpectralBinding(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/Spellshock.java b/Mage.Sets/src/mage/cards/s/Spellshock.java index b7caa19b968..fe9e870337c 100644 --- a/Mage.Sets/src/mage/cards/s/Spellshock.java +++ b/Mage.Sets/src/mage/cards/s/Spellshock.java @@ -42,7 +42,7 @@ class SpellshockTriggeredAbility extends TriggeredAbilityImpl { public SpellshockTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player")); } @@ -76,4 +76,4 @@ class SpellshockTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever a player casts a spell, {this} deals 2 damage to that player."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SpikedPitTrap.java b/Mage.Sets/src/mage/cards/s/SpikedPitTrap.java index 16d39d3d93d..593d0181194 100644 --- a/Mage.Sets/src/mage/cards/s/SpikedPitTrap.java +++ b/Mage.Sets/src/mage/cards/s/SpikedPitTrap.java @@ -39,14 +39,11 @@ public final class SpikedPitTrap extends CardImpl { this.addAbility(ability); // 1-9 | Spiked Pit Trap deals 5 damage to that creature. - effect.addTableEntry(1, 9, new DamageTargetEffect( - 5, true, "that creature" - )); + effect.addTableEntry(1, 9, new DamageTargetEffect(5).withTargetDescription("that creature")); // 10-20 | Spike Pit Trap deals 5 damage to that creature. Create a Treasure token. - effect.addTableEntry(10, 20, new DamageTargetEffect( - 5, true, "that creature." - ), new CreateTokenEffect(new TreasureToken())); + effect.addTableEntry(10, 20, new DamageTargetEffect(5).withTargetDescription("that creature"), + new CreateTokenEffect(new TreasureToken())); } private SpikedPitTrap(final SpikedPitTrap card) { diff --git a/Mage.Sets/src/mage/cards/s/SpiritWaterRevival.java b/Mage.Sets/src/mage/cards/s/SpiritWaterRevival.java new file mode 100644 index 00000000000..9bb9f2375c6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiritWaterRevival.java @@ -0,0 +1,52 @@ +package mage.cards.s; + +import mage.abilities.condition.common.WaterbendedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.AddContinuousEffectToGame; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.abilities.effects.common.ShuffleYourGraveyardIntoLibraryEffect; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +import mage.abilities.keyword.WaterbendAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiritWaterRevival extends CardImpl { + + public SpiritWaterRevival(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}{U}"); + + // As an additional cost to cast this spell, you may waterbend {6}. + this.addAbility(new WaterbendAbility(6)); + + // Draw two cards. If this spell's additional cost was paid, instead shuffle your graveyard into your library, draw seven cards, and you have no maximum hand size for the rest of the game. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new ShuffleYourGraveyardIntoLibraryEffect(), new DrawCardSourceControllerEffect(2), + WaterbendedCondition.instance, "draw two cards. If this spell's additional cost was paid, " + + "instead shuffle your graveyard into your library, draw seven cards, " + + "and you have no maximum hand size for the rest of the game" + ).addEffect(new DrawCardSourceControllerEffect(7)) + .addEffect(new AddContinuousEffectToGame(new MaximumHandSizeControllerEffect( + Integer.MAX_VALUE, Duration.EndOfGame, MaximumHandSizeControllerEffect.HandSizeModification.SET + )))); + + // Exile Spirit Water Revival. + this.getSpellAbility().addEffect(new ExileSpellEffect().concatBy("
")); + } + + private SpiritWaterRevival(final SpiritWaterRevival card) { + super(card); + } + + @Override + public SpiritWaterRevival copy() { + return new SpiritWaterRevival(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpringLoadedSawblades.java b/Mage.Sets/src/mage/cards/s/SpringLoadedSawblades.java index d9c7374a10f..19c939bd874 100644 --- a/Mage.Sets/src/mage/cards/s/SpringLoadedSawblades.java +++ b/Mage.Sets/src/mage/cards/s/SpringLoadedSawblades.java @@ -2,45 +2,73 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; import mage.abilities.keyword.CraftAbility; +import mage.abilities.keyword.CrewAbility; import mage.abilities.keyword.FlashAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.TargetPermanent; +import mage.target.common.TargetControlledPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class SpringLoadedSawblades extends CardImpl { +public final class SpringLoadedSawblades extends TransformingDoubleFacedCard { + private static final FilterControlledPermanent bladeWheelFilter + = new FilterControlledArtifactPermanent("other untapped artifacts you control"); private static final FilterPermanent filter = new FilterOpponentsCreaturePermanent("tapped creature an opponent controls"); static { filter.add(TappedPredicate.TAPPED); + bladeWheelFilter.add(AnotherPredicate.instance); + bladeWheelFilter.add(TappedPredicate.UNTAPPED); } public SpringLoadedSawblades(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}"); - this.secondSideCardClazz = mage.cards.b.BladewheelChariot.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{W}", + "Bladewheel Chariot", + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "W"); + + this.getRightHalfCard().setPT(5, 5); // Flash - this.addAbility(FlashAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlashAbility.getInstance()); // When Spring-Loaded Sawblades enters the battlefield, it deals 5 damage to target tapped creature an opponent controls. Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(5, "it")); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Craft with artifact {3}{W} - this.addAbility(new CraftAbility("{3}{W}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{3}{W}")); + + // Bladewheel Chariot + + // Tap two other untapped artifacts you control: Bladewheel Chariot becomes an artifact creature until end of turn. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new AddCardTypeSourceEffect( + Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE + ).setText("{this} becomes an artifact creature until end of turn"), new TapTargetCost(new TargetControlledPermanent(2, bladeWheelFilter)))); + + // Crew 1 + this.getRightHalfCard().addAbility(new CrewAbility(1)); } private SpringLoadedSawblades(final SpringLoadedSawblades card) { diff --git a/Mage.Sets/src/mage/cards/s/StandUnited.java b/Mage.Sets/src/mage/cards/s/StandUnited.java new file mode 100644 index 00000000000..adb0aaa10ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StandUnited.java @@ -0,0 +1,66 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StandUnited extends CardImpl { + + public StandUnited(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G/W}"); + + // Target creature gets +2/+2 until end of turn. If it's an Ally, scry 2. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2)); + this.getSpellAbility().addEffect(new StandUnitedEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private StandUnited(final StandUnited card) { + super(card); + } + + @Override + public StandUnited copy() { + return new StandUnited(this); + } +} + +class StandUnitedEffect extends OneShotEffect { + + StandUnitedEffect() { + super(Outcome.Benefit); + staticText = "If it's an Ally, scry 2"; + } + + private StandUnitedEffect(final StandUnitedEffect effect) { + super(effect); + } + + @Override + public StandUnitedEffect copy() { + return new StandUnitedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + return player != null && permanent != null + && permanent.hasSubtype(SubType.ALLY, game) + && player.scry(2, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StartledAwake.java b/Mage.Sets/src/mage/cards/s/StartledAwake.java index d9e1a5b049b..d46bc468036 100644 --- a/Mage.Sets/src/mage/cards/s/StartledAwake.java +++ b/Mage.Sets/src/mage/cards/s/StartledAwake.java @@ -1,17 +1,21 @@ package mage.cards.s; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.MillCardsTargetEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.keyword.SkulkAbility; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.cards.TransformingDoubleFacedCardHalf; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -22,22 +26,34 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class StartledAwake extends CardImpl { +public final class StartledAwake extends TransformingDoubleFacedCard { public StartledAwake(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.SORCERY}, new SubType[]{}, "{2}{U}{U}", + "Persistent Nightmare", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.NIGHTMARE}, "U"); - this.secondSideCardClazz = mage.cards.p.PersistentNightmare.class; + this.getRightHalfCard().setPT(1, 1); // Target opponent puts the top thirteen cards of their library into their graveyard. - this.getSpellAbility().addTarget(new TargetOpponent()); - this.getSpellAbility().addEffect(new MillCardsTargetEffect(13)); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetOpponent()); + this.getLeftHalfCard().getSpellAbility().addEffect(new MillCardsTargetEffect(13)); // {3}{U}{U}: Put Startled Awake from your graveyard onto the battlefield transformed. Activate this ability only any time you could cast a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( Zone.GRAVEYARD, new StartledAwakeReturnTransformedEffect(), new ManaCostsImpl<>("{3}{U}{U}") )); + + // Persistent Nightmare + + // Skulk + this.getRightHalfCard().addAbility(new SkulkAbility()); + + // When Persistent Nightmare deals combat damage to a player, return it to its owner's hand. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new ReturnToHandSourceEffect(), false + ).setTriggerPhrase("When {this} deals combat damage to a player, ")); } private StartledAwake(final StartledAwake card) { @@ -76,8 +92,12 @@ class StartledAwakeReturnTransformedEffect extends OneShotEffect { if (game.getState().getZone(source.getSourceId()) != Zone.GRAVEYARD) { return true; } - game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), true); - controller.moveCards(card, Zone.BATTLEFIELD, source, game); + Card backSide = ((TransformingDoubleFacedCardHalf) card).getOtherSide(); + if (backSide == null) { + return true; + } + game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + backSide.getId(), true); + controller.moveCards(backSide, Zone.BATTLEFIELD, source, game); return true; } } diff --git a/Mage.Sets/src/mage/cards/s/StormOfMemories.java b/Mage.Sets/src/mage/cards/s/StormOfMemories.java new file mode 100644 index 00000000000..8536d02670a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StormOfMemories.java @@ -0,0 +1,141 @@ +package mage.cards.s; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.keyword.StormAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.players.Player; +import mage.util.CardUtil; +import mage.util.RandomUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StormOfMemories extends CardImpl { + + public StormOfMemories(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}{R}{R}"); + + // Storm + this.addAbility(new StormAbility()); + + // Exile an instant or sorcery card with mana value 3 or less from your graveyard at random. You may cast it without paying its mana cost. If that spell would be put into a graveyard, exile it instead. + this.getSpellAbility().addEffect(new StormOfMemoriesEffect()); + } + + private StormOfMemories(final StormOfMemories card) { + super(card); + } + + @Override + public StormOfMemories copy() { + return new StormOfMemories(this); + } +} + +class StormOfMemoriesEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterInstantOrSorceryCard(); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + + StormOfMemoriesEffect() { + super(Outcome.Benefit); + staticText = "exile an instant or sorcery card with mana value 3 or less from your graveyard at random. " + + "You may cast it without paying its mana cost. If that spell would be put into a graveyard, exile it instead."; + } + + private StormOfMemoriesEffect(final StormOfMemoriesEffect effect) { + super(effect); + } + + @Override + public StormOfMemoriesEffect copy() { + return new StormOfMemoriesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = RandomUtil.randomFromCollection(player.getGraveyard().getCards(filter, game)); + return card != null && CardUtil.castSpellWithAttributesForFree( + player, source, game, new CardsImpl(card), + StaticFilters.FILTER_CARD, StormOfMemoriesTracker.instance + ); + } +} + +enum StormOfMemoriesTracker implements CardUtil.SpellCastTracker { + instance; + + @Override + public boolean checkCard(Card card, Game game) { + return true; + } + + @Override + public void addCard(Card card, Ability source, Game game) { + game.addEffect(new StormOfMemoriesReplacementEffect(card, game), source); + } +} + +class StormOfMemoriesReplacementEffect extends ReplacementEffectImpl { + + private final MageObjectReference mor; + + StormOfMemoriesReplacementEffect(Card card, Game game) { + super(Duration.EndOfTurn, Outcome.Exile); + this.mor = new MageObjectReference(card.getMainCard(), game); + } + + private StormOfMemoriesReplacementEffect(final StormOfMemoriesReplacementEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public StormOfMemoriesReplacementEffect copy() { + return new StormOfMemoriesReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + Card card = mor.getCard(game); + return controller != null + && card != null + && controller.moveCards(card, Zone.EXILED, source, game); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.getToZone() == Zone.GRAVEYARD + && zEvent.getTargetId().equals(mor.getSourceId()); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StructuralCollapse.java b/Mage.Sets/src/mage/cards/s/StructuralCollapse.java index f95d4fd4ca8..f1f315c38b2 100644 --- a/Mage.Sets/src/mage/cards/s/StructuralCollapse.java +++ b/Mage.Sets/src/mage/cards/s/StructuralCollapse.java @@ -26,7 +26,7 @@ public final class StructuralCollapse extends CardImpl { .setText("target player sacrifices an artifact")); this.getSpellAbility().addEffect(new SacrificeEffect(StaticFilters.FILTER_LANDS, 1, "Target player") .setText("and a land of their choice")); - this.getSpellAbility().addEffect(new DamageTargetEffect(2, true, "that player")); + this.getSpellAbility().addEffect(new DamageTargetEffect(2).withTargetDescription("that player")); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/s/SuddenShock.java b/Mage.Sets/src/mage/cards/s/SuddenShock.java index 4d989df4170..0d0db16afc5 100644 --- a/Mage.Sets/src/mage/cards/s/SuddenShock.java +++ b/Mage.Sets/src/mage/cards/s/SuddenShock.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.SplitSecondAbility; import mage.cards.CardImpl; @@ -9,6 +7,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * * @author LevelX2 @@ -18,11 +18,11 @@ public final class SuddenShock extends CardImpl { public SuddenShock(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); - // Split second this.addAbility(new SplitSecondAbility()); + // Sudden Shock deals 2 damage to any target. - this.getSpellAbility().addEffect(new DamageTargetEffect(2, true)); + this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/s/SulfuricVortex.java b/Mage.Sets/src/mage/cards/s/SulfuricVortex.java index caadd18288e..095760ee847 100644 --- a/Mage.Sets/src/mage/cards/s/SulfuricVortex.java +++ b/Mage.Sets/src/mage/cards/s/SulfuricVortex.java @@ -28,7 +28,7 @@ public final class SulfuricVortex extends CardImpl { // At the beginning of each player's upkeep, Sulfuric Vortex deals 2 damage to that player. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER, new DamageTargetEffect(2, true, "that player"), false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER, new DamageTargetEffect(2).withTargetDescription("that player"), false)); // If a player would gain life, that player gains no life instead. this.addAbility(new SimpleStaticAbility(new SulfuricVortexReplacementEffect())); diff --git a/Mage.Sets/src/mage/cards/s/SummonAlexander.java b/Mage.Sets/src/mage/cards/s/SummonAlexander.java deleted file mode 100644 index 6a752a4b835..00000000000 --- a/Mage.Sets/src/mage/cards/s/SummonAlexander.java +++ /dev/null @@ -1,63 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.common.PreventAllDamageToAllEffect; -import mage.abilities.effects.common.TapAllEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SagaChapter; -import mage.constants.SubType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SummonAlexander extends CardImpl { - - public SummonAlexander(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.CONSTRUCT); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.nightCard = true; - this.color.setWhite(true); - - // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I, II -- Prevent all damage that would be dealt to creatures you control this turn. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, - new PreventAllDamageToAllEffect( - Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED - ) - ); - - // III -- Tap all creatures your opponents control. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, - new TapAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES) - ); - this.addAbility(sagaAbility.withShowSacText(true)); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private SummonAlexander(final SummonAlexander card) { - super(card); - } - - @Override - public SummonAlexander copy() { - return new SummonAlexander(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SummonBrynhildr.java b/Mage.Sets/src/mage/cards/s/SummonBrynhildr.java index c78cc9eb20d..c8328f7f9a0 100644 --- a/Mage.Sets/src/mage/cards/s/SummonBrynhildr.java +++ b/Mage.Sets/src/mage/cards/s/SummonBrynhildr.java @@ -139,12 +139,17 @@ class SummonBrynhildrWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { if (event.getType() != GameEvent.EventType.COUNTER_ADDED - || !CounterType.STUN.getName().equals(event.getData())) { + || !CounterType.LORE.getName().equals(event.getData())) { return; } Permanent permanent = game.getPermanent(event.getTargetId()); + int offset = 0; + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + offset++; + } if (permanent != null) { - map.computeIfAbsent(new MageObjectReference(permanent, game), x -> new HashSet<>()) + map.computeIfAbsent(new MageObjectReference(permanent, game, offset), x -> new HashSet<>()) .add(event.getPlayerId()); } } diff --git a/Mage.Sets/src/mage/cards/s/SummonEsperMaduin.java b/Mage.Sets/src/mage/cards/s/SummonEsperMaduin.java deleted file mode 100644 index a8015ec0963..00000000000 --- a/Mage.Sets/src/mage/cards/s/SummonEsperMaduin.java +++ /dev/null @@ -1,103 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.mana.BasicManaEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.CardsImpl; -import mage.constants.*; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SummonEsperMaduin extends CardImpl { - - public SummonEsperMaduin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.ELEMENTAL); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.nightCard = true; - this.color.setGreen(true); - - // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I -- Reveal the top card of your library. If it's a permanent card, put it into your hand. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new SummonEsperMaduinEffect()); - - // II -- Add {G}{G}. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new BasicManaEffect(Mana.GreenMana(2))); - - // III -- Other creatures you control get +2/+2 and gain trample until end of turn. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, - new BoostControlledEffect( - 2, 2, Duration.EndOfTurn, true - ).setText("other creatures you control get +2/+2"), - new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_PERMANENT_CREATURE, true - ).setText("and gain trample until end of turn") - ); - this.addAbility(sagaAbility.withShowSacText(true)); - } - - private SummonEsperMaduin(final SummonEsperMaduin card) { - super(card); - } - - @Override - public SummonEsperMaduin copy() { - return new SummonEsperMaduin(this); - } -} - -class SummonEsperMaduinEffect extends OneShotEffect { - - SummonEsperMaduinEffect() { - super(Outcome.Benefit); - staticText = "reveal the top card of your library. If it's a permanent card, put it into your hand"; - } - - private SummonEsperMaduinEffect(final SummonEsperMaduinEffect effect) { - super(effect); - } - - @Override - public SummonEsperMaduinEffect copy() { - return new SummonEsperMaduinEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Card card = player.getLibrary().getFromTop(game); - if (card == null) { - return false; - } - player.revealCards(source, new CardsImpl(card), game); - if (card.isPermanent(game)) { - player.moveCards(card, Zone.HAND, source, game); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SuperiorSpiderMan.java b/Mage.Sets/src/mage/cards/s/SuperiorSpiderMan.java index 1e7959688c6..d3224526610 100644 --- a/Mage.Sets/src/mage/cards/s/SuperiorSpiderMan.java +++ b/Mage.Sets/src/mage/cards/s/SuperiorSpiderMan.java @@ -41,7 +41,8 @@ public final class SuperiorSpiderMan extends CardImpl { this.toughness = new MageInt(4); // Mind Swap -- You may have Superior Spider-Man enter as a copy of any creature card in a graveyard, except his name is Superior Spider-Man and he's a 4/4 Spider Human Hero in addition to his other types. When you do, exile that card. - this.addAbility(new EntersBattlefieldAbility(new SuperiorSpiderManCopyEffect(), true)); + this.addAbility(new EntersBattlefieldAbility(new SuperiorSpiderManCopyEffect(), true) + .withFlavorWord("Mind Swap")); } private SuperiorSpiderMan(final SuperiorSpiderMan card) { diff --git a/Mage.Sets/src/mage/cards/s/SurgicalSuiteHospitalRoom.java b/Mage.Sets/src/mage/cards/s/SurgicalSuiteHospitalRoom.java index daa9c7beb46..05814b89827 100644 --- a/Mage.Sets/src/mage/cards/s/SurgicalSuiteHospitalRoom.java +++ b/Mage.Sets/src/mage/cards/s/SurgicalSuiteHospitalRoom.java @@ -1,7 +1,5 @@ package mage.cards.s; -import java.util.UUID; - import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; import mage.abilities.common.UnlockThisDoorTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; @@ -19,6 +17,8 @@ import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.target.common.TargetAttackingCreature; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * * @author oscscull @@ -45,19 +45,19 @@ public final class SurgicalSuiteHospitalRoom extends RoomCard { "{1}{W}", "{3}{W}", SpellAbilityType.SPLIT); this.subtype.add(SubType.ROOM); - // Left half ability - "When you unlock this door, return target creature card with mana value 3 or - // less from your graveyard to the battlefield." + // Left half ability - "When you unlock this door, return target creature card with mana value 3 or less from your graveyard to the battlefield." UnlockThisDoorTriggeredAbility left = new UnlockThisDoorTriggeredAbility( new ReturnFromGraveyardToBattlefieldTargetEffect(), false, true); left.addTarget(new TargetCardInYourGraveyard(filter)); + this.getLeftHalfCard().addAbility(left); // Right half ability - "Whenever you attack, put a +1/+1 counter on target attacking creature." AttacksWithCreaturesTriggeredAbility right = new AttacksWithCreaturesTriggeredAbility( new AddCountersTargetEffect(CounterType.P1P1.createInstance()), 1 ); right.addTarget(new TargetAttackingCreature()); + this.getRightHalfCard().addAbility(right); - this.addRoomAbilities(left, right); } private SurgicalSuiteHospitalRoom(final SurgicalSuiteHospitalRoom card) { diff --git a/Mage.Sets/src/mage/cards/s/Swampbenders.java b/Mage.Sets/src/mage/cards/s/Swampbenders.java new file mode 100644 index 00000000000..f7df97e858a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Swampbenders.java @@ -0,0 +1,90 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Swampbenders extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( + new FilterPermanent(SubType.SWAMP, "Swamps on the battlefield") + ); + + public Swampbenders(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Swampbenders's power and toughness are each equal to the number of Swamps on the battlefield. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(xValue))); + + // Lands you control are Swamps in addition to their other types. + this.addAbility(new SimpleStaticAbility(new SwampbendersEffect())); + } + + private Swampbenders(final Swampbenders card) { + super(card); + } + + @Override + public Swampbenders copy() { + return new Swampbenders(this); + } +} + +class SwampbendersEffect extends ContinuousEffectImpl { + + SwampbendersEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.AIDontUseIt); + staticText = "lands you control are Swamps in addition to their other types."; + this.dependendToTypes.add(DependencyType.BecomeNonbasicLand); + this.dependencyTypes.add(DependencyType.BecomeSwamp); + } + + private SwampbendersEffect(final SwampbendersEffect effect) { + super(effect); + } + + @Override + public SwampbendersEffect copy() { + return new SwampbendersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Ability ability = new BlackManaAbility(); + for (Permanent land : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_LAND, source.getControllerId(), game + )) { + // 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects + // So the ability removing has to be done before Layer 6 + // Lands have their mana ability intrinsically, so that is added in layer 4 + land.addSubType(game, SubType.SWAMP); + if (!land.getAbilities().containsRule(ability)) { + land.addAbility(ability, source.getSourceId(), game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/Swelter.java b/Mage.Sets/src/mage/cards/s/Swelter.java index 946e3ddbf1b..e1dd60adffc 100644 --- a/Mage.Sets/src/mage/cards/s/Swelter.java +++ b/Mage.Sets/src/mage/cards/s/Swelter.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -18,7 +17,7 @@ public final class Swelter extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}"); // Swelter deals 2 damage to each of two target creatures. - this.getSpellAbility().addEffect(new DamageTargetEffect(2, true, "each of two target creatures")); + this.getSpellAbility().addEffect(new DamageTargetEffect(2).withTargetDescription("each of two target creatures")); this.getSpellAbility().addTarget(new TargetCreaturePermanent(2, 2)); } diff --git a/Mage.Sets/src/mage/cards/t/Takklemaggot.java b/Mage.Sets/src/mage/cards/t/Takklemaggot.java index 45ccdda4756..14eb164f46e 100644 --- a/Mage.Sets/src/mage/cards/t/Takklemaggot.java +++ b/Mage.Sets/src/mage/cards/t/Takklemaggot.java @@ -202,7 +202,7 @@ class TakklemaggotUpkeepAbility extends TriggeredAbilityImpl { private final UUID playerId; TakklemaggotUpkeepAbility(UUID playerId) { - super(Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that player") + super(Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player") .setTargetPointer(new FixedTarget(playerId)), false); this.playerId = playerId; setTriggerPhrase("At the beginning of that player's upkeep, "); diff --git a/Mage.Sets/src/mage/cards/t/TaleOfKataraAndToph.java b/Mage.Sets/src/mage/cards/t/TaleOfKataraAndToph.java new file mode 100644 index 00000000000..80eaafa54f0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TaleOfKataraAndToph.java @@ -0,0 +1,110 @@ +package mage.cards.t; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TaleOfKataraAndToph extends CardImpl { + + public TaleOfKataraAndToph(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + // Creatures you control have "Whenever this creature becomes tapped for the first time during each of your turns, put a +1/+1 counter on it." + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new TaleOfKataraAndTophTriggeredAbility(), + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES + )), new TaleOfKataraAndTophWatcher()); + } + + private TaleOfKataraAndToph(final TaleOfKataraAndToph card) { + super(card); + } + + @Override + public TaleOfKataraAndToph copy() { + return new TaleOfKataraAndToph(this); + } +} + +class TaleOfKataraAndTophTriggeredAbility extends TriggeredAbilityImpl { + + TaleOfKataraAndTophTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()).setText("put a +1/+1 counter on it")); + setTriggerPhrase("Whenever this creature becomes tapped for the first time during each of your turns, "); + } + + private TaleOfKataraAndTophTriggeredAbility(final TaleOfKataraAndTophTriggeredAbility ability) { + super(ability); + } + + @Override + public TaleOfKataraAndTophTriggeredAbility copy() { + return new TaleOfKataraAndTophTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TAPPED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.isActivePlayer(getControllerId()) + && event.getTargetId().equals(getSourceId()) + && TaleOfKataraAndTophWatcher.checkEvent(game, this, event); + } +} + +class TaleOfKataraAndTophWatcher extends Watcher { + + private final Map map = new HashMap<>(); + + TaleOfKataraAndTophWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.TAPPED) { + map.putIfAbsent(new MageObjectReference(event.getTargetId(), game), event.getId()); + } + } + + @Override + public void reset() { + super.reset(); + map.clear(); + } + + static boolean checkEvent(Game game, Ability source, GameEvent event) { + return Objects.equals( + game.getState() + .getWatcher(TaleOfKataraAndTophWatcher.class) + .map + .get(new MageObjectReference(source.getSourceObject(game), game)), + event.getId() + ); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TaleOfMomo.java b/Mage.Sets/src/mage/cards/t/TaleOfMomo.java new file mode 100644 index 00000000000..b7f19660166 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TaleOfMomo.java @@ -0,0 +1,48 @@ +package mage.cards.t; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CreatureLeftThisTurnCondition; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.watchers.common.CreatureLeftBattlefieldWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TaleOfMomo extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("an Ally creature card"); + + static { + filter.add(SubType.ALLY.getPredicate()); + } + + public TaleOfMomo(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}"); + + // This spell costs {2} less to cast if a creature left the battlefield under your control this turn. + this.addAbility(new SimpleStaticAbility( + new SpellCostReductionSourceEffect(2, CreatureLeftThisTurnCondition.instance) + ).addHint(CreatureLeftThisTurnCondition.getHint()), new CreatureLeftBattlefieldWatcher()); + + // Search your library and/or graveyard for an Ally creature card, reveal it, and put it into your hand. If you search your library this way, shuffle. + this.getSpellAbility().addEffect(new SearchLibraryGraveyardPutInHandEffect(filter)); + } + + private TaleOfMomo(final TaleOfMomo card) { + super(card); + } + + @Override + public TaleOfMomo copy() { + return new TaleOfMomo(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TamiyoInquisitiveStudent.java b/Mage.Sets/src/mage/cards/t/TamiyoInquisitiveStudent.java index 6db926dfb59..e6d6683fe6a 100644 --- a/Mage.Sets/src/mage/cards/t/TamiyoInquisitiveStudent.java +++ b/Mage.Sets/src/mage/cards/t/TamiyoInquisitiveStudent.java @@ -1,50 +1,87 @@ package mage.cards.t; -import mage.MageInt; -import mage.constants.Pronoun; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.AttacksAllTriggeredAbility; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DrawNthCardTriggeredAbility; -import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.common.delayed.UntilYourNextTurnDelayedTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerLibraryCount; +import mage.abilities.dynamicvalue.common.HalfValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.*; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.keyword.InvestigateEffect; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.command.emblems.TamiyoSeasonedScholarEmblem; +import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; /** * @author Susucr */ -public final class TamiyoInquisitiveStudent extends CardImpl { +public final class TamiyoInquisitiveStudent extends TransformingDoubleFacedCard { + + private static final DynamicValue xValue = new HalfValue(CardsInControllerLibraryCount.instance, true); public TamiyoInquisitiveStudent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.MOONFOLK, SubType.WIZARD}, "{U}", + "Tamiyo, Seasoned Scholar", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.TAMIYO}, "GU"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.MOONFOLK); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(0); - this.toughness = new MageInt(3); - - this.secondSideCardClazz = TamiyoSeasonedScholar.class; + this.getLeftHalfCard().setPT(0, 3); + this.getRightHalfCard().setStartingLoyalty(2); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Whenever Tamiyo, Inquisitive Student attacks, investigate. - this.addAbility(new AttacksTriggeredAbility(new InvestigateEffect())); + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new InvestigateEffect())); // When you draw your third card in a turn, exile Tamiyo, then return her to the battlefield transformed under her owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DrawNthCardTriggeredAbility( + this.getLeftHalfCard().addAbility(new DrawNthCardTriggeredAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.SHE), false, 3 ).setTriggerPhrase("When you draw your third card in a turn, ")); + + // Tamiyo, Seasoned Scholar + + // +2: Until your next turn, whenever a creature attacks you or a planeswalker you control, it gets -1/-0 until end of turn. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect( + new UntilYourNextTurnDelayedTriggeredAbility( + new AttacksAllTriggeredAbility( + new BoostTargetEffect(-1, 0, Duration.EndOfTurn) + .setText("it gets -1/-0 until end of turn"), + false, StaticFilters.FILTER_PERMANENT_CREATURE, + SetTargetPointer.PERMANENT, true + ) + ) + ), 2)); + + // -3: Return target instant or sorcery card from your graveyard to your hand. If it's a green card, add one mana of any color. + Ability ability = new LoyaltyAbility(new TamiyoSeasonedScholarMinus3Effect(), -3); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); + this.getRightHalfCard().addAbility(ability); + + // -7: Draw cards equal to half the number of cards in your library, rounded up. You get an emblem with "You have no maximum hand size." + ability = new LoyaltyAbility( + new DrawCardSourceControllerEffect(xValue) + .setText("Draw cards equal to half the number of cards in your library, rounded up."), + -7 + ); + ability.addEffect(new GetEmblemEffect(new TamiyoSeasonedScholarEmblem())); + this.getRightHalfCard().addAbility(ability); } private TamiyoInquisitiveStudent(final TamiyoInquisitiveStudent card) { @@ -56,3 +93,36 @@ public final class TamiyoInquisitiveStudent extends CardImpl { return new TamiyoInquisitiveStudent(this); } } + +class TamiyoSeasonedScholarMinus3Effect extends OneShotEffect { + + TamiyoSeasonedScholarMinus3Effect() { + super(Outcome.DrawCard); + this.staticText = "Return target instant or sorcery card from your graveyard to your hand. " + + "If it's a green card, add one mana of any color"; + } + + private TamiyoSeasonedScholarMinus3Effect(final TamiyoSeasonedScholarMinus3Effect effect) { + super(effect); + } + + @Override + public TamiyoSeasonedScholarMinus3Effect copy() { + return new TamiyoSeasonedScholarMinus3Effect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = game.getCard(source.getFirstTarget()); + if (card == null) { + return false; + } + Effect effect = new ReturnToHandTargetEffect(); + effect.setTargetPointer(getTargetPointer().copy()); + effect.apply(game, source); + if (card.getColor(game).isGreen()) { + new AddManaOfAnyColorEffect().apply(game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TamiyoSeasonedScholar.java b/Mage.Sets/src/mage/cards/t/TamiyoSeasonedScholar.java deleted file mode 100644 index 22fb297f6d1..00000000000 --- a/Mage.Sets/src/mage/cards/t/TamiyoSeasonedScholar.java +++ /dev/null @@ -1,115 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.AttacksAllTriggeredAbility; -import mage.abilities.common.delayed.UntilYourNextTurnDelayedTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.CardsInControllerLibraryCount; -import mage.abilities.dynamicvalue.common.HalfValue; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.mana.AddManaOfAnyColorEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.command.emblems.TamiyoSeasonedScholarEmblem; -import mage.target.common.TargetCardInYourGraveyard; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class TamiyoSeasonedScholar extends CardImpl { - - private static final DynamicValue xValue = new HalfValue(CardsInControllerLibraryCount.instance, true); - - public TamiyoSeasonedScholar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.TAMIYO); - this.setStartingLoyalty(2); - - this.color.setGreen(true); - this.color.setBlue(true); - this.nightCard = true; - - // +2: Until your next turn, whenever a creature attacks you or a planeswalker you control, it gets -1/-0 until end of turn. - this.addAbility(new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect( - new UntilYourNextTurnDelayedTriggeredAbility( - new AttacksAllTriggeredAbility( - new BoostTargetEffect(-1, 0, Duration.EndOfTurn) - .setText("it gets -1/-0 until end of turn"), - false, StaticFilters.FILTER_PERMANENT_CREATURE, - SetTargetPointer.PERMANENT, true - ) - ) - ), 2)); - - // -3: Return target instant or sorcery card from your graveyard to your hand. If it's a green card, add one mana of any color. - Ability ability = new LoyaltyAbility(new TamiyoSeasonedScholarMinus3Effect(), -3); - ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); - this.addAbility(ability); - - // -7: Draw cards equal to half the number of cards in your library, rounded up. You get an emblem with "You have no maximum hand size." - ability = new LoyaltyAbility( - new DrawCardSourceControllerEffect(xValue) - .setText("Draw cards equal to half the number of cards in your library, rounded up."), - -7 - ); - ability.addEffect(new GetEmblemEffect(new TamiyoSeasonedScholarEmblem())); - this.addAbility(ability); - } - - private TamiyoSeasonedScholar(final TamiyoSeasonedScholar card) { - super(card); - } - - @Override - public TamiyoSeasonedScholar copy() { - return new TamiyoSeasonedScholar(this); - } -} - -class TamiyoSeasonedScholarMinus3Effect extends OneShotEffect { - - TamiyoSeasonedScholarMinus3Effect() { - super(Outcome.DrawCard); - this.staticText = "Return target instant or sorcery card from your graveyard to your hand. " - + "If it's a green card, add one mana of any color"; - } - - private TamiyoSeasonedScholarMinus3Effect(final TamiyoSeasonedScholarMinus3Effect effect) { - super(effect); - } - - @Override - public TamiyoSeasonedScholarMinus3Effect copy() { - return new TamiyoSeasonedScholarMinus3Effect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Card card = game.getCard(source.getFirstTarget()); - if (card == null) { - return false; - } - Effect effect = new ReturnToHandTargetEffect(); - effect.setTargetPointer(getTargetPointer().copy()); - effect.apply(game, source); - if (card.getColor(game).isGreen()) { - new AddManaOfAnyColorEffect().apply(game, source); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TeamAvatar.java b/Mage.Sets/src/mage/cards/t/TeamAvatar.java new file mode 100644 index 00000000000..016451df906 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TeamAvatar.java @@ -0,0 +1,55 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksAloneControlledTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TeamAvatar extends CardImpl { + + public TeamAvatar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // Whenever a creature you control attacks alone, it gets +X/+X until end of turn, where X is the number of creatures you control. + this.addAbility(new AttacksAloneControlledTriggeredAbility( + new BoostTargetEffect(CreaturesYouControlCount.PLURAL, CreaturesYouControlCount.PLURAL) + .setText("it gets +X/+X until end of turn, where X is the number of creatures you control"), + true, false + ).addHint(CreaturesYouControlHint.instance)); + + // {2}{W}, Discard this card: It deals damage equal to the number of creatures you control to target creature. + Ability ability = new SimpleActivatedAbility( + Zone.HAND, + new DamageTargetEffect(CreaturesYouControlCount.PLURAL) + .setText("it deals damage equal to the number of creatures you control to target creature"), + new ManaCostsImpl<>("{2}{W}") + ); + ability.addCost(new DiscardSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private TeamAvatar(final TeamAvatar card) { + super(card); + } + + @Override + public TeamAvatar copy() { + return new TeamAvatar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TectonicSplit.java b/Mage.Sets/src/mage/cards/t/TectonicSplit.java new file mode 100644 index 00000000000..68ad7b29898 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TectonicSplit.java @@ -0,0 +1,109 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.permanent.CanBeSacrificedPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetSacrifice; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TectonicSplit extends CardImpl { + + public TectonicSplit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}{G}"); + + // As an additional cost to cast this spell, sacrifice half the lands you control, rounded up. + this.getSpellAbility().addCost(new TectonicSplitCost()); + + // Hexproof + this.addAbility(HexproofAbility.getInstance()); + + // Lands you control have "{T}: Add three mana of any one color." + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new SimpleManaAbility(new AddManaOfAnyColorEffect(3), new TapSourceCost()), + Duration.WhileOnBattlefield, StaticFilters.FILTER_LANDS + ))); + } + + private TectonicSplit(final TectonicSplit card) { + super(card); + } + + @Override + public TectonicSplit copy() { + return new TectonicSplit(this); + } +} + +class TectonicSplitCost extends CostImpl { + + private static final FilterPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(CanBeSacrificedPredicate.instance); + } + + TectonicSplitCost() { + super(); + setText("sacrifice half the lands you control, rounded up"); + } + + private TectonicSplitCost(final TectonicSplitCost cost) { + super(cost); + } + + @Override + public TectonicSplitCost copy() { + return new TectonicSplitCost(this); + } + + @Override + public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + return 2 * game.getBattlefield().count(filter, controllerId, source, game) + >= game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, controllerId, source, game); + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + Player player = game.getPlayer(controllerId); + if (player == null) { + paid = false; + return paid; + } + int count = (1 + game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, controllerId, source, game)) / 2; + if (count == 0) { + paid = true; + return paid; + } + TargetSacrifice target = new TargetSacrifice(count, StaticFilters.FILTER_LAND); + player.choose(Outcome.Sacrifice, target, source, game); + for (UUID targetId : target.getTargets()) { + Optional.ofNullable(targetId) + .map(game::getPermanent) + .ifPresent(permanent -> permanent.sacrifice(source, game)); + } + paid = true; + return paid; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TecutlanTheSearingRift.java b/Mage.Sets/src/mage/cards/t/TecutlanTheSearingRift.java deleted file mode 100644 index f9874232e46..00000000000 --- a/Mage.Sets/src/mage/cards/t/TecutlanTheSearingRift.java +++ /dev/null @@ -1,92 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.CastSpellPaidBySourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.keyword.DiscoverEffect; -import mage.abilities.mana.RedManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.FilterSpell; -import mage.filter.predicate.mageobject.PermanentPredicate; -import mage.game.Game; -import mage.game.stack.Spell; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class TecutlanTheSearingRift extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("a permanent spell"); - - static { - filter.add(PermanentPredicate.instance); - } - - public TecutlanTheSearingRift(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.CAVE); - - // (Transforms from Brass's Tunnel-Grinder.) - this.nightCard = true; - - // {T}: Add {R}. - this.addAbility(new RedManaAbility()); - - // Whenever you cast a permanent spell using mana produced by Tecutlan, the Searing Rift, discover X, where X is that spell's mana value. - this.addAbility(new CastSpellPaidBySourceTriggeredAbility( - new TecutlanTheSearingRiftEffect(), - filter, true - )); - } - - private TecutlanTheSearingRift(final TecutlanTheSearingRift card) { - super(card); - } - - @Override - public TecutlanTheSearingRift copy() { - return new TecutlanTheSearingRift(this); - } -} - -class TecutlanTheSearingRiftEffect extends OneShotEffect { - - TecutlanTheSearingRiftEffect() { - super(Outcome.Benefit); - staticText = "discover X, where X is that spell's mana value"; - } - - private TecutlanTheSearingRiftEffect(final TecutlanTheSearingRiftEffect effect) { - super(effect); - } - - @Override - public TecutlanTheSearingRiftEffect copy() { - return new TecutlanTheSearingRiftEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - - Spell spell = game.getSpellOrLKIStack(getTargetPointer().getFirst(game, source)); - int mv = spell == null ? 0 : Math.max(0, spell.getManaValue()); - - DiscoverEffect.doDiscover(controller, mv, game, source); - return true; - } - -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TempleOfAclazotz.java b/Mage.Sets/src/mage/cards/t/TempleOfAclazotz.java deleted file mode 100644 index ca7fc5af6cb..00000000000 --- a/Mage.Sets/src/mage/cards/t/TempleOfAclazotz.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.mana.BlackManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TempleOfAclazotz extends CardImpl { - - public TempleOfAclazotz(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.nightCard = true; - - // {T}: Add {B} - this.addAbility(new BlackManaAbility()); - - // {T}, Sacrifice a creature: You gain life equal to the sacrificed creature's toughness. - Ability ability = new SimpleActivatedAbility(new GainLifeEffect(SacrificeCostCreaturesToughness.instance) - .setText("you gain life equal to the sacrificed creature's toughness"), new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); - this.addAbility(ability); - } - - private TempleOfAclazotz(final TempleOfAclazotz card) { - super(card); - } - - @Override - public TempleOfAclazotz copy() { - return new TempleOfAclazotz(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TempleOfTheDead.java b/Mage.Sets/src/mage/cards/t/TempleOfTheDead.java deleted file mode 100644 index 0c63338958b..00000000000 --- a/Mage.Sets/src/mage/cards/t/TempleOfTheDead.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.hint.ConditionHint; -import mage.abilities.hint.Hint; -import mage.abilities.mana.BlackManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.TargetController; -import mage.constants.TimingRule; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class TempleOfTheDead extends CardImpl { - - private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 2, TargetController.ANY); - private static final Hint hint = new ConditionHint(condition); - - public TempleOfTheDead(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - this.nightCard = true; - - // (Transforms from Aclazotz, Deepest Betrayal.) - - // {T}: Add {B}. - this.addAbility(new BlackManaAbility()); - - // {2}{B}, {T}: Transform Temple of the Dead. Activate only if a player has one or fewer cards in hand and only as a sorcery. - Ability ability = new ActivateIfConditionActivatedAbility( - new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}"), condition - ).setTiming(TimingRule.SORCERY); - ability.addCost(new TapSourceCost()); - this.addAbility(ability.addHint(hint)); - } - - private TempleOfTheDead(final TempleOfTheDead card) { - super(card); - } - - @Override - public TempleOfTheDead copy() { - return new TempleOfTheDead(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/Tephraderm.java b/Mage.Sets/src/mage/cards/t/Tephraderm.java index b11e1487ed2..e18f2d35259 100644 --- a/Mage.Sets/src/mage/cards/t/Tephraderm.java +++ b/Mage.Sets/src/mage/cards/t/Tephraderm.java @@ -4,8 +4,6 @@ import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.DealsDamageToThisAllTriggeredAbility; import mage.abilities.dynamicvalue.common.SavedDamageValue; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -57,7 +55,8 @@ public final class Tephraderm extends CardImpl { class TephradermSpellDamageTriggeredAbility extends TriggeredAbilityImpl { TephradermSpellDamageTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(0)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(SavedDamageValue.MUCH).withTargetDescription("that spell's controller")); + setTriggerPhrase("Whenever a spell deals damage to {this}, "); } private TephradermSpellDamageTriggeredAbility(final TephradermSpellDamageTriggeredAbility ability) { @@ -74,18 +73,12 @@ class TephradermSpellDamageTriggeredAbility extends TriggeredAbilityImpl { if (!event.getTargetId().equals(this.getSourceId())) { return false; } - StackObject sourceSpell = game.getStack().getStackObject(event.getSourceId()); if (sourceSpell != null && StaticFilters.FILTER_SPELL.match(sourceSpell, getControllerId(), this, game)) { - for (Effect effect : getEffects()) { - if (effect instanceof DamageTargetEffect) { - effect.setTargetPointer(new FixedTarget(sourceSpell.getControllerId())); - ((DamageTargetEffect) effect).setAmount(StaticValue.get(event.getAmount())); - } - } + this.getEffects().setTargetPointer(new FixedTarget(sourceSpell.getControllerId())); + this.getEffects().setValue("damage", event.getAmount()); return true; } - return false; } @@ -94,8 +87,4 @@ class TephradermSpellDamageTriggeredAbility extends TriggeredAbilityImpl { return new TephradermSpellDamageTriggeredAbility(this); } - @Override - public String getRule() { - return "Whenever a spell deals damage to {this}, {this} deals that much damage to that spell's controller."; - } } diff --git a/Mage.Sets/src/mage/cards/t/ThatsRoughBuddy.java b/Mage.Sets/src/mage/cards/t/ThatsRoughBuddy.java new file mode 100644 index 00000000000..21ef23bc7de --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThatsRoughBuddy.java @@ -0,0 +1,48 @@ +package mage.cards.t; + +import mage.abilities.condition.common.CreatureLeftThisTurnCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThatsRoughBuddy extends CardImpl { + + public ThatsRoughBuddy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + this.subtype.add(SubType.LESSON); + + // Put a +1/+1 counter on target creature. Put two +1/+1 counters on that creature instead if a creature left the battlefield under your control this turn. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)), + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), + CreatureLeftThisTurnCondition.instance, "put a +1/+1 counter on target creature. Put two +1/+1 " + + "counters on that creature instead if a creature left the battlefield under your control this turn" + )); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addHint(CreatureLeftThisTurnCondition.getHint()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); + } + + private ThatsRoughBuddy(final ThatsRoughBuddy card) { + super(card); + } + + @Override + public ThatsRoughBuddy copy() { + return new ThatsRoughBuddy(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheArgentEtchings.java b/Mage.Sets/src/mage/cards/t/TheArgentEtchings.java deleted file mode 100644 index e9cd482513d..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheArgentEtchings.java +++ /dev/null @@ -1,118 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DestroyAllEffect; -import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.keyword.IncubateEffect; -import mage.abilities.keyword.DoubleStrikeAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.filter.predicate.permanent.TokenPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TheArgentEtchings extends CardImpl { - - private static final FilterPermanent filter - = new FilterPermanent("other permanents except for artifacts, lands, and Phyrexians"); - - static { - filter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); - filter.add(Predicates.not(CardType.LAND.getPredicate())); - filter.add(Predicates.not(SubType.PHYREXIAN.getPredicate())); - filter.add(AnotherPredicate.instance); - } - - public TheArgentEtchings(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.SAGA); - this.color.setWhite(true); - this.nightCard = true; - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I -- Incubate 2 five times, then transform all Incubator tokens you control. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new TheArgentEtchingsEffect()); - - // II -- Creatures you control get +1/+1 and gain double strike until end of turn. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_II, - new BoostControlledEffect(1, 1, Duration.EndOfTurn) - .setText("creatures you control get +1/+1"), - new GainAbilityControlledEffect( - DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_CONTROLLED_CREATURE - ).setText("and gain double strike until end of turn") - ); - - // III -- Destroy all other permanents except for artifacts, lands, and Phyrexians. Exile The Argent Etchings, then return it to the battlefield. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, - new DestroyAllEffect(filter), - new ExileSourceAndReturnFaceUpEffect() - ); - this.addAbility(sagaAbility); - } - - private TheArgentEtchings(final TheArgentEtchings card) { - super(card); - } - - @Override - public TheArgentEtchings copy() { - return new TheArgentEtchings(this); - } -} - -class TheArgentEtchingsEffect extends OneShotEffect { - - private static final FilterPermanent filter = new FilterControlledPermanent(SubType.INCUBATOR); - - static { - filter.add(TokenPredicate.TRUE); - } - - TheArgentEtchingsEffect() { - super(Outcome.Benefit); - staticText = "incubate 2 five times, then transform all Incubator tokens you control"; - } - - private TheArgentEtchingsEffect(final TheArgentEtchingsEffect effect) { - super(effect); - } - - @Override - public TheArgentEtchingsEffect copy() { - return new TheArgentEtchingsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - for (int i = 0; i < 5; i++) { - IncubateEffect.doIncubate(2, game, source); - } - for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source, game - )) { - permanent.transform(source, game); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheBalrogDurinsBane.java b/Mage.Sets/src/mage/cards/t/TheBalrogDurinsBane.java index 70f07c591a2..3476a47d6dd 100644 --- a/Mage.Sets/src/mage/cards/t/TheBalrogDurinsBane.java +++ b/Mage.Sets/src/mage/cards/t/TheBalrogDurinsBane.java @@ -9,7 +9,6 @@ import mage.abilities.dynamicvalue.common.PermanentsSacrificedThisTurnCount; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; -import mage.abilities.hint.common.PermanentsSacrificedThisTurnHint; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -23,13 +22,12 @@ import mage.watchers.common.PermanentsSacrificedWatcher; import java.util.UUID; /** - * * @author Susucr */ public final class TheBalrogDurinsBane extends CardImpl { private static final FilterCreaturePermanent filterNonLegendary - = new FilterCreaturePermanent("except by legendary creatures"); + = new FilterCreaturePermanent("except by legendary creatures"); static { filterNonLegendary.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); @@ -37,7 +35,7 @@ public final class TheBalrogDurinsBane extends CardImpl { public TheBalrogDurinsBane(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{R}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.AVATAR); this.subtype.add(SubType.DEMON); @@ -46,12 +44,12 @@ public final class TheBalrogDurinsBane extends CardImpl { // This spell costs {1} less to cast for each permanent sacrificed this turn. this.addAbility( - new SimpleStaticAbility( - Zone.ALL, - new SpellCostReductionSourceEffect(PermanentsSacrificedThisTurnCount.instance) - .setText("this spell costs {1} less to cast for each permanent sacrificed this turn") - ).addHint(PermanentsSacrificedThisTurnHint.instance).setRuleAtTheTop(true), - new PermanentsSacrificedWatcher() + new SimpleStaticAbility( + Zone.ALL, + new SpellCostReductionSourceEffect(PermanentsSacrificedThisTurnCount.ALL) + .setText("this spell costs {1} less to cast for each permanent sacrificed this turn") + ).addHint(PermanentsSacrificedThisTurnCount.ALL.getHint()).setRuleAtTheTop(true), + new PermanentsSacrificedWatcher() ); // Haste @@ -59,7 +57,7 @@ public final class TheBalrogDurinsBane extends CardImpl { // The Balrog, Durin's Bane can't be blocked except by legendary creatures. this.addAbility(new SimpleEvasionAbility((new CantBeBlockedByCreaturesSourceEffect( - filterNonLegendary, Duration.WhileOnBattlefield + filterNonLegendary, Duration.WhileOnBattlefield )))); // When The Balrog dies, destroy target artifact or creature an opponent controls. diff --git a/Mage.Sets/src/mage/cards/t/TheBlueSpirit.java b/Mage.Sets/src/mage/cards/t/TheBlueSpirit.java new file mode 100644 index 00000000000..53c080c6ec7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheBlueSpirit.java @@ -0,0 +1,73 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.IsPhaseCondition; +import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.watchers.common.SpellsCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheBlueSpirit extends CardImpl { + + private static final Condition condition = new IsPhaseCondition(TurnPhase.COMBAT); + + public TheBlueSpirit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // You may cast the first creature spell you cast each turn as though it had flash. + this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( + new CastAsThoughItHadFlashAllEffect( + Duration.WhileOnBattlefield, StaticFilters.FILTER_CARD_CREATURE + ), TheBlueSpiritCondition.instance + ).setText("you may cast the first creature spell you cast each turn as though it had flash"))); + + // Whenever a nontoken creature you control enters during combat, draw a card. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN + ).withTriggerCondition(condition)); + } + + private TheBlueSpirit(final TheBlueSpirit card) { + super(card); + } + + @Override + public TheBlueSpirit copy() { + return new TheBlueSpirit(this); + } +} + +enum TheBlueSpiritCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game + .getState() + .getWatcher(SpellsCastWatcher.class) + .getSpellsCastThisTurn(source.getControllerId()) + .stream() + .noneMatch(spell -> spell.isCreature(game)); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheBoulderReadyToRumble.java b/Mage.Sets/src/mage/cards/t/TheBoulderReadyToRumble.java index 1d84e42f907..484bf07e95b 100644 --- a/Mage.Sets/src/mage/cards/t/TheBoulderReadyToRumble.java +++ b/Mage.Sets/src/mage/cards/t/TheBoulderReadyToRumble.java @@ -26,7 +26,7 @@ import java.util.UUID; */ public final class TheBoulderReadyToRumble extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent("creatures you control with power 4 or greater"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("the number of creatures you control with power 4 or greater"); static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); @@ -46,7 +46,7 @@ public final class TheBoulderReadyToRumble extends CardImpl { this.toughness = new MageInt(4); // Whenever The Boulder attacks, earthbend X, where X is the number of creatures you control with power 4 or greater. - Ability ability = new AttacksTriggeredAbility(new EarthbendTargetEffect(xValue)); + Ability ability = new AttacksTriggeredAbility(new EarthbendTargetEffect(xValue, true)); ability.addTarget(new TargetControlledLandPermanent()); this.addAbility(ability.addHint(hint)); } diff --git a/Mage.Sets/src/mage/cards/t/TheDarknessCrystal.java b/Mage.Sets/src/mage/cards/t/TheDarknessCrystal.java index baa92ca3fcc..bdaf1d41a72 100644 --- a/Mage.Sets/src/mage/cards/t/TheDarknessCrystal.java +++ b/Mage.Sets/src/mage/cards/t/TheDarknessCrystal.java @@ -23,6 +23,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.PermanentToken; import mage.players.Player; import mage.target.common.TargetCardInExile; import mage.util.CardUtil; @@ -139,6 +140,7 @@ class TheDarknessCrystalExileEffect extends ReplacementEffectImpl { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; return zEvent.isDiesEvent() && zEvent.getTarget().isCreature(game) + && !(zEvent.getTarget() instanceof PermanentToken) && game.getOpponents(source.getControllerId()).contains(zEvent.getTarget().getControllerId()); } diff --git a/Mage.Sets/src/mage/cards/t/TheDestinedThief.java b/Mage.Sets/src/mage/cards/t/TheDestinedThief.java index 05e610242ec..73c9238334d 100644 --- a/Mage.Sets/src/mage/cards/t/TheDestinedThief.java +++ b/Mage.Sets/src/mage/cards/t/TheDestinedThief.java @@ -72,7 +72,7 @@ class TheDestinedThiefTriggeredAbility extends TriggeredAbilityImpl implements B new DrawDiscardControllerEffect(1, 1), FullPartyCondition.instance, "draw a card, then discard a card. " + "If you have a full party, instead draw three cards" - ), true); + ), false); setTriggerPhrase("Whenever one or more creatures you control deal combat damage to one or more players, "); } diff --git a/Mage.Sets/src/mage/cards/t/TheDukeRebelSentry.java b/Mage.Sets/src/mage/cards/t/TheDukeRebelSentry.java new file mode 100644 index 00000000000..44e0cde7d50 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheDukeRebelSentry.java @@ -0,0 +1,64 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheDukeRebelSentry extends CardImpl { + + public TheDukeRebelSentry(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // The Duke enters with a +1/+1 counter on him. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + "with a +1/+1 counter on him" + )); + + // {T}, Remove a counter from The Duke: Put a +1/+1 counter on another target creature you control. It gains hexproof until end of turn. + Ability ability = new SimpleActivatedAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new TapSourceCost() + ); + ability.addCost(new RemoveCountersSourceCost(1)); + ability.addEffect(new GainAbilityTargetEffect(HexproofAbility.getInstance()) + .setText("It gains hexproof until end of turn")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + this.addAbility(ability); + } + + private TheDukeRebelSentry(final TheDukeRebelSentry card) { + super(card); + } + + @Override + public TheDukeRebelSentry copy() { + return new TheDukeRebelSentry(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheEarthKing.java b/Mage.Sets/src/mage/cards/t/TheEarthKing.java new file mode 100644 index 00000000000..b3c54da0b4b --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheEarthKing.java @@ -0,0 +1,91 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.game.permanent.token.BearsCompanionBearToken; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheEarthKing extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public TheEarthKing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When The Earth King enters, create a 4/4 green Bear creature token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new BearsCompanionBearToken()))); + + // Whenever one or more creatures you control with power 4 or greater attack, search your library for up to that many basic land cards, put them onto the battlefield tapped, then shuffle. + this.addAbility(new AttacksWithCreaturesTriggeredAbility(new TheEarthKingEffect(), 1, filter) + .setTriggerPhrase("Whenever one or more creatures you control with power 4 or greater attack, ")); + } + + private TheEarthKing(final TheEarthKing card) { + super(card); + } + + @Override + public TheEarthKing copy() { + return new TheEarthKing(this); + } +} + +class TheEarthKingEffect extends OneShotEffect { + + TheEarthKingEffect() { + super(Outcome.Benefit); + staticText = "search your library for up to that many basic land cards, " + + "put them onto the battlefield tapped, then shuffle"; + } + + private TheEarthKingEffect(final TheEarthKingEffect effect) { + super(effect); + } + + @Override + public TheEarthKingEffect copy() { + return new TheEarthKingEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int count = (Integer) getValue(AttacksWithCreaturesTriggeredAbility.VALUEKEY_NUMBER_ATTACKERS); + return new SearchLibraryPutInPlayEffect(new TargetCardInLibrary( + 0, count, StaticFilters.FILTER_CARD_BASIC_LANDS + ), true).apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheFireNationDrill.java b/Mage.Sets/src/mage/cards/t/TheFireNationDrill.java new file mode 100644 index 00000000000..7c9f6e8df9c --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheFireNationDrill.java @@ -0,0 +1,113 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.CompoundAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.LoseAbilityAllEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheFireNationDrill extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(TargetController.OPPONENT.getControllerPredicate()); + } + + public TheFireNationDrill(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(6); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When The Fire Nation Drill enters, you may tap it. When you do, destroy target creature with power 4 or less. + this.addAbility(new EntersBattlefieldTriggeredAbility(new TheFireNationDrillEffect())); + + // {1}: Permanents your opponents control lose hexproof and indestructible until end of turn. + this.addAbility(new SimpleActivatedAbility(new LoseAbilityAllEffect( + new CompoundAbility(HexproofAbility.getInstance(), IndestructibleAbility.getInstance()), Duration.EndOfTurn, filter + ).setText("permanents your opponents control lose hexproof and indestructible until end of turn."), new GenericManaCost(1))); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + } + + private TheFireNationDrill(final TheFireNationDrill card) { + super(card); + } + + @Override + public TheFireNationDrill copy() { + return new TheFireNationDrill(this); + } +} + +// custom effect needed as we can't use TapSourceCost with DoWhenCostPaid due to it not ignoring summoning sickness +class TheFireNationDrillEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with power 4 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 5)); + } + + TheFireNationDrillEffect() { + super(Outcome.Benefit); + staticText = "you may tap it. When you do, destroy target creature with power 4 or less"; + } + + private TheFireNationDrillEffect(final TheFireNationDrillEffect effect) { + super(effect); + } + + @Override + public TheFireNationDrillEffect copy() { + return new TheFireNationDrillEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (player == null + || permanent == null + || permanent.isTapped() + || !player.chooseUse(Outcome.Tap, "Tap " + permanent.getIdName() + '?', source, game) + || !permanent.tap(source, game)) { + return false; + } + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new DestroyTargetEffect(), false); + ability.addTarget(new TargetPermanent(filter)); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheLastAgniKai.java b/Mage.Sets/src/mage/cards/t/TheLastAgniKai.java new file mode 100644 index 00000000000..a35026f1559 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheLastAgniKai.java @@ -0,0 +1,92 @@ +package mage.cards.t; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.YouDontLoseManaEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.ManaType; +import mage.constants.Outcome; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; +import mage.target.targetpointer.EachTargetPointer; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class TheLastAgniKai extends CardImpl { + + public TheLastAgniKai(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // Target creature you control fights target creature an opponent controls. If the creature the opponent controls is dealt excess damage this way, add that much {R}. + this.getSpellAbility().addEffect(new TheLastAgniKaiEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); + + // Until end of turn, you don't lose unspent red mana as steps and phases end. + this.getSpellAbility().addEffect(new YouDontLoseManaEffect(Duration.EndOfTurn, ManaType.RED).concatBy("
")); + } + + private TheLastAgniKai(final TheLastAgniKai card) { + super(card); + } + + @Override + public TheLastAgniKai copy() { + return new TheLastAgniKai(this); + } +} + +class TheLastAgniKaiEffect extends OneShotEffect { + + TheLastAgniKaiEffect() { + super(Outcome.Benefit); + staticText = "target creature you control fights target creature an opponent controls. " + + "If the creature the opponent controls is dealt excess damage this way, add that much {R}"; + this.setTargetPointer(new EachTargetPointer()); + } + + private TheLastAgniKaiEffect(final TheLastAgniKaiEffect effect) { + super(effect); + } + + @Override + public TheLastAgniKaiEffect copy() { + return new TheLastAgniKaiEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (permanents.size() < 2) { + return false; + } + int excess = permanents.get(0).fightWithExcess(permanents.get(1), source, game, true); + if (excess > 0) { + Optional.ofNullable(source) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .ifPresent(player -> player.getManaPool().addMana(Mana.RedMana(excess), game, source)); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheLegendOfKyoshi.java b/Mage.Sets/src/mage/cards/t/TheLegendOfKyoshi.java index 1ba57a2371b..a07bc9bd4a9 100644 --- a/Mage.Sets/src/mage/cards/t/TheLegendOfKyoshi.java +++ b/Mage.Sets/src/mage/cards/t/TheLegendOfKyoshi.java @@ -37,13 +37,15 @@ public final class TheLegendOfKyoshi extends CardImpl { sagaAbility.addChapterEffect( this, SagaChapter.CHAPTER_I, new DrawCardSourceControllerEffect(GreatestAmongPermanentsValue.POWER_CONTROLLED_CREATURES) + .setText("draw cards equal to the greatest power among creatures you control") ); // II -- Earthbend X, where X is the number of cards in your hand. That land becomes an Island in addition to its other types. sagaAbility.addChapterEffect( this, SagaChapter.CHAPTER_II, new Effects( - new EarthbendTargetEffect(CardsInControllerHandCount.ANY), + new EarthbendTargetEffect(CardsInControllerHandCount.ANY, true) + .setText("earthbend X, where X is the number of cards in your hand"), new AddCardSubTypeTargetEffect(SubType.ISLAND, Duration.Custom) .setText("That land becomes an Island in addition to its other types") ), new TargetControlledLandPermanent() diff --git a/Mage.Sets/src/mage/cards/t/TheLegendOfRoku.java b/Mage.Sets/src/mage/cards/t/TheLegendOfRoku.java index 7b87b91d5ff..37aa1bd902f 100644 --- a/Mage.Sets/src/mage/cards/t/TheLegendOfRoku.java +++ b/Mage.Sets/src/mage/cards/t/TheLegendOfRoku.java @@ -1,10 +1,9 @@ package mage.cards.t; -import mage.Mana; import mage.abilities.common.SagaAbility; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; -import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; import mage.abilities.keyword.TransformAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -36,7 +35,7 @@ public final class TheLegendOfRoku extends CardImpl { ); // II -- Add one mana of any color. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new BasicManaEffect(Mana.AnyMana(1))); + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new AddManaOfAnyColorEffect(1)); // III -- Exile this Saga, then return it to the battlefield transformed under your control. this.addAbility(new TransformAbility()); diff --git a/Mage.Sets/src/mage/cards/t/TheLegendOfYangchen.java b/Mage.Sets/src/mage/cards/t/TheLegendOfYangchen.java new file mode 100644 index 00000000000..e38cae32e99 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheLegendOfYangchen.java @@ -0,0 +1,110 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.Effects; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponent; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheLegendOfYangchen extends CardImpl { + + public TheLegendOfYangchen(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{W}"); + + this.subtype.add(SubType.SAGA); + this.secondSideCardClazz = mage.cards.a.AvatarYangchen.class; + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I -- Starting with you, each player chooses up to one permanent with mana value 3 or greater from among permanents your opponents control. Exile those permanents. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new TheLegendOfYangchenEffect()); + + // II -- You may have target opponent draw three cards. If you do, draw three cards. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, + new Effects( + new DrawCardTargetEffect(3).setText("have target opponent draw three cards. If you do"), + new DrawCardSourceControllerEffect(3).concatBy(",") + ), new TargetOpponent(), true + ); + + // III -- Exile this Saga, then return it to the battlefield transformed under your control. + this.addAbility(new TransformAbility()); + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.addAbility(sagaAbility); + } + + private TheLegendOfYangchen(final TheLegendOfYangchen card) { + super(card); + } + + @Override + public TheLegendOfYangchen copy() { + return new TheLegendOfYangchen(this); + } +} + +class TheLegendOfYangchenEffect extends OneShotEffect { + + TheLegendOfYangchenEffect() { + super(Outcome.Benefit); + staticText = "starting with you, each player chooses up to one permanent with mana value 3 or greater " + + "from among permanents your opponents control. Exile those permanents"; + } + + private TheLegendOfYangchenEffect(final TheLegendOfYangchenEffect effect) { + super(effect); + } + + @Override + public TheLegendOfYangchenEffect copy() { + return new TheLegendOfYangchenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + FilterPermanent filter = new FilterPermanent(); + filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 2)); + filter.add(Predicates.not(new ControllerIdPredicate(source.getControllerId()))); + Set permanents = new HashSet<>(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; + } + TargetPermanent target = new TargetPermanent(0, 1, filter, true); + player.choose(Outcome.Exile, target, source, game); + permanents.add(game.getPermanent(target.getFirstTarget())); + } + permanents.removeIf(Objects::isNull); + if (permanents.isEmpty()) { + return false; + } + Player player = game.getPlayer(source.getControllerId()); + return player != null && player.moveCards(permanents, Zone.EXILED, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TigerDillo.java b/Mage.Sets/src/mage/cards/t/TigerDillo.java index 7738560091a..ba03f8c3142 100644 --- a/Mage.Sets/src/mage/cards/t/TigerDillo.java +++ b/Mage.Sets/src/mage/cards/t/TigerDillo.java @@ -24,7 +24,7 @@ import java.util.UUID; */ public final class TigerDillo extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you control another creature with power 4 or greater"); static { filter.add(AnotherPredicate.instance); @@ -32,9 +32,7 @@ public final class TigerDillo extends CardImpl { } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); - private static final Hint hint = new ConditionHint( - condition, "You control another creature with power 4 or greature" - ); + private static final Hint hint = new ConditionHint(condition); public TigerDillo(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); diff --git a/Mage.Sets/src/mage/cards/t/TimberShredder.java b/Mage.Sets/src/mage/cards/t/TimberShredder.java deleted file mode 100644 index 6fe22125f0b..00000000000 --- a/Mage.Sets/src/mage/cards/t/TimberShredder.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.t; - -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class TimberShredder extends CardImpl { - - public TimberShredder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(2); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Timber Shredder. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private TimberShredder(final TimberShredder card) { - super(card); - } - - @Override - public TimberShredder copy() { - return new TimberShredder(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TinybonesBaubleBurglar.java b/Mage.Sets/src/mage/cards/t/TinybonesBaubleBurglar.java index 83473f261c3..b26b3873ca8 100644 --- a/Mage.Sets/src/mage/cards/t/TinybonesBaubleBurglar.java +++ b/Mage.Sets/src/mage/cards/t/TinybonesBaubleBurglar.java @@ -213,8 +213,8 @@ class TinybonesBaubleBurglarSpendAnyManaEffect extends AsThoughEffectImpl implem cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); } else if (card instanceof CardWithSpellOption) { cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); - } else if (card instanceof ModalDoubleFacedCard) { - cardState = game.getLastKnownInformationCard(((ModalDoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); + } else if (card instanceof DoubleFacedCard) { + cardState = game.getLastKnownInformationCard(((DoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); } else { cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); } diff --git a/Mage.Sets/src/mage/cards/t/TitanHunter.java b/Mage.Sets/src/mage/cards/t/TitanHunter.java index 4697836741b..88087d5b0af 100644 --- a/Mage.Sets/src/mage/cards/t/TitanHunter.java +++ b/Mage.Sets/src/mage/cards/t/TitanHunter.java @@ -39,7 +39,7 @@ public final class TitanHunter extends CardImpl { // At the beginning of each player's end step, if no creatures died this turn, Titan Hunter deals 4 damage to that player. this.addAbility(new BeginningOfEndStepTriggeredAbility( TargetController.EACH_PLAYER, - new DamageTargetEffect(4, true, "that player"), + new DamageTargetEffect(4).withTargetDescription("that player"), false, condition ).addHint(MorbidHint.instance)); diff --git a/Mage.Sets/src/mage/cards/t/TophEarthbendingMaster.java b/Mage.Sets/src/mage/cards/t/TophEarthbendingMaster.java index 40e3ace50f1..b47049de3fa 100644 --- a/Mage.Sets/src/mage/cards/t/TophEarthbendingMaster.java +++ b/Mage.Sets/src/mage/cards/t/TophEarthbendingMaster.java @@ -42,7 +42,7 @@ public final class TophEarthbendingMaster extends CardImpl { ))); // Whenever you attack, earthbend X, where X is the number of experience counters you have. - Ability ability = new AttacksWithCreaturesTriggeredAbility(new EarthbendTargetEffect(xValue), 1); + Ability ability = new AttacksWithCreaturesTriggeredAbility(new EarthbendTargetEffect(xValue, true), 1); ability.addTarget(new TargetControlledLandPermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TophGreatestEarthbender.java b/Mage.Sets/src/mage/cards/t/TophGreatestEarthbender.java index f40f25e154b..7a0d5fc3fa5 100644 --- a/Mage.Sets/src/mage/cards/t/TophGreatestEarthbender.java +++ b/Mage.Sets/src/mage/cards/t/TophGreatestEarthbender.java @@ -42,7 +42,7 @@ public final class TophGreatestEarthbender extends CardImpl { this.toughness = new MageInt(3); // When Toph enters, earthbend X, where X is the amount of mana spent to cast her. - Ability ability = new EntersBattlefieldTriggeredAbility(new EarthbendTargetEffect(ManaSpentToCastCount.instance)); + Ability ability = new EntersBattlefieldTriggeredAbility(new EarthbendTargetEffect(ManaSpentToCastCount.instance, true)); ability.addTarget(new TargetControlledLandPermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/TophHardheadedTeacher.java b/Mage.Sets/src/mage/cards/t/TophHardheadedTeacher.java new file mode 100644 index 00000000000..7d47a19656e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TophHardheadedTeacher.java @@ -0,0 +1,91 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TophHardheadedTeacher extends CardImpl { + + public TophHardheadedTeacher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When Toph enters, you may discard a card. If you do, return target instant or sorcery card from your graveyard to your hand. + Ability ability = new EntersBattlefieldTriggeredAbility( + new DoIfCostPaid(new ReturnFromGraveyardToHandTargetEffect(), new DiscardCardCost()) + ); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); + this.addAbility(ability); + + // Whenever you cast a spell, earthbend 1. If that spell is a Lesson, put an additional +1/+1 counter on that land. + ability = new SpellCastControllerTriggeredAbility(new EarthbendTargetEffect(1), false); + ability.addEffect(new TophHardheadedTeacherEffect()); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + } + + private TophHardheadedTeacher(final TophHardheadedTeacher card) { + super(card); + } + + @Override + public TophHardheadedTeacher copy() { + return new TophHardheadedTeacher(this); + } +} + +class TophHardheadedTeacherEffect extends OneShotEffect { + + TophHardheadedTeacherEffect() { + super(Outcome.Benefit); + staticText = "If that spell is a Lesson, put an additional +1/+1 counter on that land"; + } + + private TophHardheadedTeacherEffect(final TophHardheadedTeacherEffect effect) { + super(effect); + } + + @Override + public TophHardheadedTeacherEffect copy() { + return new TophHardheadedTeacherEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = (Spell) getValue("spellCast"); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + return spell != null && permanent != null + && spell.hasSubtype(SubType.LESSON, game) + && permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TovolarsMagehunter.java b/Mage.Sets/src/mage/cards/t/TovolarsMagehunter.java index 3879bc96f68..24b484f51df 100644 --- a/Mage.Sets/src/mage/cards/t/TovolarsMagehunter.java +++ b/Mage.Sets/src/mage/cards/t/TovolarsMagehunter.java @@ -32,7 +32,7 @@ public final class TovolarsMagehunter extends CardImpl { // Whenever an opponent casts a spell, Tovolar's Magehunter deals 2 damage to that player. this.addAbility(new SpellCastOpponentTriggeredAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player"), + Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player"), StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.PLAYER )); diff --git a/Mage.Sets/src/mage/cards/t/TrustyBoomerang.java b/Mage.Sets/src/mage/cards/t/TrustyBoomerang.java new file mode 100644 index 00000000000..e3f89637b55 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TrustyBoomerang.java @@ -0,0 +1,91 @@ +package mage.cards.t; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effects; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityWithAttachmentEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Targets; +import mage.target.common.TargetCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TrustyBoomerang extends CardImpl { + + public TrustyBoomerang(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature has "{1}, {T}: Tap target creature. Return Trusty Boomerang to its owner's hand." + this.addAbility(new SimpleStaticAbility(new GainAbilityWithAttachmentEffect( + "equipped creature has \"{1}, {T}: Tap target creature. Return {this} to its owner's hand.\"", + new Effects(new ReturnToHandTargetEffect(), new TrustyBoomerangEffect()), + new Targets(new TargetCreaturePermanent()), null, + new GenericManaCost(1), new TapSourceCost() + ))); + + // Equip {1} + this.addAbility(new EquipAbility(1)); + } + + private TrustyBoomerang(final TrustyBoomerang card) { + super(card); + } + + @Override + public TrustyBoomerang copy() { + return new TrustyBoomerang(this); + } +} + +class TrustyBoomerangEffect extends OneShotEffect { + + TrustyBoomerangEffect() { + super(Outcome.Benefit); + } + + private TrustyBoomerangEffect(final TrustyBoomerangEffect effect) { + super(effect); + } + + @Override + public TrustyBoomerangEffect copy() { + return new TrustyBoomerangEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = (Permanent) getValue("attachedPermanent"); + return player != null && permanent != null && player.moveCards(permanent, Zone.HAND, source, game); + } + + @Override + public String getText(Mode mode) { + return "return " + + Optional.ofNullable((Permanent) getValue("attachedPermanent")) + .map(MageObject::getName) + .orElse("Trusty Boomerang") + + " to its owner's hand"; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TyLeeChiBlocker.java b/Mage.Sets/src/mage/cards/t/TyLeeChiBlocker.java new file mode 100644 index 00000000000..b2bc303ebe1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TyLeeChiBlocker.java @@ -0,0 +1,56 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DontUntapInControllersUntapStepTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.ProwessAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TyLeeChiBlocker extends CardImpl { + + public TyLeeChiBlocker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PERFORMER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Prowess + this.addAbility(new ProwessAbility()); + + // When Ty Lee enters, tap up to one target creature. It doesn't untap during its controller's untap step for as long as you control Ty Lee. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); + ability.addEffect(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled, "it")); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + } + + private TyLeeChiBlocker(final TyLeeChiBlocker card) { + super(card); + } + + @Override + public TyLeeChiBlocker copy() { + return new TyLeeChiBlocker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnclesMusings.java b/Mage.Sets/src/mage/cards/u/UnclesMusings.java new file mode 100644 index 00000000000..644782180ea --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnclesMusings.java @@ -0,0 +1,44 @@ +package mage.cards.u; + +import mage.abilities.dynamicvalue.common.ColorsOfManaSpentToCastCount; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetsCountAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnclesMusings extends CardImpl { + + public UnclesMusings(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}{G}"); + + // Converge -- Return up to X permanent cards from your graveyard to your hand, where X is the number of colors of mana spent to cast this spell. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect() + .setText("return up to X permanent cards from your graveyard to your hand, " + + "where X is the number of colors of mana spent to cast this spell")); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_PERMANENT)); + this.getSpellAbility().setTargetAdjuster(new TargetsCountAdjuster(ColorsOfManaSpentToCastCount.getInstance())); + this.getSpellAbility().setAbilityWord(AbilityWord.CONVERGE); + + // Exile Uncle's Musings. + this.getSpellAbility().addEffect(new ExileSpellEffect().concatBy("
")); + } + + private UnclesMusings(final UnclesMusings card) { + super(card); + } + + @Override + public UnclesMusings copy() { + return new UnclesMusings(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnderworldDreams.java b/Mage.Sets/src/mage/cards/u/UnderworldDreams.java index 6fec7feb0c5..2f34acedc29 100644 --- a/Mage.Sets/src/mage/cards/u/UnderworldDreams.java +++ b/Mage.Sets/src/mage/cards/u/UnderworldDreams.java @@ -18,7 +18,7 @@ public final class UnderworldDreams extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}{B}{B}"); // Whenever an opponent draws a card, Underworld Dreams deals 1 damage to that player. - this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1, true, "that player"), false, true)); + this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that player"), false, true)); } private UnderworldDreams(final UnderworldDreams card) { diff --git a/Mage.Sets/src/mage/cards/u/UnholyAnnexRitualChamber.java b/Mage.Sets/src/mage/cards/u/UnholyAnnexRitualChamber.java index 04773cc23ab..0e84acb85eb 100644 --- a/Mage.Sets/src/mage/cards/u/UnholyAnnexRitualChamber.java +++ b/Mage.Sets/src/mage/cards/u/UnholyAnnexRitualChamber.java @@ -45,11 +45,11 @@ public final class UnholyAnnexRitualChamber extends RoomCard { new PermanentsOnTheBattlefieldCondition(filter), "If you control a Demon, each opponent loses 2 life and you gain 2 life. Otherwise, you lose 2 life" )); left.addHint(new ConditionHint(new PermanentsOnTheBattlefieldCondition(filter), "You control a Demon")); + this.getLeftHalfCard().addAbility(left); // Ritual Chamber: When you unlock this door, create a 6/6 black Demon creature token with flying. Ability right = new UnlockThisDoorTriggeredAbility(new CreateTokenEffect(new Demon66Token()), false, false); - - this.addRoomAbilities(left, right); + this.getRightHalfCard().addAbility(right); } private UnholyAnnexRitualChamber(final UnholyAnnexRitualChamber card) { diff --git a/Mage.Sets/src/mage/cards/u/UnholyFiend.java b/Mage.Sets/src/mage/cards/u/UnholyFiend.java deleted file mode 100644 index 726ca0db1bb..00000000000 --- a/Mage.Sets/src/mage/cards/u/UnholyFiend.java +++ /dev/null @@ -1,41 +0,0 @@ - -package mage.cards.u; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.effects.common.LoseLifeSourceControllerEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author Loki - */ -public final class UnholyFiend extends CardImpl { - - public UnholyFiend(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.HORROR); - - this.color.setBlack(true); - - this.power = new MageInt(3); - this.toughness = new MageInt(3); - - this.nightCard = true; - - this.addAbility(new BeginningOfEndStepTriggeredAbility(new LoseLifeSourceControllerEffect(1))); - } - - private UnholyFiend(final UnholyFiend card) { - super(card); - } - - @Override - public UnholyFiend copy() { - return new UnholyFiend(this); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UnimpededTrespasser.java b/Mage.Sets/src/mage/cards/u/UnimpededTrespasser.java deleted file mode 100644 index 71bf6341fa8..00000000000 --- a/Mage.Sets/src/mage/cards/u/UnimpededTrespasser.java +++ /dev/null @@ -1,40 +0,0 @@ - -package mage.cards.u; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.CantBeBlockedSourceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class UnimpededTrespasser extends CardImpl { - - public UnimpededTrespasser(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlue(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Unimpeded Trespasser can't be blocked. - this.addAbility(new CantBeBlockedSourceAbility()); - } - - private UnimpededTrespasser(final UnimpededTrespasser card) { - super(card); - } - - @Override - public UnimpededTrespasser copy() { - return new UnimpededTrespasser(this); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UninvitedGeist.java b/Mage.Sets/src/mage/cards/u/UninvitedGeist.java index 4f142aba650..d3a58adfc90 100644 --- a/Mage.Sets/src/mage/cards/u/UninvitedGeist.java +++ b/Mage.Sets/src/mage/cards/u/UninvitedGeist.java @@ -1,13 +1,12 @@ package mage.cards.u; -import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.CantBeBlockedSourceAbility; import mage.abilities.keyword.SkulkAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -16,23 +15,27 @@ import java.util.UUID; /** * @author fireshoes */ -public final class UninvitedGeist extends CardImpl { +public final class UninvitedGeist extends TransformingDoubleFacedCard { public UninvitedGeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{2}{U}", + "Unimpeded Trespasser", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U"); - this.secondSideCardClazz = mage.cards.u.UnimpededTrespasser.class; + this.getLeftHalfCard().setPT(2, 2); + this.getRightHalfCard().setPT(3, 3); // Skulk (This creature can't be blocked by creatures with greater power.) - this.addAbility(new SkulkAbility()); + this.getLeftHalfCard().addAbility(new SkulkAbility()); // When Uninvited Geist deals combat damage to a player, transform it. - this.addAbility(new TransformAbility()); - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new TransformSourceEffect(), false)); + this.getLeftHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new TransformSourceEffect(), false)); + // Unimpeded Trespasser + + // Unimpeded Trespasser can't be blocked. + this.getRightHalfCard().addAbility(new CantBeBlockedSourceAbility()); } private UninvitedGeist(final UninvitedGeist card) { diff --git a/Mage.Sets/src/mage/cards/u/UnluckyCabbageMerchant.java b/Mage.Sets/src/mage/cards/u/UnluckyCabbageMerchant.java new file mode 100644 index 00000000000..37d0e1f4564 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnluckyCabbageMerchant.java @@ -0,0 +1,92 @@ +package mage.cards.u; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.FoodToken; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnluckyCabbageMerchant extends CardImpl { + + public UnluckyCabbageMerchant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When this creature enters, create a Food token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken()))); + + // Whenever you sacrifice a Food, you may search your library for a basic land card and put it onto the battlefield tapped. If you search your library this way, put this creature on the bottom of its owner's library, then shuffle. + this.addAbility(new SacrificePermanentTriggeredAbility( + new UnluckyCabbageMerchantEffect(), StaticFilters.FILTER_CONTROLLED_FOOD + )); + } + + private UnluckyCabbageMerchant(final UnluckyCabbageMerchant card) { + super(card); + } + + @Override + public UnluckyCabbageMerchant copy() { + return new UnluckyCabbageMerchant(this); + } +} + +class UnluckyCabbageMerchantEffect extends OneShotEffect { + + UnluckyCabbageMerchantEffect() { + super(Outcome.Benefit); + staticText = "you may search your library for a basic land card and put it onto the battlefield tapped. " + + "If you search your library this way, put this creature on the bottom of its owner's library, then shuffle"; + } + + private UnluckyCabbageMerchantEffect(final UnluckyCabbageMerchantEffect effect) { + super(effect); + } + + @Override + public UnluckyCabbageMerchantEffect copy() { + return new UnluckyCabbageMerchantEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || !player.chooseUse( + Outcome.PutLandInPlay, "Search your library for a basic land?", source, game + )) { + return false; + } + TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); + if (!player.searchLibrary(target, source, game)) { + return false; + } + player.moveCards( + player.getLibrary().getCard(target.getFirstTarget(), game), Zone.BATTLEFIELD, + source, game, true, false, false, null + ); + player.putCardsOnBottomOfLibrary(source.getSourcePermanentIfItStillExists(game), game, source); + player.shuffleLibrary(source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/u/UrbanRetreat.java b/Mage.Sets/src/mage/cards/u/UrbanRetreat.java index f47fcec2a02..d24fb23966c 100644 --- a/Mage.Sets/src/mage/cards/u/UrbanRetreat.java +++ b/Mage.Sets/src/mage/cards/u/UrbanRetreat.java @@ -48,7 +48,7 @@ public final class UrbanRetreat extends CardImpl { // {2}, Return a tapped creature you control to its owner's hand: Put this card from your hand onto the battlefield. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(Zone.HAND, new UrbanRetreatEffect(), new GenericManaCost(2)); - ability.addCost(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent())); + ability.addCost(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/u/UrborgStalker.java b/Mage.Sets/src/mage/cards/u/UrborgStalker.java index e8550aaf34a..d96e751b782 100644 --- a/Mage.Sets/src/mage/cards/u/UrborgStalker.java +++ b/Mage.Sets/src/mage/cards/u/UrborgStalker.java @@ -41,7 +41,7 @@ public final class UrborgStalker extends CardImpl { // At the beginning of each player's upkeep, if that player controls a nonblack, nonland permanent, Urborg Stalker deals 1 damage to that player. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.EACH_PLAYER, new DamageTargetEffect(1, true, "that player"), false + TargetController.EACH_PLAYER, new DamageTargetEffect(1).withTargetDescription("that player"), false ).withInterveningIf(condition)); } diff --git a/Mage.Sets/src/mage/cards/u/UrzasRage.java b/Mage.Sets/src/mage/cards/u/UrzasRage.java index cd87a10bf6e..acb769b082b 100644 --- a/Mage.Sets/src/mage/cards/u/UrzasRage.java +++ b/Mage.Sets/src/mage/cards/u/UrzasRage.java @@ -28,7 +28,7 @@ public final class UrzasRage extends CardImpl { // Urza's Rage deals 3 damage to any target. If Urza's Rage was kicked, instead it deals 10 damage to that creature or player and the damage can't be prevented. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(10, false), new DamageTargetEffect(3), + new DamageTargetEffect(10).withCantBePrevented(), new DamageTargetEffect(3), KickedCondition.ONCE, "{this} deals 3 damage to any target. If this spell was kicked, " + "instead it deals 10 damage to that permanent or player and the damage can't be prevented." )); diff --git a/Mage.Sets/src/mage/cards/v/VengefulTracker.java b/Mage.Sets/src/mage/cards/v/VengefulTracker.java index 7bf08122781..2a0e65cb2dc 100644 --- a/Mage.Sets/src/mage/cards/v/VengefulTracker.java +++ b/Mage.Sets/src/mage/cards/v/VengefulTracker.java @@ -25,7 +25,7 @@ public final class VengefulTracker extends CardImpl { // Whenever an opponent sacrifices an artifact, Vengeful Tracker deals 2 damage to them. this.addAbility(new SacrificePermanentTriggeredAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "them"), + Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("them"), StaticFilters.FILTER_PERMANENT_ARTIFACT, TargetController.OPPONENT, SetTargetPointer.PLAYER, false )); } diff --git a/Mage.Sets/src/mage/cards/v/VengefulVillagers.java b/Mage.Sets/src/mage/cards/v/VengefulVillagers.java index 287c86f2764..88bd7151378 100644 --- a/Mage.Sets/src/mage/cards/v/VengefulVillagers.java +++ b/Mage.Sets/src/mage/cards/v/VengefulVillagers.java @@ -36,7 +36,7 @@ public final class VengefulVillagers extends CardImpl { new AddCountersTargetEffect(CounterType.STUN.createInstance()) .setText("put a stun counter on the chosen creature"), new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE) - )); + ).concatBy(", then")); ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java b/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java deleted file mode 100644 index 99a77ff529a..00000000000 --- a/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java +++ /dev/null @@ -1,53 +0,0 @@ -package mage.cards.v; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class VisionOfTheUnspeakable extends CardImpl { - - public VisionOfTheUnspeakable(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Vision of the Unspeakable gets +1/+1 for each card in your hand. - this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( - CardsInControllerHandCount.ANY_SINGULAR, - CardsInControllerHandCount.ANY_SINGULAR, - Duration.WhileOnBattlefield - ))); - } - - private VisionOfTheUnspeakable(final VisionOfTheUnspeakable card) { - super(card); - } - - @Override - public VisionOfTheUnspeakable copy() { - return new VisionOfTheUnspeakable(this); - } -} diff --git a/Mage.Sets/src/mage/cards/v/VivisPersistence.java b/Mage.Sets/src/mage/cards/v/VivisPersistence.java index 683cda73419..6eb766d062c 100644 --- a/Mage.Sets/src/mage/cards/v/VivisPersistence.java +++ b/Mage.Sets/src/mage/cards/v/VivisPersistence.java @@ -21,7 +21,7 @@ import java.util.UUID; */ public final class VivisPersistence extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("you commander"); + private static final FilterPermanent filter = new FilterPermanent("your commander"); static { filter.add(TargetController.YOU.getOwnerPredicate()); diff --git a/Mage.Sets/src/mage/cards/w/Waildrifter.java b/Mage.Sets/src/mage/cards/w/Waildrifter.java deleted file mode 100644 index 321a1d31d12..00000000000 --- a/Mage.Sets/src/mage/cards/w/Waildrifter.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class Waildrifter extends CardImpl { - - public Waildrifter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HIPPOGRIFF); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // If Waildrifter would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private Waildrifter(final Waildrifter card) { - super(card); - } - - @Override - public Waildrifter copy() { - return new Waildrifter(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WalkInClosetForgottenCellar.java b/Mage.Sets/src/mage/cards/w/WalkInClosetForgottenCellar.java index 1c78a4c29da..5cebbbdc39c 100644 --- a/Mage.Sets/src/mage/cards/w/WalkInClosetForgottenCellar.java +++ b/Mage.Sets/src/mage/cards/w/WalkInClosetForgottenCellar.java @@ -25,6 +25,7 @@ public final class WalkInClosetForgottenCellar extends RoomCard { // Walk-In Closet: You may play lands from your graveyard. SimpleStaticAbility left = new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playLands()); + this.getLeftHalfCard().addAbility(left); // Forgotten Cellar: When you unlock this door, you may cast spells from your graveyard this turn, and if a card would be put into your graveyard from anywhere this turn, exile it instead. UnlockThisDoorTriggeredAbility right = new UnlockThisDoorTriggeredAbility( @@ -34,8 +35,7 @@ public final class WalkInClosetForgottenCellar extends RoomCard { right.addEffect(new GraveyardFromAnywhereExileReplacementEffect(Duration.EndOfTurn).concatBy(", and") .setText("if a card would be put into your graveyard from anywhere this turn, exile it instead") ); - - this.addRoomAbilities(left, right); + this.getRightHalfCard().addAbility(right); } private WalkInClosetForgottenCellar(final WalkInClosetForgottenCellar card) { diff --git a/Mage.Sets/src/mage/cards/w/WanShiTongAllKnowing.java b/Mage.Sets/src/mage/cards/w/WanShiTongAllKnowing.java new file mode 100644 index 00000000000..b815237b611 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WanShiTongAllKnowing.java @@ -0,0 +1,54 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.PutIntoLibraryOneOrMoreTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.game.permanent.token.SpiritWorldToken; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WanShiTongAllKnowing extends CardImpl { + + public WanShiTongAllKnowing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Wan Shi Tong enters, target nonland permanent's owner puts it into their library second from the top or on the bottom. + Ability ability = new EntersBattlefieldTriggeredAbility(new PutOnTopOrBottomLibraryTargetEffect(2, false)); + ability.addTarget(new TargetNonlandPermanent()); + this.addAbility(ability); + + // Whenever one or more cards are put into a library from anywhere, create two 1/1 colorless Spirit creature tokens with "This token can't block or be blocked by non-Spirit creatures." + this.addAbility(new PutIntoLibraryOneOrMoreTriggeredAbility(new CreateTokenEffect(new SpiritWorldToken(), 2))); + } + + private WanShiTongAllKnowing(final WanShiTongAllKnowing card) { + super(card); + } + + @Override + public WanShiTongAllKnowing copy() { + return new WanShiTongAllKnowing(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WanShiTongLibrarian.java b/Mage.Sets/src/mage/cards/w/WanShiTongLibrarian.java new file mode 100644 index 00000000000..00eee523b53 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WanShiTongLibrarian.java @@ -0,0 +1,100 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.dynamicvalue.common.HalfValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WanShiTongLibrarian extends CardImpl { + + private static final DynamicValue xValue = new HalfValue(GetXValue.instance, false); + + public WanShiTongLibrarian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{U}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Wan Shi Tong enters, put X +1/+1 counters on him. Then draw half X cards, rounded down. + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(), GetXValue.instance) + .setText("put X +1/+1 counters on him") + ); + ability.addEffect(new DrawCardSourceControllerEffect(xValue).setText("Then draw half X cards, rounded down")); + this.addAbility(ability); + + // Whenever an opponent searches their library, put a +1/+1 counter on Wan Shi Tong and draw a card. + this.addAbility(new WanShiTongLibrarianTriggeredAbility()); + } + + private WanShiTongLibrarian(final WanShiTongLibrarian card) { + super(card); + } + + @Override + public WanShiTongLibrarian copy() { + return new WanShiTongLibrarian(this); + } +} + +class WanShiTongLibrarianTriggeredAbility extends TriggeredAbilityImpl { + + WanShiTongLibrarianTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + this.setTriggerPhrase("Whenever an opponent searches their library, "); + this.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + } + + private WanShiTongLibrarianTriggeredAbility(final WanShiTongLibrarianTriggeredAbility ability) { + super(ability); + } + + @Override + public WanShiTongLibrarianTriggeredAbility copy() { + return new WanShiTongLibrarianTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LIBRARY_SEARCHED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.getOpponents(getControllerId()).contains(event.getPlayerId()); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WarriorsResolve.java b/Mage.Sets/src/mage/cards/w/WarriorsResolve.java index 0c384a11e75..eef11172417 100644 --- a/Mage.Sets/src/mage/cards/w/WarriorsResolve.java +++ b/Mage.Sets/src/mage/cards/w/WarriorsResolve.java @@ -40,7 +40,7 @@ public final class WarriorsResolve extends CardImpl { // Creatures you control have training. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - new TrainingAbility(), Duration.WhileControlled, StaticFilters.FILTER_PERMANENT_CREATURES + new TrainingAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES ))); // At the beginning of your end step, if you control a creature with a +1/+1 counter on it that attacked this turn, draw a card. diff --git a/Mage.Sets/src/mage/cards/w/WartimeProtestors.java b/Mage.Sets/src/mage/cards/w/WartimeProtestors.java new file mode 100644 index 00000000000..4391d058b55 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WartimeProtestors.java @@ -0,0 +1,57 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WartimeProtestors extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ALLY, "another Ally you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + public WartimeProtestors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever another Ally you control enters, put a +1/+1 counter on that creature and it gains haste until end of turn. + Ability ability = new EntersBattlefieldAllTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), filter); + ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance()).setText("and it gains haste until end of turn")); + this.addAbility(ability); + } + + private WartimeProtestors(final WartimeProtestors card) { + super(card); + } + + @Override + public WartimeProtestors copy() { + return new WartimeProtestors(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WaterbendersRestoration.java b/Mage.Sets/src/mage/cards/w/WaterbendersRestoration.java new file mode 100644 index 00000000000..a2f1cf39bed --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WaterbendersRestoration.java @@ -0,0 +1,42 @@ +package mage.cards.w; + +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetadjustment.XTargetsCountAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WaterbendersRestoration extends CardImpl { + + public WaterbendersRestoration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{U}"); + + this.subtype.add(SubType.LESSON); + + // As an additional cost to cast this spell, waterbend {X}. + this.getSpellAbility().addCost(new WaterbendCost("{X}")); + + // Exile X target creatures you control. Return those cards to the battlefield under their owner's control at the beginning of the next end step. + this.getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect() + .withTargetDescription("X target creatures you control")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().setTargetAdjuster(new XTargetsCountAdjuster()); + } + + private WaterbendersRestoration(final WaterbendersRestoration card) { + super(card); + } + + @Override + public WaterbendersRestoration copy() { + return new WaterbendersRestoration(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WerewolfRansacker.java b/Mage.Sets/src/mage/cards/w/WerewolfRansacker.java deleted file mode 100644 index 4b63d6ea51f..00000000000 --- a/Mage.Sets/src/mage/cards/w/WerewolfRansacker.java +++ /dev/null @@ -1,90 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Controllable; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.common.TargetArtifactPermanent; - -import java.util.Optional; -import java.util.UUID; - -/** - * @author BetaSteward - */ -public final class WerewolfRansacker extends CardImpl { - - public WerewolfRansacker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(5); - this.toughness = new MageInt(4); - - // Whenever this creature transforms into Werewolf Ransacker, you may destroy target artifact. If that artifact is put into a graveyard this way, Werewolf Ransacker deals 3 damage to that artifact's controller. - Ability ability = new TransformIntoSourceTriggeredAbility(new WerewolfRansackerEffect(), true, true); - ability.addTarget(new TargetArtifactPermanent()); - this.addAbility(ability); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Werewolf Ransacker. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private WerewolfRansacker(final WerewolfRansacker card) { - super(card); - } - - @Override - public WerewolfRansacker copy() { - return new WerewolfRansacker(this); - } -} - -class WerewolfRansackerEffect extends OneShotEffect { - - WerewolfRansackerEffect() { - super(Outcome.DestroyPermanent); - staticText = "destroy target artifact. If that artifact is put into a graveyard this way, " + - "{this} deals 3 damage to that artifact's controller"; - } - - private WerewolfRansackerEffect(final WerewolfRansackerEffect effect) { - super(effect); - } - - @Override - public WerewolfRansackerEffect copy() { - return new WerewolfRansackerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null) { - return false; - } - permanent.destroy(source, game); - if (game.getState().getZone(permanent.getId()) != Zone.GRAVEYARD) { - return true; - } - Optional.ofNullable(permanent) - .map(Controllable::getControllerId) - .map(game::getPlayer) - .ifPresent(player -> player.damage(3, source, game)); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/w/WhiteLotusHideout.java b/Mage.Sets/src/mage/cards/w/WhiteLotusHideout.java new file mode 100644 index 00000000000..abf10305edf --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WhiteLotusHideout.java @@ -0,0 +1,56 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.ConditionalAnyColorManaAbility; +import mage.abilities.mana.conditional.ConditionalSpellManaBuilder; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterSpell; +import mage.filter.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WhiteLotusHideout extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a Lesson or Shrine spell"); + + static { + filter.add(Predicates.or( + SubType.LESSON.getPredicate(), + SubType.SHRINE.getPredicate() + )); + } + + public WhiteLotusHideout(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add one mana of any color. Spend this mana only to cast a Lesson or Shrine spell. + this.addAbility(new ConditionalAnyColorManaAbility(1, new ConditionalSpellManaBuilder(filter))); + + // {1}, {T}: Add one mana of any color. + Ability ability = new AnyColorManaAbility(new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private WhiteLotusHideout(final WhiteLotusHideout card) { + super(card); + } + + @Override + public WhiteLotusHideout copy() { + return new WhiteLotusHideout(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WhiteLotusTile.java b/Mage.Sets/src/mage/cards/w/WhiteLotusTile.java index 54c99b2fb84..2ab64090343 100644 --- a/Mage.Sets/src/mage/cards/w/WhiteLotusTile.java +++ b/Mage.Sets/src/mage/cards/w/WhiteLotusTile.java @@ -1,9 +1,10 @@ package mage.cards.w; +import mage.Mana; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.dynamicvalue.common.GreatestSharedCreatureTypeCount; -import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.mana.DynamicManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -22,8 +23,10 @@ public final class WhiteLotusTile extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // {T}: Add X mana of any one color, where X is the greatest number of creatures you control that have a creature type in common. - this.addAbility(new AnyColorManaAbility( - new TapSourceCost(), GreatestSharedCreatureTypeCount.instance, false + this.addAbility(new DynamicManaAbility( + Mana.AnyMana(1), GreatestSharedCreatureTypeCount.instance, new TapSourceCost(), + "Add X mana of any one color, where X is the greatest number of " + + "creatures you control that have a creature type in common.", true ).addHint(GreatestSharedCreatureTypeCount.getHint())); } diff --git a/Mage.Sets/src/mage/cards/w/WingShredder.java b/Mage.Sets/src/mage/cards/w/WingShredder.java deleted file mode 100644 index daf016f1dd5..00000000000 --- a/Mage.Sets/src/mage/cards/w/WingShredder.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.keyword.ReachAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class WingShredder extends CardImpl { - - public WingShredder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - this.color.setGreen(true); - this.nightCard = true; - - // Reach - this.addAbility(ReachAbility.getInstance()); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private WingShredder(final WingShredder card) { - super(card); - } - - @Override - public WingShredder copy() { - return new WingShredder(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WithengarUnbound.java b/Mage.Sets/src/mage/cards/w/WithengarUnbound.java deleted file mode 100644 index 4b170ef2642..00000000000 --- a/Mage.Sets/src/mage/cards/w/WithengarUnbound.java +++ /dev/null @@ -1,81 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.IntimidateAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.Zone; -import mage.counters.CounterType; -import mage.game.Game; -import mage.game.events.GameEvent; - -import java.util.UUID; - -/** - * @author BetaSteward - */ -public final class WithengarUnbound extends CardImpl { - - public WithengarUnbound(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.DEMON); - this.color.setBlack(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(13); - this.toughness = new MageInt(13); - - this.addAbility(FlyingAbility.getInstance()); - this.addAbility(IntimidateAbility.getInstance()); - this.addAbility(TrampleAbility.getInstance()); - - // Whenever a player loses the game, put thirteen +1/+1 counters on Withengar Unbound. - this.addAbility(new WithengarUnboundTriggeredAbility()); - } - - private WithengarUnbound(final WithengarUnbound card) { - super(card); - } - - @Override - public WithengarUnbound copy() { - return new WithengarUnbound(this); - } -} - -class WithengarUnboundTriggeredAbility extends TriggeredAbilityImpl { - - WithengarUnboundTriggeredAbility() { - super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(13)), false); - setTriggerPhrase("Whenever a player loses the game, "); - } - - private WithengarUnboundTriggeredAbility(final WithengarUnboundTriggeredAbility ability) { - super(ability); - } - - @Override - public WithengarUnboundTriggeredAbility copy() { - return new WithengarUnboundTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.LOST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/w/WretchedBonemass.java b/Mage.Sets/src/mage/cards/w/WretchedBonemass.java deleted file mode 100644 index 7de729fd930..00000000000 --- a/Mage.Sets/src/mage/cards/w/WretchedBonemass.java +++ /dev/null @@ -1,175 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; -import mage.abilities.keyword.*; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.ExileZone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.util.CardUtil; - -import java.util.Set; -import java.util.UUID; - -/** - * - * @author jeffwadsworth - */ -public final class WretchedBonemass extends CardImpl { - - public WretchedBonemass(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, null); - this.nightCard = true; - this.color.setBlack(true); - - this.subtype.add(SubType.SKELETON); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - - // Wretched Bonemass’s power and toughness are each equal to the total power of the exiled cards used to craft it. - this.addAbility(new SimpleStaticAbility(new SetBasePowerToughnessSourceEffect(WretchedBonemassDynamicValue.instance).setText("{this}'s power and toughness are each equal to the total power of the exiled cards used to craft it."))); - - // Wretched Bonemass has flying as long as an exiled card used to craft it has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance. - this.addAbility(new SimpleStaticAbility(new WretchedBonemassGainAbilityEffect())); - - } - - private WretchedBonemass(final WretchedBonemass card) { - super(card); - } - - @Override - public WretchedBonemass copy() { - return new WretchedBonemass(this); - } -} - -enum WretchedBonemassDynamicValue implements DynamicValue { - instance; - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - int totalPower = 0; - Permanent permanent = sourceAbility.getSourcePermanentIfItStillExists(game); - if (permanent == null) { - return 0; - } - ExileZone exileZone = game - .getExile() - .getExileZone(CardUtil.getExileZoneId( - game, permanent.getId(), permanent.getZoneChangeCounter(game) - 2 - )); - if (exileZone == null) { - return 0; - } - for (Card card : exileZone.getCards(game)) { - totalPower += card.getPower().getValue(); - } - return totalPower; - } - - @Override - public WretchedBonemassDynamicValue copy() { - return this; - } - - @Override - public String getMessage() { - return "total power of the exiled cards used to craft it"; - } - - @Override - public String toString() { - return "0"; - } -} - -class WretchedBonemassGainAbilityEffect extends ContinuousEffectImpl { - - WretchedBonemassGainAbilityEffect() { - super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); - staticText = "{this} has flying as long as an exiled card used to craft it has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance."; - } - - private WretchedBonemassGainAbilityEffect(final WretchedBonemassGainAbilityEffect effect) { - super(effect); - } - - @Override - public WretchedBonemassGainAbilityEffect copy() { - return new WretchedBonemassGainAbilityEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent wretchedBonemass = source.getSourcePermanentIfItStillExists(game); - if (wretchedBonemass != null) { - ExileZone exileZone = game - .getExile() - .getExileZone(CardUtil.getExileZoneId( - game, wretchedBonemass.getId(), wretchedBonemass.getZoneChangeCounter(game) - 2 - )); - if (exileZone != null - && !exileZone.isEmpty()) { - Set cardsInExile = exileZone.getCards(game); - for (Card card : cardsInExile) { - for (Ability a : card.getAbilities()) { - if (a instanceof FlyingAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof FirstStrikeAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof DoubleStrikeAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof DeathtouchAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof HasteAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof HexproofAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof IndestructibleAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof LifelinkAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof MenaceAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof ProtectionAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof IndestructibleAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof ReachAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof TrampleAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof VigilanceAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - } - } - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/z/ZukoConflicted.java b/Mage.Sets/src/mage/cards/z/ZukoConflicted.java new file mode 100644 index 00000000000..9d528c62fdc --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZukoConflicted.java @@ -0,0 +1,104 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZukoConflicted extends CardImpl { + + public ZukoConflicted(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // At the beginning of your first main phase, choose one that hasn't been chosen and you lose 2 life -- + // * Draw a card. + Ability ability = new BeginningOfFirstMainTriggeredAbility(new DrawCardSourceControllerEffect(1).setText("draw")); + ability.addEffect(new LoseLifeSourceControllerEffect(2).setText(" a card")); + ability.getModes().setChooseText("choose one that hasn't been chosen and you lose 2 life —"); + ability.getModes().setLimitUsageByOnce(false); + + // * Put a +1/+1 counter on Zuko. + ability.addMode(new Mode(new AddCountersSourceEffect(CounterType.P1P1.createInstance()).setText("put a +1/+1 counter")) + .addEffect(new LoseLifeSourceControllerEffect(2).setText(" on {this}"))); + + // * Add {R}. + ability.addMode(new Mode(new BasicManaEffect(Mana.RedMana(1)).setText("add")) + .addEffect(new LoseLifeSourceControllerEffect(2).setText("{R}"))); + + // * Exile Zuko, then return him to the battlefield under an opponent's control. + ability.addMode(new Mode(new ZukoConflictedEffect()) + .addEffect(new LoseLifeSourceControllerEffect(2).setText(" control"))); + this.addAbility(ability); + } + + private ZukoConflicted(final ZukoConflicted card) { + super(card); + } + + @Override + public ZukoConflicted copy() { + return new ZukoConflicted(this); + } +} + +class ZukoConflictedEffect extends OneShotEffect { + + ZukoConflictedEffect() { + super(Outcome.Benefit); + staticText = "exile {this}, then return him to the battlefield under an opponent's"; + } + + private ZukoConflictedEffect(final ZukoConflictedEffect effect) { + super(effect); + } + + @Override + public ZukoConflictedEffect copy() { + return new ZukoConflictedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (player == null || permanent == null) { + return false; + } + Card card = permanent.getMainCard(); + player.moveCards(permanent, Zone.EXILED, source, game); + TargetPlayer target = new TargetOpponent(true); + player.choose(outcome, target, source, game); + Player opponent = game.getPlayer(target.getFirstTarget()); + if (opponent != null) { + opponent.moveCards(card, Zone.BATTLEFIELD, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java b/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java index 8e59ffff27a..1cc47ff9291 100644 --- a/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java +++ b/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java @@ -25,19 +25,12 @@ public final class AvatarTheLastAirbender extends ExpansionSet { this.rotationSet = true; this.hasBasicLands = true; - cards.add(new SetCardInfo("Aang and La, Ocean's Fury", 204, Rarity.RARE, mage.cards.a.AangAndLaOceansFury.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aang and La, Ocean's Fury", 298, Rarity.RARE, mage.cards.a.AangAndLaOceansFury.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aang and La, Ocean's Fury", 347, Rarity.RARE, mage.cards.a.AangAndLaOceansFury.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aang and La, Ocean's Fury", 359, Rarity.RARE, mage.cards.a.AangAndLaOceansFury.class, NON_FULL_USE_VARIOUS)); + this.enablePlayBooster(Integer.MAX_VALUE); + this.numBoosterDoubleFaced = -1; + cards.add(new SetCardInfo("Aang's Iceberg", 336, Rarity.RARE, mage.cards.a.AangsIceberg.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang's Iceberg", 5, Rarity.RARE, mage.cards.a.AangsIceberg.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang's Journey", 1, Rarity.COMMON, mage.cards.a.AangsJourney.class)); - cards.add(new SetCardInfo("Aang, Destined Savior", 203, Rarity.RARE, mage.cards.a.AangDestinedSavior.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aang, Destined Savior", 304, Rarity.RARE, mage.cards.a.AangDestinedSavior.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aang, Destined Savior", 346, Rarity.RARE, mage.cards.a.AangDestinedSavior.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aang, Master of Elements", 207, Rarity.MYTHIC, mage.cards.a.AangMasterOfElements.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aang, Master of Elements", 308, Rarity.MYTHIC, mage.cards.a.AangMasterOfElements.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aang, Master of Elements", 363, Rarity.MYTHIC, mage.cards.a.AangMasterOfElements.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang, Swift Savior", 204, Rarity.RARE, mage.cards.a.AangSwiftSavior.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang, Swift Savior", 298, Rarity.RARE, mage.cards.a.AangSwiftSavior.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang, Swift Savior", 347, Rarity.RARE, mage.cards.a.AangSwiftSavior.class, NON_FULL_USE_VARIOUS)); @@ -65,6 +58,8 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Avatar Aang", 207, Rarity.MYTHIC, mage.cards.a.AvatarAang.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avatar Aang", 308, Rarity.MYTHIC, mage.cards.a.AvatarAang.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avatar Aang", 363, Rarity.MYTHIC, mage.cards.a.AvatarAang.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Avatar Destiny", 165, Rarity.RARE, mage.cards.a.AvatarDestiny.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Avatar Destiny", 333, Rarity.RARE, mage.cards.a.AvatarDestiny.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avatar Enthusiasts", 11, Rarity.COMMON, mage.cards.a.AvatarEnthusiasts.class)); cards.add(new SetCardInfo("Avatar Kuruk", 355, Rarity.MYTHIC, mage.cards.a.AvatarKuruk.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avatar Kuruk", 61, Rarity.MYTHIC, mage.cards.a.AvatarKuruk.class, NON_FULL_USE_VARIOUS)); @@ -72,9 +67,13 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Avatar Kyoshi", 358, Rarity.MYTHIC, mage.cards.a.AvatarKyoshi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avatar Roku", 145, Rarity.MYTHIC, mage.cards.a.AvatarRoku.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avatar Roku", 357, Rarity.MYTHIC, mage.cards.a.AvatarRoku.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Avatar Yangchen", 27, Rarity.MYTHIC, mage.cards.a.AvatarYangchen.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Avatar Yangchen", 354, Rarity.MYTHIC, mage.cards.a.AvatarYangchen.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avatar's Wrath", 12, Rarity.RARE, mage.cards.a.AvatarsWrath.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avatar's Wrath", 365, Rarity.RARE, mage.cards.a.AvatarsWrath.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Azula Always Lies", 84, Rarity.COMMON, mage.cards.a.AzulaAlwaysLies.class)); + cards.add(new SetCardInfo("Azula, Cunning Usurper", 208, Rarity.RARE, mage.cards.a.AzulaCunningUsurper.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Azula, Cunning Usurper", 303, Rarity.RARE, mage.cards.a.AzulaCunningUsurper.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Azula, On the Hunt", 85, Rarity.UNCOMMON, mage.cards.a.AzulaOnTheHunt.class)); cards.add(new SetCardInfo("Ba Sing Se", 266, Rarity.RARE, mage.cards.b.BaSingSe.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ba Sing Se", 388, Rarity.RARE, mage.cards.b.BaSingSe.class, NON_FULL_USE_VARIOUS)); @@ -107,6 +106,8 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Combustion Technique", 301, Rarity.UNCOMMON, mage.cards.c.CombustionTechnique.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Compassionate Healer", 13, Rarity.COMMON, mage.cards.c.CompassionateHealer.class)); cards.add(new SetCardInfo("Corrupt Court Official", 92, Rarity.COMMON, mage.cards.c.CorruptCourtOfficial.class)); + cards.add(new SetCardInfo("Crashing Wave", 300, Rarity.UNCOMMON, mage.cards.c.CrashingWave.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crashing Wave", 47, Rarity.UNCOMMON, mage.cards.c.CrashingWave.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Crescent Island Temple", 129, Rarity.UNCOMMON, mage.cards.c.CrescentIslandTemple.class)); cards.add(new SetCardInfo("Cruel Administrator", 213, Rarity.UNCOMMON, mage.cards.c.CruelAdministrator.class)); cards.add(new SetCardInfo("Cunning Maneuver", 130, Rarity.COMMON, mage.cards.c.CunningManeuver.class)); @@ -179,6 +180,8 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Foggy Swamp Hunters", 101, Rarity.COMMON, mage.cards.f.FoggySwampHunters.class)); cards.add(new SetCardInfo("Foggy Swamp Spirit Keeper", 222, Rarity.UNCOMMON, mage.cards.f.FoggySwampSpiritKeeper.class)); cards.add(new SetCardInfo("Foggy Swamp Vinebender", 180, Rarity.COMMON, mage.cards.f.FoggySwampVinebender.class)); + cards.add(new SetCardInfo("Foggy Swamp Visions", 102, Rarity.RARE, mage.cards.f.FoggySwampVisions.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Foggy Swamp Visions", 339, Rarity.RARE, mage.cards.f.FoggySwampVisions.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forecasting Fortune Teller", 51, Rarity.COMMON, mage.cards.f.ForecastingFortuneTeller.class)); cards.add(new SetCardInfo("Forest", 286, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 291, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); @@ -194,10 +197,13 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Guru Pathik", 223, Rarity.UNCOMMON, mage.cards.g.GuruPathik.class)); cards.add(new SetCardInfo("Hakoda, Selfless Commander", 23, Rarity.RARE, mage.cards.h.HakodaSelflessCommander.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hakoda, Selfless Commander", 366, Rarity.RARE, mage.cards.h.HakodaSelflessCommander.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hama, the Bloodbender", 224, Rarity.UNCOMMON, mage.cards.h.HamaTheBloodbender.class)); cards.add(new SetCardInfo("Haru, Hidden Talent", 182, Rarity.UNCOMMON, mage.cards.h.HaruHiddenTalent.class)); cards.add(new SetCardInfo("Heartless Act", 103, Rarity.UNCOMMON, mage.cards.h.HeartlessAct.class)); cards.add(new SetCardInfo("Hei Bai, Spirit of Balance", 225, Rarity.UNCOMMON, mage.cards.h.HeiBaiSpiritOfBalance.class)); + cards.add(new SetCardInfo("Hermitic Herbalist", 226, Rarity.UNCOMMON, mage.cards.h.HermiticHerbalist.class)); cards.add(new SetCardInfo("Hog-Monkey", 104, Rarity.COMMON, mage.cards.h.HogMonkey.class)); + cards.add(new SetCardInfo("Honest Work", 55, Rarity.UNCOMMON, mage.cards.h.HonestWork.class)); cards.add(new SetCardInfo("How to Start a Riot", 140, Rarity.COMMON, mage.cards.h.HowToStartARiot.class)); cards.add(new SetCardInfo("Iguana Parrot", 56, Rarity.COMMON, mage.cards.i.IguanaParrot.class)); cards.add(new SetCardInfo("Invasion Reinforcements", 24, Rarity.UNCOMMON, mage.cards.i.InvasionReinforcements.class)); @@ -206,10 +212,14 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Iroh's Demonstration", 141, Rarity.UNCOMMON, mage.cards.i.IrohsDemonstration.class)); cards.add(new SetCardInfo("Iroh, Grand Lotus", 227, Rarity.RARE, mage.cards.i.IrohGrandLotus.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Iroh, Grand Lotus", 349, Rarity.RARE, mage.cards.i.IrohGrandLotus.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Iroh, Tea Master", 228, Rarity.RARE, mage.cards.i.IrohTeaMaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Iroh, Tea Master", 381, Rarity.RARE, mage.cards.i.IrohTeaMaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 283, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 288, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Island", 293, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("It'll Quench Ya!", 58, Rarity.COMMON, mage.cards.i.ItllQuenchYa.class)); + cards.add(new SetCardInfo("Jasmine Dragon Tea Shop", 270, Rarity.RARE, mage.cards.j.JasmineDragonTeaShop.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jasmine Dragon Tea Shop", 390, Rarity.RARE, mage.cards.j.JasmineDragonTeaShop.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jeong Jeong's Deserters", 25, Rarity.COMMON, mage.cards.j.JeongJeongsDeserters.class)); cards.add(new SetCardInfo("Jeong Jeong, the Deserter", 142, Rarity.UNCOMMON, mage.cards.j.JeongJeongTheDeserter.class)); cards.add(new SetCardInfo("Jet's Brainwashing", 143, Rarity.UNCOMMON, mage.cards.j.JetsBrainwashing.class)); @@ -224,6 +234,8 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Katara, the Fearless", 350, Rarity.RARE, mage.cards.k.KataraTheFearless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Katara, the Fearless", 361, Rarity.RARE, mage.cards.k.KataraTheFearless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Knowledge Seeker", 60, Rarity.UNCOMMON, mage.cards.k.KnowledgeSeeker.class)); + cards.add(new SetCardInfo("Koh, the Face Stealer", 107, Rarity.MYTHIC, mage.cards.k.KohTheFaceStealer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Koh, the Face Stealer", 322, Rarity.MYTHIC, mage.cards.k.KohTheFaceStealer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kyoshi Battle Fan", 257, Rarity.COMMON, mage.cards.k.KyoshiBattleFan.class)); cards.add(new SetCardInfo("Kyoshi Island Plaza", 184, Rarity.UNCOMMON, mage.cards.k.KyoshiIslandPlaza.class)); cards.add(new SetCardInfo("Kyoshi Village", 271, Rarity.COMMON, mage.cards.k.KyoshiVillage.class)); @@ -254,6 +266,8 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("North Pole Gates", 274, Rarity.COMMON, mage.cards.n.NorthPoleGates.class)); cards.add(new SetCardInfo("North Pole Patrol", 65, Rarity.UNCOMMON, mage.cards.n.NorthPolePatrol.class)); cards.add(new SetCardInfo("Northern Air Temple", 111, Rarity.UNCOMMON, mage.cards.n.NorthernAirTemple.class)); + cards.add(new SetCardInfo("Obsessive Pursuit", 112, Rarity.RARE, mage.cards.o.ObsessivePursuit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obsessive Pursuit", 340, Rarity.RARE, mage.cards.o.ObsessivePursuit.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Octopus Form", 66, Rarity.COMMON, mage.cards.o.OctopusForm.class)); cards.add(new SetCardInfo("Omashu City", 275, Rarity.COMMON, mage.cards.o.OmashuCity.class)); cards.add(new SetCardInfo("Origin of Metalbending", 187, Rarity.COMMON, mage.cards.o.OriginOfMetalbending.class)); @@ -293,8 +307,11 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Rocky Rebuke", 193, Rarity.COMMON, mage.cards.r.RockyRebuke.class)); cards.add(new SetCardInfo("Rough Rhino Cavalry", 152, Rarity.COMMON, mage.cards.r.RoughRhinoCavalry.class)); cards.add(new SetCardInfo("Rowdy Snowballers", 68, Rarity.COMMON, mage.cards.r.RowdySnowballers.class)); + cards.add(new SetCardInfo("Ruinous Waterbending", 118, Rarity.UNCOMMON, mage.cards.r.RuinousWaterbending.class)); cards.add(new SetCardInfo("Rumble Arena", 277, Rarity.COMMON, mage.cards.r.RumbleArena.class)); cards.add(new SetCardInfo("Saber-Tooth Moose-Lion", 194, Rarity.COMMON, mage.cards.s.SaberToothMooseLion.class)); + cards.add(new SetCardInfo("Sandbender Scavengers", 239, Rarity.RARE, mage.cards.s.SandbenderScavengers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sandbender Scavengers", 382, Rarity.RARE, mage.cards.s.SandbenderScavengers.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sandbenders' Storm", 34, Rarity.COMMON, mage.cards.s.SandbendersStorm.class)); cards.add(new SetCardInfo("Secret Tunnel", 278, Rarity.RARE, mage.cards.s.SecretTunnel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Secret Tunnel", 392, Rarity.RARE, mage.cards.s.SecretTunnel.class, NON_FULL_USE_VARIOUS)); @@ -317,6 +334,8 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Sozin's Comet", 309, Rarity.MYTHIC, mage.cards.s.SozinsComet.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sozin's Comet", 332, Rarity.MYTHIC, mage.cards.s.SozinsComet.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sparring Dummy", 197, Rarity.UNCOMMON, mage.cards.s.SparringDummy.class)); + cards.add(new SetCardInfo("Spirit Water Revival", 370, Rarity.RARE, mage.cards.s.SpiritWaterRevival.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spirit Water Revival", 73, Rarity.RARE, mage.cards.s.SpiritWaterRevival.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Suki, Courageous Rescuer", 368, Rarity.RARE, mage.cards.s.SukiCourageousRescuer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Suki, Courageous Rescuer", 37, Rarity.RARE, mage.cards.s.SukiCourageousRescuer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Suki, Kyoshi Warrior", 243, Rarity.UNCOMMON, mage.cards.s.SukiKyoshiWarrior.class)); @@ -326,15 +345,24 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Swamp", 289, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Swamp", 294, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Swampsnare Trap", 120, Rarity.COMMON, mage.cards.s.SwampsnareTrap.class)); + cards.add(new SetCardInfo("Team Avatar", 38, Rarity.UNCOMMON, mage.cards.t.TeamAvatar.class)); cards.add(new SetCardInfo("Teo, Spirited Glider", 74, Rarity.UNCOMMON, mage.cards.t.TeoSpiritedGlider.class)); cards.add(new SetCardInfo("The Boulder, Ready to Rumble", 168, Rarity.UNCOMMON, mage.cards.t.TheBoulderReadyToRumble.class)); cards.add(new SetCardInfo("The Cave of Two Lovers", 126, Rarity.UNCOMMON, mage.cards.t.TheCaveOfTwoLovers.class)); + cards.add(new SetCardInfo("The Earth King", 172, Rarity.RARE, mage.cards.t.TheEarthKing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Earth King", 344, Rarity.RARE, mage.cards.t.TheEarthKing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Fire Nation Drill", 321, Rarity.RARE, mage.cards.t.TheFireNationDrill.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Fire Nation Drill", 98, Rarity.RARE, mage.cards.t.TheFireNationDrill.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Last Agni Kai", 144, Rarity.RARE, mage.cards.t.TheLastAgniKai.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Last Agni Kai", 314, Rarity.RARE, mage.cards.t.TheLastAgniKai.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Legend of Kuruk", 355, Rarity.MYTHIC, mage.cards.t.TheLegendOfKuruk.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Legend of Kuruk", 61, Rarity.MYTHIC, mage.cards.t.TheLegendOfKuruk.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Legend of Kyoshi", 186, Rarity.MYTHIC, mage.cards.t.TheLegendOfKyoshi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Legend of Kyoshi", 358, Rarity.MYTHIC, mage.cards.t.TheLegendOfKyoshi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Legend of Roku", 145, Rarity.MYTHIC, mage.cards.t.TheLegendOfRoku.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Legend of Roku", 357, Rarity.MYTHIC, mage.cards.t.TheLegendOfRoku.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Legend of Yangchen", 27, Rarity.MYTHIC, mage.cards.t.TheLegendOfYangchen.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Legend of Yangchen", 354, Rarity.MYTHIC, mage.cards.t.TheLegendOfYangchen.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Lion-Turtle", 232, Rarity.RARE, mage.cards.t.TheLionTurtle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Lion-Turtle", 328, Rarity.RARE, mage.cards.t.TheLionTurtle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Mechanist, Aerial Artisan", 369, Rarity.RARE, mage.cards.t.TheMechanistAerialArtisan.class, NON_FULL_USE_VARIOUS)); @@ -350,24 +378,34 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Tiger-Seal", 318, Rarity.RARE, mage.cards.t.TigerSeal.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tiger-Seal", 75, Rarity.RARE, mage.cards.t.TigerSeal.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tolls of War", 245, Rarity.UNCOMMON, mage.cards.t.TollsOfWar.class)); + cards.add(new SetCardInfo("Toph, Hardheaded Teacher", 246, Rarity.RARE, mage.cards.t.TophHardheadedTeacher.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Toph, Hardheaded Teacher", 384, Rarity.RARE, mage.cards.t.TophHardheadedTeacher.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Toph, the Blind Bandit", 198, Rarity.UNCOMMON, mage.cards.t.TophTheBlindBandit.class)); cards.add(new SetCardInfo("Toph, the First Metalbender", 247, Rarity.RARE, mage.cards.t.TophTheFirstMetalbender.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Toph, the First Metalbender", 353, Rarity.RARE, mage.cards.t.TophTheFirstMetalbender.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Toph, the First Metalbender", 362, Rarity.RARE, mage.cards.t.TophTheFirstMetalbender.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Treetop Freedom Fighters", 156, Rarity.COMMON, mage.cards.t.TreetopFreedomFighters.class)); cards.add(new SetCardInfo("True Ancestry", 199, Rarity.UNCOMMON, mage.cards.t.TrueAncestry.class)); + cards.add(new SetCardInfo("Trusty Boomerang", 260, Rarity.UNCOMMON, mage.cards.t.TrustyBoomerang.class)); cards.add(new SetCardInfo("Tundra Tank", 121, Rarity.UNCOMMON, mage.cards.t.TundraTank.class)); cards.add(new SetCardInfo("Turtle-Duck", 200, Rarity.COMMON, mage.cards.t.TurtleDuck.class)); cards.add(new SetCardInfo("Twin Blades", 157, Rarity.UNCOMMON, mage.cards.t.TwinBlades.class)); cards.add(new SetCardInfo("Ty Lee, Artful Acrobat", 158, Rarity.UNCOMMON, mage.cards.t.TyLeeArtfulAcrobat.class)); + cards.add(new SetCardInfo("Ty Lee, Chi Blocker", 371, Rarity.RARE, mage.cards.t.TyLeeChiBlocker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ty Lee, Chi Blocker", 76, Rarity.RARE, mage.cards.t.TyLeeChiBlocker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Uncle Iroh", 248, Rarity.UNCOMMON, mage.cards.u.UncleIroh.class)); cards.add(new SetCardInfo("United Front", 331, Rarity.MYTHIC, mage.cards.u.UnitedFront.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("United Front", 39, Rarity.MYTHIC, mage.cards.u.UnitedFront.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unlucky Cabbage Merchant", 201, Rarity.UNCOMMON, mage.cards.u.UnluckyCabbageMerchant.class)); cards.add(new SetCardInfo("Vengeful Villagers", 40, Rarity.UNCOMMON, mage.cards.v.VengefulVillagers.class)); cards.add(new SetCardInfo("Vindictive Warden", 249, Rarity.COMMON, mage.cards.v.VindictiveWarden.class)); cards.add(new SetCardInfo("Walltop Sentries", 202, Rarity.COMMON, mage.cards.w.WalltopSentries.class)); + cards.add(new SetCardInfo("Wan Shi Tong, Librarian", 320, Rarity.MYTHIC, mage.cards.w.WanShiTongLibrarian.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wan Shi Tong, Librarian", 78, Rarity.MYTHIC, mage.cards.w.WanShiTongLibrarian.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wandering Musicians", 250, Rarity.COMMON, mage.cards.w.WanderingMusicians.class)); cards.add(new SetCardInfo("War Balloon", 159, Rarity.UNCOMMON, mage.cards.w.WarBalloon.class)); + cards.add(new SetCardInfo("Wartime Protestors", 160, Rarity.RARE, mage.cards.w.WartimeProtestors.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wartime Protestors", 375, Rarity.RARE, mage.cards.w.WartimeProtestors.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Water Tribe Captain", 41, Rarity.COMMON, mage.cards.w.WaterTribeCaptain.class)); cards.add(new SetCardInfo("Water Tribe Rallier", 42, Rarity.UNCOMMON, mage.cards.w.WaterTribeRallier.class)); cards.add(new SetCardInfo("Waterbender Ascension", 310, Rarity.RARE, mage.cards.w.WaterbenderAscension.class, NON_FULL_USE_VARIOUS)); @@ -375,6 +413,7 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Waterbending Lesson", 80, Rarity.COMMON, mage.cards.w.WaterbendingLesson.class)); cards.add(new SetCardInfo("Waterbending Scroll", 81, Rarity.UNCOMMON, mage.cards.w.WaterbendingScroll.class)); cards.add(new SetCardInfo("Watery Grasp", 82, Rarity.COMMON, mage.cards.w.WateryGrasp.class)); + cards.add(new SetCardInfo("White Lotus Hideout", 281, Rarity.UNCOMMON, mage.cards.w.WhiteLotusHideout.class)); cards.add(new SetCardInfo("White Lotus Reinforcements", 251, Rarity.UNCOMMON, mage.cards.w.WhiteLotusReinforcements.class)); cards.add(new SetCardInfo("White Lotus Tile", 262, Rarity.MYTHIC, mage.cards.w.WhiteLotusTile.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("White Lotus Tile", 330, Rarity.MYTHIC, mage.cards.w.WhiteLotusTile.class, NON_FULL_USE_VARIOUS)); @@ -388,6 +427,8 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Zhao, the Moon Slayer", 376, Rarity.RARE, mage.cards.z.ZhaoTheMoonSlayer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zuko's Conviction", 123, Rarity.UNCOMMON, mage.cards.z.ZukosConviction.class)); cards.add(new SetCardInfo("Zuko's Exile", 3, Rarity.COMMON, mage.cards.z.ZukosExile.class)); + cards.add(new SetCardInfo("Zuko, Conflicted", 253, Rarity.RARE, mage.cards.z.ZukoConflicted.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Zuko, Conflicted", 302, Rarity.RARE, mage.cards.z.ZukoConflicted.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zuko, Exiled Prince", 163, Rarity.UNCOMMON, mage.cards.z.ZukoExiledPrince.class)); cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); diff --git a/Mage.Sets/src/mage/sets/AvatarTheLastAirbenderEternal.java b/Mage.Sets/src/mage/sets/AvatarTheLastAirbenderEternal.java index b5788a8cf8e..e5f25cf5dd7 100644 --- a/Mage.Sets/src/mage/sets/AvatarTheLastAirbenderEternal.java +++ b/Mage.Sets/src/mage/sets/AvatarTheLastAirbenderEternal.java @@ -93,6 +93,8 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Deflecting Swat", 311, Rarity.RARE, mage.cards.d.DeflectingSwat.class)); cards.add(new SetCardInfo("Deny Entry", 222, Rarity.COMMON, mage.cards.d.DenyEntry.class)); cards.add(new SetCardInfo("Descendants' Path", 167, Rarity.RARE, mage.cards.d.DescendantsPath.class)); + cards.add(new SetCardInfo("Desperate Plea", 103, Rarity.RARE, mage.cards.d.DesperatePlea.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Desperate Plea", 185, Rarity.RARE, mage.cards.d.DesperatePlea.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Diaochan, Artful Beauty", 27, Rarity.MYTHIC, mage.cards.d.DiaochanArtfulBeauty.class)); cards.add(new SetCardInfo("Diresight", 162, Rarity.COMMON, mage.cards.d.Diresight.class)); cards.add(new SetCardInfo("Dockside Extortionist", 28, Rarity.MYTHIC, mage.cards.d.DocksideExtortionist.class)); @@ -101,6 +103,7 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Dramatic Reversal", 158, Rarity.COMMON, mage.cards.d.DramaticReversal.class)); cards.add(new SetCardInfo("Drannith Magistrate", 2, Rarity.MYTHIC, mage.cards.d.DrannithMagistrate.class)); cards.add(new SetCardInfo("Duelist's Heritage", 153, Rarity.RARE, mage.cards.d.DuelistsHeritage.class)); + cards.add(new SetCardInfo("Dutiful Knowledge Seeker", 92, Rarity.UNCOMMON, mage.cards.d.DutifulKnowledgeSeeker.class)); cards.add(new SetCardInfo("Earthbending Student", 249, Rarity.UNCOMMON, mage.cards.e.EarthbendingStudent.class)); cards.add(new SetCardInfo("Earthshape", 67, Rarity.RARE, mage.cards.e.Earthshape.class)); cards.add(new SetCardInfo("Eel-Hounds", 250, Rarity.UNCOMMON, mage.cards.e.EelHounds.class)); @@ -115,15 +118,21 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Explosive Shot", 236, Rarity.COMMON, mage.cards.e.ExplosiveShot.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Explosive Shot", 279, Rarity.COMMON, mage.cards.e.ExplosiveShot.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fabled Passage", 57, Rarity.MYTHIC, mage.cards.f.FabledPassage.class)); + cards.add(new SetCardInfo("Fang, Roku's Companion", 115, Rarity.RARE, mage.cards.f.FangRokusCompanion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fang, Roku's Companion", 193, Rarity.RARE, mage.cards.f.FangRokusCompanion.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Feed the Swarm", 257, Rarity.COMMON, mage.cards.f.FeedTheSwarm.class)); cards.add(new SetCardInfo("Fervor", 29, Rarity.MYTHIC, mage.cards.f.Fervor.class)); cards.add(new SetCardInfo("Fevered Visions", 49, Rarity.MYTHIC, mage.cards.f.FeveredVisions.class)); cards.add(new SetCardInfo("Fierce Guardianship", 307, Rarity.RARE, mage.cards.f.FierceGuardianship.class)); cards.add(new SetCardInfo("Fiery Confluence", 165, Rarity.RARE, mage.cards.f.FieryConfluence.class)); + cards.add(new SetCardInfo("Fire Lord Ozai", 104, Rarity.MYTHIC, mage.cards.f.FireLordOzai.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Lord Ozai", 186, Rarity.MYTHIC, mage.cards.f.FireLordOzai.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fire Nation Ambushers", 229, Rarity.COMMON, mage.cards.f.FireNationAmbushers.class)); cards.add(new SetCardInfo("Fire Nation Archers", 237, Rarity.RARE, mage.cards.f.FireNationArchers.class)); cards.add(new SetCardInfo("Fire Nation Occupation", 105, Rarity.RARE, mage.cards.f.FireNationOccupation.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fire Nation Occupation", 187, Rarity.RARE, mage.cards.f.FireNationOccupation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Nation Salvagers", 106, Rarity.RARE, mage.cards.f.FireNationSalvagers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Nation Salvagers", 188, Rarity.RARE, mage.cards.f.FireNationSalvagers.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fire Nation Sentinels", 230, Rarity.RARE, mage.cards.f.FireNationSentinels.class)); cards.add(new SetCardInfo("Fire Nation Soldier", 238, Rarity.COMMON, mage.cards.f.FireNationSoldier.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fire Nation Soldier", 280, Rarity.COMMON, mage.cards.f.FireNationSoldier.class, NON_FULL_USE_VARIOUS)); @@ -143,8 +152,11 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Giant Fly", 107, Rarity.COMMON, mage.cards.g.GiantFly.class)); cards.add(new SetCardInfo("Gilacorn", 231, Rarity.COMMON, mage.cards.g.Gilacorn.class)); cards.add(new SetCardInfo("Heartbeat of Spring", 42, Rarity.MYTHIC, mage.cards.h.HeartbeatOfSpring.class)); + cards.add(new SetCardInfo("Hei Bai, Forest Guardian", 139, Rarity.MYTHIC, mage.cards.h.HeiBaiForestGuardian.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hei Bai, Forest Guardian", 205, Rarity.MYTHIC, mage.cards.h.HeiBaiForestGuardian.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Heroic Intervention", 43, Rarity.MYTHIC, mage.cards.h.HeroicIntervention.class)); cards.add(new SetCardInfo("Hippo-Cows", 252, Rarity.COMMON, mage.cards.h.HippoCows.class)); + cards.add(new SetCardInfo("Hog-Monkey Rampage", 255, Rarity.UNCOMMON, mage.cards.h.HogMonkeyRampage.class)); cards.add(new SetCardInfo("Hook Swords", 147, Rarity.UNCOMMON, mage.cards.h.HookSwords.class)); cards.add(new SetCardInfo("Humble Defector", 30, Rarity.MYTHIC, mage.cards.h.HumbleDefector.class)); cards.add(new SetCardInfo("Imprisoned in the Moon", 14, Rarity.MYTHIC, mage.cards.i.ImprisonedInTheMoon.class)); @@ -159,8 +171,10 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Jet, Rebel Leader", 172, Rarity.RARE, mage.cards.j.JetRebelLeader.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jet, Rebel Leader", 78, Rarity.RARE, mage.cards.j.JetRebelLeader.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Join the Dance", 50, Rarity.MYTHIC, mage.cards.j.JoinTheDance.class)); + cards.add(new SetCardInfo("Katara's Reversal", 63, Rarity.RARE, mage.cards.k.KatarasReversal.class)); cards.add(new SetCardInfo("Katara, Heroic Healer", 215, Rarity.UNCOMMON, mage.cards.k.KataraHeroicHealer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Katara, Heroic Healer", 269, Rarity.UNCOMMON, mage.cards.k.KataraHeroicHealer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Katara, Seeking Revenge", 148, Rarity.UNCOMMON, mage.cards.k.KataraSeekingRevenge.class)); cards.add(new SetCardInfo("Katara, Waterbending Master", 180, Rarity.MYTHIC, mage.cards.k.KataraWaterbendingMaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Katara, Waterbending Master", 93, Rarity.MYTHIC, mage.cards.k.KataraWaterbendingMaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kindly Customer", 79, Rarity.COMMON, mage.cards.k.KindlyCustomer.class)); @@ -189,6 +203,7 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Meteorite", 54, Rarity.MYTHIC, mage.cards.m.Meteorite.class)); cards.add(new SetCardInfo("Mirrorwing Dragon", 33, Rarity.MYTHIC, mage.cards.m.MirrorwingDragon.class)); cards.add(new SetCardInfo("Moku, Meandering Drummer", 122, Rarity.UNCOMMON, mage.cards.m.MokuMeanderingDrummer.class)); + cards.add(new SetCardInfo("Momo's Heist", 72, Rarity.RARE, mage.cards.m.MomosHeist.class)); cards.add(new SetCardInfo("Momo, Rambunctious Rascal", 217, Rarity.UNCOMMON, mage.cards.m.MomoRambunctiousRascal.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Momo, Rambunctious Rascal", 270, Rarity.UNCOMMON, mage.cards.m.MomoRambunctiousRascal.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Monk Gyatso", 173, Rarity.RARE, mage.cards.m.MonkGyatso.class, NON_FULL_USE_VARIOUS)); @@ -205,6 +220,8 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Mystical Tutor", 308, Rarity.RARE, mage.cards.m.MysticalTutor.class)); cards.add(new SetCardInfo("Nightmares and Daydreams", 94, Rarity.RARE, mage.cards.n.NightmaresAndDaydreams.class)); cards.add(new SetCardInfo("Noxious Gearhulk", 25, Rarity.MYTHIC, mage.cards.n.NoxiousGearhulk.class)); + cards.add(new SetCardInfo("Nyla, Shirshu Sleuth", 109, Rarity.RARE, mage.cards.n.NylaShirshuSleuth.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nyla, Shirshu Sleuth", 190, Rarity.RARE, mage.cards.n.NylaShirshuSleuth.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Obscuring Haze", 313, Rarity.RARE, mage.cards.o.ObscuringHaze.class)); cards.add(new SetCardInfo("Overwhelming Victory", 123, Rarity.RARE, mage.cards.o.OverwhelmingVictory.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Overwhelming Victory", 196, Rarity.RARE, mage.cards.o.OverwhelmingVictory.class, NON_FULL_USE_VARIOUS)); @@ -218,9 +235,12 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Plains", 302, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 303, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 304, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Princess Yue", 95, Rarity.UNCOMMON, mage.cards.p.PrincessYue.class)); cards.add(new SetCardInfo("Prosperity", 17, Rarity.MYTHIC, mage.cards.p.Prosperity.class)); cards.add(new SetCardInfo("Purple Pentapus", 233, Rarity.COMMON, mage.cards.p.PurplePentapus.class)); cards.add(new SetCardInfo("Razor Rings", 272, Rarity.COMMON, mage.cards.r.RazorRings.class)); + cards.add(new SetCardInfo("Reckless Blaze", 124, Rarity.RARE, mage.cards.r.RecklessBlaze.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reckless Blaze", 197, Rarity.RARE, mage.cards.r.RecklessBlaze.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Release to Memory", 5, Rarity.MYTHIC, mage.cards.r.ReleaseToMemory.class)); cards.add(new SetCardInfo("Rending Volley", 34, Rarity.MYTHIC, mage.cards.r.RendingVolley.class)); cards.add(new SetCardInfo("Return of the Wildspeaker", 44, Rarity.MYTHIC, mage.cards.r.ReturnOfTheWildspeaker.class)); @@ -240,25 +260,42 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Sledding Otter-Penguin", 273, Rarity.COMMON, mage.cards.s.SleddingOtterPenguin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Smellerbee, Rebel Fighter", 125, Rarity.RARE, mage.cards.s.SmellerbeeRebelFighter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Smellerbee, Rebel Fighter", 198, Rarity.RARE, mage.cards.s.SmellerbeeRebelFighter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sokka and Suki", 71, Rarity.RARE, mage.cards.s.SokkaAndSuki.class)); cards.add(new SetCardInfo("Sokka's Charge", 66, Rarity.RARE, mage.cards.s.SokkasCharge.class)); cards.add(new SetCardInfo("Sokka's Sword Training", 84, Rarity.COMMON, mage.cards.s.SokkasSwordTraining.class)); + cards.add(new SetCardInfo("Sokka, Swordmaster", 174, Rarity.MYTHIC, mage.cards.s.SokkaSwordmaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sokka, Swordmaster", 83, Rarity.MYTHIC, mage.cards.s.SokkaSwordmaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sokka, Wolf Cove's Protector", 219, Rarity.UNCOMMON, mage.cards.s.SokkaWolfCovesProtector.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sokka, Wolf Cove's Protector", 274, Rarity.UNCOMMON, mage.cards.s.SokkaWolfCovesProtector.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sol Ring", 316, Rarity.RARE, mage.cards.s.SolRing.class)); cards.add(new SetCardInfo("Solid Ground", 142, Rarity.UNCOMMON, mage.cards.s.SolidGround.class)); + cards.add(new SetCardInfo("Stand United", 149, Rarity.COMMON, mage.cards.s.StandUnited.class)); cards.add(new SetCardInfo("Standstill", 19, Rarity.MYTHIC, mage.cards.s.Standstill.class)); + cards.add(new SetCardInfo("Storm of Memories", 126, Rarity.RARE, mage.cards.s.StormOfMemories.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Storm of Memories", 199, Rarity.RARE, mage.cards.s.StormOfMemories.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Suki, Kyoshi Captain", 175, Rarity.RARE, mage.cards.s.SukiKyoshiCaptain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Suki, Kyoshi Captain", 85, Rarity.RARE, mage.cards.s.SukiKyoshiCaptain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sunbaked Canyon", 58, Rarity.MYTHIC, mage.cards.s.SunbakedCanyon.class)); cards.add(new SetCardInfo("Sundial of the Infinite", 55, Rarity.MYTHIC, mage.cards.s.SundialOfTheInfinite.class)); cards.add(new SetCardInfo("Suspicious Bookcase", 170, Rarity.UNCOMMON, mage.cards.s.SuspiciousBookcase.class)); + cards.add(new SetCardInfo("Swampbenders", 65, Rarity.RARE, mage.cards.s.Swampbenders.class)); cards.add(new SetCardInfo("Swiftfoot Boots", 317, Rarity.RARE, mage.cards.s.SwiftfootBoots.class)); + cards.add(new SetCardInfo("Tale of Katara and Toph", 143, Rarity.RARE, mage.cards.t.TaleOfKataraAndToph.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tale of Katara and Toph", 207, Rarity.RARE, mage.cards.t.TaleOfKataraAndToph.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tale of Momo", 176, Rarity.RARE, mage.cards.t.TaleOfMomo.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tale of Momo", 86, Rarity.RARE, mage.cards.t.TaleOfMomo.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tarnished Citadel", 59, Rarity.MYTHIC, mage.cards.t.TarnishedCitadel.class)); cards.add(new SetCardInfo("Taunting Challenge", 46, Rarity.MYTHIC, mage.cards.t.TauntingChallenge.class)); + cards.add(new SetCardInfo("Tectonic Split", 144, Rarity.RARE, mage.cards.t.TectonicSplit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tectonic Split", 208, Rarity.RARE, mage.cards.t.TectonicSplit.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Teferi's Protection", 7, Rarity.MYTHIC, mage.cards.t.TeferisProtection.class)); + cards.add(new SetCardInfo("That's Rough Buddy", 87, Rarity.UNCOMMON, mage.cards.t.ThatsRoughBuddy.class)); cards.add(new SetCardInfo("The Art of Tea", 129, Rarity.COMMON, mage.cards.t.TheArtOfTea.class)); + cards.add(new SetCardInfo("The Blue Spirit", 178, Rarity.RARE, mage.cards.t.TheBlueSpirit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Blue Spirit", 90, Rarity.RARE, mage.cards.t.TheBlueSpirit.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Cabbage Merchant", 134, Rarity.RARE, mage.cards.t.TheCabbageMerchant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Cabbage Merchant", 203, Rarity.RARE, mage.cards.t.TheCabbageMerchant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Duke, Rebel Sentry", 76, Rarity.UNCOMMON, mage.cards.t.TheDukeRebelSentry.class)); cards.add(new SetCardInfo("The Great Henge", 41, Rarity.MYTHIC, mage.cards.t.TheGreatHenge.class)); cards.add(new SetCardInfo("The Terror of Serpent's Pass", 225, Rarity.RARE, mage.cards.t.TheTerrorOfSerpentsPass.class)); cards.add(new SetCardInfo("Three Dreams", 8, Rarity.MYTHIC, mage.cards.t.ThreeDreams.class)); @@ -279,14 +316,19 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Tundra Wall", 275, Rarity.COMMON, mage.cards.t.TundraWall.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Turtle-Seals", 226, Rarity.COMMON, mage.cards.t.TurtleSeals.class)); cards.add(new SetCardInfo("Unagi's Spray", 97, Rarity.COMMON, mage.cards.u.UnagisSpray.class)); + cards.add(new SetCardInfo("Uncle's Musings", 73, Rarity.RARE, mage.cards.u.UnclesMusings.class)); cards.add(new SetCardInfo("Valakut, the Molten Pinnacle", 61, Rarity.MYTHIC, mage.cards.v.ValakutTheMoltenPinnacle.class)); cards.add(new SetCardInfo("Valorous Stance", 154, Rarity.UNCOMMON, mage.cards.v.ValorousStance.class)); cards.add(new SetCardInfo("Visions of Beyond", 21, Rarity.MYTHIC, mage.cards.v.VisionsOfBeyond.class)); cards.add(new SetCardInfo("Volcanic Torrent", 37, Rarity.MYTHIC, mage.cards.v.VolcanicTorrent.class)); + cards.add(new SetCardInfo("Wan Shi Tong, All-Knowing", 182, Rarity.MYTHIC, mage.cards.w.WanShiTongAllKnowing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wan Shi Tong, All-Knowing", 98, Rarity.MYTHIC, mage.cards.w.WanShiTongAllKnowing.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Warship Scout", 244, Rarity.COMMON, mage.cards.w.WarshipScout.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Warship Scout", 285, Rarity.COMMON, mage.cards.w.WarshipScout.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Warstorm Surge", 38, Rarity.MYTHIC, mage.cards.w.WarstormSurge.class)); cards.add(new SetCardInfo("Water Whip", 227, Rarity.RARE, mage.cards.w.WaterWhip.class)); + cards.add(new SetCardInfo("Waterbender's Restoration", 183, Rarity.RARE, mage.cards.w.WaterbendersRestoration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Waterbender's Restoration", 99, Rarity.RARE, mage.cards.w.WaterbendersRestoration.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Whirlwind Technique", 100, Rarity.UNCOMMON, mage.cards.w.WhirlwindTechnique.class)); cards.add(new SetCardInfo("Wolf Cove Villager", 221, Rarity.COMMON, mage.cards.w.WolfCoveVillager.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wolf Cove Villager", 276, Rarity.COMMON, mage.cards.w.WolfCoveVillager.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/DarkAscension.java b/Mage.Sets/src/mage/sets/DarkAscension.java index 8abef1f136e..0514b53479c 100644 --- a/Mage.Sets/src/mage/sets/DarkAscension.java +++ b/Mage.Sets/src/mage/sets/DarkAscension.java @@ -4,7 +4,6 @@ package mage.sets; import mage.cards.Card; import mage.cards.ExpansionSet; import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; import mage.collation.CardRun; @@ -57,7 +56,6 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Burden of Guilt", 4, Rarity.COMMON, mage.cards.b.BurdenOfGuilt.class)); cards.add(new SetCardInfo("Burning Oil", 84, Rarity.UNCOMMON, mage.cards.b.BurningOil.class)); cards.add(new SetCardInfo("Call to the Kindred", 30, Rarity.RARE, mage.cards.c.CallToTheKindred.class)); - cards.add(new SetCardInfo("Chalice of Death", 146, Rarity.UNCOMMON, mage.cards.c.ChaliceOfDeath.class)); cards.add(new SetCardInfo("Chalice of Life", 146, Rarity.UNCOMMON, mage.cards.c.ChaliceOfLife.class)); cards.add(new SetCardInfo("Chant of the Skifsang", 31, Rarity.COMMON, mage.cards.c.ChantOfTheSkifsang.class)); cards.add(new SetCardInfo("Chill of Foreboding", 32, Rarity.UNCOMMON, mage.cards.c.ChillOfForeboding.class)); @@ -140,7 +138,6 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Lost in the Woods", 123, Rarity.RARE, mage.cards.l.LostInTheWoods.class)); cards.add(new SetCardInfo("Loyal Cathar", 13, Rarity.COMMON, mage.cards.l.LoyalCathar.class)); cards.add(new SetCardInfo("Markov Blademaster", 96, Rarity.RARE, mage.cards.m.MarkovBlademaster.class)); - cards.add(new SetCardInfo("Markov's Servant", 55, Rarity.COMMON, mage.cards.m.MarkovsServant.class)); cards.add(new SetCardInfo("Markov Warlord", 97, Rarity.UNCOMMON, mage.cards.m.MarkovWarlord.class)); cards.add(new SetCardInfo("Midnight Guard", 14, Rarity.COMMON, mage.cards.m.MidnightGuard.class)); cards.add(new SetCardInfo("Mikaeus, the Unhallowed", 70, Rarity.MYTHIC, mage.cards.m.MikaeusTheUnhallowed.class)); @@ -155,7 +152,6 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Niblis of the Urn", 16, Rarity.UNCOMMON, mage.cards.n.NiblisOfTheUrn.class)); cards.add(new SetCardInfo("Predator Ooze", 124, Rarity.RARE, mage.cards.p.PredatorOoze.class)); cards.add(new SetCardInfo("Pyreheart Wolf", 101, Rarity.UNCOMMON, mage.cards.p.PyreheartWolf.class)); - cards.add(new SetCardInfo("Ravager of the Fells", 140, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class)); cards.add(new SetCardInfo("Ravenous Demon", 71, Rarity.RARE, mage.cards.r.RavenousDemon.class)); cards.add(new SetCardInfo("Ray of Revelation", 17, Rarity.COMMON, mage.cards.r.RayOfRevelation.class)); cards.add(new SetCardInfo("Reap the Seagraf", 72, Rarity.COMMON, mage.cards.r.ReapTheSeagraf.class)); @@ -203,9 +199,7 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Vorapede", 131, Rarity.MYTHIC, mage.cards.v.Vorapede.class)); cards.add(new SetCardInfo("Wakedancer", 79, Rarity.UNCOMMON, mage.cards.w.Wakedancer.class)); cards.add(new SetCardInfo("Warden of the Wall", 153, Rarity.UNCOMMON, mage.cards.w.WardenOfTheWall.class)); - cards.add(new SetCardInfo("Werewolf Ransacker", 81, Rarity.UNCOMMON, mage.cards.w.WerewolfRansacker.class)); cards.add(new SetCardInfo("Wild Hunger", 132, Rarity.COMMON, mage.cards.w.WildHunger.class)); - cards.add(new SetCardInfo("Withengar Unbound", 147, Rarity.MYTHIC, mage.cards.w.WithengarUnbound.class)); cards.add(new SetCardInfo("Wolfbitten Captive", 133, Rarity.RARE, mage.cards.w.WolfbittenCaptive.class)); cards.add(new SetCardInfo("Wolfhunter's Quiver", 154, Rarity.UNCOMMON, mage.cards.w.WolfhuntersQuiver.class)); cards.add(new SetCardInfo("Wrack with Madness", 107, Rarity.COMMON, mage.cards.w.WrackWithMadness.class)); diff --git a/Mage.Sets/src/mage/sets/EldritchMoon.java b/Mage.Sets/src/mage/sets/EldritchMoon.java index 5b9e2d9967f..2e178da8f64 100644 --- a/Mage.Sets/src/mage/sets/EldritchMoon.java +++ b/Mage.Sets/src/mage/sets/EldritchMoon.java @@ -47,7 +47,6 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Advanced Stitchwing", 49, Rarity.UNCOMMON, mage.cards.a.AdvancedStitchwing.class)); cards.add(new SetCardInfo("Alchemist's Greeting", 116, Rarity.COMMON, mage.cards.a.AlchemistsGreeting.class)); cards.add(new SetCardInfo("Assembled Alphas", 117, Rarity.RARE, mage.cards.a.AssembledAlphas.class)); - cards.add(new SetCardInfo("Aurora of Emrakul", 193, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class)); cards.add(new SetCardInfo("Backwoods Survivalists", 150, Rarity.COMMON, mage.cards.b.BackwoodsSurvivalists.class)); cards.add(new SetCardInfo("Bedlam Reveler", 118, Rarity.RARE, mage.cards.b.BedlamReveler.class)); cards.add(new SetCardInfo("Blessed Alliance", 13, Rarity.UNCOMMON, mage.cards.b.BlessedAlliance.class)); @@ -74,7 +73,6 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Collective Brutality", 85, Rarity.RARE, mage.cards.c.CollectiveBrutality.class)); cards.add(new SetCardInfo("Collective Defiance", 123, Rarity.RARE, mage.cards.c.CollectiveDefiance.class)); cards.add(new SetCardInfo("Collective Effort", 17, Rarity.RARE, mage.cards.c.CollectiveEffort.class)); - cards.add(new SetCardInfo("Conduit of Emrakul", 124, Rarity.UNCOMMON, mage.cards.c.ConduitOfEmrakul.class)); cards.add(new SetCardInfo("Conduit of Storms", 124, Rarity.UNCOMMON, mage.cards.c.ConduitOfStorms.class)); cards.add(new SetCardInfo("Contingency Plan", 52, Rarity.COMMON, mage.cards.c.ContingencyPlan.class)); cards.add(new SetCardInfo("Convolute", 53, Rarity.COMMON, mage.cards.c.Convolute.class)); @@ -108,7 +106,6 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Enlightened Maniac", 58, Rarity.COMMON, mage.cards.e.EnlightenedManiac.class)); cards.add(new SetCardInfo("Erupting Dreadwolf", 142, Rarity.UNCOMMON, mage.cards.e.EruptingDreadwolf.class)); cards.add(new SetCardInfo("Eternal Scourge", 7, Rarity.RARE, mage.cards.e.EternalScourge.class)); - cards.add(new SetCardInfo("Extricator of Flesh", 23, Rarity.UNCOMMON, mage.cards.e.ExtricatorOfFlesh.class)); cards.add(new SetCardInfo("Extricator of Sin", 23, Rarity.UNCOMMON, mage.cards.e.ExtricatorOfSin.class)); cards.add(new SetCardInfo("Exultant Cultist", 59, Rarity.COMMON, mage.cards.e.ExultantCultist.class)); cards.add(new SetCardInfo("Faith Unbroken", 24, Rarity.UNCOMMON, mage.cards.f.FaithUnbroken.class)); diff --git a/Mage.Sets/src/mage/sets/FinalFantasy.java b/Mage.Sets/src/mage/sets/FinalFantasy.java index 04443dac090..43a1d38d199 100644 --- a/Mage.Sets/src/mage/sets/FinalFantasy.java +++ b/Mage.Sets/src/mage/sets/FinalFantasy.java @@ -56,12 +56,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Astrologian's Planisphere", 46, Rarity.RARE, mage.cards.a.AstrologiansPlanisphere.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Astrologian's Planisphere", 581, Rarity.RARE, mage.cards.a.AstrologiansPlanisphere.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Auron's Inspiration", 8, Rarity.UNCOMMON, mage.cards.a.AuronsInspiration.class)); - cards.add(new SetCardInfo("Bahamut, Warden of Light", 16, Rarity.RARE, mage.cards.b.BahamutWardenOfLight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bahamut, Warden of Light", 376, Rarity.RARE, mage.cards.b.BahamutWardenOfLight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bahamut, Warden of Light", 428, Rarity.RARE, mage.cards.b.BahamutWardenOfLight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bahamut, Warden of Light", 521, Rarity.RARE, mage.cards.b.BahamutWardenOfLight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Balamb Garden, Airborne", 272, Rarity.RARE, mage.cards.b.BalambGardenAirborne.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Balamb Garden, Airborne", 354, Rarity.RARE, mage.cards.b.BalambGardenAirborne.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Balamb Garden, SeeD Academy", 272, Rarity.RARE, mage.cards.b.BalambGardenSeeDAcademy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Balamb Garden, SeeD Academy", 354, Rarity.RARE, mage.cards.b.BalambGardenSeeDAcademy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Balamb T-Rexaur", 173, Rarity.COMMON, mage.cards.b.BalambTRexaur.class)); @@ -100,10 +94,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Cecil, Dark Knight", 445, Rarity.RARE, mage.cards.c.CecilDarkKnight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cecil, Dark Knight", 525, Rarity.RARE, mage.cards.c.CecilDarkKnight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cecil, Dark Knight", 91, Rarity.RARE, mage.cards.c.CecilDarkKnight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cecil, Redeemed Paladin", 380, Rarity.RARE, mage.cards.c.CecilRedeemedPaladin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cecil, Redeemed Paladin", 445, Rarity.RARE, mage.cards.c.CecilRedeemedPaladin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cecil, Redeemed Paladin", 525, Rarity.RARE, mage.cards.c.CecilRedeemedPaladin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cecil, Redeemed Paladin", 91, Rarity.RARE, mage.cards.c.CecilRedeemedPaladin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chaos, the Endless", 221, Rarity.UNCOMMON, mage.cards.c.ChaosTheEndless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chaos, the Endless", 486, Rarity.UNCOMMON, mage.cards.c.ChaosTheEndless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Choco, Seeker of Paradise", 215, Rarity.RARE, mage.cards.c.ChocoSeekerOfParadise.class, NON_FULL_USE_VARIOUS)); @@ -252,10 +242,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Gran Pulse Ochu", 189, Rarity.COMMON, mage.cards.g.GranPulseOchu.class)); cards.add(new SetCardInfo("Guadosalam, Farplane Gateway", 281, Rarity.COMMON, mage.cards.g.GuadosalamFarplaneGateway.class)); cards.add(new SetCardInfo("Gysahl Greens", 190, Rarity.COMMON, mage.cards.g.GysahlGreens.class)); - cards.add(new SetCardInfo("Hades, Sorcerer of Eld", 218, Rarity.MYTHIC, mage.cards.h.HadesSorcererOfEld.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hades, Sorcerer of Eld", 394, Rarity.MYTHIC, mage.cards.h.HadesSorcererOfEld.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hades, Sorcerer of Eld", 483, Rarity.MYTHIC, mage.cards.h.HadesSorcererOfEld.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hades, Sorcerer of Eld", 539, Rarity.MYTHIC, mage.cards.h.HadesSorcererOfEld.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Haste Magic", 140, Rarity.COMMON, mage.cards.h.HasteMagic.class)); cards.add(new SetCardInfo("Hecteyes", 103, Rarity.COMMON, mage.cards.h.Hecteyes.class)); cards.add(new SetCardInfo("Hill Gigas", 141, Rarity.COMMON, mage.cards.h.HillGigas.class)); @@ -268,11 +254,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Hydaelyn, the Mothercrystal", 434, Rarity.RARE, mage.cards.h.HydaelynTheMothercrystal.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ice Flan", 55, Rarity.COMMON, mage.cards.i.IceFlan.class)); cards.add(new SetCardInfo("Ice Magic", 56, Rarity.COMMON, mage.cards.i.IceMagic.class)); - cards.add(new SetCardInfo("Ifrit, Warden of Inferno", 133, Rarity.MYTHIC, mage.cards.i.IfritWardenOfInferno.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ifrit, Warden of Inferno", 318, Rarity.MYTHIC, mage.cards.i.IfritWardenOfInferno.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ifrit, Warden of Inferno", 385, Rarity.MYTHIC, mage.cards.i.IfritWardenOfInferno.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ifrit, Warden of Inferno", 458, Rarity.MYTHIC, mage.cards.i.IfritWardenOfInferno.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ifrit, Warden of Inferno", 530, Rarity.MYTHIC, mage.cards.i.IfritWardenOfInferno.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ignis Scientia", 227, Rarity.UNCOMMON, mage.cards.i.IgnisScientia.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ignis Scientia", 492, Rarity.UNCOMMON, mage.cards.i.IgnisScientia.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Il Mheg Pixie", 57, Rarity.UNCOMMON, mage.cards.i.IlMhegPixie.class)); @@ -367,8 +348,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 575, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mysidian Elder", 145, Rarity.COMMON, mage.cards.m.MysidianElder.class)); cards.add(new SetCardInfo("Namazu Trader", 107, Rarity.COMMON, mage.cards.n.NamazuTrader.class)); - cards.add(new SetCardInfo("Neo Exdeath, Dimension's End", 220, Rarity.UNCOMMON, mage.cards.n.NeoExdeathDimensionsEnd.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Neo Exdeath, Dimension's End", 485, Rarity.UNCOMMON, mage.cards.n.NeoExdeathDimensionsEnd.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nibelheim Aflame", 146, Rarity.MYTHIC, mage.cards.n.NibelheimAflame.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nibelheim Aflame", 339, Rarity.MYTHIC, mage.cards.n.NibelheimAflame.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ninja's Blades", 108, Rarity.RARE, mage.cards.n.NinjasBlades.class)); @@ -510,8 +489,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Stolen Uniform", 332, Rarity.UNCOMMON, mage.cards.s.StolenUniform.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Stolen Uniform", 75, Rarity.UNCOMMON, mage.cards.s.StolenUniform.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Stuck in Summoner's Sanctum", 76, Rarity.COMMON, mage.cards.s.StuckInSummonersSanctum.class)); - cards.add(new SetCardInfo("Summon: Alexander", 13, Rarity.UNCOMMON, mage.cards.s.SummonAlexander.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Summon: Alexander", 357, Rarity.UNCOMMON, mage.cards.s.SummonAlexander.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Anima", 120, Rarity.UNCOMMON, mage.cards.s.SummonAnima.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Anima", 364, Rarity.UNCOMMON, mage.cards.s.SummonAnima.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Bahamut", 1, Rarity.MYTHIC, mage.cards.s.SummonBahamut.class, NON_FULL_USE_VARIOUS)); @@ -520,8 +497,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Summon: Brynhildr", 366, Rarity.RARE, mage.cards.s.SummonBrynhildr.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Choco/Mog", 35, Rarity.COMMON, mage.cards.s.SummonChocoMog.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Choco/Mog", 358, Rarity.COMMON, mage.cards.s.SummonChocoMog.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Summon: Esper Maduin", 185, Rarity.RARE, mage.cards.s.SummonEsperMaduin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Summon: Esper Maduin", 370, Rarity.RARE, mage.cards.s.SummonEsperMaduin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Esper Ramuh", 161, Rarity.UNCOMMON, mage.cards.s.SummonEsperRamuh.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Esper Ramuh", 367, Rarity.UNCOMMON, mage.cards.s.SummonEsperRamuh.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Fat Chocobo", 202, Rarity.COMMON, mage.cards.s.SummonFatChocobo.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/FromTheVaultTransform.java b/Mage.Sets/src/mage/sets/FromTheVaultTransform.java index 6bbc1f7e337..68ef3e439ca 100644 --- a/Mage.Sets/src/mage/sets/FromTheVaultTransform.java +++ b/Mage.Sets/src/mage/sets/FromTheVaultTransform.java @@ -21,26 +21,18 @@ public final class FromTheVaultTransform extends ExpansionSet { this.hasBasicLands = false; cards.add(new SetCardInfo("Archangel Avacyn", 1, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 1, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class)); cards.add(new SetCardInfo("Arguel's Blood Fast", 2, Rarity.MYTHIC, mage.cards.a.ArguelsBloodFast.class)); - cards.add(new SetCardInfo("Temple of Aclazotz", 2, Rarity.MYTHIC, mage.cards.t.TempleOfAclazotz.class)); cards.add(new SetCardInfo("Arlinn Kord", 3, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 3, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class)); cards.add(new SetCardInfo("Bloodline Keeper", 4, Rarity.MYTHIC, mage.cards.b.BloodlineKeeper.class)); - cards.add(new SetCardInfo("Lord of Lineage", 4, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class)); cards.add(new SetCardInfo("Bruna, the Fading Light", 5, Rarity.MYTHIC, mage.cards.b.BrunaTheFadingLight.class)); cards.add(new SetCardInfo("Brisela, Voice of Nightmares", "5b", Rarity.MYTHIC, mage.cards.b.BriselaVoiceOfNightmares.class)); cards.add(new SetCardInfo("Chandra, Fire of Kaladesh", 6, Rarity.MYTHIC, mage.cards.c.ChandraFireOfKaladesh.class)); - cards.add(new SetCardInfo("Chandra, Roaring Flame", 6, Rarity.MYTHIC, mage.cards.c.ChandraRoaringFlame.class)); cards.add(new SetCardInfo("Delver of Secrets", 7, Rarity.MYTHIC, mage.cards.d.DelverOfSecrets.class)); - cards.add(new SetCardInfo("Insectile Aberration", 7, Rarity.MYTHIC, mage.cards.i.InsectileAberration.class)); cards.add(new SetCardInfo("Elbrus, the Binding Blade", 8, Rarity.MYTHIC, mage.cards.e.ElbrusTheBindingBlade.class)); - cards.add(new SetCardInfo("Withengar Unbound", 8, Rarity.MYTHIC, mage.cards.w.WithengarUnbound.class)); cards.add(new SetCardInfo("Garruk Relentless", 9, Rarity.MYTHIC, mage.cards.g.GarrukRelentless.class)); cards.add(new SetCardInfo("Garruk, the Veil-Cursed", 9, Rarity.MYTHIC, mage.cards.g.GarrukTheVeilCursed.class)); cards.add(new SetCardInfo("Gisela, the Broken Blade", 10, Rarity.MYTHIC, mage.cards.g.GiselaTheBrokenBlade.class)); cards.add(new SetCardInfo("Huntmaster of the Fells", 11, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class)); - cards.add(new SetCardInfo("Ravager of the Fells", 11, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class)); cards.add(new SetCardInfo("Jace, Vryn's Prodigy", 12, Rarity.MYTHIC, mage.cards.j.JaceVrynsProdigy.class)); cards.add(new SetCardInfo("Jace, Telepath Unbound", 12, Rarity.MYTHIC, mage.cards.j.JaceTelepathUnbound.class)); cards.add(new SetCardInfo("Kytheon, Hero of Akros", 13, Rarity.MYTHIC, mage.cards.k.KytheonHeroOfAkros.class)); diff --git a/Mage.Sets/src/mage/sets/Innistrad.java b/Mage.Sets/src/mage/sets/Innistrad.java index d314bf52825..a37d00cdd8c 100644 --- a/Mage.Sets/src/mage/sets/Innistrad.java +++ b/Mage.Sets/src/mage/sets/Innistrad.java @@ -153,13 +153,11 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Heretic's Punishment", 147, Rarity.RARE, mage.cards.h.HereticsPunishment.class)); cards.add(new SetCardInfo("Hinterland Harbor", 241, Rarity.RARE, mage.cards.h.HinterlandHarbor.class)); cards.add(new SetCardInfo("Hollowhenge Scavenger", 188, Rarity.UNCOMMON, mage.cards.h.HollowhengeScavenger.class)); - cards.add(new SetCardInfo("Homicidal Brute", 47, Rarity.UNCOMMON, mage.cards.h.HomicidalBrute.class)); cards.add(new SetCardInfo("Howlpack Alpha", 193, Rarity.RARE, mage.cards.h.HowlpackAlpha.class)); cards.add(new SetCardInfo("Howlpack of Estwald", 209, Rarity.COMMON, mage.cards.h.HowlpackOfEstwald.class)); cards.add(new SetCardInfo("Hysterical Blindness", 59, Rarity.COMMON, mage.cards.h.HystericalBlindness.class)); cards.add(new SetCardInfo("Infernal Plunge", 148, Rarity.COMMON, mage.cards.i.InfernalPlunge.class)); cards.add(new SetCardInfo("Inquisitor's Flail", 227, Rarity.UNCOMMON, mage.cards.i.InquisitorsFlail.class)); - cards.add(new SetCardInfo("Insectile Aberration", 51, Rarity.COMMON, mage.cards.i.InsectileAberration.class)); cards.add(new SetCardInfo("Instigator Gang", 149, Rarity.RARE, mage.cards.i.InstigatorGang.class)); cards.add(new SetCardInfo("Intangible Virtue", 19, Rarity.UNCOMMON, mage.cards.i.IntangibleVirtue.class)); cards.add(new SetCardInfo("Into the Maw of Hell", 150, Rarity.UNCOMMON, mage.cards.i.IntoTheMawOfHell.class)); @@ -178,7 +176,6 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Laboratory Maniac", 61, Rarity.RARE, mage.cards.l.LaboratoryManiac.class)); cards.add(new SetCardInfo("Lantern Spirit", 62, Rarity.UNCOMMON, mage.cards.l.LanternSpirit.class)); cards.add(new SetCardInfo("Liliana of the Veil", 105, Rarity.MYTHIC, mage.cards.l.LilianaOfTheVeil.class)); - cards.add(new SetCardInfo("Lord of Lineage", 90, Rarity.RARE, mage.cards.l.LordOfLineage.class)); cards.add(new SetCardInfo("Lost in the Mist", 63, Rarity.COMMON, mage.cards.l.LostInTheMist.class)); cards.add(new SetCardInfo("Ludevic's Abomination", 64, Rarity.RARE, mage.cards.l.LudevicsAbomination.class)); cards.add(new SetCardInfo("Ludevic's Test Subject", 64, Rarity.RARE, mage.cards.l.LudevicsTestSubject.class)); @@ -217,7 +214,6 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Night Revelers", 153, Rarity.COMMON, mage.cards.n.NightRevelers.class)); cards.add(new SetCardInfo("Night Terrors", 111, Rarity.COMMON, mage.cards.n.NightTerrors.class)); cards.add(new SetCardInfo("Nightbird's Clutches", 154, Rarity.COMMON, mage.cards.n.NightbirdsClutches.class)); - cards.add(new SetCardInfo("Nightfall Predator", 176, Rarity.RARE, mage.cards.n.NightfallPredator.class)); cards.add(new SetCardInfo("Olivia Voldaren", 215, Rarity.MYTHIC, mage.cards.o.OliviaVoldaren.class)); cards.add(new SetCardInfo("One-Eyed Scarecrow", 230, Rarity.COMMON, mage.cards.o.OneEyedScarecrow.class)); cards.add(new SetCardInfo("Orchard Spirit", 198, Rarity.COMMON, mage.cards.o.OrchardSpirit.class)); @@ -300,7 +296,6 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Unbreathing Horde", 121, Rarity.RARE, mage.cards.u.UnbreathingHorde.class)); cards.add(new SetCardInfo("Unburial Rites", 122, Rarity.UNCOMMON, mage.cards.u.UnburialRites.class)); cards.add(new SetCardInfo("Undead Alchemist", 84, Rarity.RARE, mage.cards.u.UndeadAlchemist.class)); - cards.add(new SetCardInfo("Unholy Fiend", 8, Rarity.UNCOMMON, mage.cards.u.UnholyFiend.class)); cards.add(new SetCardInfo("Unruly Mob", 39, Rarity.COMMON, mage.cards.u.UnrulyMob.class)); cards.add(new SetCardInfo("Urgent Exorcism", 40, Rarity.COMMON, mage.cards.u.UrgentExorcism.class)); cards.add(new SetCardInfo("Vampire Interloper", 123, Rarity.COMMON, mage.cards.v.VampireInterloper.class)); diff --git a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java index d2e0b5fbf70..aa578902369 100644 --- a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java +++ b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java @@ -60,12 +60,10 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Avabruck Caretaker", 187, Rarity.MYTHIC, mage.cards.a.AvabruckCaretaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avabruck Caretaker", 384, Rarity.MYTHIC, mage.cards.a.AvabruckCaretaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ballista Watcher", 143, Rarity.UNCOMMON, mage.cards.b.BallistaWatcher.class)); - cards.add(new SetCardInfo("Ballista Wielder", 143, Rarity.UNCOMMON, mage.cards.b.BallistaWielder.class)); cards.add(new SetCardInfo("Belligerent Guest", 144, Rarity.COMMON, mage.cards.b.BelligerentGuest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Belligerent Guest", 301, Rarity.COMMON, mage.cards.b.BelligerentGuest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Binding Geist", 48, Rarity.COMMON, mage.cards.b.BindingGeist.class)); cards.add(new SetCardInfo("Biolume Egg", 49, Rarity.UNCOMMON, mage.cards.b.BiolumeEgg.class)); - cards.add(new SetCardInfo("Biolume Serpent", 49, Rarity.UNCOMMON, mage.cards.b.BiolumeSerpent.class)); cards.add(new SetCardInfo("Bleed Dry", 94, Rarity.COMMON, mage.cards.b.BleedDry.class)); cards.add(new SetCardInfo("Blood Fountain", 95, Rarity.COMMON, mage.cards.b.BloodFountain.class)); cards.add(new SetCardInfo("Blood Hypnotist", 145, Rarity.UNCOMMON, mage.cards.b.BloodHypnotist.class, NON_FULL_USE_VARIOUS)); @@ -80,8 +78,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Bloodcrazed Socialite", 96, Rarity.COMMON, mage.cards.b.BloodcrazedSocialite.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodsoaked Reveler", 128, Rarity.UNCOMMON, mage.cards.b.BloodsoakedReveler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodsoaked Reveler", 295, Rarity.UNCOMMON, mage.cards.b.BloodsoakedReveler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bloodsworn Knight", 289, Rarity.UNCOMMON, mage.cards.b.BloodswornKnight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bloodsworn Knight", 97, Rarity.UNCOMMON, mage.cards.b.BloodswornKnight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodsworn Squire", 289, Rarity.UNCOMMON, mage.cards.b.BloodswornSquire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodsworn Squire", 97, Rarity.UNCOMMON, mage.cards.b.BloodswornSquire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodtithe Harvester", 232, Rarity.UNCOMMON, mage.cards.b.BloodtitheHarvester.class, NON_FULL_USE_VARIOUS)); @@ -95,12 +91,10 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Bramble Wurm", 189, Rarity.UNCOMMON, mage.cards.b.BrambleWurm.class)); cards.add(new SetCardInfo("Bride's Gown", 4, Rarity.UNCOMMON, mage.cards.b.BridesGown.class)); cards.add(new SetCardInfo("Brine Comber", 233, Rarity.UNCOMMON, mage.cards.b.BrineComber.class)); - cards.add(new SetCardInfo("Brinebound Gift", 233, Rarity.UNCOMMON, mage.cards.b.BrineboundGift.class)); cards.add(new SetCardInfo("By Invitation Only", 346, Rarity.RARE, mage.cards.b.ByInvitationOnly.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("By Invitation Only", 5, Rarity.RARE, mage.cards.b.ByInvitationOnly.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cackling Culprit", 28, Rarity.UNCOMMON, mage.cards.c.CacklingCulprit.class)); cards.add(new SetCardInfo("Cartographer's Survey", 190, Rarity.UNCOMMON, mage.cards.c.CartographersSurvey.class)); - cards.add(new SetCardInfo("Catapult Captain", 99, Rarity.UNCOMMON, mage.cards.c.CatapultCaptain.class)); cards.add(new SetCardInfo("Catapult Fodder", 99, Rarity.UNCOMMON, mage.cards.c.CatapultFodder.class)); cards.add(new SetCardInfo("Catlike Curiosity", 69, Rarity.UNCOMMON, mage.cards.c.CatlikeCuriosity.class)); cards.add(new SetCardInfo("Cemetery Desecrator", 100, Rarity.MYTHIC, mage.cards.c.CemeteryDesecrator.class, NON_FULL_USE_VARIOUS)); @@ -123,7 +117,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Cipherbound Spirit", 79, Rarity.UNCOMMON, mage.cards.c.CipherboundSpirit.class)); cards.add(new SetCardInfo("Circle of Confinement", 329, Rarity.UNCOMMON, mage.cards.c.CircleOfConfinement.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Circle of Confinement", 7, Rarity.UNCOMMON, mage.cards.c.CircleOfConfinement.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Clever Distraction", 9, Rarity.UNCOMMON, mage.cards.c.CleverDistraction.class)); cards.add(new SetCardInfo("Cloaked Cadet", 192, Rarity.UNCOMMON, mage.cards.c.CloakedCadet.class)); cards.add(new SetCardInfo("Cobbled Lancer", 52, Rarity.UNCOMMON, mage.cards.c.CobbledLancer.class)); cards.add(new SetCardInfo("Concealing Curtains", 101, Rarity.RARE, mage.cards.c.ConcealingCurtains.class, NON_FULL_USE_VARIOUS)); @@ -144,13 +137,10 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Dawnhart Disciple", 196, Rarity.COMMON, mage.cards.d.DawnhartDisciple.class)); cards.add(new SetCardInfo("Dawnhart Geist", 8, Rarity.UNCOMMON, mage.cards.d.DawnhartGeist.class)); cards.add(new SetCardInfo("Daybreak Combatants", 153, Rarity.COMMON, mage.cards.d.DaybreakCombatants.class)); - cards.add(new SetCardInfo("Deadly Dancer", 141, Rarity.UNCOMMON, mage.cards.d.DeadlyDancer.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Deadly Dancer", 300, Rarity.UNCOMMON, mage.cards.d.DeadlyDancer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Deathcap Glade", 261, Rarity.RARE, mage.cards.d.DeathcapGlade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Deathcap Glade", 281, Rarity.RARE, mage.cards.d.DeathcapGlade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Demonic Bargain", 103, Rarity.RARE, mage.cards.d.DemonicBargain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Demonic Bargain", 368, Rarity.RARE, mage.cards.d.DemonicBargain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Depraved Harvester", 104, Rarity.COMMON, mage.cards.d.DepravedHarvester.class)); cards.add(new SetCardInfo("Desperate Farmer", 104, Rarity.COMMON, mage.cards.d.DesperateFarmer.class)); cards.add(new SetCardInfo("Dig Up", 197, Rarity.RARE, mage.cards.d.DigUp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dig Up", 387, Rarity.RARE, mage.cards.d.DigUp.class, NON_FULL_USE_VARIOUS)); @@ -166,8 +156,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Dominating Vampire", 407, Rarity.RARE, mage.cards.d.DominatingVampire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Doomed Dissenter", 106, Rarity.COMMON, mage.cards.d.DoomedDissenter.class)); cards.add(new SetCardInfo("Dormant Grove", 198, Rarity.UNCOMMON, mage.cards.d.DormantGrove.class)); - cards.add(new SetCardInfo("Dorothea's Retribution", 235, Rarity.RARE, mage.cards.d.DorotheasRetribution.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dorothea's Retribution", 322, Rarity.RARE, mage.cards.d.DorotheasRetribution.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dorothea, Vengeful Victim", 235, Rarity.RARE, mage.cards.d.DorotheaVengefulVictim.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dorothea, Vengeful Victim", 322, Rarity.RARE, mage.cards.d.DorotheaVengefulVictim.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dread Fugue", 107, Rarity.UNCOMMON, mage.cards.d.DreadFugue.class)); @@ -178,13 +166,9 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Dreamroot Cascade", 282, Rarity.RARE, mage.cards.d.DreamrootCascade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dreamshackle Geist", 358, Rarity.RARE, mage.cards.d.DreamshackleGeist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dreamshackle Geist", 58, Rarity.RARE, mage.cards.d.DreamshackleGeist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Drogskol Armaments", 10, Rarity.COMMON, mage.cards.d.DrogskolArmaments.class)); cards.add(new SetCardInfo("Drogskol Infantry", 10, Rarity.COMMON, mage.cards.d.DrogskolInfantry.class)); cards.add(new SetCardInfo("Dying to Serve", 109, Rarity.RARE, mage.cards.d.DyingToServe.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dying to Serve", 370, Rarity.RARE, mage.cards.d.DyingToServe.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Edgar Markov's Coffin", 236, Rarity.RARE, mage.cards.e.EdgarMarkovsCoffin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Edgar Markov's Coffin", 311, Rarity.RARE, mage.cards.e.EdgarMarkovsCoffin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Edgar Markov's Coffin", 341, Rarity.RARE, mage.cards.e.EdgarMarkovsCoffin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Edgar's Awakening", 110, Rarity.UNCOMMON, mage.cards.e.EdgarsAwakening.class)); cards.add(new SetCardInfo("Edgar, Charmed Groom", 236, Rarity.RARE, mage.cards.e.EdgarCharmedGroom.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Edgar, Charmed Groom", 311, Rarity.RARE, mage.cards.e.EdgarCharmedGroom.class, NON_FULL_USE_VARIOUS)); @@ -229,7 +213,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Glorious Sunrise", 388, Rarity.RARE, mage.cards.g.GloriousSunrise.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gluttonous Guest", 114, Rarity.COMMON, mage.cards.g.GluttonousGuest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gluttonous Guest", 292, Rarity.COMMON, mage.cards.g.GluttonousGuest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gnarled Grovestrider", 198, Rarity.UNCOMMON, mage.cards.g.GnarledGrovestrider.class)); cards.add(new SetCardInfo("Graf Reaver", 115, Rarity.RARE, mage.cards.g.GrafReaver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Graf Reaver", 371, Rarity.RARE, mage.cards.g.GrafReaver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grisly Ritual", 116, Rarity.COMMON, mage.cards.g.GrislyRitual.class)); @@ -262,8 +245,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Heron-Blessed Geist", 19, Rarity.COMMON, mage.cards.h.HeronBlessedGeist.class)); cards.add(new SetCardInfo("Hiveheart Shaman", 202, Rarity.RARE, mage.cards.h.HiveheartShaman.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hiveheart Shaman", 390, Rarity.RARE, mage.cards.h.HiveheartShaman.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hollowhenge Huntmaster", 187, Rarity.MYTHIC, mage.cards.h.HollowhengeHuntmaster.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hollowhenge Huntmaster", 384, Rarity.MYTHIC, mage.cards.h.HollowhengeHuntmaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Honeymoon Hearse", 160, Rarity.UNCOMMON, mage.cards.h.HoneymoonHearse.class)); cards.add(new SetCardInfo("Honored Heirloom", 257, Rarity.COMMON, mage.cards.h.HonoredHeirloom.class)); cards.add(new SetCardInfo("Hookhand Mariner", 203, Rarity.COMMON, mage.cards.h.HookhandMariner.class)); @@ -393,8 +374,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Restless Bloodseeker", 128, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Restless Bloodseeker", 295, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Retrieve", 215, Rarity.UNCOMMON, mage.cards.r.Retrieve.class)); - cards.add(new SetCardInfo("Revealing Eye", 101, Rarity.RARE, mage.cards.r.RevealingEye.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Revealing Eye", 367, Rarity.RARE, mage.cards.r.RevealingEye.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Riphook Raider", 203, Rarity.COMMON, mage.cards.r.RiphookRaider.class)); cards.add(new SetCardInfo("Rot-Tide Gargantua", 129, Rarity.COMMON, mage.cards.r.RotTideGargantua.class)); cards.add(new SetCardInfo("Runebound Wolf", 176, Rarity.UNCOMMON, mage.cards.r.RuneboundWolf.class)); @@ -404,7 +383,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Rural Recruit", 216, Rarity.COMMON, mage.cards.r.RuralRecruit.class)); cards.add(new SetCardInfo("Sanctify", 33, Rarity.COMMON, mage.cards.s.Sanctify.class)); cards.add(new SetCardInfo("Sanguine Statuette", 177, Rarity.UNCOMMON, mage.cards.s.SanguineStatuette.class)); - cards.add(new SetCardInfo("Savage Packmate", 234, Rarity.UNCOMMON, mage.cards.s.SavagePackmate.class)); cards.add(new SetCardInfo("Savior of Ollenbock", 330, Rarity.MYTHIC, mage.cards.s.SaviorOfOllenbock.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Savior of Ollenbock", 34, Rarity.MYTHIC, mage.cards.s.SaviorOfOllenbock.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Savior of Ollenbock", 352, Rarity.MYTHIC, mage.cards.s.SaviorOfOllenbock.class, NON_FULL_USE_VARIOUS)); @@ -421,8 +399,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Sigarda's Summons", 36, Rarity.RARE, mage.cards.s.SigardasSummons.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sigarda's Summons", 404, Rarity.RARE, mage.cards.s.SigardasSummons.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sigardian Paladin", 247, Rarity.UNCOMMON, mage.cards.s.SigardianPaladin.class)); - cards.add(new SetCardInfo("Sinner's Judgment", 12, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sinner's Judgment", 348, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Skulking Killer", 130, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Skulking Killer", 296, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Skull Skaab", 248, Rarity.UNCOMMON, mage.cards.s.SkullSkaab.class)); @@ -433,7 +409,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Sorin the Mirthless", 297, Rarity.MYTHIC, mage.cards.s.SorinTheMirthless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sorin the Mirthless", 337, Rarity.MYTHIC, mage.cards.s.SorinTheMirthless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Soulcipher Board", 79, Rarity.UNCOMMON, mage.cards.s.SoulcipherBoard.class)); - cards.add(new SetCardInfo("Spectral Binding", 48, Rarity.COMMON, mage.cards.s.SpectralBinding.class)); cards.add(new SetCardInfo("Spiked Ripsaw", 220, Rarity.UNCOMMON, mage.cards.s.SpikedRipsaw.class)); cards.add(new SetCardInfo("Splendid Reclamation", 221, Rarity.RARE, mage.cards.s.SplendidReclamation.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Splendid Reclamation", 393, Rarity.RARE, mage.cards.s.SplendidReclamation.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/InnistradDoubleFeature.java b/Mage.Sets/src/mage/sets/InnistradDoubleFeature.java index 5c5007cae54..87c7f024a56 100644 --- a/Mage.Sets/src/mage/sets/InnistradDoubleFeature.java +++ b/Mage.Sets/src/mage/sets/InnistradDoubleFeature.java @@ -34,12 +34,10 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Alchemist's Gambit", 407, Rarity.RARE, mage.cards.a.AlchemistsGambit.class)); cards.add(new SetCardInfo("Alchemist's Retrieval", 314, Rarity.COMMON, mage.cards.a.AlchemistsRetrieval.class)); cards.add(new SetCardInfo("Alluring Suitor", 408, Rarity.UNCOMMON, mage.cards.a.AlluringSuitor.class)); - cards.add(new SetCardInfo("Ambitious Farmhand", 2, Rarity.UNCOMMON, mage.cards.a.AmbitiousFarmhand.class)); cards.add(new SetCardInfo("Ancestor's Embrace", 289, Rarity.COMMON, mage.cards.a.AncestorsEmbrace.class)); cards.add(new SetCardInfo("Ancestral Anger", 409, Rarity.COMMON, mage.cards.a.AncestralAnger.class)); cards.add(new SetCardInfo("Ancient Lumberknot", 497, Rarity.UNCOMMON, mage.cards.a.AncientLumberknot.class)); cards.add(new SetCardInfo("Angelfire Ignition", 209, Rarity.RARE, mage.cards.a.AngelfireIgnition.class)); - cards.add(new SetCardInfo("Angelic Enforcer", 17, Rarity.MYTHIC, mage.cards.a.AngelicEnforcer.class)); cards.add(new SetCardInfo("Angelic Quartermaster", 269, Rarity.UNCOMMON, mage.cards.a.AngelicQuartermaster.class)); cards.add(new SetCardInfo("Anje, Maid of Dishonor", 498, Rarity.RARE, mage.cards.a.AnjeMaidOfDishonor.class)); cards.add(new SetCardInfo("Apprentice Sharpshooter", 452, Rarity.COMMON, mage.cards.a.ApprenticeSharpshooter.class)); @@ -47,7 +45,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Archghoul of Thraben", 360, Rarity.UNCOMMON, mage.cards.a.ArchghoulOfThraben.class)); cards.add(new SetCardInfo("Archive Haunt", 68, Rarity.UNCOMMON, mage.cards.a.ArchiveHaunt.class)); cards.add(new SetCardInfo("Ardent Elementalist", 128, Rarity.COMMON, mage.cards.a.ArdentElementalist.class)); - cards.add(new SetCardInfo("Arlinn, the Moon's Fury", 211, Rarity.MYTHIC, mage.cards.a.ArlinnTheMoonsFury.class)); cards.add(new SetCardInfo("Arlinn, the Pack's Hope", 211, Rarity.MYTHIC, mage.cards.a.ArlinnThePacksHope.class)); cards.add(new SetCardInfo("Arm the Cathars", 270, Rarity.UNCOMMON, mage.cards.a.ArmTheCathars.class)); cards.add(new SetCardInfo("Arrogant Outlaw", 84, Rarity.COMMON, mage.cards.a.ArrogantOutlaw.class)); @@ -55,12 +52,9 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Ashmouth Dragon", 159, Rarity.RARE, mage.cards.a.AshmouthDragon.class)); cards.add(new SetCardInfo("Augur of Autumn", 168, Rarity.RARE, mage.cards.a.AugurOfAutumn.class)); cards.add(new SetCardInfo("Avabruck Caretaker", 454, Rarity.MYTHIC, mage.cards.a.AvabruckCaretaker.class)); - cards.add(new SetCardInfo("Awoken Demon", 100, Rarity.COMMON, mage.cards.a.AwokenDemon.class)); cards.add(new SetCardInfo("Baithook Angler", 42, Rarity.COMMON, mage.cards.b.BaithookAngler.class)); cards.add(new SetCardInfo("Ballista Watcher", 410, Rarity.UNCOMMON, mage.cards.b.BallistaWatcher.class)); - cards.add(new SetCardInfo("Ballista Wielder", 410, Rarity.UNCOMMON, mage.cards.b.BallistaWielder.class)); cards.add(new SetCardInfo("Baneblade Scoundrel", 85, Rarity.UNCOMMON, mage.cards.b.BanebladeScoundrel.class)); - cards.add(new SetCardInfo("Baneclaw Marauder", 85, Rarity.UNCOMMON, mage.cards.b.BaneclawMarauder.class)); cards.add(new SetCardInfo("Bat Whisperer", 86, Rarity.COMMON, mage.cards.b.BatWhisperer.class)); cards.add(new SetCardInfo("Belligerent Guest", 411, Rarity.COMMON, mage.cards.b.BelligerentGuest.class)); cards.add(new SetCardInfo("Beloved Beggar", 3, Rarity.UNCOMMON, mage.cards.b.BelovedBeggar.class)); @@ -68,7 +62,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Bereaved Survivor", 4, Rarity.UNCOMMON, mage.cards.b.BereavedSurvivor.class)); cards.add(new SetCardInfo("Binding Geist", 315, Rarity.COMMON, mage.cards.b.BindingGeist.class)); cards.add(new SetCardInfo("Biolume Egg", 316, Rarity.UNCOMMON, mage.cards.b.BiolumeEgg.class)); - cards.add(new SetCardInfo("Biolume Serpent", 316, Rarity.UNCOMMON, mage.cards.b.BiolumeSerpent.class)); cards.add(new SetCardInfo("Bird Admirer", 169, Rarity.COMMON, mage.cards.b.BirdAdmirer.class)); cards.add(new SetCardInfo("Bladebrand", 87, Rarity.COMMON, mage.cards.b.Bladebrand.class)); cards.add(new SetCardInfo("Bladestitched Skaab", 212, Rarity.UNCOMMON, mage.cards.b.BladestitchedSkaab.class)); @@ -83,7 +76,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Bloodcrazed Socialite", 363, Rarity.COMMON, mage.cards.b.BloodcrazedSocialite.class)); cards.add(new SetCardInfo("Bloodline Culling", 89, Rarity.RARE, mage.cards.b.BloodlineCulling.class)); cards.add(new SetCardInfo("Bloodsoaked Reveler", 395, Rarity.UNCOMMON, mage.cards.b.BloodsoakedReveler.class)); - cards.add(new SetCardInfo("Bloodsworn Knight", 364, Rarity.UNCOMMON, mage.cards.b.BloodswornKnight.class)); cards.add(new SetCardInfo("Bloodsworn Squire", 364, Rarity.UNCOMMON, mage.cards.b.BloodswornSquire.class)); cards.add(new SetCardInfo("Bloodthirsty Adversary", 129, Rarity.MYTHIC, mage.cards.b.BloodthirstyAdversary.class)); cards.add(new SetCardInfo("Bloodtithe Collector", 90, Rarity.UNCOMMON, mage.cards.b.BloodtitheCollector.class)); @@ -101,7 +93,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Bride's Gown", 271, Rarity.UNCOMMON, mage.cards.b.BridesGown.class)); cards.add(new SetCardInfo("Brimstone Vandal", 130, Rarity.COMMON, mage.cards.b.BrimstoneVandal.class)); cards.add(new SetCardInfo("Brine Comber", 500, Rarity.UNCOMMON, mage.cards.b.BrineComber.class)); - cards.add(new SetCardInfo("Brinebound Gift", 500, Rarity.UNCOMMON, mage.cards.b.BrineboundGift.class)); cards.add(new SetCardInfo("Brood Weaver", 173, Rarity.UNCOMMON, mage.cards.b.BroodWeaver.class)); cards.add(new SetCardInfo("Brutal Cathar", 7, Rarity.RARE, mage.cards.b.BrutalCathar.class)); cards.add(new SetCardInfo("Burly Breaker", 174, Rarity.UNCOMMON, mage.cards.b.BurlyBreaker.class)); @@ -114,7 +105,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Candlelit Cavalry", 175, Rarity.COMMON, mage.cards.c.CandlelitCavalry.class)); cards.add(new SetCardInfo("Candletrap", 9, Rarity.COMMON, mage.cards.c.Candletrap.class)); cards.add(new SetCardInfo("Cartographer's Survey", 457, Rarity.UNCOMMON, mage.cards.c.CartographersSurvey.class)); - cards.add(new SetCardInfo("Catapult Captain", 366, Rarity.UNCOMMON, mage.cards.c.CatapultCaptain.class)); cards.add(new SetCardInfo("Catapult Fodder", 366, Rarity.UNCOMMON, mage.cards.c.CatapultFodder.class)); cards.add(new SetCardInfo("Cathar Commando", 10, Rarity.COMMON, mage.cards.c.CatharCommando.class)); cards.add(new SetCardInfo("Cathar's Call", 11, Rarity.UNCOMMON, mage.cards.c.CatharsCall.class)); @@ -130,7 +120,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Champion of the Perished", 91, Rarity.RARE, mage.cards.c.ChampionOfThePerished.class)); cards.add(new SetCardInfo("Chandra, Dressed to Kill", 416, Rarity.MYTHIC, mage.cards.c.ChandraDressedToKill.class)); cards.add(new SetCardInfo("Change of Fortune", 417, Rarity.RARE, mage.cards.c.ChangeOfFortune.class)); - cards.add(new SetCardInfo("Chapel Shieldgeist", 13, Rarity.UNCOMMON, mage.cards.c.ChapelShieldgeist.class)); cards.add(new SetCardInfo("Chaplain of Alms", 13, Rarity.UNCOMMON, mage.cards.c.ChaplainOfAlms.class)); cards.add(new SetCardInfo("Child of the Pack", 501, Rarity.UNCOMMON, mage.cards.c.ChildOfThePack.class)); cards.add(new SetCardInfo("Chill of the Grave", 318, Rarity.COMMON, mage.cards.c.ChillOfTheGrave.class)); @@ -139,7 +128,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Circle of Confinement", 274, Rarity.UNCOMMON, mage.cards.c.CircleOfConfinement.class)); cards.add(new SetCardInfo("Clarion Cathars", 14, Rarity.COMMON, mage.cards.c.ClarionCathars.class)); cards.add(new SetCardInfo("Clear Shot", 176, Rarity.UNCOMMON, mage.cards.c.ClearShot.class)); - cards.add(new SetCardInfo("Clever Distraction", 276, Rarity.UNCOMMON, mage.cards.c.CleverDistraction.class)); cards.add(new SetCardInfo("Cloaked Cadet", 459, Rarity.UNCOMMON, mage.cards.c.CloakedCadet.class)); cards.add(new SetCardInfo("Cobbled Lancer", 319, Rarity.UNCOMMON, mage.cards.c.CobbledLancer.class)); cards.add(new SetCardInfo("Component Collector", 43, Rarity.COMMON, mage.cards.c.ComponentCollector.class)); @@ -152,7 +140,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Courier Bat", 369, Rarity.COMMON, mage.cards.c.CourierBat.class)); cards.add(new SetCardInfo("Covert Cutpurse", 92, Rarity.UNCOMMON, mage.cards.c.CovertCutpurse.class)); cards.add(new SetCardInfo("Covetous Castaway", 45, Rarity.UNCOMMON, mage.cards.c.CovetousCastaway.class)); - cards.add(new SetCardInfo("Covetous Geist", 92, Rarity.UNCOMMON, mage.cards.c.CovetousGeist.class)); cards.add(new SetCardInfo("Cradle of Safety", 321, Rarity.COMMON, mage.cards.c.CradleOfSafety.class)); cards.add(new SetCardInfo("Crawl from the Cellar", 93, Rarity.COMMON, mage.cards.c.CrawlFromTheCellar.class)); cards.add(new SetCardInfo("Crawling Infestation", 460, Rarity.UNCOMMON, mage.cards.c.CrawlingInfestation.class)); @@ -168,25 +155,19 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Curse of Shaken Faith", 134, Rarity.RARE, mage.cards.c.CurseOfShakenFaith.class)); cards.add(new SetCardInfo("Curse of Silence", 15, Rarity.RARE, mage.cards.c.CurseOfSilence.class)); cards.add(new SetCardInfo("Curse of Surveillance", 46, Rarity.RARE, mage.cards.c.CurseOfSurveillance.class)); - cards.add(new SetCardInfo("Dauntless Avenger", 4, Rarity.UNCOMMON, mage.cards.d.DauntlessAvenger.class)); cards.add(new SetCardInfo("Dawnhart Disciple", 463, Rarity.COMMON, mage.cards.d.DawnhartDisciple.class)); cards.add(new SetCardInfo("Dawnhart Geist", 275, Rarity.UNCOMMON, mage.cards.d.DawnhartGeist.class)); cards.add(new SetCardInfo("Dawnhart Mentor", 179, Rarity.UNCOMMON, mage.cards.d.DawnhartMentor.class)); cards.add(new SetCardInfo("Dawnhart Rejuvenator", 180, Rarity.COMMON, mage.cards.d.DawnhartRejuvenator.class)); cards.add(new SetCardInfo("Dawnhart Wardens", 216, Rarity.UNCOMMON, mage.cards.d.DawnhartWardens.class)); cards.add(new SetCardInfo("Daybreak Combatants", 420, Rarity.COMMON, mage.cards.d.DaybreakCombatants.class)); - cards.add(new SetCardInfo("Deadly Dancer", 408, Rarity.UNCOMMON, mage.cards.d.DeadlyDancer.class)); - cards.add(new SetCardInfo("Deathbonnet Hulk", 181, Rarity.UNCOMMON, mage.cards.d.DeathbonnetHulk.class)); cards.add(new SetCardInfo("Deathbonnet Sprout", 181, Rarity.UNCOMMON, mage.cards.d.DeathbonnetSprout.class)); cards.add(new SetCardInfo("Deathcap Glade", 528, Rarity.RARE, mage.cards.d.DeathcapGlade.class)); cards.add(new SetCardInfo("Defend the Celestus", 182, Rarity.UNCOMMON, mage.cards.d.DefendTheCelestus.class)); cards.add(new SetCardInfo("Defenestrate", 95, Rarity.COMMON, mage.cards.d.Defenestrate.class)); cards.add(new SetCardInfo("Delver of Secrets", 47, Rarity.UNCOMMON, mage.cards.d.DelverOfSecrets.class)); cards.add(new SetCardInfo("Demonic Bargain", 370, Rarity.RARE, mage.cards.d.DemonicBargain.class)); - cards.add(new SetCardInfo("Dennick, Pious Apparition", 217, Rarity.RARE, mage.cards.d.DennickPiousApparition.class)); cards.add(new SetCardInfo("Dennick, Pious Apprentice", 217, Rarity.RARE, mage.cards.d.DennickPiousApprentice.class)); - cards.add(new SetCardInfo("Departed Soulkeeper", 218, Rarity.UNCOMMON, mage.cards.d.DepartedSoulkeeper.class)); - cards.add(new SetCardInfo("Depraved Harvester", 371, Rarity.COMMON, mage.cards.d.DepravedHarvester.class)); cards.add(new SetCardInfo("Deserted Beach", 260, Rarity.RARE, mage.cards.d.DesertedBeach.class)); cards.add(new SetCardInfo("Desperate Farmer", 371, Rarity.COMMON, mage.cards.d.DesperateFarmer.class)); cards.add(new SetCardInfo("Devious Cover-Up", 48, Rarity.COMMON, mage.cards.d.DeviousCoverUp.class)); @@ -194,7 +175,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Dig Up", 464, Rarity.RARE, mage.cards.d.DigUp.class)); cards.add(new SetCardInfo("Dire-Strain Anarchist", 448, Rarity.MYTHIC, mage.cards.d.DireStrainAnarchist.class)); cards.add(new SetCardInfo("Dire-Strain Brawler", 203, Rarity.COMMON, mage.cards.d.DireStrainBrawler.class)); - cards.add(new SetCardInfo("Dire-Strain Demolisher", 174, Rarity.UNCOMMON, mage.cards.d.DireStrainDemolisher.class)); cards.add(new SetCardInfo("Dire-Strain Rampage", 219, Rarity.RARE, mage.cards.d.DireStrainRampage.class)); cards.add(new SetCardInfo("Diregraf Horde", 96, Rarity.COMMON, mage.cards.d.DiregrafHorde.class)); cards.add(new SetCardInfo("Diregraf Rebirth", 220, Rarity.UNCOMMON, mage.cards.d.DiregrafRebirth.class)); @@ -206,7 +186,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Dominating Vampire", 421, Rarity.RARE, mage.cards.d.DominatingVampire.class)); cards.add(new SetCardInfo("Doomed Dissenter", 373, Rarity.COMMON, mage.cards.d.DoomedDissenter.class)); cards.add(new SetCardInfo("Dormant Grove", 465, Rarity.UNCOMMON, mage.cards.d.DormantGrove.class)); - cards.add(new SetCardInfo("Dorothea's Retribution", 502, Rarity.RARE, mage.cards.d.DorotheasRetribution.class)); cards.add(new SetCardInfo("Dorothea, Vengeful Victim", 502, Rarity.RARE, mage.cards.d.DorotheaVengefulVictim.class)); cards.add(new SetCardInfo("Dread Fugue", 374, Rarity.UNCOMMON, mage.cards.d.DreadFugue.class)); cards.add(new SetCardInfo("Dreadfeast Demon", 375, Rarity.RARE, mage.cards.d.DreadfeastDemon.class)); @@ -214,7 +193,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Dreadlight Monstrosity", 324, Rarity.COMMON, mage.cards.d.DreadlightMonstrosity.class)); cards.add(new SetCardInfo("Dreamroot Cascade", 529, Rarity.RARE, mage.cards.d.DreamrootCascade.class)); cards.add(new SetCardInfo("Dreamshackle Geist", 325, Rarity.RARE, mage.cards.d.DreamshackleGeist.class)); - cards.add(new SetCardInfo("Drogskol Armaments", 277, Rarity.COMMON, mage.cards.d.DrogskolArmaments.class)); cards.add(new SetCardInfo("Drogskol Infantry", 277, Rarity.COMMON, mage.cards.d.DrogskolInfantry.class)); cards.add(new SetCardInfo("Drownyard Amalgam", 50, Rarity.COMMON, mage.cards.d.DrownyardAmalgam.class)); cards.add(new SetCardInfo("Dryad's Revival", 183, Rarity.UNCOMMON, mage.cards.d.DryadsRevival.class)); @@ -225,7 +203,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Eaten Alive", 99, Rarity.COMMON, mage.cards.e.EatenAlive.class)); cards.add(new SetCardInfo("Eccentric Farmer", 185, Rarity.COMMON, mage.cards.e.EccentricFarmer.class)); cards.add(new SetCardInfo("Ecstatic Awakener", 100, Rarity.COMMON, mage.cards.e.EcstaticAwakener.class)); - cards.add(new SetCardInfo("Edgar Markov's Coffin", 503, Rarity.RARE, mage.cards.e.EdgarMarkovsCoffin.class)); cards.add(new SetCardInfo("Edgar's Awakening", 377, Rarity.UNCOMMON, mage.cards.e.EdgarsAwakening.class)); cards.add(new SetCardInfo("Edgar, Charmed Groom", 503, Rarity.RARE, mage.cards.e.EdgarCharmedGroom.class)); cards.add(new SetCardInfo("Electric Revelation", 135, Rarity.COMMON, mage.cards.e.ElectricRevelation.class)); @@ -278,17 +255,14 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Geistflame Reservoir", 142, Rarity.RARE, mage.cards.g.GeistflameReservoir.class)); cards.add(new SetCardInfo("Geistlight Snare", 327, Rarity.UNCOMMON, mage.cards.g.GeistlightSnare.class)); cards.add(new SetCardInfo("Geistwave", 56, Rarity.COMMON, mage.cards.g.Geistwave.class)); - cards.add(new SetCardInfo("Generous Soul", 3, Rarity.UNCOMMON, mage.cards.g.GenerousSoul.class)); cards.add(new SetCardInfo("Geralf, Visionary Stitcher", 328, Rarity.RARE, mage.cards.g.GeralfVisionaryStitcher.class)); cards.add(new SetCardInfo("Ghastly Mimicry", 335, Rarity.RARE, mage.cards.g.GhastlyMimicry.class)); - cards.add(new SetCardInfo("Ghostly Castigator", 45, Rarity.UNCOMMON, mage.cards.g.GhostlyCastigator.class)); cards.add(new SetCardInfo("Ghoulcaller's Harvest", 225, Rarity.RARE, mage.cards.g.GhoulcallersHarvest.class)); cards.add(new SetCardInfo("Ghoulish Procession", 102, Rarity.UNCOMMON, mage.cards.g.GhoulishProcession.class)); cards.add(new SetCardInfo("Gift of Fangs", 380, Rarity.COMMON, mage.cards.g.GiftOfFangs.class)); cards.add(new SetCardInfo("Gisa, Glorious Resurrector", 103, Rarity.RARE, mage.cards.g.GisaGloriousResurrector.class)); cards.add(new SetCardInfo("Glorious Sunrise", 467, Rarity.RARE, mage.cards.g.GloriousSunrise.class)); cards.add(new SetCardInfo("Gluttonous Guest", 381, Rarity.COMMON, mage.cards.g.GluttonousGuest.class)); - cards.add(new SetCardInfo("Gnarled Grovestrider", 465, Rarity.UNCOMMON, mage.cards.g.GnarledGrovestrider.class)); cards.add(new SetCardInfo("Graf Reaver", 382, Rarity.RARE, mage.cards.g.GrafReaver.class)); cards.add(new SetCardInfo("Grafted Identity", 57, Rarity.RARE, mage.cards.g.GraftedIdentity.class)); cards.add(new SetCardInfo("Graveyard Glutton", 104, Rarity.RARE, mage.cards.g.GraveyardGlutton.class)); @@ -320,11 +294,9 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Heron-Blessed Geist", 286, Rarity.COMMON, mage.cards.h.HeronBlessedGeist.class)); cards.add(new SetCardInfo("Hiveheart Shaman", 469, Rarity.RARE, mage.cards.h.HiveheartShaman.class)); cards.add(new SetCardInfo("Hobbling Zombie", 106, Rarity.COMMON, mage.cards.h.HobblingZombie.class)); - cards.add(new SetCardInfo("Hollowhenge Huntmaster", 454, Rarity.MYTHIC, mage.cards.h.HollowhengeHuntmaster.class)); cards.add(new SetCardInfo("Homestead Courage", 24, Rarity.COMMON, mage.cards.h.HomesteadCourage.class)); cards.add(new SetCardInfo("Honeymoon Hearse", 427, Rarity.UNCOMMON, mage.cards.h.HoneymoonHearse.class)); cards.add(new SetCardInfo("Honored Heirloom", 524, Rarity.COMMON, mage.cards.h.HonoredHeirloom.class)); - cards.add(new SetCardInfo("Hook-Haunt Drifter", 42, Rarity.COMMON, mage.cards.h.HookHauntDrifter.class)); cards.add(new SetCardInfo("Hookhand Mariner", 470, Rarity.COMMON, mage.cards.h.HookhandMariner.class)); cards.add(new SetCardInfo("Hopeful Initiate", 287, Rarity.RARE, mage.cards.h.HopefulInitiate.class)); cards.add(new SetCardInfo("Hostile Hostel", 264, Rarity.MYTHIC, mage.cards.h.HostileHostel.class)); @@ -343,7 +315,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Infested Werewolf", 473, Rarity.UNCOMMON, mage.cards.i.InfestedWerewolf.class)); cards.add(new SetCardInfo("Inherited Fiend", 105, Rarity.UNCOMMON, mage.cards.i.InheritedFiend.class)); cards.add(new SetCardInfo("Innocent Traveler", 388, Rarity.UNCOMMON, mage.cards.i.InnocentTraveler.class)); - cards.add(new SetCardInfo("Insectile Aberration", 47, Rarity.UNCOMMON, mage.cards.i.InsectileAberration.class)); cards.add(new SetCardInfo("Inspired Idea", 331, Rarity.RARE, mage.cards.i.InspiredIdea.class)); cards.add(new SetCardInfo("Into the Night", 430, Rarity.UNCOMMON, mage.cards.i.IntoTheNight.class)); cards.add(new SetCardInfo("Intrepid Adversary", 25, Rarity.MYTHIC, mage.cards.i.IntrepidAdversary.class)); @@ -372,7 +343,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Lantern of the Lost", 526, Rarity.UNCOMMON, mage.cards.l.LanternOfTheLost.class)); cards.add(new SetCardInfo("Lanterns' Lift", 333, Rarity.COMMON, mage.cards.l.LanternsLift.class)); cards.add(new SetCardInfo("Larder Zombie", 58, Rarity.COMMON, mage.cards.l.LarderZombie.class)); - cards.add(new SetCardInfo("Leeching Lurker", 94, Rarity.RARE, mage.cards.l.LeechingLurker.class)); cards.add(new SetCardInfo("Lier, Disciple of the Drowned", 59, Rarity.MYTHIC, mage.cards.l.LierDiscipleOfTheDrowned.class)); cards.add(new SetCardInfo("Liesa, Forgotten Archangel", 232, Rarity.RARE, mage.cards.l.LiesaForgottenArchangel.class)); cards.add(new SetCardInfo("Light Up the Night", 146, Rarity.RARE, mage.cards.l.LightUpTheNight.class)); @@ -403,7 +373,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Mischievous Catgeist", 336, Rarity.UNCOMMON, mage.cards.m.MischievousCatgeist.class)); cards.add(new SetCardInfo("Moldgraf Millipede", 476, Rarity.COMMON, mage.cards.m.MoldgrafMillipede.class)); cards.add(new SetCardInfo("Moonlit Ambusher", 479, Rarity.UNCOMMON, mage.cards.m.MoonlitAmbusher.class)); - cards.add(new SetCardInfo("Moonrage Brute", 7, Rarity.RARE, mage.cards.m.MoonrageBrute.class)); cards.add(new SetCardInfo("Moonrager's Slash", 148, Rarity.COMMON, mage.cards.m.MoonragersSlash.class)); cards.add(new SetCardInfo("Moonsilver Key", 255, Rarity.UNCOMMON, mage.cards.m.MoonsilverKey.class)); cards.add(new SetCardInfo("Moonveil Regent", 149, Rarity.MYTHIC, mage.cards.m.MoonveilRegent.class)); @@ -481,7 +450,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Restless Bloodseeker", 395, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class)); cards.add(new SetCardInfo("Retrieve", 482, Rarity.UNCOMMON, mage.cards.r.Retrieve.class)); cards.add(new SetCardInfo("Return to Nature", 195, Rarity.COMMON, mage.cards.r.ReturnToNature.class)); - cards.add(new SetCardInfo("Revealing Eye", 368, Rarity.RARE, mage.cards.r.RevealingEye.class)); cards.add(new SetCardInfo("Revenge of the Drowned", 72, Rarity.COMMON, mage.cards.r.RevengeOfTheDrowned.class)); cards.add(new SetCardInfo("Riphook Raider", 470, Rarity.COMMON, mage.cards.r.RiphookRaider.class)); cards.add(new SetCardInfo("Rise of the Ants", 196, Rarity.UNCOMMON, mage.cards.r.RiseOfTheAnts.class)); @@ -500,14 +468,12 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Sanctify", 300, Rarity.COMMON, mage.cards.s.Sanctify.class)); cards.add(new SetCardInfo("Sanguine Statuette", 444, Rarity.UNCOMMON, mage.cards.s.SanguineStatuette.class)); cards.add(new SetCardInfo("Saryth, the Viper's Fang", 197, Rarity.RARE, mage.cards.s.SarythTheVipersFang.class)); - cards.add(new SetCardInfo("Savage Packmate", 501, Rarity.UNCOMMON, mage.cards.s.SavagePackmate.class)); cards.add(new SetCardInfo("Savior of Ollenbock", 301, Rarity.MYTHIC, mage.cards.s.SaviorOfOllenbock.class)); cards.add(new SetCardInfo("Sawblade Slinger", 484, Rarity.UNCOMMON, mage.cards.s.SawbladeSlinger.class)); cards.add(new SetCardInfo("Scattered Thoughts", 341, Rarity.COMMON, mage.cards.s.ScatteredThoughts.class)); cards.add(new SetCardInfo("Screaming Swarm", 342, Rarity.UNCOMMON, mage.cards.s.ScreamingSwarm.class)); cards.add(new SetCardInfo("Seafaring Werewolf", 80, Rarity.RARE, mage.cards.s.SeafaringWerewolf.class)); cards.add(new SetCardInfo("Search Party Captain", 32, Rarity.COMMON, mage.cards.s.SearchPartyCaptain.class)); - cards.add(new SetCardInfo("Seasoned Cathar", 2, Rarity.UNCOMMON, mage.cards.s.SeasonedCathar.class)); cards.add(new SetCardInfo("Secrets of the Key", 73, Rarity.COMMON, mage.cards.s.SecretsOfTheKey.class)); cards.add(new SetCardInfo("Seize the Storm", 158, Rarity.UNCOMMON, mage.cards.s.SeizeTheStorm.class)); cards.add(new SetCardInfo("Selhoff Entomber", 343, Rarity.COMMON, mage.cards.s.SelhoffEntomber.class)); @@ -526,7 +492,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Sigardian Paladin", 514, Rarity.UNCOMMON, mage.cards.s.SigardianPaladin.class)); cards.add(new SetCardInfo("Sigardian Savior", 34, Rarity.MYTHIC, mage.cards.s.SigardianSavior.class)); cards.add(new SetCardInfo("Silver Bolt", 258, Rarity.COMMON, mage.cards.s.SilverBolt.class)); - cards.add(new SetCardInfo("Sinner's Judgment", 279, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class)); cards.add(new SetCardInfo("Siphon Insight", 241, Rarity.RARE, mage.cards.s.SiphonInsight.class)); cards.add(new SetCardInfo("Skaab Wrangler", 75, Rarity.UNCOMMON, mage.cards.s.SkaabWrangler.class)); cards.add(new SetCardInfo("Skulking Killer", 397, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class)); @@ -542,7 +507,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Soul-Guide Gryff", 35, Rarity.COMMON, mage.cards.s.SoulGuideGryff.class)); cards.add(new SetCardInfo("Soulcipher Board", 346, Rarity.UNCOMMON, mage.cards.s.SoulcipherBoard.class)); cards.add(new SetCardInfo("Spectral Adversary", 77, Rarity.MYTHIC, mage.cards.s.SpectralAdversary.class)); - cards.add(new SetCardInfo("Spectral Binding", 315, Rarity.COMMON, mage.cards.s.SpectralBinding.class)); cards.add(new SetCardInfo("Spellrune Howler", 160, Rarity.UNCOMMON, mage.cards.s.SpellruneHowler.class)); cards.add(new SetCardInfo("Spellrune Painter", 160, Rarity.UNCOMMON, mage.cards.s.SpellrunePainter.class)); cards.add(new SetCardInfo("Spiked Ripsaw", 487, Rarity.UNCOMMON, mage.cards.s.SpikedRipsaw.class)); @@ -633,7 +597,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Voldaren Stinger", 167, Rarity.COMMON, mage.cards.v.VoldarenStinger.class)); cards.add(new SetCardInfo("Volt-Charged Berserker", 450, Rarity.UNCOMMON, mage.cards.v.VoltChargedBerserker.class)); cards.add(new SetCardInfo("Voltaic Visionary", 450, Rarity.UNCOMMON, mage.cards.v.VoltaicVisionary.class)); - cards.add(new SetCardInfo("Waildrifter", 55, Rarity.COMMON, mage.cards.w.Waildrifter.class)); cards.add(new SetCardInfo("Wake to Slaughter", 250, Rarity.RARE, mage.cards.w.WakeToSlaughter.class)); cards.add(new SetCardInfo("Wandering Mind", 518, Rarity.UNCOMMON, mage.cards.w.WanderingMind.class)); cards.add(new SetCardInfo("Wanderlight Spirit", 353, Rarity.COMMON, mage.cards.w.WanderlightSpirit.class)); @@ -649,7 +612,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Whispering Wizard", 355, Rarity.UNCOMMON, mage.cards.w.WhisperingWizard.class)); cards.add(new SetCardInfo("Wildsong Howler", 472, Rarity.RARE, mage.cards.w.WildsongHowler.class)); cards.add(new SetCardInfo("Willow Geist", 207, Rarity.RARE, mage.cards.w.WillowGeist.class)); - cards.add(new SetCardInfo("Wing Shredder", 169, Rarity.COMMON, mage.cards.w.WingShredder.class)); cards.add(new SetCardInfo("Winged Portent", 356, Rarity.RARE, mage.cards.w.WingedPortent.class)); cards.add(new SetCardInfo("Winterthorn Blessing", 251, Rarity.UNCOMMON, mage.cards.w.WinterthornBlessing.class)); cards.add(new SetCardInfo("Witch's Web", 494, Rarity.COMMON, mage.cards.w.WitchsWeb.class)); diff --git a/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java b/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java index 5617a15cdf1..34a26a0de74 100644 --- a/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java +++ b/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java @@ -42,17 +42,11 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Abandon the Post", 127, Rarity.COMMON, mage.cards.a.AbandonThePost.class)); cards.add(new SetCardInfo("Adeline, Resplendent Cathar", 1, Rarity.RARE, mage.cards.a.AdelineResplendentCathar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Adeline, Resplendent Cathar", 312, Rarity.RARE, mage.cards.a.AdelineResplendentCathar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ambitious Farmhand", 2, Rarity.UNCOMMON, mage.cards.a.AmbitiousFarmhand.class)); cards.add(new SetCardInfo("Angelfire Ignition", 209, Rarity.RARE, mage.cards.a.AngelfireIgnition.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Angelfire Ignition", 367, Rarity.RARE, mage.cards.a.AngelfireIgnition.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Angelic Enforcer", 17, Rarity.MYTHIC, mage.cards.a.AngelicEnforcer.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Angelic Enforcer", 327, Rarity.MYTHIC, mage.cards.a.AngelicEnforcer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arcane Infusion", 210, Rarity.UNCOMMON, mage.cards.a.ArcaneInfusion.class)); cards.add(new SetCardInfo("Archive Haunt", 68, Rarity.UNCOMMON, mage.cards.a.ArchiveHaunt.class)); cards.add(new SetCardInfo("Ardent Elementalist", 128, Rarity.COMMON, mage.cards.a.ArdentElementalist.class)); - cards.add(new SetCardInfo("Arlinn, the Moon's Fury", 211, Rarity.MYTHIC, mage.cards.a.ArlinnTheMoonsFury.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arlinn, the Moon's Fury", 279, Rarity.MYTHIC, mage.cards.a.ArlinnTheMoonsFury.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arlinn, the Moon's Fury", 307, Rarity.MYTHIC, mage.cards.a.ArlinnTheMoonsFury.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn, the Pack's Hope", 211, Rarity.MYTHIC, mage.cards.a.ArlinnThePacksHope.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn, the Pack's Hope", 279, Rarity.MYTHIC, mage.cards.a.ArlinnThePacksHope.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn, the Pack's Hope", 307, Rarity.MYTHIC, mage.cards.a.ArlinnThePacksHope.class, NON_FULL_USE_VARIOUS)); @@ -61,12 +55,9 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Ashmouth Dragon", 358, Rarity.RARE, mage.cards.a.AshmouthDragon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Augur of Autumn", 168, Rarity.RARE, mage.cards.a.AugurOfAutumn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Augur of Autumn", 360, Rarity.RARE, mage.cards.a.AugurOfAutumn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Awoken Demon", 100, Rarity.COMMON, mage.cards.a.AwokenDemon.class)); cards.add(new SetCardInfo("Baithook Angler", 42, Rarity.COMMON, mage.cards.b.BaithookAngler.class)); cards.add(new SetCardInfo("Baneblade Scoundrel", 289, Rarity.UNCOMMON, mage.cards.b.BanebladeScoundrel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Baneblade Scoundrel", 85, Rarity.UNCOMMON, mage.cards.b.BanebladeScoundrel.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Baneclaw Marauder", 289, Rarity.UNCOMMON, mage.cards.b.BaneclawMarauder.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Baneclaw Marauder", 85, Rarity.UNCOMMON, mage.cards.b.BaneclawMarauder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bat Whisperer", 86, Rarity.COMMON, mage.cards.b.BatWhisperer.class)); cards.add(new SetCardInfo("Beloved Beggar", 3, Rarity.UNCOMMON, mage.cards.b.BelovedBeggar.class)); cards.add(new SetCardInfo("Benevolent Geist", 336, Rarity.RARE, mage.cards.b.BenevolentGeist.class, NON_FULL_USE_VARIOUS)); @@ -110,7 +101,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Champion of the Perished", 344, Rarity.RARE, mage.cards.c.ChampionOfThePerished.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Champion of the Perished", 385, Rarity.RARE, mage.cards.c.ChampionOfThePerished.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Champion of the Perished", 91, Rarity.RARE, mage.cards.c.ChampionOfThePerished.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chapel Shieldgeist", 13, Rarity.UNCOMMON, mage.cards.c.ChapelShieldgeist.class)); cards.add(new SetCardInfo("Chaplain of Alms", 13, Rarity.UNCOMMON, mage.cards.c.ChaplainOfAlms.class)); cards.add(new SetCardInfo("Chilling Chronicle", 63, Rarity.UNCOMMON, mage.cards.c.ChillingChronicle.class)); cards.add(new SetCardInfo("Clarion Cathars", 14, Rarity.COMMON, mage.cards.c.ClarionCathars.class)); @@ -124,7 +114,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Corpse Cobble", 214, Rarity.UNCOMMON, mage.cards.c.CorpseCobble.class)); cards.add(new SetCardInfo("Covert Cutpurse", 92, Rarity.UNCOMMON, mage.cards.c.CovertCutpurse.class)); cards.add(new SetCardInfo("Covetous Castaway", 45, Rarity.UNCOMMON, mage.cards.c.CovetousCastaway.class)); - cards.add(new SetCardInfo("Covetous Geist", 92, Rarity.UNCOMMON, mage.cards.c.CovetousGeist.class)); cards.add(new SetCardInfo("Crawl from the Cellar", 93, Rarity.COMMON, mage.cards.c.CrawlFromTheCellar.class)); cards.add(new SetCardInfo("Creeping Inn", 264, Rarity.MYTHIC, mage.cards.c.CreepingInn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Creeping Inn", 379, Rarity.MYTHIC, mage.cards.c.CreepingInn.class, NON_FULL_USE_VARIOUS)); @@ -139,31 +128,24 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Curse of Silence", 326, Rarity.RARE, mage.cards.c.CurseOfSilence.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Curse of Surveillance", 334, Rarity.RARE, mage.cards.c.CurseOfSurveillance.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Curse of Surveillance", 46, Rarity.RARE, mage.cards.c.CurseOfSurveillance.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dauntless Avenger", 4, Rarity.UNCOMMON, mage.cards.d.DauntlessAvenger.class)); cards.add(new SetCardInfo("Dawnhart Mentor", 179, Rarity.UNCOMMON, mage.cards.d.DawnhartMentor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dawnhart Mentor", 300, Rarity.UNCOMMON, mage.cards.d.DawnhartMentor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dawnhart Rejuvenator", 180, Rarity.COMMON, mage.cards.d.DawnhartRejuvenator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dawnhart Rejuvenator", 301, Rarity.COMMON, mage.cards.d.DawnhartRejuvenator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dawnhart Wardens", 216, Rarity.UNCOMMON, mage.cards.d.DawnhartWardens.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dawnhart Wardens", 308, Rarity.UNCOMMON, mage.cards.d.DawnhartWardens.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Deathbonnet Hulk", 181, Rarity.UNCOMMON, mage.cards.d.DeathbonnetHulk.class)); cards.add(new SetCardInfo("Deathbonnet Sprout", 181, Rarity.UNCOMMON, mage.cards.d.DeathbonnetSprout.class)); cards.add(new SetCardInfo("Defend the Celestus", 182, Rarity.UNCOMMON, mage.cards.d.DefendTheCelestus.class)); cards.add(new SetCardInfo("Defenestrate", 95, Rarity.COMMON, mage.cards.d.Defenestrate.class)); cards.add(new SetCardInfo("Delver of Secrets", 47, Rarity.UNCOMMON, mage.cards.d.DelverOfSecrets.class)); - cards.add(new SetCardInfo("Dennick, Pious Apparition", 217, Rarity.RARE, mage.cards.d.DennickPiousApparition.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dennick, Pious Apparition", 317, Rarity.RARE, mage.cards.d.DennickPiousApparition.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dennick, Pious Apprentice", 217, Rarity.RARE, mage.cards.d.DennickPiousApprentice.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dennick, Pious Apprentice", 317, Rarity.RARE, mage.cards.d.DennickPiousApprentice.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Departed Soulkeeper", 218, Rarity.UNCOMMON, mage.cards.d.DepartedSoulkeeper.class)); cards.add(new SetCardInfo("Deserted Beach", 260, Rarity.RARE, mage.cards.d.DesertedBeach.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Deserted Beach", 281, Rarity.RARE, mage.cards.d.DesertedBeach.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Devious Cover-Up", 48, Rarity.COMMON, mage.cards.d.DeviousCoverUp.class)); cards.add(new SetCardInfo("Devoted Grafkeeper", 218, Rarity.UNCOMMON, mage.cards.d.DevotedGrafkeeper.class)); cards.add(new SetCardInfo("Dire-Strain Brawler", 203, Rarity.COMMON, mage.cards.d.DireStrainBrawler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dire-Strain Brawler", 305, Rarity.COMMON, mage.cards.d.DireStrainBrawler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire-Strain Demolisher", 174, Rarity.UNCOMMON, mage.cards.d.DireStrainDemolisher.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire-Strain Demolisher", 299, Rarity.UNCOMMON, mage.cards.d.DireStrainDemolisher.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dire-Strain Rampage", 219, Rarity.RARE, mage.cards.d.DireStrainRampage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dire-Strain Rampage", 370, Rarity.RARE, mage.cards.d.DireStrainRampage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Diregraf Horde", 96, Rarity.COMMON, mage.cards.d.DiregrafHorde.class)); @@ -221,8 +203,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Geistflame Reservoir", 142, Rarity.RARE, mage.cards.g.GeistflameReservoir.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Geistflame Reservoir", 355, Rarity.RARE, mage.cards.g.GeistflameReservoir.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Geistwave", 56, Rarity.COMMON, mage.cards.g.Geistwave.class)); - cards.add(new SetCardInfo("Generous Soul", 3, Rarity.UNCOMMON, mage.cards.g.GenerousSoul.class)); - cards.add(new SetCardInfo("Ghostly Castigator", 45, Rarity.UNCOMMON, mage.cards.g.GhostlyCastigator.class)); cards.add(new SetCardInfo("Ghoulcaller's Harvest", 225, Rarity.RARE, mage.cards.g.GhoulcallersHarvest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghoulcaller's Harvest", 372, Rarity.RARE, mage.cards.g.GhoulcallersHarvest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghoulish Procession", 102, Rarity.UNCOMMON, mage.cards.g.GhoulishProcession.class)); @@ -248,7 +228,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Heirloom Mirror", 105, Rarity.UNCOMMON, mage.cards.h.HeirloomMirror.class)); cards.add(new SetCardInfo("Hobbling Zombie", 106, Rarity.COMMON, mage.cards.h.HobblingZombie.class)); cards.add(new SetCardInfo("Homestead Courage", 24, Rarity.COMMON, mage.cards.h.HomesteadCourage.class)); - cards.add(new SetCardInfo("Hook-Haunt Drifter", 42, Rarity.COMMON, mage.cards.h.HookHauntDrifter.class)); cards.add(new SetCardInfo("Hostile Hostel", 264, Rarity.MYTHIC, mage.cards.h.HostileHostel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hostile Hostel", 379, Rarity.MYTHIC, mage.cards.h.HostileHostel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hound Tamer", 187, Rarity.UNCOMMON, mage.cards.h.HoundTamer.class, NON_FULL_USE_VARIOUS)); @@ -259,7 +238,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Infernal Grasp", 107, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Infernal Grasp", 389, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Inherited Fiend", 105, Rarity.UNCOMMON, mage.cards.i.InheritedFiend.class)); - cards.add(new SetCardInfo("Insectile Aberration", 47, Rarity.UNCOMMON, mage.cards.i.InsectileAberration.class)); cards.add(new SetCardInfo("Intrepid Adversary", 25, Rarity.MYTHIC, mage.cards.i.IntrepidAdversary.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Intrepid Adversary", 329, Rarity.MYTHIC, mage.cards.i.IntrepidAdversary.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 270, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); @@ -278,8 +256,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Kessig Naturalist", 310, Rarity.UNCOMMON, mage.cards.k.KessigNaturalist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lambholt Harrier", 145, Rarity.COMMON, mage.cards.l.LambholtHarrier.class)); cards.add(new SetCardInfo("Larder Zombie", 58, Rarity.COMMON, mage.cards.l.LarderZombie.class)); - cards.add(new SetCardInfo("Leeching Lurker", 345, Rarity.RARE, mage.cards.l.LeechingLurker.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Leeching Lurker", 94, Rarity.RARE, mage.cards.l.LeechingLurker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lier, Disciple of the Drowned", 313, Rarity.MYTHIC, mage.cards.l.LierDiscipleOfTheDrowned.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lier, Disciple of the Drowned", 59, Rarity.MYTHIC, mage.cards.l.LierDiscipleOfTheDrowned.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Liesa, Forgotten Archangel", 232, Rarity.RARE, mage.cards.l.LiesaForgottenArchangel.class, NON_FULL_USE_VARIOUS)); @@ -304,8 +280,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Memory Deluge", 337, Rarity.RARE, mage.cards.m.MemoryDeluge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Memory Deluge", 62, Rarity.RARE, mage.cards.m.MemoryDeluge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Might of the Old Ways", 189, Rarity.COMMON, mage.cards.m.MightOfTheOldWays.class)); - cards.add(new SetCardInfo("Moonrage Brute", 286, Rarity.RARE, mage.cards.m.MoonrageBrute.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Moonrage Brute", 7, Rarity.RARE, mage.cards.m.MoonrageBrute.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Moonrager's Slash", 148, Rarity.COMMON, mage.cards.m.MoonragersSlash.class)); cards.add(new SetCardInfo("Moonsilver Key", 255, Rarity.UNCOMMON, mage.cards.m.MoonsilverKey.class)); cards.add(new SetCardInfo("Moonveil Regent", 149, Rarity.MYTHIC, mage.cards.m.MoonveilRegent.class, NON_FULL_USE_VARIOUS)); @@ -387,7 +361,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Seafaring Werewolf", 288, Rarity.RARE, mage.cards.s.SeafaringWerewolf.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Seafaring Werewolf", 80, Rarity.RARE, mage.cards.s.SeafaringWerewolf.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Search Party Captain", 32, Rarity.COMMON, mage.cards.s.SearchPartyCaptain.class)); - cards.add(new SetCardInfo("Seasoned Cathar", 2, Rarity.UNCOMMON, mage.cards.s.SeasonedCathar.class)); cards.add(new SetCardInfo("Secrets of the Key", 73, Rarity.COMMON, mage.cards.s.SecretsOfTheKey.class)); cards.add(new SetCardInfo("Seize the Storm", 158, Rarity.UNCOMMON, mage.cards.s.SeizeTheStorm.class)); cards.add(new SetCardInfo("Shadowbeast Sighting", 198, Rarity.COMMON, mage.cards.s.ShadowbeastSighting.class)); @@ -499,13 +472,10 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Vivisection", 83, Rarity.UNCOMMON, mage.cards.v.Vivisection.class)); cards.add(new SetCardInfo("Voldaren Ambusher", 166, Rarity.UNCOMMON, mage.cards.v.VoldarenAmbusher.class)); cards.add(new SetCardInfo("Voldaren Stinger", 167, Rarity.COMMON, mage.cards.v.VoldarenStinger.class)); - cards.add(new SetCardInfo("Waildrifter", 55, Rarity.COMMON, mage.cards.w.Waildrifter.class)); cards.add(new SetCardInfo("Wake to Slaughter", 250, Rarity.RARE, mage.cards.w.WakeToSlaughter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wake to Slaughter", 376, Rarity.RARE, mage.cards.w.WakeToSlaughter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Willow Geist", 207, Rarity.RARE, mage.cards.w.WillowGeist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Willow Geist", 366, Rarity.RARE, mage.cards.w.WillowGeist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wing Shredder", 169, Rarity.COMMON, mage.cards.w.WingShredder.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wing Shredder", 298, Rarity.COMMON, mage.cards.w.WingShredder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Winterthorn Blessing", 251, Rarity.UNCOMMON, mage.cards.w.WinterthornBlessing.class)); cards.add(new SetCardInfo("Wrenn and Seven", 208, Rarity.MYTHIC, mage.cards.w.WrennAndSeven.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wrenn and Seven", 278, Rarity.MYTHIC, mage.cards.w.WrennAndSeven.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/InnistradRemastered.java b/Mage.Sets/src/mage/sets/InnistradRemastered.java index cb192ab1fb0..929fbb28697 100644 --- a/Mage.Sets/src/mage/sets/InnistradRemastered.java +++ b/Mage.Sets/src/mage/sets/InnistradRemastered.java @@ -35,8 +35,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Alchemist's Greeting", 140, Rarity.COMMON, mage.cards.a.AlchemistsGreeting.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Alchemist's Greeting", 393, Rarity.COMMON, mage.cards.a.AlchemistsGreeting.class,RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Altered Ego", 228, Rarity.RARE, mage.cards.a.AlteredEgo.class)); - cards.add(new SetCardInfo("Ambitious Farmhand", 448, Rarity.UNCOMMON, mage.cards.a.AmbitiousFarmhand.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Ambitious Farmhand", 8, Rarity.UNCOMMON, mage.cards.a.AmbitiousFarmhand.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ambush Viper", 186, Rarity.COMMON, mage.cards.a.AmbushViper.class)); cards.add(new SetCardInfo("Ancestral Anger", 141, Rarity.COMMON, mage.cards.a.AncestralAnger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ancestral Anger", 394, Rarity.COMMON, mage.cards.a.AncestralAnger.class,RETRO_ART_USE_VARIOUS)); @@ -52,22 +50,14 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Archghoul of Thraben", 95, Rarity.UNCOMMON, mage.cards.a.ArchghoulOfThraben.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn Kord", 230, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn Kord", 324, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 230, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 324, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ashmouth Blade", 269, Rarity.UNCOMMON, mage.cards.a.AshmouthBlade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ashmouth Blade", 473, Rarity.UNCOMMON, mage.cards.a.AshmouthBlade.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Asylum Visitor", 371, Rarity.UNCOMMON, mage.cards.a.AsylumVisitor.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Asylum Visitor", 96, Rarity.UNCOMMON, mage.cards.a.AsylumVisitor.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aurora of Emrakul", 260, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aurora of Emrakul", 472, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Avacyn, Angel of Hope", 477, Rarity.MYTHIC, mage.cards.a.AvacynAngelOfHope.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Avacyn, Angel of Hope", 482, Rarity.MYTHIC, mage.cards.a.AvacynAngelOfHope.class, FULL_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 11, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 449, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Avacynian Priest", 12, Rarity.COMMON, mage.cards.a.AvacynianPriest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avacynian Priest", 334, Rarity.COMMON, mage.cards.a.AvacynianPriest.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Awoken Demon", 107, Rarity.COMMON, mage.cards.a.AwokenDemon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Awoken Demon", 462, Rarity.COMMON, mage.cards.a.AwokenDemon.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Awoken Horror", 460, Rarity.RARE, mage.cards.a.AwokenHorror.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Awoken Horror", 91, Rarity.RARE, mage.cards.a.AwokenHorror.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Balefire Dragon", 479, Rarity.MYTHIC, mage.cards.b.BalefireDragon.class, RETRO_ART)); @@ -77,8 +67,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Bedlam Reveler", 312, Rarity.RARE, mage.cards.b.BedlamReveler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Biolume Egg", 455, Rarity.UNCOMMON, mage.cards.b.BiolumeEgg.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Biolume Egg", 54, Rarity.UNCOMMON, mage.cards.b.BiolumeEgg.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Biolume Serpent", 455, Rarity.UNCOMMON, mage.cards.b.BiolumeSerpent.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Biolume Serpent", 54, Rarity.UNCOMMON, mage.cards.b.BiolumeSerpent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bladestitched Skaab", 231, Rarity.UNCOMMON, mage.cards.b.BladestitchedSkaab.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bladestitched Skaab", 426, Rarity.UNCOMMON, mage.cards.b.BladestitchedSkaab.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Blazing Torch", 254, Rarity.COMMON, mage.cards.b.BlazingTorch.class)); @@ -125,8 +113,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Cathars' Crusade", 17, Rarity.RARE, mage.cards.c.CatharsCrusade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cathars' Crusade", 337, Rarity.RARE, mage.cards.c.CatharsCrusade.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Cathars' Crusade", 483, Rarity.RARE, mage.cards.c.CatharsCrusade.class, FULL_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Chalice of Death", 257, Rarity.UNCOMMON, mage.cards.c.ChaliceOfDeath.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chalice of Death", 471, Rarity.UNCOMMON, mage.cards.c.ChaliceOfDeath.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Chalice of Life", 257, Rarity.UNCOMMON, mage.cards.c.ChaliceOfLife.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chalice of Life", 471, Rarity.UNCOMMON, mage.cards.c.ChaliceOfLife.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Chandra, Dressed to Kill", 148, Rarity.MYTHIC, mage.cards.c.ChandraDressedToKill.class)); @@ -141,7 +127,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Collective Brutality", 375, Rarity.RARE, mage.cards.c.CollectiveBrutality.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Collective Defiance", 149, Rarity.RARE, mage.cards.c.CollectiveDefiance.class)); cards.add(new SetCardInfo("Compelling Deterrence", 57, Rarity.UNCOMMON, mage.cards.c.CompellingDeterrence.class)); - cards.add(new SetCardInfo("Conduit of Emrakul", 150, Rarity.COMMON, mage.cards.c.ConduitOfEmrakul.class)); cards.add(new SetCardInfo("Conduit of Storms", 150, Rarity.COMMON, mage.cards.c.ConduitOfStorms.class)); cards.add(new SetCardInfo("Conjurer's Closet", 259, Rarity.RARE, mage.cards.c.ConjurersCloset.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Conjurer's Closet", 321, Rarity.RARE, mage.cards.c.ConjurersCloset.class, NON_FULL_USE_VARIOUS)); @@ -176,7 +161,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Demonic Taskmaster", 377, Rarity.UNCOMMON, mage.cards.d.DemonicTaskmaster.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Demonmail Hauberk", 261, Rarity.UNCOMMON, mage.cards.d.DemonmailHauberk.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Demonmail Hauberk", 442, Rarity.UNCOMMON, mage.cards.d.DemonmailHauberk.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Depraved Harvester", 105, Rarity.COMMON, mage.cards.d.DepravedHarvester.class)); cards.add(new SetCardInfo("Deranged Assistant", 61, Rarity.COMMON, mage.cards.d.DerangedAssistant.class)); cards.add(new SetCardInfo("Deserted Beach", 276, Rarity.RARE, mage.cards.d.DesertedBeach.class)); cards.add(new SetCardInfo("Desperate Farmer", 105, Rarity.COMMON, mage.cards.d.DesperateFarmer.class)); @@ -240,8 +224,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Geistcatcher's Rig", 264, Rarity.UNCOMMON, mage.cards.g.GeistcatchersRig.class)); cards.add(new SetCardInfo("Geistlight Snare", 356, Rarity.UNCOMMON, mage.cards.g.GeistlightSnare.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Geistlight Snare", 66, Rarity.UNCOMMON, mage.cards.g.GeistlightSnare.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ghostly Castigator", 456, Rarity.UNCOMMON, mage.cards.g.GhostlyCastigator.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Ghostly Castigator", 58, Rarity.UNCOMMON, mage.cards.g.GhostlyCastigator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghoulish Procession", 110, Rarity.UNCOMMON, mage.cards.g.GhoulishProcession.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghoulish Procession", 378, Rarity.UNCOMMON, mage.cards.g.GhoulishProcession.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Ghoultree", 198, Rarity.UNCOMMON, mage.cards.g.Ghoultree.class, NON_FULL_USE_VARIOUS)); @@ -310,8 +292,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Infernal Grasp", 119, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Infernal Grasp", 310, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Infernal Grasp", 385, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class,RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Insectile Aberration", 457, Rarity.COMMON, mage.cards.i.InsectileAberration.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Insectile Aberration", 60, Rarity.COMMON, mage.cards.i.InsectileAberration.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Inspiring Captain", 28, Rarity.COMMON, mage.cards.i.InspiringCaptain.class)); cards.add(new SetCardInfo("Intangible Virtue", 29, Rarity.UNCOMMON, mage.cards.i.IntangibleVirtue.class)); cards.add(new SetCardInfo("Intrepid Provisioner", 205, Rarity.COMMON, mage.cards.i.IntrepidProvisioner.class)); @@ -325,9 +305,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Join the Dance", 432, Rarity.UNCOMMON, mage.cards.j.JoinTheDance.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Killing Wave", 121, Rarity.UNCOMMON, mage.cards.k.KillingWave.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Killing Wave", 386, Rarity.UNCOMMON, mage.cards.k.KillingWave.class,RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Krallenhorde Howler", 193, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Krallenhorde Howler", 323, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Krallenhorde Howler", 467, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Kruin Outlaw", 161, Rarity.RARE, mage.cards.k.KruinOutlaw.class)); cards.add(new SetCardInfo("Laboratory Maniac", 304, Rarity.UNCOMMON, mage.cards.l.LaboratoryManiac.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Laboratory Maniac", 359, Rarity.UNCOMMON, mage.cards.l.LaboratoryManiac.class, RETRO_ART_USE_VARIOUS)); @@ -342,9 +319,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Lightning Mauler", 399, Rarity.UNCOMMON, mage.cards.l.LightningMauler.class,RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Liliana of the Veil", 475, Rarity.MYTHIC, mage.cards.l.LilianaOfTheVeil.class, RETRO_ART)); cards.add(new SetCardInfo("Lingering Souls", 30, Rarity.UNCOMMON, mage.cards.l.LingeringSouls.class)); - cards.add(new SetCardInfo("Lord of Lineage", 327, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lord of Lineage", 461, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Lord of Lineage", 98, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lumberknot", 206, Rarity.UNCOMMON, mage.cards.l.Lumberknot.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lumberknot", 414, Rarity.UNCOMMON, mage.cards.l.Lumberknot.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Luminous Phantom", 32, Rarity.COMMON, mage.cards.l.LuminousPhantom.class, NON_FULL_USE_VARIOUS)); @@ -411,15 +385,10 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Overgrown Farmland", 281, Rarity.RARE, mage.cards.o.OvergrownFarmland.class)); cards.add(new SetCardInfo("Pack Guardian", 211, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Pack Guardian", 416, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Perfected Form", 454, Rarity.UNCOMMON, mage.cards.p.PerfectedForm.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Perfected Form", 52, Rarity.UNCOMMON, mage.cards.p.PerfectedForm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 288, Rarity.LAND, mage.cards.basiclands.Plains.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 289, Rarity.LAND, mage.cards.basiclands.Plains.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Rally the Peasants", 347, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Rally the Peasants", 37, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ravager of the Fells", 241, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ravager of the Fells", 325, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ravager of the Fells", 470, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Reckless Scholar", 81, Rarity.COMMON, mage.cards.r.RecklessScholar.class)); cards.add(new SetCardInfo("Reforge the Soul", 167, Rarity.RARE, mage.cards.r.ReforgeTheSoul.class)); cards.add(new SetCardInfo("Restless Bloodseeker", 128, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class, NON_FULL_USE_VARIOUS)); @@ -437,8 +406,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Scorned Villager", 212, Rarity.COMMON, mage.cards.s.ScornedVillager.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Scorned Villager", 468, Rarity.COMMON, mage.cards.s.ScornedVillager.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Scrounged Scythe", 265, Rarity.COMMON, mage.cards.s.ScroungedScythe.class)); - cards.add(new SetCardInfo("Seasoned Cathar", 448, Rarity.UNCOMMON, mage.cards.s.SeasonedCathar.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Seasoned Cathar", 8, Rarity.UNCOMMON, mage.cards.s.SeasonedCathar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Second Harvest", 213, Rarity.RARE, mage.cards.s.SecondHarvest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Second Harvest", 417, Rarity.RARE, mage.cards.s.SecondHarvest.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Seize the Storm", 170, Rarity.COMMON, mage.cards.s.SeizeTheStorm.class, NON_FULL_USE_VARIOUS)); @@ -521,7 +488,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Through the Breach", 175, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Through the Breach", 404, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Through the Breach", 487, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, FULL_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Timber Shredder", 203, Rarity.COMMON, mage.cards.t.TimberShredder.class)); cards.add(new SetCardInfo("Tireless Tracker", 219, Rarity.RARE, mage.cards.t.TirelessTracker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tireless Tracker", 318, Rarity.RARE, mage.cards.t.TirelessTracker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Torens, Fist of the Angels", 250, Rarity.RARE, mage.cards.t.TorensFistOfTheAngels.class)); diff --git a/Mage.Sets/src/mage/sets/Ixalan.java b/Mage.Sets/src/mage/sets/Ixalan.java index f8f7a904b35..ac805618e76 100644 --- a/Mage.Sets/src/mage/sets/Ixalan.java +++ b/Mage.Sets/src/mage/sets/Ixalan.java @@ -74,7 +74,6 @@ public final class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Cobbled Wings", 233, Rarity.COMMON, mage.cards.c.CobbledWings.class)); cards.add(new SetCardInfo("Colossal Dreadmaw", 180, Rarity.COMMON, mage.cards.c.ColossalDreadmaw.class)); cards.add(new SetCardInfo("Commune with Dinosaurs", 181, Rarity.COMMON, mage.cards.c.CommuneWithDinosaurs.class)); - cards.add(new SetCardInfo("Conqueror's Foothold", 234, Rarity.RARE, mage.cards.c.ConquerorsFoothold.class)); cards.add(new SetCardInfo("Conqueror's Galleon", 234, Rarity.RARE, mage.cards.c.ConquerorsGalleon.class)); cards.add(new SetCardInfo("Contract Killing", 95, Rarity.COMMON, mage.cards.c.ContractKilling.class)); cards.add(new SetCardInfo("Costly Plunder", 96, Rarity.COMMON, mage.cards.c.CostlyPlunder.class)); @@ -179,7 +178,6 @@ public final class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Lightning Strike", 149, Rarity.UNCOMMON, mage.cards.l.LightningStrike.class)); cards.add(new SetCardInfo("Lookout's Dispersal", 62, Rarity.UNCOMMON, mage.cards.l.LookoutsDispersal.class)); cards.add(new SetCardInfo("Looming Altisaur", 23, Rarity.COMMON, mage.cards.l.LoomingAltisaur.class)); - cards.add(new SetCardInfo("Lost Vale", 235, Rarity.RARE, mage.cards.l.LostVale.class)); cards.add(new SetCardInfo("Lurking Chupacabra", 111, Rarity.UNCOMMON, mage.cards.l.LurkingChupacabra.class)); cards.add(new SetCardInfo("Makeshift Munitions", 151, Rarity.UNCOMMON, mage.cards.m.MakeshiftMunitions.class)); cards.add(new SetCardInfo("Marauding Looter", 225, Rarity.UNCOMMON, mage.cards.m.MaraudingLooter.class)); @@ -299,7 +297,6 @@ public final class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Swashbuckling", 167, Rarity.COMMON, mage.cards.s.Swashbuckling.class)); cards.add(new SetCardInfo("Sword-Point Diplomacy", 126, Rarity.RARE, mage.cards.s.SwordPointDiplomacy.class)); cards.add(new SetCardInfo("Tempest Caller", 86, Rarity.UNCOMMON, mage.cards.t.TempestCaller.class)); - cards.add(new SetCardInfo("Temple of Aclazotz", 90, Rarity.RARE, mage.cards.t.TempleOfAclazotz.class)); cards.add(new SetCardInfo("Territorial Hammerskull", 41, Rarity.COMMON, mage.cards.t.TerritorialHammerskull.class)); cards.add(new SetCardInfo("Thaumatic Compass", 249, Rarity.RARE, mage.cards.t.ThaumaticCompass.class)); cards.add(new SetCardInfo("Thrash of Raptors", 168, Rarity.COMMON, mage.cards.t.ThrashOfRaptors.class)); diff --git a/Mage.Sets/src/mage/sets/IxalanPromos.java b/Mage.Sets/src/mage/sets/IxalanPromos.java index d472b0c1307..0c55b5ea44a 100644 --- a/Mage.Sets/src/mage/sets/IxalanPromos.java +++ b/Mage.Sets/src/mage/sets/IxalanPromos.java @@ -42,7 +42,6 @@ public class IxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Captivating Crew", "137s", Rarity.RARE, mage.cards.c.CaptivatingCrew.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Carnage Tyrant", "179p", Rarity.MYTHIC, mage.cards.c.CarnageTyrant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Carnage Tyrant", "179s", Rarity.MYTHIC, mage.cards.c.CarnageTyrant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Conqueror's Foothold", "234s", Rarity.RARE, mage.cards.c.ConquerorsFoothold.class)); cards.add(new SetCardInfo("Conqueror's Galleon", "234s", Rarity.RARE, mage.cards.c.ConquerorsGalleon.class)); cards.add(new SetCardInfo("Daring Saboteur", "49s", Rarity.RARE, mage.cards.d.DaringSaboteur.class)); cards.add(new SetCardInfo("Deadeye Tracker", "99p", Rarity.RARE, mage.cards.d.DeadeyeTracker.class, NON_FULL_USE_VARIOUS)); @@ -82,7 +81,6 @@ public class IxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Kopala, Warden of Waves", "61p", Rarity.RARE, mage.cards.k.KopalaWardenOfWaves.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kopala, Warden of Waves", "61s", Rarity.RARE, mage.cards.k.KopalaWardenOfWaves.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Legion's Landing", "22s", Rarity.RARE, mage.cards.l.LegionsLanding.class)); - cards.add(new SetCardInfo("Lost Vale", "235s", Rarity.RARE, mage.cards.l.LostVale.class)); cards.add(new SetCardInfo("Mavren Fein, Dusk Apostle", "24p", Rarity.RARE, mage.cards.m.MavrenFeinDuskApostle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mavren Fein, Dusk Apostle", "24s", Rarity.RARE, mage.cards.m.MavrenFeinDuskApostle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Old-Growth Dryads", "199s", Rarity.RARE, mage.cards.o.OldGrowthDryads.class)); @@ -128,7 +126,6 @@ public class IxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Sunpetal Grove", "257s", Rarity.RARE, mage.cards.s.SunpetalGrove.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sword-Point Diplomacy", "126p", Rarity.RARE, mage.cards.s.SwordPointDiplomacy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sword-Point Diplomacy", "126s", Rarity.RARE, mage.cards.s.SwordPointDiplomacy.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of Aclazotz", "90s", Rarity.RARE, mage.cards.t.TempleOfAclazotz.class)); cards.add(new SetCardInfo("Thaumatic Compass", "249s", Rarity.RARE, mage.cards.t.ThaumaticCompass.class)); cards.add(new SetCardInfo("Tilonalli's Skinshifter", "170s", Rarity.RARE, mage.cards.t.TilonallisSkinshifter.class)); cards.add(new SetCardInfo("Tishana, Voice of Thunder", "230s", Rarity.MYTHIC, mage.cards.t.TishanaVoiceOfThunder.class)); diff --git a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java index 35596662e26..5a166126a18 100644 --- a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java +++ b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java @@ -88,7 +88,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Boseiju, Who Endures", 266, Rarity.RARE, mage.cards.b.BoseijuWhoEndures.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Boseiju, Who Endures", 412, Rarity.RARE, mage.cards.b.BoseijuWhoEndures.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Boseiju, Who Endures", 501, Rarity.RARE, mage.cards.b.BoseijuWhoEndures.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Branch of Boseiju", 177, Rarity.UNCOMMON, mage.cards.b.BranchOfBoseiju.class)); cards.add(new SetCardInfo("Brilliant Restoration", 363, Rarity.RARE, mage.cards.b.BrilliantRestoration.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Brilliant Restoration", 434, Rarity.RARE, mage.cards.b.BrilliantRestoration.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Brilliant Restoration", 7, Rarity.RARE, mage.cards.b.BrilliantRestoration.class, NON_FULL_USE_VARIOUS)); @@ -193,7 +192,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Greater Tanuki", 189, Rarity.COMMON, mage.cards.g.GreaterTanuki.class)); cards.add(new SetCardInfo("Guardians of Oboro", 317, Rarity.COMMON, mage.cards.g.GuardiansOfOboro.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Guardians of Oboro", 56, Rarity.COMMON, mage.cards.g.GuardiansOfOboro.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hand of Enlightenment", 11, Rarity.COMMON, mage.cards.h.HandOfEnlightenment.class)); cards.add(new SetCardInfo("Harmonious Emergence", 190, Rarity.COMMON, mage.cards.h.HarmoniousEmergence.class)); cards.add(new SetCardInfo("Heiko Yamazaki, the General", 146, Rarity.UNCOMMON, mage.cards.h.HeikoYamazakiTheGeneral.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Heiko Yamazaki, the General", 321, Rarity.UNCOMMON, mage.cards.h.HeikoYamazakiTheGeneral.class, NON_FULL_USE_VARIOUS)); @@ -215,7 +213,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Hinata, Dawn-Crowned", 487, Rarity.RARE, mage.cards.h.HinataDawnCrowned.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Historian's Wisdom", 192, Rarity.UNCOMMON, mage.cards.h.HistoriansWisdom.class)); cards.add(new SetCardInfo("Hotshot Mechanic", 16, Rarity.UNCOMMON, mage.cards.h.HotshotMechanic.class)); - cards.add(new SetCardInfo("Imperial Moth", 4, Rarity.COMMON, mage.cards.i.ImperialMoth.class)); cards.add(new SetCardInfo("Imperial Oath", 17, Rarity.COMMON, mage.cards.i.ImperialOath.class)); cards.add(new SetCardInfo("Imperial Recovery Unit", 18, Rarity.UNCOMMON, mage.cards.i.ImperialRecoveryUnit.class)); cards.add(new SetCardInfo("Imperial Subduer", 19, Rarity.COMMON, mage.cards.i.ImperialSubduer.class, NON_FULL_USE_VARIOUS)); @@ -312,7 +309,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 25, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 367, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 439, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Likeness of the Seeker", 172, Rarity.UNCOMMON, mage.cards.l.LikenessOfTheSeeker.class)); cards.add(new SetCardInfo("Lion Sash", 26, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lion Sash", 368, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lion Sash", 440, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS)); @@ -582,7 +578,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Vessel of the All-Consuming", 361, Rarity.MYTHIC, mage.cards.v.VesselOfTheAllConsuming.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vessel of the All-Consuming", 486, Rarity.MYTHIC, mage.cards.v.VesselOfTheAllConsuming.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Virus Beetle", 128, Rarity.COMMON, mage.cards.v.VirusBeetle.class)); - cards.add(new SetCardInfo("Vision of the Unspeakable", 48, Rarity.UNCOMMON, mage.cards.v.VisionOfTheUnspeakable.class)); cards.add(new SetCardInfo("Voltage Surge", 171, Rarity.COMMON, mage.cards.v.VoltageSurge.class)); cards.add(new SetCardInfo("Walking Skyscraper", 263, Rarity.UNCOMMON, mage.cards.w.WalkingSkyscraper.class)); cards.add(new SetCardInfo("Wanderer's Intervention", 41, Rarity.COMMON, mage.cards.w.WanderersIntervention.class)); diff --git a/Mage.Sets/src/mage/sets/LorwynEclipsed.java b/Mage.Sets/src/mage/sets/LorwynEclipsed.java index 8d0ca69aa6e..befe63c281e 100644 --- a/Mage.Sets/src/mage/sets/LorwynEclipsed.java +++ b/Mage.Sets/src/mage/sets/LorwynEclipsed.java @@ -39,8 +39,6 @@ public final class LorwynEclipsed extends ExpansionSet { cards.add(new SetCardInfo("Formidable Speaker", 366, Rarity.RARE, mage.cards.f.FormidableSpeaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hallowed Fountain", 265, Rarity.RARE, mage.cards.h.HallowedFountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hallowed Fountain", 347, Rarity.RARE, mage.cards.h.HallowedFountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Isilu, Carrier of Twilight", 13, Rarity.MYTHIC, mage.cards.i.IsiluCarrierOfTwilight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Isilu, Carrier of Twilight", 286, Rarity.MYTHIC, mage.cards.i.IsiluCarrierOfTwilight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Morningtide's Light", 27, Rarity.MYTHIC, mage.cards.m.MorningtidesLight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Morningtide's Light", 301, Rarity.MYTHIC, mage.cards.m.MorningtidesLight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mutable Explorer", 186, Rarity.RARE, mage.cards.m.MutableExplorer.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/MagicOnlinePromos.java b/Mage.Sets/src/mage/sets/MagicOnlinePromos.java index bcb19295bb5..fbf0d6992f0 100644 --- a/Mage.Sets/src/mage/sets/MagicOnlinePromos.java +++ b/Mage.Sets/src/mage/sets/MagicOnlinePromos.java @@ -4,9 +4,6 @@ import mage.cards.ExpansionSet; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.Arrays; -import java.util.List; - /** * https://scryfall.com/sets/prm */ @@ -103,7 +100,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Angel of Suffering", 99767, Rarity.MYTHIC, mage.cards.a.AngelOfSuffering.class)); cards.add(new SetCardInfo("Angel of the Ruins", 90002, Rarity.RARE, mage.cards.a.AngelOfTheRuins.class)); cards.add(new SetCardInfo("Angelfire Ignition", 94080, Rarity.RARE, mage.cards.a.AngelfireIgnition.class)); - cards.add(new SetCardInfo("Angelic Enforcer", 93888, Rarity.MYTHIC, mage.cards.a.AngelicEnforcer.class)); cards.add(new SetCardInfo("Angelic Sleuth", 99921, Rarity.RARE, mage.cards.a.AngelicSleuth.class)); cards.add(new SetCardInfo("Anger of the Gods", 102265, Rarity.RARE, mage.cards.a.AngerOfTheGods.class)); cards.add(new SetCardInfo("Angrath, Captain of Chaos", 72237, Rarity.UNCOMMON, mage.cards.a.AngrathCaptainOfChaos.class, NON_FULL_USE_VARIOUS)); @@ -159,7 +155,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Argivian Archaeologist", 219, Rarity.RARE, mage.cards.a.ArgivianArchaeologist.class, RETRO_ART)); cards.add(new SetCardInfo("Argothian Enchantress", 36104, Rarity.RARE, mage.cards.a.ArgothianEnchantress.class, RETRO_ART)); cards.add(new SetCardInfo("Arid Mesa", 91405, Rarity.RARE, mage.cards.a.AridMesa.class)); - cards.add(new SetCardInfo("Arlinn, the Moon's Fury", 94060, Rarity.MYTHIC, mage.cards.a.ArlinnTheMoonsFury.class)); cards.add(new SetCardInfo("Arlinn, the Pack's Hope", 94060, Rarity.MYTHIC, mage.cards.a.ArlinnThePacksHope.class)); cards.add(new SetCardInfo("Arlinn, Voice of the Pack", 72239, Rarity.UNCOMMON, mage.cards.a.ArlinnVoiceOfThePack.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn, Voice of the Pack", 77973, Rarity.UNCOMMON, mage.cards.a.ArlinnVoiceOfThePack.class, NON_FULL_USE_VARIOUS)); @@ -1233,7 +1228,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Hoard Hauler", 99747, Rarity.RARE, mage.cards.h.HoardHauler.class)); cards.add(new SetCardInfo("Hobgoblin Bandit Lord", 92734, Rarity.RARE, mage.cards.h.HobgoblinBanditLord.class)); cards.add(new SetCardInfo("Hofri Ghostforge", 90278, Rarity.MYTHIC, mage.cards.h.HofriGhostforge.class)); - cards.add(new SetCardInfo("Hollowhenge Huntmaster", 95433, Rarity.MYTHIC, mage.cards.h.HollowhengeHuntmaster.class)); cards.add(new SetCardInfo("Hollowhenge Overlord", 95419, Rarity.RARE, mage.cards.h.HollowhengeOverlord.class)); cards.add(new SetCardInfo("Honor of the Pure", 43554, Rarity.RARE, mage.cards.h.HonorOfThePure.class)); cards.add(new SetCardInfo("Honored Hierarch", 57598, Rarity.RARE, mage.cards.h.HonoredHierarch.class)); @@ -1320,7 +1314,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Inscription of Abundance", 83728, Rarity.RARE, mage.cards.i.InscriptionOfAbundance.class)); cards.add(new SetCardInfo("Inscription of Insight", 83802, Rarity.RARE, mage.cards.i.InscriptionOfInsight.class)); cards.add(new SetCardInfo("Inscription of Ruin", 83798, Rarity.RARE, mage.cards.i.InscriptionOfRuin.class)); - cards.add(new SetCardInfo("Insidious Mist", 60472, Rarity.RARE, mage.cards.i.InsidiousMist.class)); cards.add(new SetCardInfo("Inspired Idea", 95307, Rarity.RARE, mage.cards.i.InspiredIdea.class)); cards.add(new SetCardInfo("Inspired Ultimatum", 80899, Rarity.RARE, mage.cards.i.InspiredUltimatum.class)); cards.add(new SetCardInfo("Inspiring Refrain", 90034, Rarity.RARE, mage.cards.i.InspiringRefrain.class)); @@ -1531,7 +1524,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Leaf-Crowned Visionary", 103462, Rarity.RARE, mage.cards.l.LeafCrownedVisionary.class)); cards.add(new SetCardInfo("Leatherback Baloth", 43576, Rarity.UNCOMMON, mage.cards.l.LeatherbackBaloth.class)); cards.add(new SetCardInfo("Ledger Shredder", 99733, Rarity.RARE, mage.cards.l.LedgerShredder.class)); - cards.add(new SetCardInfo("Leeching Lurker", 93988, Rarity.RARE, mage.cards.l.LeechingLurker.class)); cards.add(new SetCardInfo("Legion Angel", 83754, Rarity.RARE, mage.cards.l.LegionAngel.class)); cards.add(new SetCardInfo("Legions to Ashes", 105784, Rarity.RARE, mage.cards.l.LegionsToAshes.class)); cards.add(new SetCardInfo("Leinore, Autumn Sovereign", 94054, Rarity.MYTHIC, mage.cards.l.LeinoreAutumnSovereign.class)); @@ -2224,7 +2216,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Retaliator Griffin", 43546, Rarity.RARE, mage.cards.r.RetaliatorGriffin.class)); cards.add(new SetCardInfo("Retriever Phoenix", 90094, Rarity.RARE, mage.cards.r.RetrieverPhoenix.class)); cards.add(new SetCardInfo("Return to Dust", 86104, Rarity.UNCOMMON, mage.cards.r.ReturnToDust.class)); - cards.add(new SetCardInfo("Revealing Eye", 95351, Rarity.RARE, mage.cards.r.RevealingEye.class)); cards.add(new SetCardInfo("Revenant", 32192, Rarity.RARE, mage.cards.r.Revenant.class, RETRO_ART)); cards.add(new SetCardInfo("Reverse Engineer", 64995, Rarity.UNCOMMON, mage.cards.r.ReverseEngineer.class)); cards.add(new SetCardInfo("Revival Experiment", 90220, Rarity.RARE, mage.cards.r.RevivalExperiment.class)); @@ -2458,7 +2449,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Simic Signet", 62391, Rarity.COMMON, mage.cards.s.SimicSignet.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sin Collector", 50112, Rarity.UNCOMMON, mage.cards.s.SinCollector.class)); cards.add(new SetCardInfo("Sinkhole", 43566, Rarity.RARE, mage.cards.s.Sinkhole.class)); - cards.add(new SetCardInfo("Sinner's Judgment", 95279, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class)); cards.add(new SetCardInfo("Siphon Insight", 94066, Rarity.RARE, mage.cards.s.SiphonInsight.class)); cards.add(new SetCardInfo("Sisay, Weatherlight Captain", 91211, Rarity.RARE, mage.cards.s.SisayWeatherlightCaptain.class, RETRO_ART)); cards.add(new SetCardInfo("Skarrg Goliath", 47989, Rarity.RARE, mage.cards.s.SkarrgGoliath.class)); diff --git a/Mage.Sets/src/mage/sets/MagicOrigins.java b/Mage.Sets/src/mage/sets/MagicOrigins.java index 5b3187549d1..b63aa10a45c 100644 --- a/Mage.Sets/src/mage/sets/MagicOrigins.java +++ b/Mage.Sets/src/mage/sets/MagicOrigins.java @@ -72,7 +72,6 @@ public final class MagicOrigins extends ExpansionSet { cards.add(new SetCardInfo("Caves of Koilos", 245, Rarity.RARE, mage.cards.c.CavesOfKoilos.class)); cards.add(new SetCardInfo("Celestial Flare", 8, Rarity.COMMON, mage.cards.c.CelestialFlare.class)); cards.add(new SetCardInfo("Chandra, Fire of Kaladesh", 135, Rarity.MYTHIC, mage.cards.c.ChandraFireOfKaladesh.class)); - cards.add(new SetCardInfo("Chandra, Roaring Flame", 135, Rarity.MYTHIC, mage.cards.c.ChandraRoaringFlame.class)); cards.add(new SetCardInfo("Chandra's Fury", 136, Rarity.COMMON, mage.cards.c.ChandrasFury.class)); cards.add(new SetCardInfo("Chandra's Ignition", 137, Rarity.RARE, mage.cards.c.ChandrasIgnition.class)); cards.add(new SetCardInfo("Charging Griffin", 9, Rarity.COMMON, mage.cards.c.ChargingGriffin.class)); diff --git a/Mage.Sets/src/mage/sets/MagicOriginsPromos.java b/Mage.Sets/src/mage/sets/MagicOriginsPromos.java index b76caff8a79..07480981180 100644 --- a/Mage.Sets/src/mage/sets/MagicOriginsPromos.java +++ b/Mage.Sets/src/mage/sets/MagicOriginsPromos.java @@ -25,7 +25,6 @@ public class MagicOriginsPromos extends ExpansionSet { cards.add(new SetCardInfo("Alhammarret, High Arbiter", "43s", Rarity.RARE, mage.cards.a.AlhammarretHighArbiter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chandra's Ignition", "137s", Rarity.RARE, mage.cards.c.ChandrasIgnition.class)); cards.add(new SetCardInfo("Chandra, Fire of Kaladesh", "135s", Rarity.MYTHIC, mage.cards.c.ChandraFireOfKaladesh.class)); - cards.add(new SetCardInfo("Chandra, Roaring Flame", "135s", Rarity.MYTHIC, mage.cards.c.ChandraRoaringFlame.class)); cards.add(new SetCardInfo("Conclave Naturalists", 171, Rarity.UNCOMMON, mage.cards.c.ConclaveNaturalists.class)); cards.add(new SetCardInfo("Dark Petition", "90s", Rarity.RARE, mage.cards.d.DarkPetition.class)); cards.add(new SetCardInfo("Despoiler of Souls", "93s", Rarity.RARE, mage.cards.d.DespoilerOfSouls.class)); diff --git a/Mage.Sets/src/mage/sets/MarchOfTheMachine.java b/Mage.Sets/src/mage/sets/MarchOfTheMachine.java index 4a286cd8326..96ae38826a0 100644 --- a/Mage.Sets/src/mage/sets/MarchOfTheMachine.java +++ b/Mage.Sets/src/mage/sets/MarchOfTheMachine.java @@ -2,15 +2,15 @@ package mage.sets; import mage.cards.Card; import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; -import mage.util.RandomUtil; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardRepository; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; import mage.collation.CardRun; import mage.collation.RarityConfiguration; +import mage.constants.Rarity; +import mage.constants.SetType; +import mage.util.RandomUtil; import java.util.ArrayList; import java.util.List; @@ -62,19 +62,15 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Awaken the Maelstrom", 230, Rarity.RARE, mage.cards.a.AwakenTheMaelstrom.class)); cards.add(new SetCardInfo("Awakened Skyclave", 194, Rarity.UNCOMMON, mage.cards.a.AwakenedSkyclave.class)); cards.add(new SetCardInfo("Axgard Artisan", 332, Rarity.UNCOMMON, mage.cards.a.AxgardArtisan.class)); - cards.add(new SetCardInfo("Ayara, Furnace Queen", 296, Rarity.RARE, mage.cards.a.AyaraFurnaceQueen.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ayara, Furnace Queen", 90, Rarity.RARE, mage.cards.a.AyaraFurnaceQueen.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ayara, Widow of the Realm", 296, Rarity.RARE, mage.cards.a.AyaraWidowOfTheRealm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ayara, Widow of the Realm", 90, Rarity.RARE, mage.cards.a.AyaraWidowOfTheRealm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Baral and Kari Zev", 218, Rarity.RARE, mage.cards.b.BaralAndKariZev.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Baral and Kari Zev", 302, Rarity.RARE, mage.cards.b.BaralAndKariZev.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Beamtown Beatstick", 131, Rarity.COMMON, mage.cards.b.BeamtownBeatstick.class)); - cards.add(new SetCardInfo("Belenon War Anthem", 20, Rarity.UNCOMMON, mage.cards.b.BelenonWarAnthem.class)); cards.add(new SetCardInfo("Belligerent Regisaur", 191, Rarity.RARE, mage.cards.b.BelligerentRegisaur.class)); cards.add(new SetCardInfo("Bladed Battle-Fan", 91, Rarity.COMMON, mage.cards.b.BladedBattleFan.class)); cards.add(new SetCardInfo("Blighted Burgeoning", 177, Rarity.COMMON, mage.cards.b.BlightedBurgeoning.class)); cards.add(new SetCardInfo("Blightreaper Thallid", 92, Rarity.UNCOMMON, mage.cards.b.BlightreaperThallid.class)); - cards.add(new SetCardInfo("Blightsower Thallid", 92, Rarity.UNCOMMON, mage.cards.b.BlightsowerThallid.class)); cards.add(new SetCardInfo("Bloated Processor", 357, Rarity.RARE, mage.cards.b.BloatedProcessor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloated Processor", 93, Rarity.RARE, mage.cards.b.BloatedProcessor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodfeather Phoenix", 132, Rarity.RARE, mage.cards.b.BloodfeatherPhoenix.class, NON_FULL_USE_VARIOUS)); @@ -107,7 +103,6 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("City on Fire", 363, Rarity.RARE, mage.cards.c.CityOnFire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Collective Nightmare", 95, Rarity.UNCOMMON, mage.cards.c.CollectiveNightmare.class)); cards.add(new SetCardInfo("Coming In Hot", 136, Rarity.COMMON, mage.cards.c.ComingInHot.class)); - cards.add(new SetCardInfo("Compleated Conjurer", 49, Rarity.UNCOMMON, mage.cards.c.CompleatedConjurer.class)); cards.add(new SetCardInfo("Compleated Huntmaster", 96, Rarity.UNCOMMON, mage.cards.c.CompleatedHuntmaster.class)); cards.add(new SetCardInfo("Complete the Circuit", 351, Rarity.RARE, mage.cards.c.CompleteTheCircuit.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Complete the Circuit", 52, Rarity.RARE, mage.cards.c.CompleteTheCircuit.class, NON_FULL_USE_VARIOUS)); @@ -151,8 +146,6 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Essence of Orthodoxy", 376, Rarity.RARE, mage.cards.e.EssenceOfOrthodoxy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Etali, Primal Conqueror", 137, Rarity.RARE, mage.cards.e.EtaliPrimalConqueror.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Etali, Primal Conqueror", 298, Rarity.RARE, mage.cards.e.EtaliPrimalConqueror.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Etali, Primal Sickness", 137, Rarity.RARE, mage.cards.e.EtaliPrimalSickness.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Etali, Primal Sickness", 298, Rarity.RARE, mage.cards.e.EtaliPrimalSickness.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Etched Familiar", 101, Rarity.COMMON, mage.cards.e.EtchedFamiliar.class)); cards.add(new SetCardInfo("Etched Host Doombringer", 102, Rarity.COMMON, mage.cards.e.EtchedHostDoombringer.class)); cards.add(new SetCardInfo("Expedition Lookout", 56, Rarity.COMMON, mage.cards.e.ExpeditionLookout.class)); @@ -179,7 +172,6 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Ghalta and Mavren", 307, Rarity.RARE, mage.cards.g.GhaltaAndMavren.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghalta and Mavren", 386, Rarity.RARE, mage.cards.g.GhaltaAndMavren.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gift of Compleation", 106, Rarity.UNCOMMON, mage.cards.g.GiftOfCompleation.class)); - cards.add(new SetCardInfo("Gitaxian Mindstinger", 88, Rarity.COMMON, mage.cards.g.GitaxianMindstinger.class)); cards.add(new SetCardInfo("Gitaxian Spellstalker", 151, Rarity.UNCOMMON, mage.cards.g.GitaxianSpellstalker.class)); cards.add(new SetCardInfo("Glissa, Herald of Predation", 226, Rarity.RARE, mage.cards.g.GlissaHeraldOfPredation.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Glissa, Herald of Predation", 308, Rarity.RARE, mage.cards.g.GlissaHeraldOfPredation.class, NON_FULL_USE_VARIOUS)); @@ -339,7 +331,6 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Plains", 277, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 282, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Plains", 283, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Plated Kilnbeast", 178, Rarity.COMMON, mage.cards.p.PlatedKilnbeast.class)); cards.add(new SetCardInfo("Polukranos Reborn", 200, Rarity.RARE, mage.cards.p.PolukranosReborn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Polukranos Reborn", 300, Rarity.RARE, mage.cards.p.PolukranosReborn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Polukranos, Engine of Ruin", 200, Rarity.RARE, mage.cards.p.PolukranosEngineOfRuin.class, NON_FULL_USE_VARIOUS)); @@ -434,9 +425,6 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Terror of Towashi", 378, Rarity.RARE, mage.cards.t.TerrorOfTowashi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thalia and The Gitrog Monster", 255, Rarity.MYTHIC, mage.cards.t.ThaliaAndTheGitrogMonster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thalia and The Gitrog Monster", 316, Rarity.MYTHIC, mage.cards.t.ThaliaAndTheGitrogMonster.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Argent Etchings", 12, Rarity.MYTHIC, mage.cards.t.TheArgentEtchings.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Argent Etchings", 292, Rarity.MYTHIC, mage.cards.t.TheArgentEtchings.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Argent Etchings", 338, Rarity.MYTHIC, mage.cards.t.TheArgentEtchings.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Broken Sky", 241, Rarity.RARE, mage.cards.t.TheBrokenSky.class)); cards.add(new SetCardInfo("The Grand Evolution", 213, Rarity.MYTHIC, mage.cards.t.TheGrandEvolution.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Grand Evolution", 301, Rarity.MYTHIC, mage.cards.t.TheGrandEvolution.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/MarvelLegendsSeriesInserts.java b/Mage.Sets/src/mage/sets/MarvelLegendsSeriesInserts.java index 7a4ebe5eb0c..9381ea8a8b2 100644 --- a/Mage.Sets/src/mage/sets/MarvelLegendsSeriesInserts.java +++ b/Mage.Sets/src/mage/sets/MarvelLegendsSeriesInserts.java @@ -23,7 +23,6 @@ public class MarvelLegendsSeriesInserts extends ExpansionSet { cards.add(new SetCardInfo("Anti-Venom, Horrifying Healer", 1, Rarity.MYTHIC, mage.cards.a.AntiVenomHorrifyingHealer.class)); cards.add(new SetCardInfo("Huntmaster of the Fells", 3, Rarity.RARE, mage.cards.h.HuntmasterOfTheFells.class)); cards.add(new SetCardInfo("Iron Spider, Stark Upgrade", 4, Rarity.RARE, mage.cards.i.IronSpiderStarkUpgrade.class)); - cards.add(new SetCardInfo("Ravager of the Fells", 3, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class)); cards.add(new SetCardInfo("Spectacular Spider-Man", 2, Rarity.RARE, mage.cards.s.SpectacularSpiderMan.class)); } } diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index ae7b50e8bc2..8f713b9a4d7 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -4,15 +4,11 @@ import mage.cards.ExpansionSet; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.Arrays; -import java.util.List; - /** * @author TheElk801 */ public final class MarvelsSpiderMan extends ExpansionSet { - private static final List unfinished = Arrays.asList("Eddie Brock", "Gwen Stacy", "Miles Morales", "Norman Osborn", "Peter Parker"); private static final MarvelsSpiderMan instance = new MarvelsSpiderMan(); public static MarvelsSpiderMan getInstance() { @@ -310,7 +306,5 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("With Great Power...", 24, Rarity.RARE, mage.cards.w.WithGreatPower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("With Great Power...", 248, Rarity.RARE, mage.cards.w.WithGreatPower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wraith, Vicious Vigilante", 160, Rarity.UNCOMMON, mage.cards.w.WraithViciousVigilante.class)); - - cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); } } diff --git a/Mage.Sets/src/mage/sets/ModernHorizons3.java b/Mage.Sets/src/mage/sets/ModernHorizons3.java index 513ede80f78..88b11d81e19 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons3.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons3.java @@ -41,9 +41,6 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Aether Spike", 50, Rarity.COMMON, mage.cards.a.AetherSpike.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aether Spike", 398, Rarity.COMMON, mage.cards.a.AetherSpike.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Ajani Fells the Godsire", 19, Rarity.UNCOMMON, mage.cards.a.AjaniFellsTheGodsire.class)); - cards.add(new SetCardInfo("Ajani, Nacatl Avenger", 237, Rarity.MYTHIC, mage.cards.a.AjaniNacatlAvenger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ajani, Nacatl Avenger", 442, Rarity.MYTHIC, mage.cards.a.AjaniNacatlAvenger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ajani, Nacatl Avenger", 468, Rarity.MYTHIC, mage.cards.a.AjaniNacatlAvenger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ajani, Nacatl Pariah", 237, Rarity.MYTHIC, mage.cards.a.AjaniNacatlPariah.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ajani, Nacatl Pariah", 442, Rarity.MYTHIC, mage.cards.a.AjaniNacatlPariah.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ajani, Nacatl Pariah", 468, Rarity.MYTHIC, mage.cards.a.AjaniNacatlPariah.class, NON_FULL_USE_VARIOUS)); @@ -482,9 +479,6 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 242, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 443, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 469, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tamiyo, Seasoned Scholar", 242, Rarity.MYTHIC, mage.cards.t.TamiyoSeasonedScholar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tamiyo, Seasoned Scholar", 443, Rarity.MYTHIC, mage.cards.t.TamiyoSeasonedScholar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tamiyo, Seasoned Scholar", 469, Rarity.MYTHIC, mage.cards.t.TamiyoSeasonedScholar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Temperamental Oozewagg", 172, Rarity.COMMON, mage.cards.t.TemperamentalOozewagg.class)); cards.add(new SetCardInfo("Tempest Harvester", 73, Rarity.COMMON, mage.cards.t.TempestHarvester.class)); cards.add(new SetCardInfo("Territory Culler", 173, Rarity.UNCOMMON, mage.cards.t.TerritoryCuller.class)); diff --git a/Mage.Sets/src/mage/sets/PioneerMasters.java b/Mage.Sets/src/mage/sets/PioneerMasters.java index e05c6791aa7..7e1e7b012f8 100644 --- a/Mage.Sets/src/mage/sets/PioneerMasters.java +++ b/Mage.Sets/src/mage/sets/PioneerMasters.java @@ -142,7 +142,6 @@ public class PioneerMasters extends ExpansionSet { cards.add(new SetCardInfo("Expedite", 374, Rarity.COMMON, mage.cards.e.Expedite.class)); cards.add(new SetCardInfo("Experiment One", 173, Rarity.UNCOMMON, mage.cards.e.ExperimentOne.class)); cards.add(new SetCardInfo("Exquisite Firecraft", 133, Rarity.RARE, mage.cards.e.ExquisiteFirecraft.class)); - cards.add(new SetCardInfo("Extricator of Flesh", 12, Rarity.UNCOMMON, mage.cards.e.ExtricatorOfFlesh.class)); cards.add(new SetCardInfo("Extricator of Sin", 12, Rarity.UNCOMMON, mage.cards.e.ExtricatorOfSin.class)); cards.add(new SetCardInfo("Fall of the Hammer", 134, Rarity.COMMON, mage.cards.f.FallOfTheHammer.class)); cards.add(new SetCardInfo("Fallaji Archaeologist", 55, Rarity.COMMON, mage.cards.f.FallajiArchaeologist.class)); diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index 3b956af573e..07b11bafc73 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -182,7 +182,6 @@ public final class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Riverwise Augur", 48, Rarity.UNCOMMON, mage.cards.r.RiverwiseAugur.class)); cards.add(new SetCardInfo("Sadistic Skymarcher", 85, Rarity.UNCOMMON, mage.cards.s.SadisticSkymarcher.class)); cards.add(new SetCardInfo("Sailor of Means", 49, Rarity.COMMON, mage.cards.s.SailorOfMeans.class)); - cards.add(new SetCardInfo("Sanctum of the Sun", 176, Rarity.MYTHIC, mage.cards.s.SanctumOfTheSun.class)); cards.add(new SetCardInfo("Sanguine Glorifier", 20, Rarity.COMMON, mage.cards.s.SanguineGlorifier.class)); cards.add(new SetCardInfo("Sea Legs", 50, Rarity.COMMON, mage.cards.s.SeaLegs.class)); cards.add(new SetCardInfo("Seafloor Oracle", 51, Rarity.RARE, mage.cards.s.SeafloorOracle.class)); diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalanPromos.java b/Mage.Sets/src/mage/sets/RivalsOfIxalanPromos.java index 1fa372d0e88..d01a374be83 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalanPromos.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalanPromos.java @@ -80,7 +80,6 @@ public class RivalsOfIxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Rekindling Phoenix", "111p", Rarity.MYTHIC, mage.cards.r.RekindlingPhoenix.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rekindling Phoenix", "111s", Rarity.MYTHIC, mage.cards.r.RekindlingPhoenix.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Release to the Wind", "46s", Rarity.RARE, mage.cards.r.ReleaseToTheWind.class)); - cards.add(new SetCardInfo("Sanctum of the Sun", "176s", Rarity.MYTHIC, mage.cards.s.SanctumOfTheSun.class)); cards.add(new SetCardInfo("Seafloor Oracle", "51p", Rarity.RARE, mage.cards.s.SeafloorOracle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Seafloor Oracle", "51s", Rarity.RARE, mage.cards.s.SeafloorOracle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Siegehorn Ceratops", "171p", Rarity.RARE, mage.cards.s.SiegehornCeratops.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/SanDiegoComicCon2015.java b/Mage.Sets/src/mage/sets/SanDiegoComicCon2015.java index f36f6f8a0d8..ebe390ac11f 100644 --- a/Mage.Sets/src/mage/sets/SanDiegoComicCon2015.java +++ b/Mage.Sets/src/mage/sets/SanDiegoComicCon2015.java @@ -21,7 +21,6 @@ public class SanDiegoComicCon2015 extends ExpansionSet { this.hasBasicLands = false; cards.add(new SetCardInfo("Chandra, Fire of Kaladesh", 135, Rarity.MYTHIC, mage.cards.c.ChandraFireOfKaladesh.class)); - cards.add(new SetCardInfo("Chandra, Roaring Flame", 135, Rarity.MYTHIC, mage.cards.c.ChandraRoaringFlame.class)); cards.add(new SetCardInfo("Gideon, Battle-Forged", 23, Rarity.MYTHIC, mage.cards.g.GideonBattleForged.class)); cards.add(new SetCardInfo("Jace, Telepath Unbound", 60, Rarity.MYTHIC, mage.cards.j.JaceTelepathUnbound.class)); cards.add(new SetCardInfo("Jace, Vryn's Prodigy", 60, Rarity.MYTHIC, mage.cards.j.JaceVrynsProdigy.class)); diff --git a/Mage.Sets/src/mage/sets/SecretLairDrop.java b/Mage.Sets/src/mage/sets/SecretLairDrop.java index 2875eacd749..44f8823b6ac 100644 --- a/Mage.Sets/src/mage/sets/SecretLairDrop.java +++ b/Mage.Sets/src/mage/sets/SecretLairDrop.java @@ -507,7 +507,6 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Kozilek, the Great Distortion", 493, Rarity.MYTHIC, mage.cards.k.KozilekTheGreatDistortion.class)); cards.add(new SetCardInfo("Primeval Titan", 494, Rarity.MYTHIC, mage.cards.p.PrimevalTitan.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Huntmaster of the Fells", 495, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ravager of the Fells", 495, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Platinum Angel", 496, Rarity.RARE, mage.cards.p.PlatinumAngel.class)); cards.add(new SetCardInfo("Brimaz, King of Oreskos", 497, Rarity.MYTHIC, mage.cards.b.BrimazKingOfOreskos.class)); cards.add(new SetCardInfo("Arcanis the Omnipotent", 498, Rarity.RARE, mage.cards.a.ArcanisTheOmnipotent.class)); @@ -706,7 +705,6 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Dakkon Blackblade", 698, Rarity.RARE, mage.cards.d.DakkonBlackblade.class)); cards.add(new SetCardInfo("Olivia, Mobilized for War", 699, Rarity.MYTHIC, mage.cards.o.OliviaMobilizedForWar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Huntmaster of the Fells", 700, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ravager of the Fells", 700, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Elspeth, Knight-Errant", 701, Rarity.MYTHIC, mage.cards.e.ElspethKnightErrant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wastes", 704, Rarity.RARE, mage.cards.w.Wastes.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Wastes", 705, Rarity.RARE, mage.cards.w.Wastes.class, FULL_ART_BFZ_VARIOUS)); @@ -726,7 +724,6 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Thought-Knot Seer", 720, Rarity.RARE, mage.cards.t.ThoughtKnotSeer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Diabolic Tutor", 721, Rarity.RARE, mage.cards.d.DiabolicTutor.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Delver of Secrets", 722, Rarity.RARE, mage.cards.d.DelverOfSecrets.class)); - cards.add(new SetCardInfo("Insectile Aberration", 722, Rarity.RARE, mage.cards.i.InsectileAberration.class)); cards.add(new SetCardInfo("Brainstorm", 723, Rarity.RARE, mage.cards.b.Brainstorm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lightning Strike", 724, Rarity.RARE, mage.cards.l.LightningStrike.class)); cards.add(new SetCardInfo("Fleshbag Marauder", 725, Rarity.RARE, mage.cards.f.FleshbagMarauder.class, NON_FULL_USE_VARIOUS)); @@ -1063,9 +1060,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Eldrazi Temple", 1154, Rarity.RARE, mage.cards.e.EldraziTemple.class)); cards.add(new SetCardInfo("Esika, God of the Tree", 1155, Rarity.MYTHIC, mage.cards.e.EsikaGodOfTheTree.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Archangel Avacyn", 1156, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 1156, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodline Keeper", 1157, Rarity.RARE, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lord of Lineage", 1157, Rarity.RARE, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nicol Bolas, the Ravager", 1158, Rarity.MYTHIC, mage.cards.n.NicolBolasTheRavager.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nicol Bolas, the Arisen", 1158, Rarity.MYTHIC, mage.cards.n.NicolBolasTheArisen.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Westvale Abbey", 1159, Rarity.RARE, mage.cards.w.WestvaleAbbey.class, NON_FULL_USE_VARIOUS)); @@ -1120,9 +1115,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Inkmoth Nexus", 1207, Rarity.RARE, mage.cards.i.InkmothNexus.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Esika, God of the Tree", 1208, Rarity.MYTHIC, mage.cards.e.EsikaGodOfTheTree.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Archangel Avacyn", 1209, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 1209, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodline Keeper", 1210, Rarity.RARE, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lord of Lineage", 1210, Rarity.RARE, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nicol Bolas, the Ravager", 1211, Rarity.MYTHIC, mage.cards.n.NicolBolasTheRavager.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nicol Bolas, the Arisen", 1211, Rarity.MYTHIC, mage.cards.n.NicolBolasTheArisen.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Westvale Abbey", 1212, Rarity.RARE, mage.cards.w.WestvaleAbbey.class, NON_FULL_USE_VARIOUS)); @@ -1613,7 +1606,6 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Scrying Sheets", 1606, Rarity.RARE, mage.cards.s.ScryingSheets.class)); cards.add(new SetCardInfo("Thespian's Stage", 1607, Rarity.RARE, mage.cards.t.ThespiansStage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avabruck Caretaker", 1608, Rarity.MYTHIC, mage.cards.a.AvabruckCaretaker.class)); - cards.add(new SetCardInfo("Hollowhenge Huntmaster", 1608, Rarity.MYTHIC, mage.cards.h.HollowhengeHuntmaster.class)); cards.add(new SetCardInfo("Beastmaster Ascension", 1609, Rarity.RARE, mage.cards.b.BeastmasterAscension.class)); cards.add(new SetCardInfo("Howl of the Night Pack", 1610, Rarity.RARE, mage.cards.h.HowlOfTheNightPack.class)); cards.add(new SetCardInfo("Second Harvest", 1611, Rarity.RARE, mage.cards.s.SecondHarvest.class)); diff --git a/Mage.Sets/src/mage/sets/SecretLairShowdown.java b/Mage.Sets/src/mage/sets/SecretLairPromo.java similarity index 92% rename from Mage.Sets/src/mage/sets/SecretLairShowdown.java rename to Mage.Sets/src/mage/sets/SecretLairPromo.java index 3f32c7ceb5b..5c17194773c 100644 --- a/Mage.Sets/src/mage/sets/SecretLairShowdown.java +++ b/Mage.Sets/src/mage/sets/SecretLairPromo.java @@ -7,16 +7,16 @@ import mage.constants.SetType; /** * https://scryfall.com/sets/slp */ -public class SecretLairShowdown extends ExpansionSet { +public class SecretLairPromo extends ExpansionSet { - private static final SecretLairShowdown instance = new SecretLairShowdown(); + private static final SecretLairPromo instance = new SecretLairPromo(); - public static SecretLairShowdown getInstance() { + public static SecretLairPromo getInstance() { return instance; } - private SecretLairShowdown() { - super("Secret Lair Showdown", "SLP", ExpansionSet.buildDate(2023, 2, 17), SetType.PROMOTIONAL); + private SecretLairPromo() { + super("Secret Lair Promo", "SLP", ExpansionSet.buildDate(2023, 2, 17), SetType.PROMOTIONAL); this.hasBoosters = false; this.hasBasicLands = true; @@ -32,6 +32,7 @@ public class SecretLairShowdown extends ExpansionSet { cards.add(new SetCardInfo("Fauna Shaman", 41, Rarity.RARE, mage.cards.f.FaunaShaman.class)); cards.add(new SetCardInfo("Flowerfoot Swordmaster", 46, Rarity.RARE, mage.cards.f.FlowerfootSwordmaster.class)); cards.add(new SetCardInfo("Force of Despair", 29, Rarity.RARE, mage.cards.f.ForceOfDespair.class, FULL_ART)); + cards.add(new SetCardInfo("Forest", 35, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Garruk Wildspeaker", 42, Rarity.MYTHIC, mage.cards.g.GarrukWildspeaker.class)); cards.add(new SetCardInfo("Goblin Guide", 23, Rarity.RARE, mage.cards.g.GoblinGuide.class)); cards.add(new SetCardInfo("Innkeeper's Talent", 45, Rarity.RARE, mage.cards.i.InnkeepersTalent.class, FULL_ART)); diff --git a/Mage.Sets/src/mage/sets/ShadowsOfThePast.java b/Mage.Sets/src/mage/sets/ShadowsOfThePast.java index c84cbce0064..3a9b0e6b694 100644 --- a/Mage.Sets/src/mage/sets/ShadowsOfThePast.java +++ b/Mage.Sets/src/mage/sets/ShadowsOfThePast.java @@ -71,7 +71,6 @@ public class ShadowsOfThePast extends ExpansionSet { cards.add(new SetCardInfo("Invisible Stalker", 17, Rarity.UNCOMMON, mage.cards.i.InvisibleStalker.class)); cards.add(new SetCardInfo("Kruin Outlaw", 42, Rarity.RARE, mage.cards.k.KruinOutlaw.class)); cards.add(new SetCardInfo("Lingering Souls", 9, Rarity.UNCOMMON, mage.cards.l.LingeringSouls.class)); - cards.add(new SetCardInfo("Lord of Lineage", 27, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class)); cards.add(new SetCardInfo("Mayor of Avabruck", 53, Rarity.RARE, mage.cards.m.MayorOfAvabruck.class)); cards.add(new SetCardInfo("Mist Raven", 18, Rarity.COMMON, mage.cards.m.MistRaven.class)); cards.add(new SetCardInfo("Moonmist", 54, Rarity.COMMON, mage.cards.m.Moonmist.class)); @@ -79,7 +78,6 @@ public class ShadowsOfThePast extends ExpansionSet { cards.add(new SetCardInfo("Mystic Retrieval", 20, Rarity.UNCOMMON, mage.cards.m.MysticRetrieval.class)); cards.add(new SetCardInfo("Past in Flames", 43, Rarity.MYTHIC, mage.cards.p.PastInFlames.class)); cards.add(new SetCardInfo("Rally the Peasants", 10, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class)); - cards.add(new SetCardInfo("Ravager of the Fells", 64, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class)); cards.add(new SetCardInfo("Requiem Angel", 11, Rarity.RARE, mage.cards.r.RequiemAngel.class)); cards.add(new SetCardInfo("Seance", 12, Rarity.UNCOMMON, mage.cards.s.Seance.class)); cards.add(new SetCardInfo("Selhoff Occultist", 21, Rarity.COMMON, mage.cards.s.SelhoffOccultist.class)); diff --git a/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java b/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java index bd1e36b3394..f9aa8c5f5ef 100644 --- a/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java +++ b/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java @@ -43,29 +43,24 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Alms of the Vein", 98, Rarity.COMMON, mage.cards.a.AlmsOfTheVein.class)); cards.add(new SetCardInfo("Altered Ego", 241, Rarity.RARE, mage.cards.a.AlteredEgo.class)); cards.add(new SetCardInfo("Always Watching", 1, Rarity.RARE, mage.cards.a.AlwaysWatching.class)); - cards.add(new SetCardInfo("Ancient of the Equinox", 194, Rarity.UNCOMMON, mage.cards.a.AncientOfTheEquinox.class)); cards.add(new SetCardInfo("Angel of Deliverance", 2, Rarity.RARE, mage.cards.a.AngelOfDeliverance.class)); cards.add(new SetCardInfo("Angelic Purge", 3, Rarity.COMMON, mage.cards.a.AngelicPurge.class)); cards.add(new SetCardInfo("Anguished Unmaking", 242, Rarity.RARE, mage.cards.a.AnguishedUnmaking.class)); cards.add(new SetCardInfo("Apothecary Geist", 4, Rarity.COMMON, mage.cards.a.ApothecaryGeist.class)); cards.add(new SetCardInfo("Archangel Avacyn", 5, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class)); cards.add(new SetCardInfo("Arlinn Kord", 243, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 243, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class)); cards.add(new SetCardInfo("Ashmouth Blade", 260, Rarity.UNCOMMON, mage.cards.a.AshmouthBlade.class)); cards.add(new SetCardInfo("Asylum Visitor", 99, Rarity.RARE, mage.cards.a.AsylumVisitor.class)); cards.add(new SetCardInfo("Autumnal Gloom", 194, Rarity.UNCOMMON, mage.cards.a.AutumnalGloom.class)); cards.add(new SetCardInfo("Avacyn's Judgment", 145, Rarity.RARE, mage.cards.a.AvacynsJudgment.class)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 5, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class)); cards.add(new SetCardInfo("Avacynian Missionaries", 6, Rarity.UNCOMMON, mage.cards.a.AvacynianMissionaries.class)); cards.add(new SetCardInfo("Awoken Horror", 92, Rarity.RARE, mage.cards.a.AwokenHorror.class)); - cards.add(new SetCardInfo("Bearer of Overwhelming Truths", 54, Rarity.UNCOMMON, mage.cards.b.BearerOfOverwhelmingTruths.class)); cards.add(new SetCardInfo("Behind the Scenes", 100, Rarity.UNCOMMON, mage.cards.b.BehindTheScenes.class)); cards.add(new SetCardInfo("Behold the Beyond", 101, Rarity.MYTHIC, mage.cards.b.BeholdTheBeyond.class)); cards.add(new SetCardInfo("Biting Rain", 102, Rarity.UNCOMMON, mage.cards.b.BitingRain.class)); cards.add(new SetCardInfo("Bloodmad Vampire", 146, Rarity.COMMON, mage.cards.b.BloodmadVampire.class)); cards.add(new SetCardInfo("Bound by Moonsilver", 7, Rarity.UNCOMMON, mage.cards.b.BoundByMoonsilver.class)); cards.add(new SetCardInfo("Brain in a Jar", 252, Rarity.RARE, mage.cards.b.BrainInAJar.class)); - cards.add(new SetCardInfo("Branded Howler", 149, Rarity.COMMON, mage.cards.b.BrandedHowler.class)); cards.add(new SetCardInfo("Breakneck Rider", 147, Rarity.UNCOMMON, mage.cards.b.BreakneckRider.class)); cards.add(new SetCardInfo("Briarbridge Patrol", 195, Rarity.UNCOMMON, mage.cards.b.BriarbridgePatrol.class)); cards.add(new SetCardInfo("Broken Concentration", 50, Rarity.UNCOMMON, mage.cards.b.BrokenConcentration.class)); @@ -176,10 +171,8 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Incorrigible Youths", 166, Rarity.UNCOMMON, mage.cards.i.IncorrigibleYouths.class)); cards.add(new SetCardInfo("Indulgent Aristocrat", 118, Rarity.UNCOMMON, mage.cards.i.IndulgentAristocrat.class)); cards.add(new SetCardInfo("Inexorable Blob", 212, Rarity.RARE, mage.cards.i.InexorableBlob.class)); - cards.add(new SetCardInfo("Infectious Curse", 97, Rarity.UNCOMMON, mage.cards.i.InfectiousCurse.class)); cards.add(new SetCardInfo("Inner Struggle", 167, Rarity.UNCOMMON, mage.cards.i.InnerStruggle.class)); cards.add(new SetCardInfo("Inquisitor's Ox", 24, Rarity.COMMON, mage.cards.i.InquisitorsOx.class)); - cards.add(new SetCardInfo("Insidious Mist", 108, Rarity.RARE, mage.cards.i.InsidiousMist.class)); cards.add(new SetCardInfo("Insolent Neonate", 168, Rarity.COMMON, mage.cards.i.InsolentNeonate.class)); cards.add(new SetCardInfo("Inspiring Captain", 25, Rarity.COMMON, mage.cards.i.InspiringCaptain.class)); cards.add(new SetCardInfo("Intrepid Provisioner", 213, Rarity.COMMON, mage.cards.i.IntrepidProvisioner.class)); @@ -194,15 +187,12 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Kessig Dire Swine", 214, Rarity.COMMON, mage.cards.k.KessigDireSwine.class)); cards.add(new SetCardInfo("Kessig Forgemaster", 169, Rarity.UNCOMMON, mage.cards.k.KessigForgemaster.class)); cards.add(new SetCardInfo("Kindly Stranger", 119, Rarity.UNCOMMON, mage.cards.k.KindlyStranger.class)); - cards.add(new SetCardInfo("Krallenhorde Howler", 203, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class)); - cards.add(new SetCardInfo("Lambholt Butcher", 215, Rarity.UNCOMMON, mage.cards.l.LambholtButcher.class)); cards.add(new SetCardInfo("Lambholt Pacifist", 215, Rarity.UNCOMMON, mage.cards.l.LambholtPacifist.class)); cards.add(new SetCardInfo("Lamplighter of Selhoff", 72, Rarity.COMMON, mage.cards.l.LamplighterOfSelhoff.class)); cards.add(new SetCardInfo("Lightning Axe", 170, Rarity.UNCOMMON, mage.cards.l.LightningAxe.class)); cards.add(new SetCardInfo("Liliana's Indignation", 120, Rarity.UNCOMMON, mage.cards.l.LilianasIndignation.class)); cards.add(new SetCardInfo("Loam Dryad", 216, Rarity.COMMON, mage.cards.l.LoamDryad.class)); cards.add(new SetCardInfo("Lone Wolf of the Natterknolls", 209, Rarity.UNCOMMON, mage.cards.l.LoneWolfOfTheNatterknolls.class)); - cards.add(new SetCardInfo("Lunarch Inquisitors", 6, Rarity.UNCOMMON, mage.cards.l.LunarchInquisitors.class)); cards.add(new SetCardInfo("Macabre Waltz", 121, Rarity.COMMON, mage.cards.m.MacabreWaltz.class)); cards.add(new SetCardInfo("Mad Prophet", 171, Rarity.UNCOMMON, mage.cards.m.MadProphet.class)); cards.add(new SetCardInfo("Magmatic Chasm", 172, Rarity.COMMON, mage.cards.m.MagmaticChasm.class)); @@ -228,7 +218,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Nahiri's Machinations", 28, Rarity.UNCOMMON, mage.cards.n.NahirisMachinations.class)); cards.add(new SetCardInfo("Nahiri, the Harbinger", 247, Rarity.MYTHIC, mage.cards.n.NahiriTheHarbinger.class)); cards.add(new SetCardInfo("Nearheath Chaplain", 29, Rarity.UNCOMMON, mage.cards.n.NearheathChaplain.class)); - cards.add(new SetCardInfo("Neck Breaker", 147, Rarity.UNCOMMON, mage.cards.n.NeckBreaker.class)); cards.add(new SetCardInfo("Neglected Heirloom", 260, Rarity.UNCOMMON, mage.cards.n.NeglectedHeirloom.class)); cards.add(new SetCardInfo("Nephalia Moondrakes", 75, Rarity.RARE, mage.cards.n.NephaliaMoondrakes.class)); cards.add(new SetCardInfo("Niblis of Dusk", 76, Rarity.COMMON, mage.cards.n.NiblisOfDusk.class)); @@ -244,8 +233,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Pack Guardian", 221, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class)); cards.add(new SetCardInfo("Pale Rider of Trostad", 128, Rarity.UNCOMMON, mage.cards.p.PaleRiderOfTrostad.class)); cards.add(new SetCardInfo("Paranoid Parish-Blade", 33, Rarity.UNCOMMON, mage.cards.p.ParanoidParishBlade.class)); - cards.add(new SetCardInfo("Perfected Form", 49, Rarity.UNCOMMON, mage.cards.p.PerfectedForm.class)); - cards.add(new SetCardInfo("Persistent Nightmare", 88, Rarity.MYTHIC, mage.cards.p.PersistentNightmare.class)); cards.add(new SetCardInfo("Pick the Brain", 129, Rarity.UNCOMMON, mage.cards.p.PickTheBrain.class)); cards.add(new SetCardInfo("Pieces of the Puzzle", 78, Rarity.COMMON, mage.cards.p.PiecesOfThePuzzle.class)); cards.add(new SetCardInfo("Pious Evangel", 34, Rarity.UNCOMMON, mage.cards.p.PiousEvangel.class)); @@ -331,7 +318,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Thraben Gargoyle", 266, Rarity.UNCOMMON, mage.cards.t.ThrabenGargoyle.class)); cards.add(new SetCardInfo("Thraben Inspector", 44, Rarity.COMMON, mage.cards.t.ThrabenInspector.class)); cards.add(new SetCardInfo("Throttle", 138, Rarity.COMMON, mage.cards.t.Throttle.class)); - cards.add(new SetCardInfo("Timber Shredder", 210, Rarity.COMMON, mage.cards.t.TimberShredder.class)); cards.add(new SetCardInfo("Tireless Tracker", 233, Rarity.RARE, mage.cards.t.TirelessTracker.class)); cards.add(new SetCardInfo("To the Slaughter", 139, Rarity.RARE, mage.cards.t.ToTheSlaughter.class)); cards.add(new SetCardInfo("Tooth Collector", 140, Rarity.UNCOMMON, mage.cards.t.ToothCollector.class)); @@ -347,7 +333,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Ulvenwald Hydra", 235, Rarity.MYTHIC, mage.cards.u.UlvenwaldHydra.class)); cards.add(new SetCardInfo("Ulvenwald Mysteries", 236, Rarity.UNCOMMON, mage.cards.u.UlvenwaldMysteries.class)); cards.add(new SetCardInfo("Uncaged Fury", 188, Rarity.COMMON, mage.cards.u.UncagedFury.class)); - cards.add(new SetCardInfo("Unimpeded Trespasser", 94, Rarity.UNCOMMON, mage.cards.u.UnimpededTrespasser.class)); cards.add(new SetCardInfo("Uninvited Geist", 94, Rarity.UNCOMMON, mage.cards.u.UninvitedGeist.class)); cards.add(new SetCardInfo("Unruly Mob", 47, Rarity.COMMON, mage.cards.u.UnrulyMob.class)); cards.add(new SetCardInfo("Vampire Noble", 143, Rarity.COMMON, mage.cards.v.VampireNoble.class)); diff --git a/Mage.Sets/src/mage/sets/ShadowsOverInnistradPromos.java b/Mage.Sets/src/mage/sets/ShadowsOverInnistradPromos.java index 8c445e2fa97..9e53eaafb27 100644 --- a/Mage.Sets/src/mage/sets/ShadowsOverInnistradPromos.java +++ b/Mage.Sets/src/mage/sets/ShadowsOverInnistradPromos.java @@ -29,10 +29,8 @@ public class ShadowsOverInnistradPromos extends ExpansionSet { cards.add(new SetCardInfo("Anguished Unmaking", 242, Rarity.RARE, mage.cards.a.AnguishedUnmaking.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Archangel Avacyn", "5s", Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class)); cards.add(new SetCardInfo("Arlinn Kord", "243s", Rarity.MYTHIC, mage.cards.a.ArlinnKord.class)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", "243s", Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class)); cards.add(new SetCardInfo("Asylum Visitor", "99s", Rarity.RARE, mage.cards.a.AsylumVisitor.class)); cards.add(new SetCardInfo("Avacyn's Judgment", "145s", Rarity.RARE, mage.cards.a.AvacynsJudgment.class)); - cards.add(new SetCardInfo("Avacyn, the Purifier", "5s", Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class)); cards.add(new SetCardInfo("Awoken Horror", "92s", Rarity.RARE, mage.cards.a.AwokenHorror.class)); cards.add(new SetCardInfo("Behold the Beyond", "101s", Rarity.MYTHIC, mage.cards.b.BeholdTheBeyond.class)); cards.add(new SetCardInfo("Brain in a Jar", "252s", Rarity.RARE, mage.cards.b.BrainInAJar.class)); @@ -73,8 +71,6 @@ public class ShadowsOverInnistradPromos extends ExpansionSet { cards.add(new SetCardInfo("Harness the Storm", "163s", Rarity.RARE, mage.cards.h.HarnessTheStorm.class)); cards.add(new SetCardInfo("Incorrigible Youths", 166, Rarity.UNCOMMON, mage.cards.i.IncorrigibleYouths.class)); cards.add(new SetCardInfo("Inexorable Blob", "212s", Rarity.RARE, mage.cards.i.InexorableBlob.class)); - cards.add(new SetCardInfo("Insidious Mist", "108s", Rarity.RARE, mage.cards.i.InsidiousMist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Insidious Mist", 108, Rarity.RARE, mage.cards.i.InsidiousMist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Invocation of Saint Traft", "246s", Rarity.RARE, mage.cards.i.InvocationOfSaintTraft.class)); cards.add(new SetCardInfo("Jace, Unraveler of Secrets", "69s", Rarity.MYTHIC, mage.cards.j.JaceUnravelerOfSecrets.class)); cards.add(new SetCardInfo("Markov Dreadknight", "122s", Rarity.RARE, mage.cards.m.MarkovDreadknight.class, NON_FULL_USE_VARIOUS)); @@ -86,7 +82,6 @@ public class ShadowsOverInnistradPromos extends ExpansionSet { cards.add(new SetCardInfo("Odric, Lunarch Marshal", "31s", Rarity.RARE, mage.cards.o.OdricLunarchMarshal.class)); cards.add(new SetCardInfo("Olivia, Mobilized for War", "248s", Rarity.MYTHIC, mage.cards.o.OliviaMobilizedForWar.class)); cards.add(new SetCardInfo("Ormendahl, Profane Prince", "281s", Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class)); - cards.add(new SetCardInfo("Persistent Nightmare", "88s", Rarity.MYTHIC, mage.cards.p.PersistentNightmare.class)); cards.add(new SetCardInfo("Port Town", "278s", Rarity.RARE, mage.cards.p.PortTown.class)); cards.add(new SetCardInfo("Prized Amalgam", "249s", Rarity.RARE, mage.cards.p.PrizedAmalgam.class)); cards.add(new SetCardInfo("Rattlechains", "81s", Rarity.RARE, mage.cards.r.Rattlechains.class)); diff --git a/Mage.Sets/src/mage/sets/ShadowsOverInnistradRemastered.java b/Mage.Sets/src/mage/sets/ShadowsOverInnistradRemastered.java index 8739ee9b6ea..6cdd42e309e 100644 --- a/Mage.Sets/src/mage/sets/ShadowsOverInnistradRemastered.java +++ b/Mage.Sets/src/mage/sets/ShadowsOverInnistradRemastered.java @@ -39,14 +39,10 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Apothecary Geist", 12, Rarity.COMMON, mage.cards.a.ApothecaryGeist.class)); cards.add(new SetCardInfo("Archangel Avacyn", 13, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class)); cards.add(new SetCardInfo("Arlinn Kord", 230, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 230, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class)); cards.add(new SetCardInfo("Ashmouth Blade", 256, Rarity.UNCOMMON, mage.cards.a.AshmouthBlade.class)); cards.add(new SetCardInfo("Assembled Alphas", 141, Rarity.RARE, mage.cards.a.AssembledAlphas.class)); - cards.add(new SetCardInfo("Aurora of Emrakul", 248, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class)); cards.add(new SetCardInfo("Avacyn's Judgment", 142, Rarity.RARE, mage.cards.a.AvacynsJudgment.class)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 13, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class)); cards.add(new SetCardInfo("Awoken Horror", 95, Rarity.RARE, mage.cards.a.AwokenHorror.class)); - cards.add(new SetCardInfo("Bearer of Overwhelming Truths", 59, Rarity.UNCOMMON, mage.cards.b.BearerOfOverwhelmingTruths.class)); cards.add(new SetCardInfo("Bedlam Reveler", 143, Rarity.RARE, mage.cards.b.BedlamReveler.class)); cards.add(new SetCardInfo("Biting Rain", 99, Rarity.UNCOMMON, mage.cards.b.BitingRain.class)); cards.add(new SetCardInfo("Blessed Alliance", 14, Rarity.UNCOMMON, mage.cards.b.BlessedAlliance.class)); @@ -74,7 +70,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Collective Defiance", 148, Rarity.RARE, mage.cards.c.CollectiveDefiance.class)); cards.add(new SetCardInfo("Collective Effort", 19, Rarity.RARE, mage.cards.c.CollectiveEffort.class)); cards.add(new SetCardInfo("Compelling Deterrence", 55, Rarity.UNCOMMON, mage.cards.c.CompellingDeterrence.class)); - cards.add(new SetCardInfo("Conduit of Emrakul", 149, Rarity.COMMON, mage.cards.c.ConduitOfEmrakul.class)); cards.add(new SetCardInfo("Conduit of Storms", 149, Rarity.COMMON, mage.cards.c.ConduitOfStorms.class)); cards.add(new SetCardInfo("Confirm Suspicions", 56, Rarity.RARE, mage.cards.c.ConfirmSuspicions.class)); cards.add(new SetCardInfo("Confront the Unknown", 190, Rarity.COMMON, mage.cards.c.ConfrontTheUnknown.class)); @@ -183,7 +178,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Incendiary Flow", 163, Rarity.COMMON, mage.cards.i.IncendiaryFlow.class)); cards.add(new SetCardInfo("Incited Rabble", 53, Rarity.UNCOMMON, mage.cards.i.IncitedRabble.class)); cards.add(new SetCardInfo("Indulgent Aristocrat", 118, Rarity.UNCOMMON, mage.cards.i.IndulgentAristocrat.class)); - cards.add(new SetCardInfo("Infectious Curse", 97, Rarity.UNCOMMON, mage.cards.i.InfectiousCurse.class)); cards.add(new SetCardInfo("Ingenious Skaab", 75, Rarity.COMMON, mage.cards.i.IngeniousSkaab.class)); cards.add(new SetCardInfo("Insatiable Gorgers", 164, Rarity.COMMON, mage.cards.i.InsatiableGorgers.class)); cards.add(new SetCardInfo("Insolent Neonate", 165, Rarity.COMMON, mage.cards.i.InsolentNeonate.class)); @@ -198,7 +192,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Jace's Scrutiny", 78, Rarity.COMMON, mage.cards.j.JacesScrutiny.class)); cards.add(new SetCardInfo("Jace, Unraveler of Secrets", 77, Rarity.MYTHIC, mage.cards.j.JaceUnravelerOfSecrets.class)); cards.add(new SetCardInfo("Kindly Stranger", 107, Rarity.UNCOMMON, mage.cards.k.KindlyStranger.class)); - cards.add(new SetCardInfo("Krallenhorde Howler", 194, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class)); cards.add(new SetCardInfo("Laboratory Brute", 79, Rarity.COMMON, mage.cards.l.LaboratoryBrute.class)); cards.add(new SetCardInfo("Lightning Axe", 166, Rarity.UNCOMMON, mage.cards.l.LightningAxe.class)); cards.add(new SetCardInfo("Liliana's Elite", 120, Rarity.COMMON, mage.cards.l.LilianasElite.class)); @@ -244,7 +237,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Ormendahl, Profane Prince", 275, Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class)); cards.add(new SetCardInfo("Pack Guardian", 208, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class)); cards.add(new SetCardInfo("Permeating Mass", 209, Rarity.RARE, mage.cards.p.PermeatingMass.class)); - cards.add(new SetCardInfo("Persistent Nightmare", 90, Rarity.MYTHIC, mage.cards.p.PersistentNightmare.class)); cards.add(new SetCardInfo("Pick the Brain", 129, Rarity.UNCOMMON, mage.cards.p.PickTheBrain.class)); cards.add(new SetCardInfo("Pieces of the Puzzle", 85, Rarity.UNCOMMON, mage.cards.p.PiecesOfThePuzzle.class)); cards.add(new SetCardInfo("Plains", 277, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); @@ -313,7 +305,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Thornhide Wolves", 218, Rarity.COMMON, mage.cards.t.ThornhideWolves.class)); cards.add(new SetCardInfo("Thraben Foulbloods", 135, Rarity.COMMON, mage.cards.t.ThrabenFoulbloods.class)); cards.add(new SetCardInfo("Thraben Inspector", 51, Rarity.COMMON, mage.cards.t.ThrabenInspector.class)); - cards.add(new SetCardInfo("Timber Shredder", 201, Rarity.COMMON, mage.cards.t.TimberShredder.class)); cards.add(new SetCardInfo("Tireless Tracker", 219, Rarity.RARE, mage.cards.t.TirelessTracker.class)); cards.add(new SetCardInfo("Topplegeist", 52, Rarity.UNCOMMON, mage.cards.t.Topplegeist.class)); cards.add(new SetCardInfo("Tormenting Voice", 181, Rarity.COMMON, mage.cards.t.TormentingVoice.class)); diff --git a/Mage.Sets/src/mage/sets/StarWars.java b/Mage.Sets/src/mage/sets/StarWars.java index b2f364c873b..fe63f0a5ab6 100644 --- a/Mage.Sets/src/mage/sets/StarWars.java +++ b/Mage.Sets/src/mage/sets/StarWars.java @@ -99,7 +99,6 @@ public final class StarWars extends ExpansionSet { cards.add(new SetCardInfo("Darth Maul", 178, Rarity.RARE, mage.cards.d.DarthMaul.class)); cards.add(new SetCardInfo("Darth Sidious, Sith Lord", 179, Rarity.MYTHIC, mage.cards.d.DarthSidiousSithLord.class)); cards.add(new SetCardInfo("Darth Tyranus, Count of Serenno", 180, Rarity.MYTHIC, mage.cards.d.DarthTyranusCountOfSerenno.class)); - cards.add(new SetCardInfo("Darth Vader", 140, Rarity.MYTHIC, mage.cards.d.DarthVader.class)); cards.add(new SetCardInfo("Death Trooper", 71, Rarity.UNCOMMON, mage.cards.d.DeathTrooper.class)); cards.add(new SetCardInfo("Delay Tactic", 504, Rarity.COMMON, mage.cards.d.DelayTactic.class)); cards.add(new SetCardInfo("Deploy The Troops", 8, Rarity.UNCOMMON, mage.cards.d.DeployTheTroops.class)); diff --git a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java index b69a7f099d0..d2c77c86f58 100644 --- a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java @@ -1,15 +1,12 @@ package mage.sets; -import mage.cards.Card; import mage.cards.ExpansionSet; -import mage.cards.repository.CardInfo; -import mage.constants.Rarity; -import mage.constants.SetType; -import mage.util.RandomUtil; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; import mage.collation.CardRun; import mage.collation.RarityConfiguration; +import mage.constants.Rarity; +import mage.constants.SetType; import java.util.ArrayList; import java.util.List; @@ -77,7 +74,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Belligerent Yearling", 133, Rarity.UNCOMMON, mage.cards.b.BelligerentYearling.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Belligerent Yearling", 320, Rarity.UNCOMMON, mage.cards.b.BelligerentYearling.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bitter Triumph", 91, Rarity.UNCOMMON, mage.cards.b.BitterTriumph.class)); - cards.add(new SetCardInfo("Bladewheel Chariot", 36, Rarity.UNCOMMON, mage.cards.b.BladewheelChariot.class)); cards.add(new SetCardInfo("Bloodletter of Aclazotz", 336, Rarity.MYTHIC, mage.cards.b.BloodletterOfAclazotz.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodletter of Aclazotz", 92, Rarity.MYTHIC, mage.cards.b.BloodletterOfAclazotz.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodthorn Flail", 93, Rarity.UNCOMMON, mage.cards.b.BloodthornFlail.class)); @@ -86,8 +82,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Brackish Blunder", 46, Rarity.COMMON, mage.cards.b.BrackishBlunder.class)); cards.add(new SetCardInfo("Braided Net", 360, Rarity.RARE, mage.cards.b.BraidedNet.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Braided Net", 47, Rarity.RARE, mage.cards.b.BraidedNet.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Braided Quipu", 360, Rarity.RARE, mage.cards.b.BraidedQuipu.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Braided Quipu", 47, Rarity.RARE, mage.cards.b.BraidedQuipu.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Brass's Tunnel-Grinder", 135, Rarity.RARE, mage.cards.b.BrasssTunnelGrinder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Brass's Tunnel-Grinder", 373, Rarity.RARE, mage.cards.b.BrasssTunnelGrinder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Brazen Blademaster", 136, Rarity.COMMON, mage.cards.b.BrazenBlademaster.class)); @@ -136,7 +130,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Cosmium Blast", 7, Rarity.COMMON, mage.cards.c.CosmiumBlast.class)); cards.add(new SetCardInfo("Cosmium Confluence", 181, Rarity.RARE, mage.cards.c.CosmiumConfluence.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cosmium Confluence", 379, Rarity.RARE, mage.cards.c.CosmiumConfluence.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cosmium Kiln", 6, Rarity.UNCOMMON, mage.cards.c.CosmiumKiln.class)); cards.add(new SetCardInfo("Council of Echoes", 51, Rarity.UNCOMMON, mage.cards.c.CouncilOfEchoes.class)); cards.add(new SetCardInfo("Curator of Sun's Creation", 141, Rarity.UNCOMMON, mage.cards.c.CuratorOfSunsCreation.class)); cards.add(new SetCardInfo("Daring Discovery", 142, Rarity.COMMON, mage.cards.d.DaringDiscovery.class)); @@ -156,8 +149,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Didact Echo", 53, Rarity.COMMON, mage.cards.d.DidactEcho.class)); cards.add(new SetCardInfo("Digsite Conservator", 252, Rarity.UNCOMMON, mage.cards.d.DigsiteConservator.class)); cards.add(new SetCardInfo("Dinotomaton", 144, Rarity.COMMON, mage.cards.d.Dinotomaton.class)); - cards.add(new SetCardInfo("Dire Blunderbuss", 145, Rarity.RARE, mage.cards.d.DireBlunderbuss.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire Blunderbuss", 374, Rarity.RARE, mage.cards.d.DireBlunderbuss.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dire Flail", 145, Rarity.RARE, mage.cards.d.DireFlail.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dire Flail", 374, Rarity.RARE, mage.cards.d.DireFlail.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Disruptor Wanderglyph", 253, Rarity.COMMON, mage.cards.d.DisruptorWanderglyph.class)); @@ -187,7 +178,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Frilled Cave-Wurm", 57, Rarity.COMMON, mage.cards.f.FrilledCaveWurm.class)); cards.add(new SetCardInfo("Fungal Fortitude", 106, Rarity.COMMON, mage.cards.f.FungalFortitude.class)); cards.add(new SetCardInfo("Gargantuan Leech", 107, Rarity.UNCOMMON, mage.cards.g.GargantuanLeech.class)); - cards.add(new SetCardInfo("Geode Grotto", 146, Rarity.UNCOMMON, mage.cards.g.GeodeGrotto.class)); cards.add(new SetCardInfo("Geological Appraiser", 150, Rarity.UNCOMMON, mage.cards.g.GeologicalAppraiser.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Geological Appraiser", 407, Rarity.UNCOMMON, mage.cards.g.GeologicalAppraiser.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Get Lost", 14, Rarity.RARE, mage.cards.g.GetLost.class, NON_FULL_USE_VARIOUS)); @@ -426,8 +416,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Tarrian's Soulcleaver", 264, Rarity.RARE, mage.cards.t.TarriansSoulcleaver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tarrian's Soulcleaver", 389, Rarity.RARE, mage.cards.t.TarriansSoulcleaver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tectonic Hazard", 169, Rarity.COMMON, mage.cards.t.TectonicHazard.class)); - cards.add(new SetCardInfo("Tecutlan, the Searing Rift", 135, Rarity.RARE, mage.cards.t.TecutlanTheSearingRift.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tecutlan, the Searing Rift", 373, Rarity.RARE, mage.cards.t.TecutlanTheSearingRift.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Temple of Civilization", 26, Rarity.MYTHIC, mage.cards.t.TempleOfCivilization.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Temple of Civilization", 314, Rarity.MYTHIC, mage.cards.t.TempleOfCivilization.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Temple of Cultivation", 204, Rarity.MYTHIC, mage.cards.t.TempleOfCultivation.class, NON_FULL_USE_VARIOUS)); @@ -436,8 +424,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Temple of Cyclical Time", 67, Rarity.MYTHIC, mage.cards.t.TempleOfCyclicalTime.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Temple of Power", 158, Rarity.MYTHIC, mage.cards.t.TempleOfPower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Temple of Power", 317, Rarity.MYTHIC, mage.cards.t.TempleOfPower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of the Dead", 316, Rarity.MYTHIC, mage.cards.t.TempleOfTheDead.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of the Dead", 88, Rarity.MYTHIC, mage.cards.t.TempleOfTheDead.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tendril of the Mycotyrant", 215, Rarity.UNCOMMON, mage.cards.t.TendrilOfTheMycotyrant.class)); cards.add(new SetCardInfo("Terror Tide", 127, Rarity.RARE, mage.cards.t.TerrorTide.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Terror Tide", 372, Rarity.RARE, mage.cards.t.TerrorTide.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalanCommander.java b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalanCommander.java index 0a1ca2edf90..14f9f6d5b44 100644 --- a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalanCommander.java +++ b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalanCommander.java @@ -31,7 +31,6 @@ public final class TheLostCavernsOfIxalanCommander extends ExpansionSet { cards.add(new SetCardInfo("Amulet of Vigor", 103, Rarity.RARE, mage.cards.a.AmuletOfVigor.class)); cards.add(new SetCardInfo("Angrath's Marauders", 215, Rarity.RARE, mage.cards.a.AngrathsMarauders.class)); cards.add(new SetCardInfo("Apex Altisaur", 232, Rarity.RARE, mage.cards.a.ApexAltisaur.class)); - cards.add(new SetCardInfo("Apex Observatory", 15, Rarity.MYTHIC, mage.cards.a.ApexObservatory.class)); cards.add(new SetCardInfo("Arcane Signet", 104, Rarity.UNCOMMON, mage.cards.a.ArcaneSignet.class)); cards.add(new SetCardInfo("Arch of Orazca", 319, Rarity.RARE, mage.cards.a.ArchOfOrazca.class)); cards.add(new SetCardInfo("Archaeomancer's Map", 101, Rarity.RARE, mage.cards.a.ArchaeomancersMap.class)); @@ -329,7 +328,6 @@ public final class TheLostCavernsOfIxalanCommander extends ExpansionSet { cards.add(new SetCardInfo("Windfall", 180, Rarity.UNCOMMON, mage.cards.w.Windfall.class)); cards.add(new SetCardInfo("Worn Powerstone", 120, Rarity.UNCOMMON, mage.cards.w.WornPowerstone.class)); cards.add(new SetCardInfo("Wrathful Raptors", 88, Rarity.RARE, mage.cards.w.WrathfulRaptors.class)); - cards.add(new SetCardInfo("Wretched Bonemass", 10, Rarity.RARE, mage.cards.w.WretchedBonemass.class)); cards.add(new SetCardInfo("Xavier Sal, Infested Captain", 14, Rarity.RARE, mage.cards.x.XavierSalInfestedCaptain.class)); cards.add(new SetCardInfo("Xenagos, God of Revels", 295, Rarity.MYTHIC, mage.cards.x.XenagosGodOfRevels.class)); cards.add(new SetCardInfo("Xolatoyac, the Smiling Flood", 8, Rarity.MYTHIC, mage.cards.x.XolatoyacTheSmilingFlood.class)); diff --git a/Mage.Sets/src/mage/sets/Transformers.java b/Mage.Sets/src/mage/sets/Transformers.java index 0e8daddb516..7ea26010c82 100644 --- a/Mage.Sets/src/mage/sets/Transformers.java +++ b/Mage.Sets/src/mage/sets/Transformers.java @@ -19,11 +19,8 @@ public final class Transformers extends ExpansionSet { super("Transformers", "BOT", ExpansionSet.buildDate(2022, 11, 18), SetType.SUPPLEMENTAL); this.hasBasicLands = false; - cards.add(new SetCardInfo("Arcee, Acrobatic Coupe", 7, Rarity.MYTHIC, mage.cards.a.ArceeAcrobaticCoupe.class)); cards.add(new SetCardInfo("Arcee, Sharpshooter", 7, Rarity.MYTHIC, mage.cards.a.ArceeSharpshooter.class)); - cards.add(new SetCardInfo("Blitzwing, Adaptive Assailant", 4, Rarity.MYTHIC, mage.cards.b.BlitzwingAdaptiveAssailant.class)); cards.add(new SetCardInfo("Blitzwing, Cruel Tormentor", 4, Rarity.MYTHIC, mage.cards.b.BlitzwingCruelTormentor.class)); - cards.add(new SetCardInfo("Cyclonus, Cybertronian Fighter", 9, Rarity.MYTHIC, mage.cards.c.CyclonusCybertronianFighter.class)); cards.add(new SetCardInfo("Cyclonus, the Saboteur", 9, Rarity.MYTHIC, mage.cards.c.CyclonusTheSaboteur.class)); cards.add(new SetCardInfo("Flamewar, Brash Veteran", 10, Rarity.MYTHIC, mage.cards.f.FlamewarBrashVeteran.class)); cards.add(new SetCardInfo("Flamewar, Streetwise Operative", 10, Rarity.MYTHIC, mage.cards.f.FlamewarStreetwiseOperative.class)); @@ -33,9 +30,7 @@ public final class Transformers extends ExpansionSet { cards.add(new SetCardInfo("Jetfire, Ingenious Scientist", 3, Rarity.MYTHIC, mage.cards.j.JetfireIngeniousScientist.class)); cards.add(new SetCardInfo("Megatron, Destructive Force", 12, Rarity.MYTHIC, mage.cards.m.MegatronDestructiveForce.class)); cards.add(new SetCardInfo("Megatron, Tyrant", 12, Rarity.MYTHIC, mage.cards.m.MegatronTyrant.class)); - cards.add(new SetCardInfo("Optimus Prime, Autobot Leader", 13, Rarity.MYTHIC, mage.cards.o.OptimusPrimeAutobotLeader.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Optimus Prime, Hero", 13, Rarity.MYTHIC, mage.cards.o.OptimusPrimeHero.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Optimus Prime, Autobot Leader", 27, Rarity.MYTHIC, mage.cards.o.OptimusPrimeAutobotLeader.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Optimus Prime, Hero", 27, Rarity.MYTHIC, mage.cards.o.OptimusPrimeHero.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ratchet, Field Medic", 2, Rarity.MYTHIC, mage.cards.r.RatchetFieldMedic.class)); cards.add(new SetCardInfo("Ratchet, Rescue Racer", 2, Rarity.MYTHIC, mage.cards.r.RatchetRescueRacer.class)); diff --git a/Mage.Sets/src/mage/sets/XLNTreasureChest.java b/Mage.Sets/src/mage/sets/XLNTreasureChest.java index 79d13733466..d4268f37d84 100644 --- a/Mage.Sets/src/mage/sets/XLNTreasureChest.java +++ b/Mage.Sets/src/mage/sets/XLNTreasureChest.java @@ -23,19 +23,16 @@ public class XLNTreasureChest extends ExpansionSet { cards.add(new SetCardInfo("Adanto, the First Fort", 22, Rarity.RARE, mage.cards.a.AdantoTheFirstFort.class)); cards.add(new SetCardInfo("Arguel's Blood Fast", 90, Rarity.RARE, mage.cards.a.ArguelsBloodFast.class)); cards.add(new SetCardInfo("Azcanta, the Sunken Ruin", 74, Rarity.RARE, mage.cards.a.AzcantaTheSunkenRuin.class)); - cards.add(new SetCardInfo("Conqueror's Foothold", 234, Rarity.RARE, mage.cards.c.ConquerorsFoothold.class)); cards.add(new SetCardInfo("Conqueror's Galleon", 234, Rarity.RARE, mage.cards.c.ConquerorsGalleon.class)); cards.add(new SetCardInfo("Dowsing Dagger", 235, Rarity.RARE, mage.cards.d.DowsingDagger.class)); cards.add(new SetCardInfo("Growing Rites of Itlimoc", 191, Rarity.RARE, mage.cards.g.GrowingRitesOfItlimoc.class)); cards.add(new SetCardInfo("Itlimoc, Cradle of the Sun", 191, Rarity.RARE, mage.cards.i.ItlimocCradleOfTheSun.class)); cards.add(new SetCardInfo("Legion's Landing", 22, Rarity.RARE, mage.cards.l.LegionsLanding.class)); - cards.add(new SetCardInfo("Lost Vale", 235, Rarity.RARE, mage.cards.l.LostVale.class)); cards.add(new SetCardInfo("Primal Amulet", 243, Rarity.RARE, mage.cards.p.PrimalAmulet.class)); cards.add(new SetCardInfo("Primal Wellspring", 243, Rarity.RARE, mage.cards.p.PrimalWellspring.class)); cards.add(new SetCardInfo("Search for Azcanta", 74, Rarity.RARE, mage.cards.s.SearchForAzcanta.class)); cards.add(new SetCardInfo("Spires of Orazca", 249, Rarity.RARE, mage.cards.s.SpiresOfOrazca.class)); cards.add(new SetCardInfo("Spitfire Bastion", 173, Rarity.RARE, mage.cards.s.SpitfireBastion.class)); - cards.add(new SetCardInfo("Temple of Aclazotz", 90, Rarity.RARE, mage.cards.t.TempleOfAclazotz.class)); cards.add(new SetCardInfo("Thaumatic Compass", 249, Rarity.RARE, mage.cards.t.ThaumaticCompass.class)); cards.add(new SetCardInfo("Treasure Cove", 250, Rarity.RARE, mage.cards.t.TreasureCove.class)); cards.add(new SetCardInfo("Treasure Map", 250, Rarity.RARE, mage.cards.t.TreasureMap.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/IncubateTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/IncubateTest.java index f2e12c3e5e0..b81b26e844b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/IncubateTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/IncubateTest.java @@ -200,23 +200,8 @@ public class IncubateTest extends CardTestPlayerBase { setChoice(playerA, true); // use copy setChoice(playerA, "Phyrexian Token"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 2); - - // kill original token - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target destroy"); - addTarget(playerA, "Phyrexian Token[no copy]"); - waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after kill", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 1); - showBattlefield("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA); - - // try to transform back side (nothing happen) - // 701.28c - // If a spell or ability instructs a player to transform a permanent that isn’t represented by a - // transforming token or a transforming double-faced card, nothing happens. - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target transform", "Phyrexian Token"); - waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after transform", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Incubator Token", 0); - checkPermanentCount("after transform", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 1); + checkPermanentCount("after copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 1); + // copy dies to state based actions setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java index 04417cc619c..c8ccc2e413d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java @@ -1,17 +1,290 @@ package org.mage.test.cards.abilities.keywords; +import mage.ObjectColor; +import mage.abilities.common.SagaAbility; +import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.constants.CardType; import mage.constants.PhaseStep; +import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * @author LevelX2 */ public class TransformTest extends CardTestPlayerBase { + + /* + Silvercoat Lion + {1}{W} + Creature - Cat + + 2/2 + */ + private static final String silvercoatLion = "Silvercoat Lion"; + + /* + Lightning Bolt + {R} + Instant + Lightning Bolt deals 3 damage to any target. + */ + private static final String lightningBolt = "Lightning Bolt"; + + /* + Azusa's Many Journeys + {1}{G} + Enchantment - Saga + (As this Saga enters and after your draw step, add a lore counter.) + I - You may play an additional land this turn. + II - You gain 3 life. + III - Exile this Saga, then return it to the battlefield transformed under your control. + Likeness of the Seeker + + Enchantment Creature - Human Monk + Whenever Likeness of the Seeker becomes blocked, untap up to three lands you control. + 3/3 + */ + private static final String azusasManyJourneys = "Azusa's Many Journeys"; + private static final String likenessOfTheSeeker = "Likeness of the Seeker"; + + /* + Liliana, Heretical Healer + {1}{B}{B} + Legendary Creature - Human Cleric + Lifelink + Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield. + 2/3 + + Liliana, Defiant Necromancer + Legendary Planeswalker - Liliana + +2: Each player discards a card. + -X: Return target nonlegendary creature with converted mana cost X from your graveyard to the battlefield. + -8: You get an emblem with "Whenever a creature you control dies, return it to the battlefield under your control at the beginning of the next end step." + */ + private static final String lilianaHereticalHealer = "Liliana, Heretical Healer"; + private static final String lilianaDefiantNecromancer = "Liliana, Defiant Necromancer"; + + /* + Languish + {2}{B}{B} + Sorcery + All creatures get -4/-4 until end of turn. + */ + private static final String languish = "Languish"; + + /* + Nissa, Vastwood Seer + {2}{G} + Legendary Creature - Elf Scout + When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library. + Whenever a land enters the battlefield under your control, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control. + 2/2 + + Nissa, Sage Animist + Legendary Planeswalker - Nissa + +1: Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand. + -2: Put a legendary 4/4 green Elemental creature token named Ashaya, the Awoken World onto the battlefield. + -7: Untap up to six target lands. They become 6/6 Elemental creatures. They're still lands. + */ + private static final String nissaVastwoodSeer = "Nissa, Vastwood Seer"; + private static final String nissaSageAnimist = "Nissa, Sage Animist"; + + /* + Fireball + {X}{R} + Sorcery + Fireball deals X damage divided evenly, rounded down, among any number of target creatures and/or players. + Fireball costs {1} more to cast for each target beyond the first. + */ + private static final String fireball = "Fireball"; + + /* + Infernal Scarring + {1}{B} + Enchantment - Aura + Enchant creature + Enchanted creature gets +2/+0 and has "When this creature dies, draw a card." + */ + private static final String infernalScarring = "Infernal Scarring"; + + /* + Autumnal Gloom + {2}{G} + Enchantment + {B}: Put the top card of your library into your graveyard. + Delirium - At the beginning of your end step, if there are four or more card types among cards in your graveyard, transform Autumnal Gloom. + + Ancient of the Equinox + Creature - Treefolk + Trample, hexproof + 4/4 + */ + private static final String autumnalGloom = "Autumnal Gloom"; + private static final String ancientOfTheEquinox = "Ancient of the Equinox"; + + /* + Huntmaster of the Fells + {2}{R}{G} + Creature - Human Werewolf + Whenever this creature enters the battlefield or transforms into Huntmaster of the Fells, put a 2/2 green Wolf creature token onto the battlefield and you gain 2 life. + At the beginning of each upkeep, if no spells were cast last turn, transform Huntmaster of the Fells. + 2/2 + + Ravager of the Fells + Creature - Werewolf + Trample + Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. + At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells. + 4/4 + */ + private static final String huntmasterOfTheFells = "Huntmaster of the Fells"; + private static final String ravagerOfTheFells = "Ravager of the Fells"; + + /* + Eldrazi Displacer + {2}{W} + Creature - Eldrazi + Devoid + {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control. + 3/3 + */ + private static final String eldraziDisplacer = "Eldrazi Displacer"; + + /* + Howlpack Piper + {3}{G} + Creature - Human Werewolf + This spell can't be countered. + {1}{G}, {T}: You may put a creature card from your hand onto the battlefield. If it's a Wolf or Werewolf, untap Howlpack Piper. Activate only as a sorcery. + Daybound + 2/2 + + Wildsong Howler + Creature - Werewolf + Whenever this creature enters the battlefield or transforms into Wildsong Howler, look at the top six cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + Nightbound + 4/4 + */ + private static final String howlpackPiper = "Howlpack Piper"; + private static final String wildsongHowler = "Wildsong Howler"; + + /* + Thing in the Ice + {1}{U} + Creature - Horror + Defender + Thing in the Ice enters the battlefield with four ice counters on it. + Whenever you cast an instant or sorcery spell, remove an ice counter from Thing in the Ice. Then if it has no ice counters on it, transform it. + + Awoken Horror + Creature - Kraken Horror + When this creature transforms into Awoken Horrow, return all non-Horror creatures to their owners' hands. + 7/8 + */ + private static final String thingInTheIce = "Thing in the Ice"; + private static final String awokenHorror = "Awoken Horror"; + + /* + Banners Raised + {R} + Instant + Creatures you control get +1/+0 until end of turn. + */ + private static final String bannersRaised = "Banners Raised"; + + /* + Phantasmal Image + {1}{U} + Creature - Illusion + You may have Phantasmal Image enter the battlefield as a copy of any creature on the battlefield, except it's an Illusion in addition to its other types and it gains "When this creature becomes the target of a spell or ability, sacrifice it." + */ + private static final String phantasmalImage = "Phantasmal Image"; + + /* + Delver of Secrets + {U} + Creature - Human Wizard + At the beginning of your upkeep, look at the top card of your library. You may reveal that card. If an instant or sorcery card is revealed this way, transform Delver of Secrets. + 1/1 + + Insectile Aberration + Creature - Human Insect + Flying + 3/2 + */ + private static final String delverOfSecrets = "Delver of Secrets"; + private static final String insectileAberration = "Insectile Aberration"; + + /* + Moonmist + {1}{G} + Instant + Transform all Humans. Prevent all combat damage that would be dealt this turn by creatures other than Werewolves and Wolves. (Only double-faced cards can be transformed.) + */ + private static final String moonmist = "Moonmist"; + + /* + Maskwood Nexus + {4} + Artifact + Creatures you control are every creature type. The same is true for creature spells you control and creature cards you own that aren't on the battlefield. + {3}, {T}: Create a 2/2 blue Shapeshifter creature token with changeling. + */ + private static final String maskwoodNexus = "Maskwood Nexus"; + + /* + Dress Down + {1}{U} + Enchantment + Flash + When Dress Down enters the battlefield, draw a card. + Creatures lose all abilities. + At the beginning of the end step, sacrifice Dress Down. + */ + private static final String dressDown = "Dress Down"; + + /* + Baithook Angler + {1}{U} + Creature - Human Peasant + Disturb {1}{U} + 2/1 + + Hook-Haunt Drifter + Creature - Spirit + Flying + If Hook-Haunt Drifter would be put into a graveyard from anywhere, exile it instead. + 1/2 + */ + private static final String baithookAngler = "Baithook Angler"; + private static final String hookHauntDrifter = "Hook-Haunt Drifter"; + + /* + Croaking Counterpart + {1}{G}{U} + Sorcery + Create a token that's a copy of target non-Frog creature, except it's a 1/1 green Frog. + Flashback {3}{G}{U} + */ + private static final String croakingCounterpart = "Croaking Counterpart"; + + /* + Abnormal Endurance + {1}{B} + Instant + Until end of turn, target creature gets +2/+0 and gains "When this creature dies, return it to the battlefield tapped under its owner's control." + */ + private static final String abnormalEndurance = "Abnormal Endurance"; + @Test public void NissaVastwoodSeerTest() { @@ -22,13 +295,13 @@ public class TransformTest extends CardTestPlayerBase { // When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library. // Whenever a land you control enters, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control. - addCard(Zone.HAND, playerA, "Nissa, Vastwood Seer"); + addCard(Zone.HAND, playerA, nissaVastwoodSeer); addCard(Zone.BATTLEFIELD, playerB, "Forest", 2); // {G}{G}, Sacrifice Rootrunner: Put target land on top of its owner's library. addCard(Zone.BATTLEFIELD, playerB, "Rootrunner"); // {2}{G}{G} - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nissa, Vastwood Seer", true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nissaVastwoodSeer, true); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "{G}{G}", "Swamp"); @@ -40,38 +313,38 @@ public class TransformTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Rootrunner", 1); - assertPermanentCount(playerA, "Nissa, Vastwood Seer", 0); - assertPermanentCount(playerA, "Nissa, Sage Animist", 1); + assertPermanentCount(playerA, nissaVastwoodSeer, 0); + assertPermanentCount(playerA, nissaSageAnimist, 1); - assertCounterCount("Nissa, Sage Animist", CounterType.LOYALTY, 4); + assertCounterCount(nissaSageAnimist, CounterType.LOYALTY, 4); assertPermanentCount(playerA, "Forest", 6); assertPermanentCount(playerA, "Swamp", 1); } @Test public void LilianaHereticalHealer() { - addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, silvercoatLion, 1); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); // Lifelink // Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield. - addCard(Zone.HAND, playerA, "Liliana, Heretical Healer"); + addCard(Zone.HAND, playerA, lilianaHereticalHealer); - addCard(Zone.HAND, playerB, "Lightning Bolt"); + addCard(Zone.HAND, playerB, lightningBolt); addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Liliana, Heretical Healer"); - castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Lightning Bolt", "Silvercoat Lion"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lilianaHereticalHealer); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, lightningBolt, silvercoatLion); setStopAt(1, PhaseStep.DECLARE_ATTACKERS); execute(); - assertGraveyardCount(playerA, "Silvercoat Lion", 1); - assertGraveyardCount(playerB, "Lightning Bolt", 1); + assertGraveyardCount(playerA, silvercoatLion, 1); + assertGraveyardCount(playerB, lightningBolt, 1); - assertPermanentCount(playerA, "Liliana, Heretical Healer", 0); - assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 1); - assertCounterCount("Liliana, Defiant Necromancer", CounterType.LOYALTY, 3); + assertPermanentCount(playerA, lilianaHereticalHealer, 0); + assertPermanentCount(playerA, lilianaDefiantNecromancer, 1); + assertCounterCount(lilianaDefiantNecromancer, CounterType.LOYALTY, 3); assertPermanentCount(playerA, "Zombie Token", 1); } @@ -84,45 +357,45 @@ public class TransformTest extends CardTestPlayerBase { */ @Test public void LilianaHereticalHealer2() { - addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, silvercoatLion, 1); // Lifelink // Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield. - addCard(Zone.BATTLEFIELD, playerA, "Liliana, Heretical Healer"); + addCard(Zone.BATTLEFIELD, playerA, lilianaHereticalHealer); // All creatures get -4/-4 until end of turn. - addCard(Zone.HAND, playerB, "Languish"); + addCard(Zone.HAND, playerB, languish); addCard(Zone.BATTLEFIELD, playerB, "Swamp", 4); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Languish"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, languish); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); - assertGraveyardCount(playerB, "Languish", 1); - assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 0); + assertGraveyardCount(playerB, languish, 1); + assertPermanentCount(playerA, lilianaDefiantNecromancer, 0); assertPermanentCount(playerA, "Zombie Token", 0); - assertGraveyardCount(playerA, "Silvercoat Lion", 1); - assertGraveyardCount(playerA, "Liliana, Heretical Healer", 1); + assertGraveyardCount(playerA, silvercoatLion, 1); + assertGraveyardCount(playerA, lilianaHereticalHealer, 1); } @Test public void TestEnchantmentToCreature() { - addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 1); - addCard(Zone.GRAVEYARD, playerA, "Lightning Bolt", 1); - addCard(Zone.GRAVEYARD, playerA, "Fireball", 1); - addCard(Zone.GRAVEYARD, playerA, "Infernal Scarring", 1); + addCard(Zone.GRAVEYARD, playerA, silvercoatLion, 1); + addCard(Zone.GRAVEYARD, playerA, lightningBolt, 1); + addCard(Zone.GRAVEYARD, playerA, fireball, 1); + addCard(Zone.GRAVEYARD, playerA, infernalScarring, 1); // {B}: Put the top card of your library into your graveyard. // Delirium &mdash At the beginning of your end step, if there are four or more card types among cards in your graveyard, transform Autumnal Gloom. - addCard(Zone.BATTLEFIELD, playerA, "Autumnal Gloom"); + addCard(Zone.BATTLEFIELD, playerA, autumnalGloom); setStopAt(2, PhaseStep.PRECOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Autumnal Gloom", 0); - assertPermanentCount(playerA, "Ancient of the Equinox", 1); + assertPermanentCount(playerA, autumnalGloom, 0); + assertPermanentCount(playerA, ancientOfTheEquinox, 1); } /** @@ -138,6 +411,7 @@ public class TransformTest extends CardTestPlayerBase { */ @Test public void testCultOfTheWaxingMoon() { + setStrictChooseMode(true); // Whenever a permanent you control transforms into a non-Human creature, put a 2/2 green Wolf creature token onto the battlefield. addCard(Zone.BATTLEFIELD, playerA, "Cult of the Waxing Moon"); // {1}{G} - Human Werewolf @@ -151,6 +425,7 @@ public class TransformTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Cult of the Waxing Moon", 1); assertPermanentCount(playerA, "Timber Shredder", 1); // Night-side card of Hinterland Logger, Werewolf (non-human) assertPermanentCount(playerA, "Wolf Token", 1); // wolf token created + assertAbilityCount(playerA, "Timber Shredder", WerewolfFrontTriggeredAbility.class, 0); // no front face ability } /** @@ -184,18 +459,42 @@ public class TransformTest extends CardTestPlayerBase { } @Test - public void testStartledAwakeMoonmist() { - addCard(Zone.HAND, playerA, "Startled Awake"); - addCard(Zone.HAND, playerA, "Moonmist"); - addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 11); - addCard(Zone.BATTLEFIELD, playerA, "Maskwood Nexus"); + public void testPersistentNightmareTrigger() { + // Target opponent puts the top thirteen cards of their library into their graveyard. + // {3}{U}{U}: Put Startled Awake from your graveyard onto the battlefield transformed. Activate this ability only any time you could cast a sorcery. + addCard(Zone.HAND, playerA, "Startled Awake"); // SORCERY {2}{U}{U}" + addCard(Zone.BATTLEFIELD, playerA, "Island", 9); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Startled Awake", playerB); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{U}{U}"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Moonmist"); + attack(3, playerA, "Persistent Nightmare"); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.COMBAT_DAMAGE); + execute(); + + assertGraveyardCount(playerB, 13); + assertGraveyardCount(playerA, "Startled Awake", 0); + assertPermanentCount(playerA, "Persistent Nightmare", 0); // Night-side card of Startled Awake + assertHandCount(playerA, "Startled Awake", 1); + } + + @Test + public void testStartledAwakeMoonmist() { + addCard(Zone.HAND, playerA, "Startled Awake"); + addCard(Zone.HAND, playerA, moonmist); + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 11); + addCard(Zone.BATTLEFIELD, playerA, maskwoodNexus); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Startled Awake", playerB); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{U}{U}"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, moonmist); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -241,6 +540,25 @@ public class TransformTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Lambholt Pacifist", 1); } + @Test + public void testDisturbExile() { + addCard(Zone.GRAVEYARD, playerA, baithookAngler); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.BATTLEFIELD, playerB, "Mountain"); + addCard(Zone.HAND, playerB, lightningBolt); + + // Disturb {1}{U} + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, hookHauntDrifter + " using Disturb"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, lightningBolt, hookHauntDrifter); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, hookHauntDrifter, 0); + assertExileCount(playerA, baithookAngler, 1); + } + /** * Mirror Mockery copies the front face of a Transformed card rather than * the current face. @@ -251,7 +569,7 @@ public class TransformTest extends CardTestPlayerBase { * Trespasser. */ @Test - public void testTransformCopyrnansformed() { + public void testTransformCopyTransformed() { // Skulk (This creature can't be blocked by creatures with greater power.) // When Uninvited Geist deals combat damage to a player, transform it. addCard(Zone.BATTLEFIELD, playerA, "Uninvited Geist"); // Creature 2/2 {2}{U} @@ -272,7 +590,7 @@ public class TransformTest extends CardTestPlayerBase { setStopAt(3, PhaseStep.COMBAT_DAMAGE); execute(); - assertLife(playerB, 15); + assertLife(playerB, 20 - 2 - 3); assertPermanentCount(playerB, "Mirror Mockery", 1); assertPermanentCount(playerA, "Unimpeded Trespasser", 1); @@ -293,16 +611,16 @@ public class TransformTest extends CardTestPlayerBase { // Transformed side: Avacyn, the Purifier - Creature 6/5 // Flying // When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent. - addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); - addCard(Zone.HAND, playerA, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerA, silvercoatLion); + addCard(Zone.HAND, playerA, lightningBolt); addCard(Zone.BATTLEFIELD, playerA, "Mountain"); // Devoid // {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control. - addCard(Zone.BATTLEFIELD, playerB, "Eldrazi Displacer", 1); + addCard(Zone.BATTLEFIELD, playerB, eldraziDisplacer, 1); addCard(Zone.BATTLEFIELD, playerB, "Wastes", 3); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Silvercoat Lion"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, lightningBolt, silvercoatLion); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{2}{C}", "Archangel Avacyn"); @@ -310,10 +628,10 @@ public class TransformTest extends CardTestPlayerBase { setStopAt(3, PhaseStep.PRECOMBAT_MAIN); execute(); - assertGraveyardCount(playerA, "Lightning Bolt", 1); - assertGraveyardCount(playerA, "Silvercoat Lion", 1); + assertGraveyardCount(playerA, lightningBolt, 1); + assertGraveyardCount(playerA, silvercoatLion, 1); - assertPermanentCount(playerB, "Eldrazi Displacer", 1); + assertPermanentCount(playerB, eldraziDisplacer, 1); assertPermanentCount(playerA, "Avacyn, the Purifier", 0); assertPermanentCount(playerA, "Archangel Avacyn", 1); } @@ -355,20 +673,20 @@ public class TransformTest extends CardTestPlayerBase { // Ravager of the Fells // Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells. - addCard(Zone.HAND, playerA, "Huntmaster of the Fells"); // Creature {2}{R}{G} + addCard(Zone.HAND, playerA, huntmasterOfTheFells); // Creature {2}{R}{G} addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); // Devoid // {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control. - addCard(Zone.HAND, playerB, "Eldrazi Displacer", 1); // Creature {2}{W} + addCard(Zone.HAND, playerB, eldraziDisplacer, 1); // Creature {2}{W} addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); addCard(Zone.BATTLEFIELD, playerB, "Wastes", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Huntmaster of the Fells"); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Eldrazi Displacer"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, huntmasterOfTheFells); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, eldraziDisplacer); - activateAbility(4, PhaseStep.UPKEEP, playerB, "{2}{C}", "Huntmaster of the Fells", "At the beginning of each upkeep"); + activateAbility(4, PhaseStep.UPKEEP, playerB, "{2}{C}", huntmasterOfTheFells, "At the beginning of each upkeep"); setStopAt(4, PhaseStep.PRECOMBAT_MAIN); execute(); @@ -376,11 +694,11 @@ public class TransformTest extends CardTestPlayerBase { assertLife(playerA, 24); assertPermanentCount(playerA, "Wolf Token", 2); - assertPermanentCount(playerB, "Eldrazi Displacer", 1); + assertPermanentCount(playerB, eldraziDisplacer, 1); - assertPermanentCount(playerA, "Ravager of the Fells", 0); - assertPermanentCount(playerA, "Huntmaster of the Fells", 1); - assertPowerToughness(playerA, "Huntmaster of the Fells", 2, 2); + assertPermanentCount(playerA, ravagerOfTheFells, 0); + assertPermanentCount(playerA, huntmasterOfTheFells, 1); + assertPowerToughness(playerA, huntmasterOfTheFells, 2, 2); assertTappedCount("Plains", true, 2); assertTappedCount("Wastes", true, 1); } @@ -392,50 +710,50 @@ public class TransformTest extends CardTestPlayerBase { // Ravager of the Fells // Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells. - addCard(Zone.HAND, playerA, "Huntmaster of the Fells"); // Creature {2}{R}{G} - addCard(Zone.HAND, playerA, "Silvercoat Lion", 2); + addCard(Zone.HAND, playerA, huntmasterOfTheFells); // Creature {2}{R}{G} + addCard(Zone.HAND, playerA, silvercoatLion, 2); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Huntmaster of the Fells", true); - castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion", true); - castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, huntmasterOfTheFells, true); + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, silvercoatLion, true); + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, silvercoatLion); setStopAt(4, PhaseStep.PRECOMBAT_MAIN); execute(); assertLife(playerA, 24); assertLife(playerB, 18); assertPermanentCount(playerA, "Wolf Token", 2); - assertPermanentCount(playerA, "Silvercoat Lion", 2); - assertPermanentCount(playerA, "Ravager of the Fells", 0); - assertPermanentCount(playerA, "Huntmaster of the Fells", 1); - assertPowerToughness(playerA, "Huntmaster of the Fells", 2, 2); + assertPermanentCount(playerA, silvercoatLion, 2); + assertPermanentCount(playerA, ravagerOfTheFells, 0); + assertPermanentCount(playerA, huntmasterOfTheFells, 1); + assertPowerToughness(playerA, huntmasterOfTheFells, 2, 2); } @Test public void testWildsongHowlerTrigger() { // The only Daybound/Nightbound card with a Transforms trigger on the back side removeAllCardsFromLibrary(playerA); - addCard(Zone.HAND, playerA, "Howlpack Piper", 2); // Creature {2}{R}{G} - addCard(Zone.LIBRARY, playerA, "Silvercoat Lion", 50); + addCard(Zone.HAND, playerA, howlpackPiper, 2); // Creature {2}{R}{G} + addCard(Zone.LIBRARY, playerA, silvercoatLion, 50); addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Howlpack Piper"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, howlpackPiper); setChoice(playerA, true); //Transform trigger - addTarget(playerA, "Silvercoat Lion"); + addTarget(playerA, silvercoatLion); - castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Howlpack Piper"); + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, howlpackPiper); setChoice(playerA, true); //ETB trigger - addTarget(playerA, "Silvercoat Lion"); + addTarget(playerA, silvercoatLion); setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); setStrictChooseMode(true); execute(); - assertPermanentCount(playerA, "Wildsong Howler", 2); - assertPermanentCount(playerA, "Howlpack Piper", 0); // They should be both transformed - assertHandCount(playerA, "Silvercoat Lion", 3); + assertPermanentCount(playerA, wildsongHowler, 2); + assertPermanentCount(playerA, howlpackPiper, 0); // They should be both transformed + assertHandCount(playerA, silvercoatLion, 3); assertHandCount(playerA, 3); //The two Silvercoat Lions from triggers and 1 from natural card draw } @@ -455,37 +773,37 @@ public class TransformTest extends CardTestPlayerBase { // Thing in the Ice enters the battlefield with four ice counters on it. // Whenever you cast an instant or sorcery spell, remove an ice counter from Thing in the Ice. // Then if it has no ice counters on it, transform it. - addCard(Zone.HAND, playerA, "Thing in the Ice"); // Creature {1}{U} + addCard(Zone.HAND, playerA, thingInTheIce); // Creature {1}{U} // Creatures you control get +1/+0 until end of turn. - addCard(Zone.HAND, playerA, "Banners Raised", 4); // Creature {R} + addCard(Zone.HAND, playerA, bannersRaised, 4); // Creature {R} addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); addCard(Zone.BATTLEFIELD, playerA, "Island", 1); // You may have Phantasmal Image enter the battlefield as a copy of any creature // on the battlefield, except it's an Illusion in addition to its other types and // it has "When this creature becomes the target of a spell or ability, sacrifice it." - addCard(Zone.HAND, playerB, "Phantasmal Image", 1); // Creature {1}{U} + addCard(Zone.HAND, playerB, phantasmalImage, 1); // Creature {1}{U} addCard(Zone.BATTLEFIELD, playerB, "Island", 2); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thing in the Ice"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, thingInTheIce); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, phantasmalImage); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); assertLife(playerA, 20); - assertGraveyardCount(playerA, "Banners Raised", 4); - assertPermanentCount(playerA, "Thing in the Ice", 0); - assertPermanentCount(playerA, "Awoken Horror", 1); - assertPowerToughness(playerA, "Awoken Horror", 7, 8); + assertGraveyardCount(playerA, bannersRaised, 4); + assertPermanentCount(playerA, thingInTheIce, 0); + assertPermanentCount(playerA, awokenHorror, 1); + assertPowerToughness(playerA, awokenHorror, 7, 8); - assertPermanentCount(playerB, "Awoken Horror", 1); - assertPowerToughness(playerB, "Awoken Horror", 7, 8); + assertPermanentCount(playerB, awokenHorror, 1); + assertPowerToughness(playerB, awokenHorror, 7, 8); } @@ -493,45 +811,45 @@ public class TransformTest extends CardTestPlayerBase { public void testMoonmistDelver() { addCard(Zone.BATTLEFIELD, playerA, "Island"); addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); - addCard(Zone.HAND, playerA, "Delver of Secrets"); - addCard(Zone.HAND, playerA, "Moonmist", 2); + addCard(Zone.HAND, playerA, delverOfSecrets); + addCard(Zone.HAND, playerA, moonmist, 2); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Delver of Secrets"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, delverOfSecrets); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Moonmist"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, moonmist); setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "Delver of Secrets", 0); - assertPermanentCount(playerA, "Insectile Aberration", 1); + assertPermanentCount(playerA, delverOfSecrets, 0); + assertPermanentCount(playerA, insectileAberration, 1); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Moonmist"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, moonmist); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); - assertPermanentCount(playerA, "Delver of Secrets", 1); - assertPermanentCount(playerA, "Insectile Aberration", 0); + assertPermanentCount(playerA, delverOfSecrets, 1); + assertPermanentCount(playerA, insectileAberration, 0); } @Test public void testMoonmistHuntmasterDressdown() { addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 6); - addCard(Zone.BATTLEFIELD, playerA, "Huntmaster of the Fells"); //Has on-transform triggers - addCard(Zone.BATTLEFIELD, playerA, "Maskwood Nexus"); //Make back side human + addCard(Zone.BATTLEFIELD, playerA, huntmasterOfTheFells); //Has on-transform triggers + addCard(Zone.BATTLEFIELD, playerA, maskwoodNexus); //Make back side human - addCard(Zone.HAND, playerA, "Dress Down"); //Creatures lose all abilities - addCard(Zone.HAND, playerA, "Moonmist", 2); + addCard(Zone.HAND, playerA, dressDown); //Creatures lose all abilities + addCard(Zone.HAND, playerA, moonmist, 2); - castSpell(1, PhaseStep.UPKEEP, playerA, "Dress Down"); + castSpell(1, PhaseStep.UPKEEP, playerA, dressDown); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Moonmist"); - checkPermanentCount("Huntmaster flipped", 1, PhaseStep.BEGIN_COMBAT, playerA, "Ravager of the Fells", 1); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Moonmist"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, moonmist); + checkPermanentCount("Huntmaster flipped", 1, PhaseStep.BEGIN_COMBAT, playerA, ravagerOfTheFells, 1); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, moonmist); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -539,8 +857,71 @@ public class TransformTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - assertGraveyardCount(playerA, "Dress Down", 1); - assertPermanentCount(playerA, "Huntmaster of the Fells", 1); + assertGraveyardCount(playerA, dressDown, 1); + assertPermanentCount(playerA, huntmasterOfTheFells, 1); assertPermanentCount(playerA, 6+1+1); } + + @Test + public void testTokenCopyTransformed() { + addCard(Zone.GRAVEYARD, playerA, baithookAngler); + addCard(Zone.BATTLEFIELD, playerA, "Breeding Pool", 5); + addCard(Zone.HAND, playerA, croakingCounterpart); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hook-Haunt Drifter using Disturb"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, croakingCounterpart, hookHauntDrifter); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + for (Permanent token : currentGame.getBattlefield().getActivePermanents(playerA.getId(), currentGame)) { + if (!(token instanceof PermanentToken)) { + continue; + } + assertTrue(token.getSubtype(currentGame).contains(SubType.FROG)); + assertEquals(ObjectColor.GREEN, token.getColor(currentGame)); + } + } + + @Test + public void testFrontSaga() { + addCard(Zone.BATTLEFIELD, playerA, azusasManyJourneys); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, azusasManyJourneys, 0); + assertPermanentCount(playerA, likenessOfTheSeeker, 1); + assertPowerToughness(playerA, likenessOfTheSeeker, 3, 3); + assertAbilityCount(playerA, likenessOfTheSeeker, SagaAbility.class, 0); // does not have saga ability + assertLife(playerA, 20 + 3); + } + + /** + * testing if a double faced card gains a death trigger, it still works correctly + */ + @Test + public void testDiesTrigger() { + addCard(Zone.BATTLEFIELD, playerA, baithookAngler); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.HAND, playerA, abnormalEndurance); + + addCard(Zone.HAND, playerB, lightningBolt); + addCard(Zone.BATTLEFIELD, playerB, "Mountain"); + + castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, lightningBolt, baithookAngler); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, abnormalEndurance, baithookAngler, lightningBolt); + + setStopAt(1, PhaseStep.DECLARE_ATTACKERS); + execute(); + + assertGraveyardCount(playerA, baithookAngler, 0); + assertGraveyardCount(playerB, lightningBolt, 1); + + assertPermanentCount(playerA, baithookAngler, 1); + assertTrue(getPermanent(baithookAngler, playerA).isTapped()); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java index 32a18f84bbb..26cc4aa5df6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java @@ -3,10 +3,13 @@ package org.mage.test.cards.copy; import mage.constants.CardType; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.game.permanent.Permanent; import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * * @author LevelX2 @@ -85,4 +88,22 @@ public class CopyCreatureCardToTokenImplTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Thrashing Brontodon", 1); assertType("Thrashing Brontodon", CardType.ARTIFACT, true); } + + @Test + public void testTokenCopyTransformedHasSecondFaceWithModifications() { + setStrictChooseMode(true); + + String hookHauntDrifter = "Hook-Haunt Drifter"; + addCard(Zone.GRAVEYARD, playerA, "Baithook Angler"); + addCard(Zone.BATTLEFIELD, playerB, "Faerie Artisans", 1); + addCard(Zone.BATTLEFIELD, playerA, "Breeding Pool", 5); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hook-Haunt Drifter using Disturb"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + Permanent token = getPermanent(hookHauntDrifter, playerB); + assertTrue(token.getCardType(currentGame).contains(CardType.ARTIFACT)); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java index 257cae4f572..07909a33372 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java @@ -907,6 +907,32 @@ public class ModalDoubleFacedCardsTest extends CardTestPlayerBase { execute(); } + @Test + public void test_Copy_AsSpell_Backside() { + addCard(Zone.HAND, playerA, "Alrund, God of the Cosmos", 1); // {3}{U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + // + // Copy target creature spell you control, except it isn't legendary if the spell is legendary. + addCard(Zone.HAND, playerA, "Double Major", 1); // {G}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + + // cast mdf card + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {U}", 2); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hakka, Whispering Raven"); + // prepare copy of spell + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major", "Hakka, Whispering Raven", "Hakka, Whispering Raven"); + checkStackSize("before copy spell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true); + checkStackSize("after copy spell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hakka, Whispering Raven", 2); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + } + @Test public void test_Copy_AsCloneFromPermanent() { addCard(Zone.HAND, playerA, "Akoum Warrior", 1); // {5}{R} @@ -1138,8 +1164,8 @@ public class ModalDoubleFacedCardsTest extends CardTestPlayerBase { Assert.assertNotNull(permanent); // MDFC on battlefield has only one side (not transformable) - Assert.assertFalse("server must not be transformable", permanent.isTransformable()); - Assert.assertNull("server must have not other side", permanent.getOtherFace()); +// Assert.assertFalse("server must not be transformable", permanent.isTransformable()); +// Assert.assertNull("server must have not other side", permanent.getOtherFace()); List rules = permanent.getRules(game); Assert.assertTrue("server must ignore side 2 - untap ability", rules.stream().noneMatch(r -> r.contains("Untap"))); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/RoomCardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/RoomCardTest.java index c7f6aad84d6..b9d380b5c23 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/RoomCardTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/RoomCardTest.java @@ -1,19 +1,191 @@ package org.mage.test.cards.cost.splitcards; -import mage.constants.CardType; -import mage.constants.EmptyNames; -import mage.constants.PhaseStep; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; +import mage.view.CardView; +import mage.view.GameView; +import mage.view.PlayerView; import org.junit.Test; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + /** * @author oscscull */ public class RoomCardTest extends CardTestPlayerBase { + /* + Bottomless Pool // Locker Room + {U} + Enchantment - Room + When you unlock this door, return up to one target creature to its owner's hand. + (You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.) + Locker Room + {4}{U} + Enchantment -- Room + Whenever one or more creatures you control deal combat damage to a player, draw a card. + (You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.) + */ + private static final String bottomlessPoolLockerRoom = "Bottomless Pool // Locker Room"; + private static final String bottomlessPool = "Bottomless Pool"; + public static final String lockerRoom = "Locker Room"; + + + @Test + public void testCardViewLeftHalf() { + setStrictChooseMode(true); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool, true); + addTarget(playerA, TestPlayer.TARGET_SKIP); + + runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + GameView gameView = getGameView(playerA); + PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null); + assertNotNull(playerView, "Player view must be found"); + CardView cardView = playerView.getBattlefield().values() + .stream() + .filter(pv -> pv.getName().equals(bottomlessPool)) + .findFirst() + .orElse(null); + assertNotNull(cardView, "Locker Room card view must be found on battlefield"); + // permanent should have 3 abilities + // unlock ability + unlock trigger from right half + info + assertEquals(3, cardView.getRules().size(), "Locker Room must have 3 rules, has: " + cardView.getRules().size()); + assertEquals("{U}", cardView.getManaCostStr(), "Mana cost must be from left half"); + StringBuilder sb = new StringBuilder("\n" + cardView.getName()); + sb.append("\n - Types: ").append(cardView.getCardTypes()); + sb.append("\n - Subtypes: ").append(cardView.getSubTypes()); + sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr()); + sb.append("\n - Abilities: "); + cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule)); + logger.info(sb.toString()); + }); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + } + + @Test + public void testCardViewRightHalf() { + setStrictChooseMode(true); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom, true); + + runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + GameView gameView = getGameView(playerA); + PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null); + assertNotNull(playerView, "Player view must be found"); + CardView cardView = playerView.getBattlefield().values() + .stream() + .filter(pv -> pv.getName().equals(lockerRoom)) + .findFirst() + .orElse(null); + assertNotNull(cardView, "Locker Room card view must be found on battlefield"); + // permanent should have 3 abilities + // unlock ability + unlock trigger from left half + info + assertEquals(3, cardView.getRules().size(), "Locker Room must have 3 rules, has: " + cardView.getRules().size()); + assertEquals("{4}{U}", cardView.getManaCostStr(), "Mana cost must be from right half"); + StringBuilder sb = new StringBuilder("\n" + cardView.getName()); + sb.append("\n - Types: ").append(cardView.getCardTypes()); + sb.append("\n - Subtypes: ").append(cardView.getSubTypes()); + sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr()); + sb.append("\n - Abilities: "); + cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule)); + logger.info(sb.toString()); + }); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + } + + @Test + public void testCardViewBothHalves() { + setStrictChooseMode(true); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool, true); + addTarget(playerA, TestPlayer.TARGET_SKIP); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half."); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + GameView gameView = getGameView(playerA); + PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null); + assertNotNull(playerView, "Player view must be found"); + CardView cardView = playerView.getBattlefield().values() + .stream() + .filter(pv -> pv.getName().equals(bottomlessPoolLockerRoom)) + .findFirst() + .orElse(null); + assertNotNull(cardView, "Locker Room card view must be found on battlefield"); + // permanent should have 3 abilities + // 1 ability from both halves + // no unlock abilities + // 1 info + String manaCost = getPermanent(bottomlessPoolLockerRoom) + .getManaCost() + .stream() + .map(Objects::toString) + .reduce("", String::concat); + assertEquals(3, cardView.getRules().size(), "Locker Room must have 3 rules, has: " + cardView.getRules().size()); + assertEquals(manaCost, cardView.getManaCostStr(), "Mana cost must be combined from both halves"); + StringBuilder sb = new StringBuilder("\n" + cardView.getName()); + sb.append("\n - Types: ").append(cardView.getCardTypes()); + sb.append("\n - Subtypes: ").append(cardView.getSubTypes()); + sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr()); + sb.append("\n - Abilities: "); + cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule)); + logger.info(sb.toString()); + }); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + } + + @Test + public void testCardViewFullyLocked() { + setStrictChooseMode(true); + addCard(Zone.BATTLEFIELD, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + + runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + GameView gameView = getGameView(playerA); + PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null); + assertNotNull(playerView, "Player view must be found"); + CardView cardView = playerView.getBattlefield().values() + .stream() + .filter(pv -> pv.getName().isEmpty()) + .findFirst() + .orElse(null); + assertNotNull(cardView, "Locked room card view must be found on battlefield"); + // permanent should have 3 abilities + // 1 info + // two unlock abilities + assertEquals(3, cardView.getRules().size(), "Locked room must have 3 rules, has: " + cardView.getRules().size()); + assertEquals("", cardView.getManaCostStr(), "Mana cost must be empty"); + StringBuilder sb = new StringBuilder("\n" + cardView.getName()); + sb.append("\n - Types: ").append(cardView.getCardTypes()); + sb.append("\n - Subtypes: ").append(cardView.getSubTypes()); + sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr()); + sb.append("\n - Abilities: "); + cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule)); + logger.info(sb.toString()); + }); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + } + // Bottomless pool is cast. It unlocks, and the trigger to return a creature // should bounce one of two grizzly bears. @Test @@ -23,13 +195,13 @@ public class RoomCardTest extends CardTestPlayerBase { // creature to its owner’s hand. // Locker Room {4}{U} Whenever one or more creatures you control deal combat // damage to a player, draw a card. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.BATTLEFIELD, playerA, "Island", 1); addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 2); checkPlayableAbility("playerA can cast Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Bottomless Pool", true); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); // Target one of playerB's "Grizzly Bears" with the return effect. addTarget(playerA, "Grizzly Bears"); @@ -43,11 +215,11 @@ public class RoomCardTest extends CardTestPlayerBase { // Verify that one "Grizzly Bears" has been returned to playerB's hand. assertHandCount(playerB, "Grizzly Bears", 1); // Verify that "Bottomless Pool" is on playerA's battlefield. - assertPermanentCount(playerA, "Bottomless Pool", 1); + assertPermanentCount(playerA, bottomlessPool, 1); // Verify that "Bottomless Pool" is an Enchantment. - assertType("Bottomless Pool", CardType.ENCHANTMENT, true); + assertType(bottomlessPool, CardType.ENCHANTMENT, true); // Verify that "Bottomless Pool" has the Room subtype. - assertSubtype("Bottomless Pool", SubType.ROOM); + assertSubtype(bottomlessPool, SubType.ROOM); } // Locker room is cast. It enters, and gives a coastal piracy effect that @@ -59,7 +231,7 @@ public class RoomCardTest extends CardTestPlayerBase { // creature to its owner’s hand. // Locker Room {4}{U} Whenever one or more creatures you control deal combat // damage to a player, draw a card. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.BATTLEFIELD, playerA, "Island", 5); // Cards to be drawn @@ -68,7 +240,7 @@ public class RoomCardTest extends CardTestPlayerBase { // 2 attackers addCard(Zone.BATTLEFIELD, playerA, "Memnite", 2); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Locker Room"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom); attack(1, playerA, "Memnite"); attack(1, playerA, "Memnite"); // After combat damage, Memnites dealt combat damage to playerB (1 damage * 2). @@ -83,9 +255,9 @@ public class RoomCardTest extends CardTestPlayerBase { // Assertions after the first execute() (Locker Room and creatures are on // battlefield, combat resolved): - assertPermanentCount(playerA, "Locker Room", 1); - assertType("Locker Room", CardType.ENCHANTMENT, true); - assertSubtype("Locker Room", SubType.ROOM); + assertPermanentCount(playerA, lockerRoom, 1); + assertType(lockerRoom, CardType.ENCHANTMENT, true); + assertSubtype(lockerRoom, SubType.ROOM); assertPermanentCount(playerA, "Memnite", 2); setStrictChooseMode(true); @@ -102,13 +274,13 @@ public class RoomCardTest extends CardTestPlayerBase { // creature to its owner’s hand. // Locker Room {4}{U} Whenever one or more creatures you control deal combat // damage to a player, draw a card. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.BATTLEFIELD, playerA, "Island", 6); // 2 creatures owned by player A addCard(Zone.BATTLEFIELD, playerA, "Memnite", 2); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Locker Room"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); checkPlayableAbility("playerA can unlock Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}: Unlock the left half.", true); @@ -125,12 +297,12 @@ public class RoomCardTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Memnite", 1); // Verify that one "Memnite" has been returned to playerA's hand. assertHandCount(playerA, "Memnite", 1); - // Verify that "Bottomless Pool // Locker Room" is on playerA's battlefield. - assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1); - // Verify that "Bottomless Pool // Locker Room" is an Enchantment. - assertType("Bottomless Pool // Locker Room", CardType.ENCHANTMENT, true); - // Verify that "Bottomless Pool // Locker Room" has the Room subtype. - assertSubtype("Bottomless Pool // Locker Room", SubType.ROOM); + // Verify that bottomlessPoolLockerRoom is on playerA's battlefield. + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); + // Verify that bottomlessPoolLockerRoom is an Enchantment. + assertType(bottomlessPoolLockerRoom, CardType.ENCHANTMENT, true); + // Verify that bottomlessPoolLockerRoom has the Room subtype. + assertSubtype(bottomlessPoolLockerRoom, SubType.ROOM); } @Test @@ -140,7 +312,7 @@ public class RoomCardTest extends CardTestPlayerBase { // creature to its owner’s hand. // Locker Room {4}{U} Whenever one or more creatures you control deal combat // damage to a player, draw a card. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.HAND, playerA, "Felidar Guardian"); addCard(Zone.BATTLEFIELD, playerA, "Island", 1); addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); @@ -148,7 +320,7 @@ public class RoomCardTest extends CardTestPlayerBase { // creatures owned by player A addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); // resolve spell cast waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // unlock and trigger bounce on Memnite @@ -160,7 +332,7 @@ public class RoomCardTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // etb and flicker on Bottomless Pool setChoice(playerA, "Yes"); - addTarget(playerA, "Bottomless Pool"); + addTarget(playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); setStopAt(1, PhaseStep.END_TURN); @@ -187,7 +359,7 @@ public class RoomCardTest extends CardTestPlayerBase { // creature to its owner’s hand. // Locker Room {4}{U} Whenever one or more creatures you control deal combat // damage to a player, draw a card. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.HAND, playerA, "Felidar Guardian"); addCard(Zone.BATTLEFIELD, playerA, "Island", 5); addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); @@ -196,7 +368,7 @@ public class RoomCardTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1); addCard(Zone.BATTLEFIELD, playerA, "Black Knight", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); // resolve spell cast waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // unlock and trigger bounce on Memnite @@ -208,7 +380,7 @@ public class RoomCardTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // etb and flicker on Bottomless Pool setChoice(playerA, "Yes"); - addTarget(playerA, "Bottomless Pool"); + addTarget(playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // can unlock again checkPlayableAbility("playerA can unlock Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA, @@ -228,7 +400,7 @@ public class RoomCardTest extends CardTestPlayerBase { // Verify that one "Black Knight" has been returned to playerA's hand. assertHandCount(playerA, "Black Knight", 1); // Verify that "Bottomless Pool" is on playerA's battlefield. - assertPermanentCount(playerA, "Bottomless Pool", 1); + assertPermanentCount(playerA, bottomlessPool, 1); // Verify that "Felidar Guardian" is on playerA's battlefield. assertPermanentCount(playerA, "Felidar Guardian", 1); } @@ -240,11 +412,11 @@ public class RoomCardTest extends CardTestPlayerBase { // creature to its owner’s hand. // Locker Room {4}{U} Whenever one or more creatures you control deal combat // damage to a player, draw a card. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.BATTLEFIELD, playerA, "Island", 6); addCard(Zone.BATTLEFIELD, playerA, "Erratic Apparition", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); // resolve spell cast waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); setChoice(playerA, "When you unlock"); // x2 triggers @@ -262,8 +434,8 @@ public class RoomCardTest extends CardTestPlayerBase { execute(); // Assertions: - // Verify that "Bottomless Pool // Locker Room" is on playerA's battlefield. - assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1); + // Verify that bottomlessPoolLockerRoom is on playerA's battlefield. + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); // Verify that "Erratic Apparition" is on playerA's battlefield. assertPermanentCount(playerA, "Erratic Apparition", 1); // Verify that "Erratic Apparition" has been pumped twice (etb + fully unlock) @@ -277,17 +449,17 @@ public class RoomCardTest extends CardTestPlayerBase { // creature to its owner’s hand. // Locker Room {4}{U} Whenever one or more creatures you control deal combat // damage to a player, draw a card. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.HAND, playerA, "See Double"); addCard(Zone.BATTLEFIELD, playerA, "Island", 5); addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1); addCard(Zone.BATTLEFIELD, playerA, "Ornithopter", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); // Copy spell on the stack castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "See Double"); setModeChoice(playerA, "1"); - addTarget(playerA, "Bottomless Pool"); + addTarget(playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 3); addTarget(playerA, "Memnite"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); @@ -303,7 +475,7 @@ public class RoomCardTest extends CardTestPlayerBase { // Verify that one "Ornithopter" has been returned to playerA's hand. assertHandCount(playerA, "Ornithopter", 1); // Verify that 2 "Bottomless Pool" are on playerA's battlefield. - assertPermanentCount(playerA, "Bottomless Pool", 2); + assertPermanentCount(playerA, bottomlessPool, 2); } @Test @@ -313,13 +485,13 @@ public class RoomCardTest extends CardTestPlayerBase { // creature to its owner's hand. // Locker Room {4}{U} Whenever one or more creatures you control deal combat // damage to a player, draw a card. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.HAND, playerA, "Clever Impersonator"); addCard(Zone.BATTLEFIELD, playerA, "Island", 6); addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1); addCard(Zone.BATTLEFIELD, playerA, "Ornithopter", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); addTarget(playerA, "Memnite"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); @@ -327,7 +499,7 @@ public class RoomCardTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clever Impersonator"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); setChoice(playerA, "Yes"); - setChoice(playerA, "Bottomless Pool"); + setChoice(playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, @@ -347,7 +519,7 @@ public class RoomCardTest extends CardTestPlayerBase { assertHandCount(playerA, "Ornithopter", 1); // Verify that the original "Bottomless Pool" is on playerA's battlefield, and a // clone. - assertPermanentCount(playerA, "Bottomless Pool", 2); + assertPermanentCount(playerA, bottomlessPool, 2); } @Test @@ -366,11 +538,11 @@ public class RoomCardTest extends CardTestPlayerBase { // {U}{U}, Sacrifice this creature: Counter target spell with the same name as a // card exiled with this creature. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.HAND, playerA, "Twiddle"); addCard(Zone.BATTLEFIELD, playerA, "Mindreaver", 1); addCard(Zone.BATTLEFIELD, playerA, "Island", 6); - addCard(Zone.LIBRARY, playerA, "Bottomless Pool // Locker Room", 1); + addCard(Zone.LIBRARY, playerA, bottomlessPoolLockerRoom, 1); addCard(Zone.LIBRARY, playerA, "Plains", 2); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Twiddle"); @@ -384,10 +556,10 @@ public class RoomCardTest extends CardTestPlayerBase { addTarget(playerA, playerA); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}{U}, Sacrifice {this}:"); - addTarget(playerA, "Bottomless Pool"); + addTarget(playerA, bottomlessPool); setStopAt(1, PhaseStep.END_TURN); setStrictChooseMode(true); @@ -424,7 +596,7 @@ public class RoomCardTest extends CardTestPlayerBase { // Target creature and all other creatures with the same name as that creature // get -3/-3 until end of turn. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room", 4); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom, 4); addCard(Zone.HAND, playerA, "Cackling Counterpart"); addCard(Zone.HAND, playerA, "Bile Blight"); addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17); @@ -432,17 +604,17 @@ public class RoomCardTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Opalescence"); // Cast Bottomless Pool (unlocked left half) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); addTarget(playerA, TestPlayer.TARGET_SKIP); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Cast Locker Room (unlocked right half) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Locker Room"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Cast Bottomless Pool then unlock Locker Room (both halves unlocked) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); addTarget(playerA, TestPlayer.TARGET_SKIP); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); @@ -451,7 +623,7 @@ public class RoomCardTest extends CardTestPlayerBase { // Create a fully locked room using Cackling Counterpart castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart"); - addTarget(playerA, "Bottomless Pool // Locker Room"); + addTarget(playerA, bottomlessPoolLockerRoom); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Cast Bile Blight targeting the fully locked room @@ -468,21 +640,21 @@ public class RoomCardTest extends CardTestPlayerBase { // then -2/-2 after Bile Blight (dies) assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 0); // Token, so nothing should be in grave - assertGraveyardCount(playerA, "Bottomless Pool // Locker Room", 0); + assertGraveyardCount(playerA, bottomlessPoolLockerRoom, 0); // Other rooms should NOT be affected by Bile Blight since they have different // names // Bottomless Pool: 1/1 base + 1/1 from anthem = 2/2 - assertPowerToughness(playerA, "Bottomless Pool", 2, 2); + assertPowerToughness(playerA, bottomlessPool, 2, 2); // Locker Room: 5/5 base + 1/1 from anthem = 6/6 - assertPowerToughness(playerA, "Locker Room", 6, 6); + assertPowerToughness(playerA, lockerRoom, 6, 6); // Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem = 7/7 - assertPowerToughness(playerA, "Bottomless Pool // Locker Room", 7, 7); + assertPowerToughness(playerA, bottomlessPoolLockerRoom, 7, 7); // Verify remaining rooms are still on battlefield - assertPermanentCount(playerA, "Bottomless Pool", 1); - assertPermanentCount(playerA, "Locker Room", 1); - assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1); + assertPermanentCount(playerA, bottomlessPool, 1); + assertPermanentCount(playerA, lockerRoom, 1); + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); } @Test @@ -515,7 +687,7 @@ public class RoomCardTest extends CardTestPlayerBase { // Target creature and all other creatures with the same name as that creature // get -3/-3 until end of turn. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room", 4); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom, 4); addCard(Zone.HAND, playerA, "Cackling Counterpart"); addCard(Zone.HAND, playerA, "Bile Blight"); addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17); @@ -523,17 +695,17 @@ public class RoomCardTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Opalescence"); // Cast Bottomless Pool (unlocked left half) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); addTarget(playerA, TestPlayer.TARGET_SKIP); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Cast Locker Room (unlocked right half) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Locker Room"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Cast Bottomless Pool then unlock Locker Room (both halves unlocked) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); addTarget(playerA, TestPlayer.TARGET_SKIP); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); @@ -542,12 +714,12 @@ public class RoomCardTest extends CardTestPlayerBase { // Create a fully locked room using Cackling Counterpart castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart"); - addTarget(playerA, "Bottomless Pool // Locker Room"); + addTarget(playerA, bottomlessPoolLockerRoom); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Cast Bile Blight targeting the half locked room castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bile Blight"); - addTarget(playerA, "Locker Room"); + addTarget(playerA, lockerRoom); setStopAt(1, PhaseStep.END_TURN); setStrictChooseMode(true); @@ -559,21 +731,21 @@ public class RoomCardTest extends CardTestPlayerBase { // since they share the "Locker Room" name component // Locker Room: 5/5 base + 1/1 from anthem - 3/3 from Bile Blight = 3/3 - assertPowerToughness(playerA, "Locker Room", 3, 3); + assertPowerToughness(playerA, lockerRoom, 3, 3); // Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem - 3/3 from Bile // Blight = 4/4 - assertPowerToughness(playerA, "Bottomless Pool // Locker Room", 4, 4); + assertPowerToughness(playerA, bottomlessPoolLockerRoom, 4, 4); // Other rooms should NOT be affected // Bottomless Pool: 1/1 base + 1/1 from anthem = 2/2 (unaffected) - assertPowerToughness(playerA, "Bottomless Pool", 2, 2); + assertPowerToughness(playerA, bottomlessPool, 2, 2); // Fully locked room: 0/0 base + 1/1 from anthem = 1/1 (unaffected) assertPowerToughness(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1, 1); // Verify all rooms are still on battlefield - assertPermanentCount(playerA, "Bottomless Pool", 1); - assertPermanentCount(playerA, "Locker Room", 1); - assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1); + assertPermanentCount(playerA, bottomlessPool, 1); + assertPermanentCount(playerA, lockerRoom, 1); + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1); } @@ -607,7 +779,7 @@ public class RoomCardTest extends CardTestPlayerBase { // Target creature and all other creatures with the same name as that creature // get -3/-3 until end of turn. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room", 4); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom, 4); addCard(Zone.HAND, playerA, "Cackling Counterpart"); addCard(Zone.HAND, playerA, "Bile Blight"); addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17); @@ -615,17 +787,17 @@ public class RoomCardTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Opalescence"); // Cast Bottomless Pool (unlocked left half) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); addTarget(playerA, TestPlayer.TARGET_SKIP); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Cast Locker Room (unlocked right half) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Locker Room"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Cast Bottomless Pool then unlock Locker Room (both halves unlocked) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); addTarget(playerA, TestPlayer.TARGET_SKIP); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); @@ -634,12 +806,12 @@ public class RoomCardTest extends CardTestPlayerBase { // Create a fully locked room using Cackling Counterpart castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart"); - addTarget(playerA, "Bottomless Pool // Locker Room"); + addTarget(playerA, bottomlessPoolLockerRoom); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Cast Bile Blight targeting the fully locked room castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bile Blight"); - addTarget(playerA, "Bottomless Pool // Locker Room"); + addTarget(playerA, bottomlessPoolLockerRoom); setStopAt(1, PhaseStep.END_TURN); setStrictChooseMode(true); @@ -647,27 +819,27 @@ public class RoomCardTest extends CardTestPlayerBase { // Assertions: // All rooms except the fully locked room should be affected by Bile Blight - // since they all share name components with "Bottomless Pool // Locker Room" + // since they all share name components with bottomlessPoolLockerRoom // Bottomless Pool: 1/1 base + 1/1 from anthem - 3/3 from Bile Blight = -1/-1 // (dies) - assertPermanentCount(playerA, "Bottomless Pool", 0); - assertGraveyardCount(playerA, "Bottomless Pool // Locker Room", 1); + assertPermanentCount(playerA, bottomlessPool, 0); + assertGraveyardCount(playerA, bottomlessPoolLockerRoom, 1); // Locker Room: 5/5 base + 1/1 from anthem - 3/3 from Bile Blight = 3/3 - assertPowerToughness(playerA, "Locker Room", 3, 3); + assertPowerToughness(playerA, lockerRoom, 3, 3); // Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem - 3/3 from Bile // Blight = 4/4 - assertPowerToughness(playerA, "Bottomless Pool // Locker Room", 4, 4); + assertPowerToughness(playerA, bottomlessPoolLockerRoom, 4, 4); // Fully locked room should NOT be affected (different name) // Fully locked room: 0/0 base + 1/1 from anthem = 1/1 (unaffected) assertPowerToughness(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1, 1); // Verify remaining rooms are still on battlefield - assertPermanentCount(playerA, "Locker Room", 1); - assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1); + assertPermanentCount(playerA, lockerRoom, 1); + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1); } @@ -678,7 +850,7 @@ public class RoomCardTest extends CardTestPlayerBase { // creature to its owner's hand. // Locker Room {4}{U} Whenever one or more creatures you control deal combat // damage to a player, draw a card. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.HAND, playerA, "Counterspell"); addCard(Zone.HAND, playerA, "Campus Renovation"); addCard(Zone.BATTLEFIELD, playerA, "Island", 3); @@ -689,16 +861,16 @@ public class RoomCardTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 1); // Cast Bottomless Pool - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); // Counter it while on stack castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Counterspell"); - addTarget(playerA, "Bottomless Pool"); + addTarget(playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Use Campus Renovation to return it from graveyard castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Campus Renovation"); - addTarget(playerA, "Bottomless Pool // Locker Room"); + addTarget(playerA, bottomlessPoolLockerRoom); setStopAt(1, PhaseStep.END_TURN); setStrictChooseMode(true); @@ -749,26 +921,26 @@ public class RoomCardTest extends CardTestPlayerBase { // As Pithing Needle enters, choose a card name. // Activated abilities of sources with the chosen name can't be activated. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.HAND, playerA, "Pithing Needle"); addCard(Zone.BATTLEFIELD, playerA, "Opalescence"); addCard(Zone.BATTLEFIELD, playerA, "Diviner's Wand"); addCard(Zone.BATTLEFIELD, playerA, "Island", 20); // Cast Bottomless Pool (unlocked left half only) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); addTarget(playerA, TestPlayer.TARGET_SKIP); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Equip Diviner's Wand activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {3}"); - addTarget(playerA, "Bottomless Pool"); + addTarget(playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Cast Pithing Needle naming the locked side castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pithing Needle"); - setChoice(playerA, "Locker Room"); + setChoice(playerA, lockerRoom); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Validate that the room can activate the gained ability @@ -789,7 +961,7 @@ public class RoomCardTest extends CardTestPlayerBase { execute(); // Verify the room is now fully unlocked - assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1); + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); } // Test converting one permanent into one room, then another (the room halves @@ -813,14 +985,14 @@ public class RoomCardTest extends CardTestPlayerBase { // or // land until end of turn. - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.HAND, playerA, "Surgical Suite // Hospital Room"); addCard(Zone.BATTLEFIELD, playerA, "Mirage Mirror"); addCard(Zone.BATTLEFIELD, playerA, "Tundra", 20); addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1); // Cast Bottomless Pool (unlocked left half only) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); addTarget(playerA, TestPlayer.TARGET_SKIP); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); @@ -832,7 +1004,7 @@ public class RoomCardTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}: {this} becomes a copy"); - addTarget(playerA, "Bottomless Pool // Locker Room"); + addTarget(playerA, bottomlessPoolLockerRoom); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half."); @@ -848,7 +1020,7 @@ public class RoomCardTest extends CardTestPlayerBase { execute(); // Verify unlocked Bottomless pool - assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1); + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); // Verify unlocked Surgical Suite assertPermanentCount(playerA, "Surgical Suite", 1); // Verify mirage mirror is Hospital Room @@ -873,32 +1045,33 @@ public class RoomCardTest extends CardTestPlayerBase { // other types, // and it has "{2}{U}{U}: Return Sakashima the Impostor to its owner's hand at // the beginning of the next end step." + String sakashimaTheImpostor = "Sakashima the Impostor"; - addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room"); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); addCard(Zone.BATTLEFIELD, playerA, "Island", 10); + addCard(Zone.BATTLEFIELD, playerA, "Opalescence"); + addCard(Zone.HAND, playerA, sakashimaTheImpostor); - addCard(Zone.HAND, playerB, "Sakashima the Impostor"); - addCard(Zone.BATTLEFIELD, playerB, "Island", 10); // Cast Bottomless Pool (unlocked left half only) - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); addTarget(playerA, TestPlayer.TARGET_SKIP); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // Cast Sakashima copying the room - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Sakashima the Impostor"); - setChoice(playerB, "Yes"); // Choose to copy - waitStackResolved(2, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sakashimaTheImpostor); + setChoice(playerA, "Yes"); // Choose to copy + setChoice(playerA, bottomlessPool); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half."); - waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - - setStopAt(2, PhaseStep.END_TURN); + setStopAt(1, PhaseStep.END_TURN); setStrictChooseMode(true); execute(); - // Verify Sakashima entered and is copying the room - assertPermanentCount(playerB, "Sakashima the Impostor", 1); + // Verify Sakashima dies to state-based actions + // copies room and because sakashima has no unlocked designations, its mana value is 0 + // opalescence makes it a 0/0 and it dies + assertPermanentCount(playerA, sakashimaTheImpostor, 0); + assertGraveyardCount(playerA, sakashimaTheImpostor, 1); } } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/khc/EtherealValkyrieTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/khc/EtherealValkyrieTest.java index dcc3b7670fd..94bd1b50a90 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/khc/EtherealValkyrieTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/khc/EtherealValkyrieTest.java @@ -36,6 +36,8 @@ public class EtherealValkyrieTest extends CardTestPlayerBase { private static final String alloyMyr = "Alloy Myr"; // Land private static final String exoticOrchard = "Exotic Orchard"; + // {U} Creature-Planeswalker TDFC + private static final String tamiyo = "Tamiyo, Inquisitive Student"; /** * Test that a regular card is playable. @@ -202,4 +204,27 @@ public class EtherealValkyrieTest extends CardTestPlayerBase { setStopAt(3, PhaseStep.PRECOMBAT_MAIN); execute(); } + + /** + * Test a TDFC, which should be castable. + */ + @Test + public void testTransformingDoubleFacedCard() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + addCard(Zone.HAND, playerA, etherealValkyrie); + addCard(Zone.HAND, playerA, tamiyo); + + setStrictChooseMode(true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, etherealValkyrie); + addTarget(playerA, tamiyo); + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Foretell {U}"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + + execute(); + assertPermanentCount(playerA, tamiyo, 1); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java index 223f35b68c7..b6cf20ff645 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java @@ -3,7 +3,6 @@ package org.mage.test.cards.single.spm; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.counters.CounterType; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -33,7 +32,6 @@ public class GwenStacyTest extends CardTestPlayerBase { private static final String ghostSpider = "Ghost-Spider"; @Test - @Ignore("Enable after transform mdfc rework") public void testGhostSpider() { setStrictChooseMode(true); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/PeterParkerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/PeterParkerTest.java index 38eeace4a37..38fe6fa6e9f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/PeterParkerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/PeterParkerTest.java @@ -7,7 +7,6 @@ import mage.constants.PhaseStep; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -18,19 +17,20 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class PeterParkerTest extends CardTestPlayerBase { /* - Peter Parker - {1}{W} - Legendary Creature - Human Scientist Hero - When Peter Parker enters, create a 2/1 green Spider creature token with reach. - {1}{G}{W}{U}: Transform Peter Parker. Activate only as a sorcery. - Amazing Spider-Man - {1}{G}{W}{U} - Legendary Creature - Spider Human Hero - Vigilance, reach - Each legendary spell you cast that's one or more colors has web-slinging {G}{W}{U}. - 4/4 - */ + Peter Parker + {1}{W} + Legendary Creature - Human Scientist Hero + When Peter Parker enters, create a 2/1 green Spider creature token with reach. + {1}{G}{W}{U}: Transform Peter Parker. Activate only as a sorcery. + Amazing Spider-Man + {1}{G}{W}{U} + Legendary Creature - Spider Human Hero + Vigilance, reach + Each legendary spell you cast that's one or more colors has web-slinging {G}{W}{U}. + 4/4 + */ private static final String peterParker = "Peter Parker"; + public static final String amazingSpiderMan = "Amazing Spider-Man"; /* @@ -73,8 +73,16 @@ public class PeterParkerTest extends CardTestPlayerBase { */ private static final String balduvianBears = "Balduvian Bears"; + /* + Unsummon + {U} + Instant + Return target creature to its owner's hand. + */ + private static final String unsummon = "Unsummon"; + + @Test - @Ignore("Enable after MDFC rework") public void testAmazingSpiderMan() { setStrictChooseMode(true); @@ -91,7 +99,7 @@ public class PeterParkerTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8); addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Amazing Spider-Man", true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, amazingSpiderMan, true); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); @@ -112,4 +120,131 @@ public class PeterParkerTest extends CardTestPlayerBase { execute(); } + + @Test + public void testTransform() { + setStrictChooseMode(true); + + addCustomCardWithAbility("tap all creatures", playerA, new SimpleActivatedAbility( + new TapAllEffect(new FilterCreaturePermanent(SubType.BEAR, "bears")), + new ManaCostsImpl<>("") + )); + + addCard(Zone.HAND, playerA, peterParker); + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8); + addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8); + addCard(Zone.BATTLEFIELD, playerA, balduvianBears); + addCard(Zone.HAND, playerA, adelbertSteiner); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, peterParker, true); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G}{W}{U}: Transform"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, adelbertSteiner + " with Web-slinging"); + setChoice(playerA, balduvianBears); // return to hand + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, amazingSpiderMan, 1); + assertPermanentCount(playerA, adelbertSteiner, 1); + assertPermanentCount(playerA, balduvianBears, 0); + assertHandCount(playerA, balduvianBears, 1); + } + + /** + * test that MDFC doesn't have static ability from one side after transforming + */ + @Test + public void testTransformLosesWebSlinging() { + setStrictChooseMode(true); + + addCustomCardWithAbility("tap all creatures", playerA, new SimpleActivatedAbility( + new TapAllEffect(new FilterCreaturePermanent(SubType.BEAR, "bears")), + new ManaCostsImpl<>("") + )); + addCustomEffect_TargetTransform(playerA); + + addCard(Zone.HAND, playerA, peterParker); + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8); + addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8); + addCard(Zone.BATTLEFIELD, playerA, balduvianBears); + addCard(Zone.HAND, playerA, adelbertSteiner); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, peterParker, true); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G}{W}{U}: Transform"); // transform to Spider-Man + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + checkPlayableAbility("card in hand has web-slinging", 1, PhaseStep.PRECOMBAT_MAIN, + playerA, "Cast " + adelbertSteiner + " with Web-slinging", true); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target transform", amazingSpiderMan); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + checkPlayableAbility("card in hand does not have web-slinging", 1, PhaseStep.PRECOMBAT_MAIN, + playerA, "Cast " + adelbertSteiner + " with Web-slinging", false); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, amazingSpiderMan, 0); + assertPermanentCount(playerA, peterParker, 1); + assertHandCount(playerA, adelbertSteiner, 1); + assertPermanentCount(playerA, balduvianBears, 1); + } + + /** + * test showing if a transformed MDFC gets re-cast, it won't trigger effects from the other face + */ + @Test + public void testTransformCastSecondSideDoesntTriggerFront() { + setStrictChooseMode(true); + + addCustomCardWithAbility("tap all creatures", playerA, new SimpleActivatedAbility( + new TapAllEffect(new FilterCreaturePermanent(SubType.BEAR, "bears")), + new ManaCostsImpl<>("") + )); + addCustomEffect_TargetTransform(playerA); + + addCard(Zone.HAND, playerA, peterParker); + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8); + addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8); + addCard(Zone.BATTLEFIELD, playerA, balduvianBears); + addCard(Zone.HAND, playerA, adelbertSteiner); + addCard(Zone.HAND, playerA, unsummon); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, amazingSpiderMan, true); + + checkPlayableAbility("card in hand has web-slinging", 1, PhaseStep.PRECOMBAT_MAIN, + playerA, "Cast " + adelbertSteiner + " with Web-slinging", true); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target transform", amazingSpiderMan); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + checkPlayableAbility("card in hand does not have web-slinging", 1, PhaseStep.PRECOMBAT_MAIN, + playerA, "Cast " + adelbertSteiner + " with Web-slinging", false); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, unsummon, peterParker, true); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, amazingSpiderMan); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, amazingSpiderMan, 1); + assertPermanentCount(playerA, peterParker, 0); + assertHandCount(playerA, adelbertSteiner, 1); + assertPermanentCount(playerA, balduvianBears, 1); + assertPermanentCount(playerA, "Spider Token", 0); + currentGame.getState().getTriggers().forEach( + (key, value) -> logger.info(key + " - " + value) + ); + } } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/unf/EmbiggenTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/unf/EmbiggenTest.java new file mode 100644 index 00000000000..216e8289557 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/unf/EmbiggenTest.java @@ -0,0 +1,50 @@ +package org.mage.test.cards.single.unf; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class EmbiggenTest extends CardTestPlayerBase { + + private static final String roar = "Relic's Roar"; + private static final String embiggen = "Embiggen"; + private static final String agent = "Blighted Agent"; + + @Test + public void testRoarFirst() { + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 2); + addCard(Zone.BATTLEFIELD, playerA, agent); + addCard(Zone.HAND, playerA, roar); + addCard(Zone.HAND, playerA, embiggen); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, roar, agent, true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, embiggen, agent, true); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPowerToughness(playerA, agent, 4 + 4 + 2, 3 + 4 + 2); + } + + @Test + public void testEmbiggenFirst() { + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 2); + addCard(Zone.BATTLEFIELD, playerA, agent); + addCard(Zone.HAND, playerA, roar); + addCard(Zone.HAND, playerA, embiggen); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, embiggen, agent, true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, roar, agent, true); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPowerToughness(playerA, agent, 4 + 3 + 1, 3 + 3 + 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java index 2fc31b9d548..6f34ecedda6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java @@ -213,14 +213,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Tangled Vale"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Vale", 2, 1, 1, 2)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Vale", 2, 2, 2, 2)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Vale"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 2, 2, 4)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 4, 4, 4)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -244,14 +242,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Riverglide Pathway"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("1: check zcc pre disfigure", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Riverglide Pathway", 2, 1, 2, 1)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Riverglide Pathway", 2, 2, 2, 2)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Riverglide Pathway"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("2: check zcc post disfigure", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 2, 4, 2)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 4, 4, 4)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -275,14 +271,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Lavaglide Pathway"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Lavaglide Pathway", 2, 1, 1, 2)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Lavaglide Pathway", 2, 2, 2, 2)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Lavaglide Pathway"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 2, 2, 4)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 4, 4, 4)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -335,14 +329,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 2, 3, 2)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 3, 3, 3)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Florahedron"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 3, 5, 3)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 5, 5, 5)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -403,25 +395,25 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tangled Florahedron"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron"); - // TODO: investigate why MDFC zcc moves separatedly. + runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 2, 3, 2)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 3, 3, 3)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Florahedron", true); - // TODO: investigate why MDFC zcc moves separatedly. + runCode("2: check zcc card", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 3, 5, 3)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 5, 5, 5)); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Tangled Florahedron"); waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron", true); - // TODO: investigate why MDFC zcc moves separatedly. + runCode("3: check zcc", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 7, 4, 7, 4)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 7, 7, 7, 7)); waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Disfigure", "Tangled Florahedron", true); - // TODO: investigate why MDFC zcc moves separatedly. + runCode("4: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 5, 9, 5)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 9, 9, 9)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -458,20 +450,19 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { runCode("3: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, (String info, Player player, Game game) -> checkZCCNormalPermanent(info, player, game, "Carrion Feeder", 5, 5)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Coat with Venom", "Carrion Feeder", true); - runCode("4: check graveyard zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCCardInGraveyard(info, player, game, "Carrion Feeder", 6)); + runCode("4: check hand zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, + (String info, Player player, Game game) -> checkZCCNormalCardInHand(info, player, game, "Carrion Feeder", 7)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); - // Vigor tries to return the Carrion Feeder card with zcc 4, so 6 doesn't return. assertGraveyardCount(playerA, "Disfigure", 1); assertGraveyardCount(playerA, "Demonic Vigor", 1); assertGraveyardCount(playerA, "Makeshift Mannequin", 1); - assertGraveyardCount(playerA, "Carrion Feeder", 1); + assertGraveyardCount(playerA, "Carrion Feeder", 0); assertPermanentCount(playerA, "Carrion Feeder", 0); - assertHandCount(playerA, "Carrion Feeder", 0); + assertHandCount(playerA, "Carrion Feeder", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 3a849814cb5..133d92dd28a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -7,6 +7,8 @@ import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectsList; import mage.cards.Card; +import mage.cards.DoubleFacedCard; +import mage.cards.DoubleFacedCardHalf; import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; import mage.cards.decks.importer.DeckImporter; @@ -773,6 +775,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement if (gameZone == Zone.BATTLEFIELD) { for (int i = 0; i < count; i++) { Card newCard = cardInfo.createCard(); + if (newCard instanceof DoubleFacedCard) { + DoubleFacedCardHalf rightHalf = ((DoubleFacedCard) newCard).getRightHalfCard(); + if (rightHalf.getName().equals(cardName) && rightHalf.isPermanent()) { + newCard = rightHalf; + } + } getBattlefieldCards(player).add(new PutToBattlefieldInfo( newCard, tapped @@ -781,7 +789,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement // TODO: is it bugged with double faced cards (wrong ref)? // add to all players String aliasId = player.generateAliasName(aliasName, useAliasMultiNames, i + 1); - currentGame.getPlayers().values().forEach(pl -> ((TestPlayer) pl).addAlias(aliasId, newCard.getId())); + Card finalNewCard = newCard; + currentGame.getPlayers().values().forEach(pl -> ((TestPlayer) pl).addAlias(aliasId, finalNewCard.getId())); } } } else { diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/CardUtilTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/CardUtilTest.java index 99e6845c60c..cd9f1eeda17 100644 --- a/Mage.Tests/src/test/java/org/mage/test/utils/CardUtilTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/utils/CardUtilTest.java @@ -21,7 +21,7 @@ public class CardUtilTest extends CardTestPlayerBase { // MDFC where both sides should be playable private static final String birgi = "Birgi, God of Storytelling"; // {2}{R}, frontside of Harnfel private static final String harnfel = "Harnfel, Horn of Bounty"; // {4}{R}, backside of Birgi - + private static final String tamiyo = "Tamiyo, Inquisitive Student"; // {U}, TDFC /** * Test that it will for trigger for discarding a MDFC but will only let you cast the nonland side. */ @@ -122,4 +122,29 @@ public class CardUtilTest extends CardTestPlayerBase { Assert.assertEquals("12345", CardUtil.substring(str, 8, ending)); Assert.assertEquals("12345", CardUtil.substring(str, 9, ending)); } + + /** + * Test that it will for trigger for discarding a TDFC but will only let you cast the front side. + */ + @Test + public void cantPlayTDFCBackSide() { + addCard(Zone.HAND, playerA, changeOfFortune); + addCard(Zone.HAND, playerA, tamiyo); + + addCard(Zone.BATTLEFIELD, playerA, oskar); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + + skipInitShuffling(); + setStrictChooseMode(true); + + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}", 4); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, changeOfFortune); + setChoice(playerA, "Yes"); + // only option is to cast front side, so auto chosen + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertPermanentCount(playerA, tamiyo, 1); + } } diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index a8dd1572a39..8db8b3fd823 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -304,7 +304,8 @@ public class VerifyCardDataTest { */ private static boolean evergreenCheck(String s) { return evergreenKeywords.contains(s) || s.startsWith("protection from") || s.startsWith("hexproof from") - || s.startsWith("ward ") || s.startsWith("rampage ") || s.startsWith("annihilator"); + || s.startsWith("ward ") || s.startsWith("rampage ") || s.startsWith("annihilator") + || s.matches("^firebending \\d"); } private static boolean eqSet(Collection a, Collection b) { @@ -328,7 +329,8 @@ public class VerifyCardDataTest { checkWrongAbilitiesTextStart(); int cardIndex = 0; - for (Card card : CardScanner.getAllCards()) { + List allCards = CardScanner.getAllCards(); + for (Card card : allCards) { cardIndex++; if (card instanceof CardWithHalves) { check(((CardWithHalves) card).getLeftHalfCard(), cardIndex); @@ -345,7 +347,7 @@ public class VerifyCardDataTest { printMessages(outputMessages); if (failed > 0) { - Assert.fail(String.format("found %d errors in %d cards verify (see errors list above)", failed, CardScanner.getAllCards().size())); + Assert.fail(String.format("found %d errors in %d cards verify (see errors list above)", failed, allCards.size())); } } @@ -649,6 +651,9 @@ public class VerifyCardDataTest { CardInfo cardInfo = CardRepository.instance.findCardsByClass(info.getCardClass().getCanonicalName()).stream().findFirst().orElse(null); Assert.assertNotNull(cardInfo); + if (cardInfo.isDoubleFacedCard()) { + break; + } Card card = cardInfo.createCard(); Card secondCard = card.getSecondCardFace(); if (secondCard != null) { @@ -959,13 +964,12 @@ public class VerifyCardDataTest { private static final Set ignoreBoosterSets = new HashSet<>(); static { - // temporary, TODO: remove after set release and mtgjson get info - ignoreBoosterSets.add("Edge of Eternities"); - // jumpstart, TODO: must implement from JumpstartPoolGenerator, see #13264 + // jumpstart, TODO: implement from JumpstartPoolGenerator, see #13264 ignoreBoosterSets.add("Jumpstart"); ignoreBoosterSets.add("Jumpstart 2022"); ignoreBoosterSets.add("Foundations Jumpstart"); ignoreBoosterSets.add("Ravnica: Clue Edition"); + ignoreBoosterSets.add("Avatar: The Last Airbender Eternal"); // joke or un-sets, low implemented cards ignoreBoosterSets.add("Unglued"); ignoreBoosterSets.add("Unhinged"); @@ -1224,7 +1228,8 @@ public class VerifyCardDataTest { cardInfo.getCardNumber(), cardInfo.getRarity(), cardInfo.getGraphicInfo())); Assert.assertNotNull(card); - if (card.getSecondCardFace() != null) { + //TODO: do we need this check after tdfc rework? + if (card.getSecondCardFace() != null && !(card instanceof DoubleFacedCard)) { containsDoubleSideCards = true; } @@ -2194,7 +2199,8 @@ public class VerifyCardDataTest { // Note that the check includes reminder text, so any keyword ability with reminder text always included in the card text doesn't need to be added // FIN added equip abilities with flavor words, allow for those. There are also cards that affect equip costs or equip abilities, exclude those // Technically Enchant should be in this list, but that's added to the SpellAbility in XMage - Pattern targetKeywordRegexPattern = Pattern.compile("^((.*— )?equip(?! cost| abilit)|bestow|partner with|modular|backup)\\b", Pattern.MULTILINE); + // Earthbend is an action word and thus can be anywhere, the rest are keywords that are always first in the line + Pattern targetKeywordRegexPattern = Pattern.compile("earthbend |^((.*— )?equip(?! cost| abilit)|bestow|partner with|modular|backup)\\b", Pattern.MULTILINE); // Checks for targeted reflexive or delayed triggered abilities, ones that only can trigger as a result of another ability // and thus have their "when" located after a previous statement (detected by a period or comma followed by a space) instead of the start. @@ -2286,11 +2292,25 @@ public class VerifyCardDataTest { fail(card, "abilities", "card has backup but is missing this.addAbility(backupAbility)"); } + // special check: DFC main card should not have abilities + if (card instanceof DoubleFacedCardHalf && !card.getMainCard().getInitAbilities().isEmpty()) { + fail(card, "abilities", "transforming double-faced card should not have abilities on the main card"); + } + + // TODO: remove after transform ability removed + // special check: new DFC implementation should not have transform ability + if (card instanceof DoubleFacedCardHalf && card.getAbilities().containsClass(TransformAbility.class) + && !card.getAbilities().containsClass(DayboundAbility.class) + && !card.getAbilities().containsClass(CraftAbility.class) + && !card.getAbilities().containsClass(SiegeAbility.class)) { + fail(card, "abilities", "new transforming double-faced card should not have transform ability"); + } + // special check: Werewolves front ability should only be on front and vice versa - if (card.getAbilities().containsClass(WerewolfFrontTriggeredAbility.class) && card.isNightCard()) { + if (card.getAbilities().containsClass(WerewolfFrontTriggeredAbility.class) && (card.isNightCard() || (card instanceof DoubleFacedCardHalf && ((DoubleFacedCardHalf) card).isBackSide()))) { fail(card, "abilities", "card is a back face werewolf with a front face ability"); } - if (card.getAbilities().containsClass(WerewolfBackTriggeredAbility.class) && !card.isNightCard()) { + if (card.getAbilities().containsClass(WerewolfBackTriggeredAbility.class) && (!card.isNightCard() && (card instanceof DoubleFacedCardHalf && !((DoubleFacedCardHalf) card).isBackSide()))) { fail(card, "abilities", "card is a front face werewolf with a back face ability"); } @@ -2308,7 +2328,7 @@ public class VerifyCardDataTest { } // special check: siege ability must be used in double faced cards only - if (card.getAbilities().containsClass(SiegeAbility.class) && card.getSecondCardFace() == null) { + if (card.getAbilities().containsClass(SiegeAbility.class) && (card.getSecondCardFace() == null && (card instanceof DoubleFacedCardHalf && ((DoubleFacedCardHalf) card).getOtherSide() == null))) { fail(card, "abilities", "miss second side settings in card with siege ability"); } @@ -2637,14 +2657,14 @@ public class VerifyCardDataTest { if (mageObject.isCreature(game)) { return "this creature"; } - if (mageObject.isLand(game)) { - return "this land"; - } for (SubType subType : selfRefNamedSubtypes) { if (mageObject.hasSubtype(subType, game)) { return "this " + subType.getDescription(); } } + if (mageObject.isLand(game)) { + return "this land"; + } if (mageObject.isBattle(game)) { return "this battle"; } @@ -2768,8 +2788,12 @@ public class VerifyCardDataTest { // format to print main card then spell card card.getInitAbilities().getRules().forEach(this::printAbilityText); ((CardWithSpellOption) card).getSpellCard().getAbilities().getRules().forEach(r -> printAbilityText(r.replace("— ", "\n"))); - } else if (card instanceof SplitCard || card instanceof ModalDoubleFacedCard) { - card.getAbilities().getRules().forEach(this::printAbilityText); + } else if (card instanceof SplitCard || card instanceof DoubleFacedCard) { + // format to print each side separately + System.out.println("=== " + ((CardWithHalves) card).getLeftHalfCard().getName() + " ==="); + ((CardWithHalves) card).getLeftHalfCard().getAbilities().getRules().forEach(this::printAbilityText); + System.out.println("=== " + ((CardWithHalves) card).getRightHalfCard().getName() + " ==="); + ((CardWithHalves) card).getRightHalfCard().getAbilities().getRules().forEach(this::printAbilityText); } else { card.getRules().forEach(this::printAbilityText); } @@ -2777,9 +2801,17 @@ public class VerifyCardDataTest { // ref card System.out.println(); MtgJsonCard refMain = MtgJsonService.card(card.getName()); - MtgJsonCard refSpell = null; + Card cardMain = card; + MtgJsonCard refTwo = null; + Card cardTwo = null; if (card instanceof CardWithSpellOption) { - refSpell = MtgJsonService.card(((CardWithSpellOption) card).getSpellCard().getName()); + refTwo = MtgJsonService.card(((CardWithSpellOption) card).getSpellCard().getName()); + cardTwo = ((CardWithSpellOption) card).getSpellCard(); + } else if (card instanceof CardWithHalves) { + refMain = MtgJsonService.card(((CardWithHalves) card).getLeftHalfCard().getName()); + cardMain = ((CardWithHalves) card).getLeftHalfCard(); + refTwo = MtgJsonService.card(((CardWithHalves) card).getRightHalfCard().getName()); + cardTwo = ((CardWithHalves) card).getRightHalfCard(); } if (refMain == null) { refMain = MtgJsonService.cardByClassName(foundClassName); @@ -2787,9 +2819,9 @@ public class VerifyCardDataTest { if (refMain != null) { System.out.println("ref: " + refMain.getNameAsFace() + " " + refMain.manaCost); System.out.println(refMain.text); - if (refSpell != null) { - System.out.println(refSpell.getNameAsFace() + " " + refSpell.manaCost); - System.out.println(refSpell.text); + if (refTwo != null) { + System.out.println("ref: " + refTwo.getNameAsFace() + " " + refTwo.manaCost); + System.out.println(refTwo.text); } } else { System.out.println("WARNING, can't find mtgjson ref for " + card.getName()); @@ -2797,9 +2829,10 @@ public class VerifyCardDataTest { // additional check to simulate diff in rules if (refMain != null) { - checkWrongAbilitiesText(card, refMain, 0, true); - } else if (refSpell != null) { - checkWrongAbilitiesText(((CardWithSpellOption) card).getSpellCard(), refSpell, 0, true); + checkWrongAbilitiesText(cardMain, refMain, 0, true); + } + if (refTwo != null) { + checkWrongAbilitiesText(cardTwo, refTwo, 0, true); } }); } diff --git a/Mage/src/main/java/mage/MageIdentifier.java b/Mage/src/main/java/mage/MageIdentifier.java index 08224c3a446..551431e689d 100644 --- a/Mage/src/main/java/mage/MageIdentifier.java +++ b/Mage/src/main/java/mage/MageIdentifier.java @@ -62,6 +62,7 @@ public enum MageIdentifier { DemilichAlternateCast, DemonicEmbraceAlternateCast, FalcoSparaPactweaverAlternateCast, + FireLordOzaiAlternateCast, HelbruteAlternateCast, IntoThePitAlternateCast, MaestrosAscendencyAlternateCast, diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldTriggeredAbility.java index 0a8aeb373d6..10df3b1f3dd 100644 --- a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldTriggeredAbility.java @@ -23,7 +23,7 @@ public class EntersBattlefieldTriggeredAbility extends TriggeredAbilityImpl { } public EntersBattlefieldTriggeredAbility(Effect effect, boolean optional) { - super(Zone.ALL, effect, optional); // Zone.All because a creature with trigger can be put into play and be sacrificed during the resolution of an effect (discard Obstinate Baloth with Smallpox) + super(Zone.BATTLEFIELD, effect, optional); // Zone.All doesn't appear to be necessary anymore (discard Obstinate Baloth with Smallpox still works) this.withRuleTextReplacement(true); // default true to replace "{this}" with "it" or "this creature" // warning, it's impossible to add text auto-replacement for creatures here (When this creature enters), diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java index e36231d922b..5703d94fe60 100644 --- a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java +++ b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java @@ -17,6 +17,9 @@ import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.stack.Spell; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** * @author LevelX2 @@ -99,11 +102,10 @@ class PutIntoGraveFromAnywhereEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { + UUID cardId = CardUtil.getMainCardId(game, source.getSourceId()); // for split cards if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD - && event.getTargetId().equals(source.getSourceId())) { - if (condition == null || condition.apply(game, source)) { - return true; - } + && (event.getTargetId().equals(cardId) || event.getTargetId().equals(source.getSourceId()))) { + return condition == null || condition.apply(game, source); } return false; } diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoLibraryOneOrMoreTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoLibraryOneOrMoreTriggeredAbility.java new file mode 100644 index 00000000000..072eb4ba031 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/PutIntoLibraryOneOrMoreTriggeredAbility.java @@ -0,0 +1,60 @@ +package mage.abilities.common; + +import mage.abilities.BatchTriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeBatchEvent; +import mage.game.events.ZoneChangeEvent; + +import java.util.Objects; + +/** + * @author TheElk801 + */ +public class PutIntoLibraryOneOrMoreTriggeredAbility extends TriggeredAbilityImpl implements BatchTriggeredAbility { + + public PutIntoLibraryOneOrMoreTriggeredAbility(Effect effect) { + this(effect, false); + } + + public PutIntoLibraryOneOrMoreTriggeredAbility(Effect effect, boolean optional) { + this(Zone.BATTLEFIELD, effect, optional); + } + + public PutIntoLibraryOneOrMoreTriggeredAbility(Zone zone, Effect effect, boolean optional) { + super(zone, effect, optional); + this.setTriggerPhrase("Whenever one or more cards are put into a library from anywhere, "); + } + + private PutIntoLibraryOneOrMoreTriggeredAbility(final PutIntoLibraryOneOrMoreTriggeredAbility ability) { + super(ability); + } + + @Override + public PutIntoLibraryOneOrMoreTriggeredAbility copy() { + return new PutIntoLibraryOneOrMoreTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE_BATCH; + } + + @Override + public boolean checkEvent(ZoneChangeEvent event, Game game) { + return Zone.LIBRARY.match(event.getToZone()); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return this + .getFilteredEvents((ZoneChangeBatchEvent) event, game) + .stream() + .map(GameEvent::getTargetId) + .map(game::getCard) + .anyMatch(Objects::nonNull); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/RoomAbility.java b/Mage/src/main/java/mage/abilities/common/RoomAbility.java new file mode 100644 index 00000000000..36c689f10a5 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/RoomAbility.java @@ -0,0 +1,39 @@ +package mage.abilities.common; + +import mage.abilities.effects.common.RoomCharacteristicsEffect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentImpl; + +// For the overall Room card flavor text and mana value effect. +public class RoomAbility extends SimpleStaticAbility { + public RoomAbility() { + super(Zone.BATTLEFIELD, new RoomCharacteristicsEffect()); + this.setRuleVisible(true); + this.setRuleAtTheTop(true); + } + + protected RoomAbility(final RoomAbility ability) { + super(ability); + } + + @Override + public String getRule() { + return "(You may cast either half. That door unlocks on the battlefield. " + + "As a sorcery, you may pay the mana cost of a locked door to unlock it.)"; + } + + @Override + public RoomAbility copy() { + return new RoomAbility(this); + } + + public void applyCharacteristics(Game game, Permanent permanent) { + ((RoomCharacteristicsEffect) this.getEffects().get(0)).removeCharacteristics(game, permanent); + } + + public void restoreUnlockedStats(Game game, PermanentImpl permanent) { + ((RoomCharacteristicsEffect) this.getEffects().get(0)).restoreUnlockedStats(game, permanent); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/RoomUnlockAbility.java b/Mage/src/main/java/mage/abilities/common/RoomUnlockAbility.java index acf23c18761..6c4786fcd39 100644 --- a/Mage/src/main/java/mage/abilities/common/RoomUnlockAbility.java +++ b/Mage/src/main/java/mage/abilities/common/RoomUnlockAbility.java @@ -12,12 +12,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** + * Special action for Room cards to unlock a locked half by paying its + * mana cost. + * This ability is only present if the corresponding half is currently + * locked. * @author oscscull - * Special action for Room cards to unlock a locked half by paying its - * mana - * cost. - * This ability is only present if the corresponding half is currently - * locked. */ public class RoomUnlockAbility extends SpecialAction { @@ -61,6 +60,10 @@ public class RoomUnlockAbility extends SpecialAction { sb.append(isLeftHalf ? "left" : "right").append(" half is locked.)"); return sb.toString(); } + + public boolean isLeftHalf() { + return isLeftHalf; + } } /** diff --git a/Mage/src/main/java/mage/abilities/common/SpellTransformedAbility.java b/Mage/src/main/java/mage/abilities/common/SpellTransformedAbility.java index 5adbff755f5..8b3dfd4eeff 100644 --- a/Mage/src/main/java/mage/abilities/common/SpellTransformedAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SpellTransformedAbility.java @@ -7,6 +7,7 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.game.Game; import mage.game.stack.Spell; @@ -20,6 +21,7 @@ import java.util.UUID; public class SpellTransformedAbility extends SpellAbility { protected final String manaCost; //This variable is only used for rules text + private boolean ignoreTransformEffect; // TODO: temporary while converting tdfc public SpellTransformedAbility(Card card, String manaCost) { super(card.getSecondFaceSpellAbility()); @@ -35,7 +37,11 @@ public class SpellTransformedAbility extends SpellAbility { this.clearManaCosts(); this.clearManaCostsToPay(); this.addCost(new ManaCostsImpl<>(manaCost)); - this.addSubAbility(new TransformAbility()); + if (!(card instanceof TransformingDoubleFacedCard)) { + this.addSubAbility(new TransformAbility()); + } else { + ignoreTransformEffect = true; + } } public SpellTransformedAbility(final SpellAbility ability) { @@ -54,6 +60,7 @@ public class SpellTransformedAbility extends SpellAbility { protected SpellTransformedAbility(final SpellTransformedAbility ability) { super(ability); this.manaCost = ability.manaCost; + this.ignoreTransformEffect = ability.ignoreTransformEffect; } @Override @@ -65,6 +72,9 @@ public class SpellTransformedAbility extends SpellAbility { public boolean activate(Game game, Set allowedIdentifiers, boolean noMana) { if (super.activate(game, allowedIdentifiers, noMana)) { game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getSourceId(), Boolean.TRUE); + if (ignoreTransformEffect) { + return true; + } // TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides) TransformedEffect effect = new TransformedEffect(); game.addEffect(effect, this); diff --git a/Mage/src/main/java/mage/abilities/condition/common/CreatureLeftThisTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CreatureLeftThisTurnCondition.java new file mode 100644 index 00000000000..b8356474519 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/CreatureLeftThisTurnCondition.java @@ -0,0 +1,30 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.game.Game; +import mage.watchers.common.CreatureLeftBattlefieldWatcher; + +/** + * @author TheElk801 + */ +public enum CreatureLeftThisTurnCondition implements Condition { + instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } + + @Override + public boolean apply(Game game, Ability source) { + return CreatureLeftBattlefieldWatcher.getNumberCreatureLeft(source.getControllerId(), game) > 0; + } + + @Override + public String toString() { + return "a creature left the battlefield under your control this turn"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/WaterbendedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/WaterbendedCondition.java new file mode 100644 index 00000000000..03a51bcb2a4 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/WaterbendedCondition.java @@ -0,0 +1,26 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.keyword.WaterbendAbility; +import mage.game.Game; +import mage.util.CardUtil; + +/** + * Checks if the spell was cast with the alternate waterbend cost + * + * @author TheElk801 + */ +public enum WaterbendedCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return CardUtil.checkSourceCostsTagExists(game, source, WaterbendAbility.WATERBEND_ACTIVATION_VALUE_KEY); + } + + @Override + public String toString() { + return "the additional cost was paid"; + } +} diff --git a/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java index 2c5b8ac5552..1c51c8030c7 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java @@ -11,7 +11,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; /** * @author BetaSteward_at_googlemail.com @@ -21,16 +23,11 @@ public class RemoveCountersSourceCost extends CostImpl { private final int amount; private final String name; - public RemoveCountersSourceCost() { - this.amount = 1; - this.name = ""; - this.text = "remove a counter from {this}"; - } - public RemoveCountersSourceCost(int amount) { this.amount = amount; this.name = ""; - this.text = "remove " + CardUtil.numberToText(amount) + " counters from {this}"; + this.text = "remove " + CardUtil.numberToText(amount, "a") + + " counter" + (amount > 1 ? "s" : "") + " from {this}"; } public RemoveCountersSourceCost(Counter counter) { @@ -87,7 +84,7 @@ public class RemoveCountersSourceCost extends CostImpl { } paid = true; } - } else if (permanent.getCounters(game).getCount(name) >= amount){ + } else if (permanent.getCounters(game).getCount(name) >= amount) { permanent.removeCounters(name, amount, source, game); this.paid = true; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java b/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java index e1ea59d094a..db762f8a0cd 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java @@ -2,7 +2,7 @@ package mage.abilities.costs.common; import mage.abilities.Ability; import mage.abilities.costs.Cost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.CostImpl; import mage.game.Game; import java.util.UUID; @@ -12,14 +12,14 @@ import java.util.UUID; * * @author TheElk801 */ -public class WaterbendCost extends ManaCostsImpl { +public class WaterbendCost extends CostImpl { public WaterbendCost(int amount) { this("{" + amount + '}'); } public WaterbendCost(String mana) { - super(""); + super(); this.text = "waterbend " + mana; } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsSacrificedThisTurnCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsSacrificedThisTurnCount.java index 51700c964c6..3173e1e8fe9 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsSacrificedThisTurnCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsSacrificedThisTurnCount.java @@ -4,6 +4,8 @@ package mage.abilities.dynamicvalue.common; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.game.Game; import mage.watchers.common.PermanentsSacrificedWatcher; @@ -11,20 +13,27 @@ import mage.watchers.common.PermanentsSacrificedWatcher; * @author Susucr */ public enum PermanentsSacrificedThisTurnCount implements DynamicValue { - instance; + ALL(true), + YOU(false); + private final boolean all; + private final Hint hint; + + PermanentsSacrificedThisTurnCount(boolean all) { + this.all = all; + this.hint = new ValueHint("Permanents " + (all ? "" : "you ") + "sacrificed this turn", this); + } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { PermanentsSacrificedWatcher watcher = game.getState().getWatcher(PermanentsSacrificedWatcher.class); - if (watcher != null) { - return watcher.getThisTurnSacrificedPermanents(); - } - return 0; + return this.all + ? watcher.getThisTurnSacrificedPermanents() + : watcher.getThisTurnSacrificedPermanents(sourceAbility.getControllerId()).size(); } @Override public PermanentsSacrificedThisTurnCount copy() { - return PermanentsSacrificedThisTurnCount.instance; + return this; } @Override @@ -34,7 +43,10 @@ public enum PermanentsSacrificedThisTurnCount implements DynamicValue { @Override public String getMessage() { - return "permanents sacrificed this turn"; + return "the number of permanents " + (this.all ? "" : "you've ") + "sacrificed this turn"; } + public Hint getHint() { + return hint; + } } diff --git a/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java index 6d8e2d6fea4..2707c3a7a90 100644 --- a/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java @@ -3,10 +3,7 @@ package mage.abilities.effects; import mage.MageIdentifier; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; -import mage.cards.Card; -import mage.cards.ModalDoubleFacedCard; -import mage.cards.SplitCard; -import mage.cards.CardWithSpellOption; +import mage.cards.*; import mage.constants.*; import mage.game.Game; import mage.players.Player; @@ -92,9 +89,9 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements player.setCastSourceIdWithAlternateMana(leftCard.getId(), null, leftCard.getSpellAbility().getCosts(), identifier); Card rightCard = ((SplitCard) card).getRightHalfCard(); player.setCastSourceIdWithAlternateMana(rightCard.getId(), null, rightCard.getSpellAbility().getCosts(), identifier); - } else if (card instanceof ModalDoubleFacedCard) { - Card leftCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); - Card rightCard = ((ModalDoubleFacedCard) card).getRightHalfCard(); + } else if (card instanceof DoubleFacedCard) { + Card leftCard = ((DoubleFacedCard) card).getLeftHalfCard(); + Card rightCard = ((DoubleFacedCard) card).getRightHalfCard(); // some MDFC's are land. IE: sea gate restoration if (!leftCard.isLand(game)) { player.setCastSourceIdWithAlternateMana(leftCard.getId(), null, leftCard.getSpellAbility().getCosts(), identifier); diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java index f464355448e..bbb9bbfa828 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java @@ -2,9 +2,11 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.MageObjectReference; +import mage.abilities.Abilities; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.Card; +import mage.abilities.common.RoomAbility; import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; @@ -63,6 +65,16 @@ public class CopyEffect extends ContinuousEffectImpl { permanent = game.getPermanentEntering(copyToObjectId); if (permanent != null) { copyToPermanent(permanent, game, source); + // Apply Room characteristics since effects aren't applied to entering permanents yet + if (permanent.hasSubtype(SubType.ROOM, game)) { + Abilities abilities = permanent.getAbilities(); + for (Ability ability : abilities) { + if (ability instanceof RoomAbility) { + ((RoomAbility) ability).applyCharacteristics(game, permanent); + break; + } + } + } // set reference to the permanent later on the battlefield so we have to add already one (if no token) to the zone change counter int ZCCDiff = 1; if (permanent instanceof PermanentToken) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java index eed991c7797..7f91a769dcc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java @@ -216,6 +216,28 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { // create token and modify all attributes permanently (without game usage) Token token = CopyTokenFunction.createTokenCopy(copyFrom, game); // needed so that entersBattlefield triggered abilities see the attributes (e.g. Master Biomancer) applier.apply(game, token, source, targetId); + // the active face should have the modified attributes + if (token.isEntersTransformed()) { + applyAdditionsToToken(token.getBackFace()); + } else { + applyAdditionsToToken(token); + } + + token.putOntoBattlefield(number, game, source, playerId == null ? source.getControllerId() : playerId, tapped, attacking, attackedPlayer, attachedTo); + for (UUID tokenId : token.getLastAddedTokenIds()) { // by cards like Doubling Season multiple tokens can be added to the battlefield + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + addedTokenPermanents.add(tokenPermanent); + // TODO: Workaround to add counters to all created tokens, necessary for correct interactions with cards like Chatterfang, Squirrel General and Ochre Jelly / Printlifter Ooze. See #10786 + if (counter != null && numberOfCounters > 0) { + tokenPermanent.addCounters(counter.createInstance(numberOfCounters), source.getControllerId(), source, game); + } + } + } + return true; + } + + private void applyAdditionsToToken(Token token) { if (becomesArtifact) { token.addCardType(CardType.ARTIFACT); } @@ -281,19 +303,6 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { token.removeAbility(ability); } } - - token.putOntoBattlefield(number, game, source, playerId == null ? source.getControllerId() : playerId, tapped, attacking, attackedPlayer, attachedTo); - for (UUID tokenId : token.getLastAddedTokenIds()) { // by cards like Doubling Season multiple tokens can be added to the battlefield - Permanent tokenPermanent = game.getPermanent(tokenId); - if (tokenPermanent != null) { - addedTokenPermanents.add(tokenPermanent); - // TODO: Workaround to add counters to all created tokens, necessary for correct interactions with cards like Chatterfang, Squirrel General and Ochre Jelly / Printlifter Ooze. See #10786 - if (counter != null && numberOfCounters > 0) { - tokenPermanent.addCounters(counter.createInstance(numberOfCounters), source.getControllerId(), source, game); - } - } - } - return true; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndAllControlledEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndAllControlledEffect.java index b62896f7e90..61d228d61ea 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndAllControlledEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndAllControlledEffect.java @@ -74,9 +74,9 @@ public class DamageTargetAndAllControlledEffect extends OneShotEffect { return staticText; } String description = getTargetPointer().describeTargets(mode.getTargets(), "that player"); - return "{this} deals " + firstAmount + "damage to " + description + - " and " + secondAmount + " damage to each " + filter.getMessage() + - " that player" + + return "{this} deals " + firstAmount + " damage to " + description + " and " + + ((firstAmount == secondAmount) ? "each " : secondAmount + " damage to each ") + + filter.getMessage() + " that player" + (description.contains("planeswalker") ? " or that planeswalker's controller" : "") + " controls"; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndSelfEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndSelfEffect.java index ea7bc7c38ea..5ba9fd27c9a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndSelfEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndSelfEffect.java @@ -70,8 +70,8 @@ public class DamageTargetAndSelfEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - return "{this} deals " + firstAmount + "damage to " + + return "{this} deals " + firstAmount + " damage to " + getTargetPointer().describeTargets(mode.getTargets(), "that creature") + - " and " + secondAmount + "damage to itself"; + " and " + secondAmount + " damage to itself"; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetControllerEffect.java index 50f4bbda6ec..0fe2b18aa26 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetControllerEffect.java @@ -62,8 +62,8 @@ public class DamageTargetAndTargetControllerEffect extends OneShotEffect { return staticText; } String description = getTargetPointer().describeTargets(mode.getTargets(), "that creature"); - return "{this} deals " + firstAmount + "damage to " + description + - " and " + secondAmount + "damage to that " + + return "{this} deals " + firstAmount + " damage to " + description + + " and " + secondAmount + " damage to that " + (description.contains(" or ") ? "permanent's" : "creature's") + " controller"; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetEffect.java index 55a951b8085..c5f81072b7d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetEffect.java @@ -66,7 +66,7 @@ public class DamageTargetAndTargetEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - return "{this} deals " + firstAmount + "damage to " + mode.getTargets().getByTag(1).getDescription() + - " and " + secondAmount + "damage to " + mode.getTargets().getByTag(2).getDescription(); + return "{this} deals " + firstAmount + " damage to " + mode.getTargets().getByTag(1).getDescription() + + " and " + secondAmount + " damage to " + mode.getTargets().getByTag(2).getDescription(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndYouEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndYouEffect.java index b1e874e845e..390d3ff6273 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndYouEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndYouEffect.java @@ -70,8 +70,8 @@ public class DamageTargetAndYouEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - return "{this} deals " + firstAmount + "damage to " + + return "{this} deals " + firstAmount + " damage to " + getTargetPointer().describeTargets(mode.getTargets(), "that creature") + - " and " + secondAmount + "damage to you"; + " and " + secondAmount + " damage to you"; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java index 217f6dd4bdf..4780d137728 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java @@ -9,8 +9,6 @@ import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.Target; -import mage.util.CardUtil; import java.util.UUID; @@ -20,76 +18,38 @@ import java.util.UUID; */ public class DamageTargetEffect extends OneShotEffect { - protected DynamicValue amount; - protected boolean preventable; - protected String targetDescription; - protected String sourceName = "{this}"; + private final DynamicValue amount; + private boolean preventable = true; + private String sourceName = "{this}"; public DamageTargetEffect(int amount) { - this(StaticValue.get(amount), true); + this(StaticValue.get(amount)); } public DamageTargetEffect(int amount, String whoDealDamageName) { - this(StaticValue.get(amount), true); - this.sourceName = whoDealDamageName; - } - - public DamageTargetEffect(int amount, boolean preventable) { - this(StaticValue.get(amount), preventable); - } - - public DamageTargetEffect(int amount, boolean preventable, String targetDescription) { - this(StaticValue.get(amount), preventable, targetDescription); - } - - public DamageTargetEffect(int amount, boolean preventable, String targetDescription, String whoDealDamageName) { - this(StaticValue.get(amount), preventable, targetDescription); + this(amount); this.sourceName = whoDealDamageName; } public DamageTargetEffect(DynamicValue amount) { - this(amount, true); + super(Outcome.Damage); + this.amount = amount; } public DamageTargetEffect(DynamicValue amount, String whoDealDamageName) { - this(amount, true); + this(amount); this.sourceName = whoDealDamageName; } - public DamageTargetEffect(DynamicValue amount, boolean preventable) { - this(amount, preventable, ""); - } - - public DamageTargetEffect(DynamicValue amount, boolean preventable, String targetDescription) { - super(Outcome.Damage); - this.amount = amount; - this.preventable = preventable; - this.targetDescription = targetDescription; - } - - public int getAmount() { - if (amount instanceof StaticValue) { - return amount.calculate(null, null, this); - } else { - return 0; - } - } - - public void setAmount(DynamicValue amount) { - this.amount = amount; - } - protected DamageTargetEffect(final DamageTargetEffect effect) { super(effect); this.amount = effect.amount.copy(); this.preventable = effect.preventable; - this.targetDescription = effect.targetDescription; this.sourceName = effect.sourceName; } - @Override - public DamageTargetEffect withTargetDescription(String targetDescription) { - this.targetDescription = targetDescription; + public DamageTargetEffect withCantBePrevented() { + this.preventable = false; return this; } @@ -129,39 +89,11 @@ public class DamageTargetEffect extends OneShotEffect { sb.append(' '); } sb.append("damage to "); - if (!targetDescription.isEmpty()) { - sb.append(targetDescription); - } else { - if (!mode.getTargets().isEmpty()) { - Target firstTarget = mode.getTargets().get(0); - String targetName = firstTarget.getTargetName(); - if (targetName.contains("any")) { - sb.append(targetName); - } else { - if (firstTarget.getMinNumberOfTargets() == 0) { - int maxTargets = firstTarget.getMaxNumberOfTargets(); - switch (maxTargets) { - case Integer.MAX_VALUE: - sb.append("any number of "); - break; - case 1: - sb.append("up to one "); - break; - default: - sb.append("each of up to "); - sb.append(CardUtil.numberToText(maxTargets)); - sb.append(' '); - } - } - if (!targetName.contains("target ")) { - sb.append("target "); - } - sb.append(targetName); - } - } else { - sb.append("that target"); - } + String targetDescription = getTargetPointer().describeTargets(mode.getTargets(), "that target"); + if (targetDescription.startsWith("up to") && !targetDescription.startsWith("up to one")) { + sb.append("each of "); } + sb.append(targetDescription); if (!message.isEmpty()) { if (message.equals("1")) { sb.append(" equal to the number of "); diff --git a/Mage/src/main/java/mage/abilities/effects/common/HarnessSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/HarnessSourceEffect.java index a47aa31f40b..ab93c997e51 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/HarnessSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/HarnessSourceEffect.java @@ -13,7 +13,7 @@ public class HarnessSourceEffect extends OneShotEffect { public HarnessSourceEffect() { super(Outcome.AIDontUseIt); - staticText = "Harness {this}. (Once harnessed, its ∞ ability is active.)"; + staticText = "Harness {this}. (Once harnessed, its ∞ ability is active.)"; } protected HarnessSourceEffect(final HarnessSourceEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java index 45dfa70ed00..76314453b36 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java @@ -68,7 +68,7 @@ public class PutOnTopOrBottomLibraryTargetEffect extends OneShotEffect { sb.append(targetText); sb.append("'s owner"); } - sb.append(" puts it"); + sb.append(" puts it "); if (position > 1) { sb.append("into their library "); sb.append(CardUtil.numberToOrdinalText(position)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java index 87875eb4962..6e5cbb61c2b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java @@ -3,7 +3,6 @@ package mage.abilities.effects.common; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; -import mage.cards.ModalDoubleFacedCard; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; @@ -37,10 +36,6 @@ public class ReturnToHandAttachedEffect extends OneShotEffect { return false; } Card card = permanent.getMainCard(); - // TODO: Once MDFC ZCC increments are fixed properly, can remove this special case. For now must allow so effect works. - if (permanent.getZoneChangeCounter(game) + 1 != card.getZoneChangeCounter(game) && !(card instanceof ModalDoubleFacedCard)) { - return false; - } return player.moveCards(card, Zone.HAND, source, game); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/RoomCharacteristicsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RoomCharacteristicsEffect.java index 05e47216f61..a7d598bf893 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RoomCharacteristicsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RoomCharacteristicsEffect.java @@ -1,8 +1,12 @@ package mage.abilities.effects.common; import mage.MageObject; -import mage.Mana; +import mage.abilities.Abilities; +import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.RoomUnlockAbility; +import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousEffectImpl; @@ -15,12 +19,13 @@ import mage.constants.SubLayer; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; +import mage.util.CardUtil; + +import java.util.UUID; /** - * @author oscscull * Continuous effect that sets the name and mana value of a Room permanent based * on its unlocked halves. - * * Functions as a characteristic-defining ability. * 709.5. Some split cards are permanent cards with a single shared type line. * A shared type line on such an object represents two static abilities that @@ -33,11 +38,13 @@ import mage.game.permanent.PermanentCard; * object's right half." * These abilities, as well as which half of that permanent a characteristic is * in, are part of that object's copiable values. + * @author oscscull */ public class RoomCharacteristicsEffect extends ContinuousEffectImpl { + public RoomCharacteristicsEffect() { - super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.CharacteristicDefining_7a, + super(Duration.WhileOnBattlefield, Layer.TextChangingEffects_3, SubLayer.NA, Outcome.Neutral); staticText = ""; } @@ -59,6 +66,107 @@ public class RoomCharacteristicsEffect extends ContinuousEffectImpl { return false; } + return removeCharacteristics(game, permanent); + } + + public boolean removeCharacteristics(Game game, Permanent permanent) { + Card roomCardBlueprint = getCard(permanent); + + if (!(roomCardBlueprint instanceof SplitCard)) { + return false; + } + + SplitCard roomCard = (SplitCard) roomCardBlueprint; + + // Remove the name based on unlocked halves + String newName = permanent.getName(); + + boolean isLeftUnlocked = permanent.isLeftDoorUnlocked(); + if (!isLeftUnlocked && roomCard.getLeftHalfCard() != null) { + newName = newName.replace(roomCard.getLeftHalfCard().getName() + " // ", ""); + } + + boolean isRightUnlocked = permanent.isRightDoorUnlocked(); + if (!isRightUnlocked && roomCard.getRightHalfCard() != null) { + newName = newName + .replace(" // " + roomCard.getRightHalfCard().getName(), "") + .replace(roomCard.getRightHalfCard().getName(), ""); + } + + permanent.setName(newName); + + // Set the mana value based on unlocked halves + // Create a new Mana object to accumulate the costs + SpellAbility roomCardSpellAbility = roomCard.getSpellAbility().copy(); + // Remove the mana from the left half's cost to our total Mana object + if (!isLeftUnlocked) { + ManaCosts leftHalfManaCost = null; + if (roomCard.getLeftHalfCard() != null && roomCard.getLeftHalfCard().getSpellAbility() != null) { + leftHalfManaCost = roomCard.getLeftHalfCard().getSpellAbility().getManaCosts(); + } + if (leftHalfManaCost != null) { + CardUtil.adjustCost(roomCardSpellAbility, leftHalfManaCost, true); + } + } + + // Remove the mana from the right half's cost to our total Mana object + if (!isRightUnlocked) { + ManaCosts rightHalfManaCost = null; + if (roomCard.getRightHalfCard() != null && roomCard.getRightHalfCard().getSpellAbility() != null) { + rightHalfManaCost = roomCard.getRightHalfCard().getSpellAbility().getManaCosts(); + } + if (rightHalfManaCost != null) { + CardUtil.adjustCost(roomCardSpellAbility, rightHalfManaCost, true); + } + } + + ManaCosts roomCardManaCosts = roomCardSpellAbility.getManaCostsToPay(); + if (roomCardManaCosts.getText().equals("{0}")) { + roomCardManaCosts = new ManaCostsImpl<>(); + } + permanent.setManaCost(roomCardManaCosts); + + + // Remove abilities from locked halves and add unlock abilities + Abilities removedLeftAbilities = new AbilitiesImpl<>(); + Abilities removedRightAbilities = new AbilitiesImpl<>(); + Card abilitySource = permanent; + if (permanent.isCopy()) { + abilitySource = (Card) permanent.getCopyFrom(); + } + for (Ability ability : abilitySource.getAbilities(game)) { + if (!isLeftUnlocked) { + if (roomCard.getLeftHalfCard() != null && roomCard.getLeftHalfCard().getAbilities().contains(ability)) { + if (!removedLeftAbilities.contains(ability)) { + removedLeftAbilities.add(ability); + } + permanent.removeAbility(ability, null, game); + continue; + } + } + if (!isRightUnlocked) { + if (roomCard.getRightHalfCard() != null && roomCard.getRightHalfCard().getAbilities().contains(ability)) { + if (!removedRightAbilities.contains(ability)) { + removedRightAbilities.add(ability); + } + permanent.removeAbility(ability, null, game); + } + } + } + // Add the Special Action to unlock doors. + // These will ONLY be active if the corresponding half is LOCKED! + if (!removedLeftAbilities.isEmpty()) { + RoomUnlockAbility leftUnlockAbility = new RoomUnlockAbility(roomCard.getLeftHalfCard().getManaCost(), true); + permanent.addAbility(leftUnlockAbility, roomCard.getLeftHalfCard().getId(), game); + } + if (!removedRightAbilities.isEmpty()) { + RoomUnlockAbility rightUnlockAbility = new RoomUnlockAbility(roomCard.getRightHalfCard().getManaCost(), false); + permanent.addAbility(rightUnlockAbility, roomCard.getRightHalfCard().getId(), game); + } + return true; + } + + private static Card getCard(Permanent permanent) { Card roomCardBlueprint; // Handle copies @@ -74,69 +182,34 @@ public class RoomCharacteristicsEffect extends ContinuousEffectImpl { } else { roomCardBlueprint = permanent.getMainCard(); } + return roomCardBlueprint; + } - if (!(roomCardBlueprint instanceof SplitCard)) { - return false; - } - - SplitCard roomCard = (SplitCard) roomCardBlueprint; - - // Set the name based on unlocked halves - String newName = ""; - - boolean isLeftUnlocked = permanent.isLeftDoorUnlocked(); - if (isLeftUnlocked && roomCard.getLeftHalfCard() != null) { - newName += roomCard.getLeftHalfCard().getName(); - } - - boolean isRightUnlocked = permanent.isRightDoorUnlocked(); - if (isRightUnlocked && roomCard.getRightHalfCard() != null) { - if (!newName.isEmpty()) { - newName += " // "; // Split card name separator - } - newName += roomCard.getRightHalfCard().getName(); - } - - permanent.setName(newName); - - // Set the mana value based on unlocked halves - // Create a new Mana object to accumulate the costs - Mana totalManaCost = new Mana(); - - // Add the mana from the left half's cost to our total Mana object - if (isLeftUnlocked) { - ManaCosts leftHalfManaCost = null; - if (roomCard.getLeftHalfCard() != null && roomCard.getLeftHalfCard().getSpellAbility() != null) { - leftHalfManaCost = roomCard.getLeftHalfCard().getSpellAbility().getManaCosts(); - } - if (leftHalfManaCost != null) { - totalManaCost.add(leftHalfManaCost.getMana()); + public void restoreUnlockedStats(Game game, Permanent permanent) { + // remove unlock abilities + for (Ability ability : permanent.getAbilities(game)) { + if (ability instanceof RoomUnlockAbility) { + if (((RoomUnlockAbility) ability).isLeftHalf() && permanent.isLeftDoorUnlocked()) { + permanent.removeAbility(ability, null, game); + } else if (!((RoomUnlockAbility) ability).isLeftHalf() && permanent.isRightDoorUnlocked()) { + permanent.removeAbility(ability, null, game); + } } } - - // Add the mana from the right half's cost to our total Mana object - if (isRightUnlocked) { - ManaCosts rightHalfManaCost = null; - if (roomCard.getRightHalfCard() != null && roomCard.getRightHalfCard().getSpellAbility() != null) { - rightHalfManaCost = roomCard.getRightHalfCard().getSpellAbility().getManaCosts(); - } - if (rightHalfManaCost != null) { - totalManaCost.add(rightHalfManaCost.getMana()); + // restore removed abilities + // copies need abilities to be added back to game state for triggers + SplitCard roomCard = (SplitCard) getCard(permanent); + UUID sourceId = permanent.isCopy() ? permanent.getId() : null; + Game gameParam = permanent.isCopy() ? game : null; + if (permanent.isLeftDoorUnlocked()) { + for (Ability ability : roomCard.getLeftHalfCard().getAbilities()) { + permanent.addAbility(ability, sourceId, gameParam, true); } } - - String newManaCostString = totalManaCost.toString(); - ManaCostsImpl newManaCosts; - - // If both halves are locked or total 0, it's 0mv. - if (newManaCostString.isEmpty() || totalManaCost.count() == 0) { - newManaCosts = new ManaCostsImpl<>(""); - } else { - newManaCosts = new ManaCostsImpl<>(newManaCostString); + if (permanent.isRightDoorUnlocked()) { + for (Ability ability : roomCard.getRightHalfCard().getAbilities()) { + permanent.addAbility(ability, sourceId, gameParam, true); + } } - - permanent.setManaCost(newManaCosts); - - return true; } } \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java index 099abc9d1ac..e6e00c1372c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java @@ -16,7 +16,7 @@ import mage.abilities.effects.common.InfoEffect; import mage.abilities.keyword.WardAbility; import mage.cards.Card; import mage.cards.CardImpl; -import mage.cards.ModalDoubleFacedCard; +import mage.cards.DoubleFacedCard; import mage.cards.repository.TokenInfo; import mage.cards.repository.TokenRepository; import mage.constants.*; @@ -375,9 +375,9 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl { // it can't transform. If the front face of the card is a creature card, you can turn it face up by paying // its mana cost. If you do, its front face will be up. - if (card instanceof ModalDoubleFacedCard) { + if (card instanceof DoubleFacedCard) { // only MDFC uses independent card sides on 2024 - return ((ModalDoubleFacedCard) card).getLeftHalfCard(); + return ((DoubleFacedCard) card).getLeftHalfCard(); } else { return card; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostControlledEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostControlledEffect.java index c1db549eaaf..36537f5a62b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostControlledEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostControlledEffect.java @@ -116,7 +116,7 @@ public class BoostControlledEffect extends ContinuousEffectImpl { StringBuilder sb = new StringBuilder(); String message = filter.getMessage().toLowerCase(Locale.ENGLISH); boolean each = message.startsWith("each"); - if (excludeSource && !each && !message.startsWith("all")) { + if (excludeSource && !each && !message.startsWith("all ")) { sb.append("other "); } sb.append(filter.getMessage()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityWithAttachmentEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityWithAttachmentEffect.java index 75102356986..3c84cdc6ae4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityWithAttachmentEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityWithAttachmentEffect.java @@ -122,7 +122,7 @@ public class GainAbilityWithAttachmentEffect extends ContinuousEffectImpl { } ability.addCost(cost.copy()); } - if (source != null && game != null) { + if (source != null && game != null && useAttachedCost != null) { ability.addCost(useAttachedCost.copy().setMageObjectReference(source, game)); } if (consumer != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/YouDontLoseManaEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/YouDontLoseManaEffect.java index 2646319f1da..1f3afd4589e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/YouDontLoseManaEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/YouDontLoseManaEffect.java @@ -14,8 +14,13 @@ public class YouDontLoseManaEffect extends ContinuousEffectImpl { private final ManaType manaType; public YouDontLoseManaEffect(ManaType manaType) { - super(Duration.WhileOnBattlefield, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment); - staticText = "you don't lose unspent " + manaType + " mana as steps and phases end"; + this(Duration.WhileOnBattlefield, manaType); + } + + public YouDontLoseManaEffect(Duration duration, ManaType manaType) { + super(duration, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment); + staticText = (duration == Duration.EndOfTurn ? "until end of turn, " : "") + + "you don't lose unspent " + manaType + " mana as steps and phases end"; this.manaType = manaType; } @@ -37,4 +42,4 @@ public class YouDontLoseManaEffect extends ContinuousEffectImpl { } return false; } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryForFourDifferentCardsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryForFourDifferentCardsEffect.java index c49f7ff6225..7d3ddde1d98 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryForFourDifferentCardsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryForFourDifferentCardsEffect.java @@ -34,7 +34,7 @@ public class SearchLibraryForFourDifferentCardsEffect extends OneShotEffect { staticText = "search your library for up to four " + filter + " with different names and reveal them. " + (useTargetPointer ? "Target" : "An") + " opponent chooses two of those cards. Put the chosen cards into your graveyard and the rest " + - putCards.getMessage(false, false) + ", then shuffle"; + putCards.getMessage(false, false) + ". Then shuffle"; } private SearchLibraryForFourDifferentCardsEffect(final SearchLibraryForFourDifferentCardsEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/EarthbendTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/EarthbendTargetEffect.java index f9d73740e2d..6f7da3fb18b 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/EarthbendTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/EarthbendTargetEffect.java @@ -28,19 +28,26 @@ import mage.util.CardUtil; public class EarthbendTargetEffect extends OneShotEffect { private final DynamicValue amount; + private final boolean withReminderText; public EarthbendTargetEffect(int amount) { - this(StaticValue.get(amount)); + this(amount, true); } - public EarthbendTargetEffect(DynamicValue amount) { + public EarthbendTargetEffect(int amount, boolean withReminderText) { + this(StaticValue.get(amount), withReminderText); + } + + public EarthbendTargetEffect(DynamicValue amount, boolean withReminderText) { super(Outcome.Benefit); this.amount = amount; + this.withReminderText = withReminderText; } private EarthbendTargetEffect(final EarthbendTargetEffect effect) { super(effect); this.amount = effect.amount; + this.withReminderText = effect.withReminderText; } @Override @@ -65,6 +72,8 @@ public class EarthbendTargetEffect extends OneShotEffect { .withAbility(HasteAbility.getInstance()), false, true, Duration.Custom ), source); + // Make the land into a creature before putting counters on, for the purposes of counter doublers that only apply to creatures. + game.processAction(); permanent.addCounters(CounterType.P1P1.createInstance(value), source, game); game.addDelayedTriggeredAbility(new EarthbendingDelayedTriggeredAbility(permanent, game), source); game.fireEvent(GameEvent.getEvent( @@ -79,11 +88,15 @@ public class EarthbendTargetEffect extends OneShotEffect { return staticText; } StringBuilder sb = new StringBuilder("earthbend "); - sb.append(amount); - if (!(amount instanceof StaticValue)) { - sb.append(", where X is "); + if (amount instanceof StaticValue) { + sb.append(amount); + } else { + sb.append("X, where X is "); sb.append(amount.getMessage()); } + if (!withReminderText) { + return sb.toString(); + } sb.append(". (Target land you control becomes a 0/0 creature with haste that's still a land. Put "); String value = amount instanceof StaticValue ? CardUtil.numberToText(((StaticValue) amount).getValue(), "a") diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ScryTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ScryTargetEffect.java index 634b2da4d30..ee17ef00cea 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/ScryTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ScryTargetEffect.java @@ -8,7 +8,6 @@ import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; -import mage.util.CardUtil; import java.util.UUID; @@ -57,7 +56,7 @@ public class ScryTargetEffect extends OneShotEffect { } StringBuilder sb = new StringBuilder(getTargetPointer().describeTargets(mode.getTargets(), "that player")); sb.append(" scries "); - sb.append(CardUtil.numberToText(amount.toString())); + sb.append(amount.toString()); return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/hint/common/PermanentsSacrificedThisTurnHint.java b/Mage/src/main/java/mage/abilities/hint/common/PermanentsSacrificedThisTurnHint.java deleted file mode 100644 index 5786ddfe5d3..00000000000 --- a/Mage/src/main/java/mage/abilities/hint/common/PermanentsSacrificedThisTurnHint.java +++ /dev/null @@ -1,28 +0,0 @@ -package mage.abilities.hint.common; - -import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.PermanentsSacrificedThisTurnCount; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; -import mage.game.Game; - -/** - * @author Susucr - */ -public enum PermanentsSacrificedThisTurnHint implements Hint { - instance; - - private static final Hint hint = new ValueHint( - "Permanents sacrificed this turn", PermanentsSacrificedThisTurnCount.instance - ); - - @Override - public String getText(Game game, Ability ability) { - return hint.getText(game, ability); - } - - @Override - public PermanentsSacrificedThisTurnHint copy() { - return this; - } -} diff --git a/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java b/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java index 70f36cad717..1a1900d55fe 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java @@ -9,6 +9,7 @@ import mage.abilities.costs.common.ExileSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.cards.TransformingDoubleFacedCardHalf; import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterPermanent; diff --git a/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java b/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java index 421a25858d3..c033bc5e8b5 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java @@ -300,6 +300,7 @@ class ForetellAddCostEffect extends ContinuousEffectImpl { if (game.getState().getZone(mainCardId) == Zone.EXILED) { String foretellCost = (String) game.getState().getValue(mainCardId.toString() + "Foretell Cost"); String foretellSplitCost = (String) game.getState().getValue(mainCardId.toString() + "Foretell Split Cost"); + // TODO: clean this up if (card instanceof SplitCard) { if (foretellCost != null) { SplitCardHalf leftHalfCard = ((SplitCard) card).getLeftHalfCard(); @@ -363,6 +364,14 @@ class ForetellAddCostEffect extends ContinuousEffectImpl { ability.setAbilityName(spellCard.getName()); game.getState().addOtherAbility(spellCard, ability); } + } else if (card instanceof TransformingDoubleFacedCard && foretellCost != null) { + Card frontCard = ((TransformingDoubleFacedCard) card).getLeftHalfCard(); + ForetellCostAbility ability = new ForetellCostAbility(foretellCost); + ability.setSourceId(frontCard.getId()); + ability.setControllerId(source.getControllerId()); + ability.setSpellAbilityType(frontCard.getSpellAbility().getSpellAbilityType()); + ability.setAbilityName(frontCard.getName()); + game.getState().addOtherAbility(frontCard, ability); } else if (foretellCost != null) { ForetellCostAbility ability = new ForetellCostAbility(foretellCost); ability.setSourceId(card.getId()); diff --git a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java index f69518cf516..47408ef3f6b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java @@ -18,7 +18,7 @@ import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; import mage.cards.CardsImpl; -import mage.cards.ModalDoubleFacedCard; +import mage.cards.DoubleFacedCard; import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; @@ -177,10 +177,10 @@ public class SuspendAbility extends SpecialAction { * or added by Jhoira of the Ghitu */ public static void addSuspendTemporaryToCard(Card card, Ability source, Game game) { - if (card instanceof ModalDoubleFacedCard) { + if (card instanceof DoubleFacedCard) { // Need to ensure the suspend ability gets put on the left side card // since counters get added to this card. - card = ((ModalDoubleFacedCard) card).getLeftHalfCard(); + card = ((DoubleFacedCard) card).getLeftHalfCard(); } SuspendAbility ability = new SuspendAbility(0, null, card, false); ability.setSourceId(card.getId()); diff --git a/Mage/src/main/java/mage/abilities/keyword/WaterbendAbility.java b/Mage/src/main/java/mage/abilities/keyword/WaterbendAbility.java new file mode 100644 index 00000000000..2ce4dfd4368 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/WaterbendAbility.java @@ -0,0 +1,99 @@ +package mage.abilities.keyword; + +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.StaticAbility; +import mage.abilities.costs.*; +import mage.abilities.costs.common.WaterbendCost; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public class WaterbendAbility extends StaticAbility implements OptionalAdditionalSourceCosts { + + private static final String promptString = "Waterbend {"; + private static final String keywordText = "As an additional cost to cast this spell, you may waterbend {"; + private static final String reminderText = "While paying a waterbend cost, you can tap your artifacts and creatures to help. Each one pays for {1}."; + private final String rule; + private final int amount; + + public static final String WATERBEND_ACTIVATION_VALUE_KEY = "waterbendActivation"; + + protected OptionalAdditionalCost additionalCost; + + public static OptionalAdditionalCost makeCost(int amount) { + OptionalAdditionalCost cost = new OptionalAdditionalCostImpl( + keywordText + amount + '}', reminderText, new WaterbendCost(amount) + ); + cost.setRepeatable(false); + return cost; + } + + public WaterbendAbility(int amount) { + this(amount, null); + } + + public WaterbendAbility(int amount, String extraInfoText) { + super(Zone.STACK, null); + this.additionalCost = makeCost(amount); + this.rule = additionalCost.getName() + ". " + (extraInfoText == null ? "" : extraInfoText + ". ") + additionalCost.getReminderText(); + this.setRuleAtTheTop(true); + this.amount = amount; + } + + private WaterbendAbility(final WaterbendAbility ability) { + super(ability); + this.rule = ability.rule; + this.additionalCost = ability.additionalCost.copy(); + this.amount = ability.amount; + } + + @Override + public WaterbendAbility copy() { + return new WaterbendAbility(this); + } + + public void resetCost() { + if (additionalCost != null) { + additionalCost.reset(); + } + } + + @Override + public void addOptionalAdditionalCosts(Ability ability, Game game) { + if (!(ability instanceof SpellAbility)) { + return; + } + + Player player = game.getPlayer(ability.getControllerId()); + if (player == null) { + return; + } + + this.resetCost(); + boolean canPay = additionalCost.canPay(ability, this, ability.getControllerId(), game); + if (!canPay || !player.chooseUse(Outcome.Exile, promptString + amount + "}?", ability, game)) { + return; + } + + additionalCost.activate(); + for (Cost cost : ((Costs) additionalCost)) { + ability.getCosts().add(cost.copy()); + } + ability.setCostsTag(WATERBEND_ACTIVATION_VALUE_KEY, null); + } + + @Override + public String getCastMessageSuffix() { + return additionalCost.getCastSuffixMessage(0); + } + + @Override + public String getRule() { + return rule; + } +} diff --git a/Mage/src/main/java/mage/cards/Card.java b/Mage/src/main/java/mage/cards/Card.java index 86a4a7eba29..b78ff8d133a 100644 --- a/Mage/src/main/java/mage/cards/Card.java +++ b/Mage/src/main/java/mage/cards/Card.java @@ -1,5 +1,6 @@ package mage.cards; +import mage.MageInt; import mage.MageObject; import mage.Mana; import mage.abilities.Abilities; @@ -72,6 +73,7 @@ public interface Card extends MageObject, Ownerable { SpellAbility getSecondFaceSpellAbility(); + //TODO: remove after tdfc rework boolean isNightCard(); default boolean meldsWith(Card card) { @@ -250,6 +252,10 @@ public interface Card extends MageObject, Ownerable { List getAttachments(); + void setPT(int power, int toughness); + + void setPT(MageInt power, MageInt toughness); + /** * @param attachment can be any object: card, permanent, token * @param source can be null for default checks like state base diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index e9664d69b97..966363ae338 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -1,5 +1,6 @@ package mage.cards; +import mage.MageInt; import mage.MageObject; import mage.MageObjectImpl; import mage.Mana; @@ -126,6 +127,11 @@ public abstract class CardImpl extends MageObjectImpl implements Card { nightCard = card.nightCard; secondSideCardClazz = card.secondSideCardClazz; secondSideCard = null; // will be set on first getSecondCardFace call if card has one + // TODO: temporary until cards tdfc cards are converted + // can do normal copy after + if (card.secondSideCard instanceof DoubleFacedCardHalf) { + secondSideCard = card.secondSideCard.copy(); + } if (card.secondSideCard instanceof MockableCard) { // workaround to support gui's mock cards secondSideCard = card.secondSideCard.copy(); @@ -393,6 +399,17 @@ public abstract class CardImpl extends MageObjectImpl implements Card { this.abilities.setControllerId(ownerId); } + @Override + public void setPT(int power, int toughness) { + this.setPT(new MageInt(power), new MageInt(toughness)); + } + + @Override + public void setPT(MageInt power, MageInt toughness) { + this.power = power; + this.toughness = toughness; + } + @Override public UUID getControllerOrOwnerId() { return getOwnerId(); @@ -517,13 +534,13 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } } - // handle half of Modal Double Faces Cards on stack - if (stackObject == null && (this instanceof ModalDoubleFacedCard)) { - stackObject = game.getStack().getSpell(((ModalDoubleFacedCard) this).getLeftHalfCard().getId(), + // handle half of Double Faces Cards on stack + if (stackObject == null && (this instanceof DoubleFacedCard)) { + stackObject = game.getStack().getSpell(((DoubleFacedCard) this).getLeftHalfCard().getId(), false); if (stackObject == null) { stackObject = game.getStack() - .getSpell(((ModalDoubleFacedCard) this).getRightHalfCard().getId(), false); + .getSpell(((DoubleFacedCard) this).getRightHalfCard().getId(), false); } } @@ -650,7 +667,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { // If a spell or ability instructs a player to transform a permanent that // isn’t represented by a transforming token or a transforming double-faced // card, nothing happens. - return this.secondSideCardClazz != null || this.nightCard; + return this.secondSideCardClazz != null || this.nightCard || this.secondSideCard != null; } @Override @@ -947,7 +964,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } } } - if (controller != null && spellAbility != null && !spellAbility.getTargets().isEmpty()){ + if (controller != null && spellAbility != null && !spellAbility.getTargets().isEmpty()) { // Line of code below functionally gets the target of the aura's Enchant ability, then compares to this permanent. Enchant improperly implemented in XMage, see #9583 // Note: stillLegalTarget used exclusively to account for Dream Leash. Can be made canTarget in the event that that card is rewritten (and "stillLegalTarget" removed from TargetImpl). canAttach &= spellAbility.getTargets().get(0).copy().withNotTarget(true).stillLegalTarget(controller, this.getId(), source, game); diff --git a/Mage/src/main/java/mage/cards/DoubleFacedCard.java b/Mage/src/main/java/mage/cards/DoubleFacedCard.java new file mode 100644 index 00000000000..f9c752e0d5a --- /dev/null +++ b/Mage/src/main/java/mage/cards/DoubleFacedCard.java @@ -0,0 +1,413 @@ +package mage.cards; + +import mage.MageInt; +import mage.MageObject; +import mage.ObjectColor; +import mage.abilities.*; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.constants.*; +import mage.counters.Counter; +import mage.counters.Counters; +import mage.game.Game; +import mage.game.GameState; +import mage.game.events.ZoneChangeEvent; +import mage.util.CardUtil; +import mage.util.SubTypes; + +import java.util.List; +import java.util.UUID; + +/** + * @author JayDi85 - originally from ModalDoubleFaceCard + */ +public abstract class DoubleFacedCard extends CardImpl implements CardWithHalves { + + protected DoubleFacedCardHalf leftHalfCard; // main card in all zone + protected DoubleFacedCardHalf rightHalfCard; // second side card, can be only in stack and battlefield zones + + protected DoubleFacedCard(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costs, SpellAbilityType spellAbilityType) { + super(ownerId, setInfo, cardTypes, costs, spellAbilityType); + } + + public DoubleFacedCard(DoubleFacedCard card) { + super(card); + // make sure all parts created and parent ref added + this.leftHalfCard = (DoubleFacedCardHalf) card.getLeftHalfCard().copy(); + leftHalfCard.setParentCard(this); + this.rightHalfCard = (DoubleFacedCardHalf) card.getRightHalfCard().copy(); + rightHalfCard.setParentCard(this); + } + + public DoubleFacedCardHalf getLeftHalfCard() { + return leftHalfCard; + } + + public DoubleFacedCardHalf getRightHalfCard() { + return leftHalfCard; + } + + public void setParts(DoubleFacedCardHalf leftHalfCard, DoubleFacedCardHalf rightHalfCard) { + // for card copy only - set new parts + this.leftHalfCard = leftHalfCard; + leftHalfCard.setParentCard(this); + this.rightHalfCard = rightHalfCard; + rightHalfCard.setParentCard(this); + } + + @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); + } + + private void setSideZones(Zone mainZone, Game game) { + switch (mainZone) { + case BATTLEFIELD: + case STACK: + throw new IllegalArgumentException("Wrong code usage: you must put to battlefield/stack only real side card (half), not main"); + default: + game.setZone(leftHalfCard.getId(), mainZone); + game.setZone(rightHalfCard.getId(), mainZone); + break; + } + checkGoodZones(game, this); + } + + @Override + public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List appliedEffects) { + if (super.moveToZone(toZone, source, game, flag, appliedEffects)) { + Zone currentZone = game.getState().getZone(getId()); + setSideZones(currentZone, game); + return true; + } + return false; + } + + @Override + public void setZone(Zone zone, Game game) { + super.setZone(zone, game); + setSideZones(zone, game); + } + + @Override + public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List appliedEffects) { + if (super.moveToExile(exileId, name, source, game, appliedEffects)) { + Zone currentZone = game.getState().getZone(getId()); + setSideZones(currentZone, game); + return true; + } + return false; + } + + /** + * Runtime check for good zones and other MDF data + */ + public static void checkGoodZones(Game game, DoubleFacedCard card) { + Card leftPart = card.getLeftHalfCard(); + Card rightPart = card.getRightHalfCard(); + + Zone zoneMain = game.getState().getZone(card.getId()); + Zone zoneLeft = game.getState().getZone(leftPart.getId()); + Zone zoneRight = game.getState().getZone(rightPart.getId()); + + // runtime check: + // * in battlefield and stack - card + one of the sides (another side in outside zone) + // * in other zones - card + both sides (need both sides due cost reductions, spell and other access before put to stack) + // + // 712.8a While a double-faced card is outside the game or in a zone other than the battlefield or stack, + // it has only the characteristics of its front face. + // + // 712.8f While a modal double-faced spell is on the stack or a modal double-faced permanent is on the battlefield, + // it has only the characteristics of the face that’s up. + Zone needZoneLeft; + Zone needZoneRight; + switch (zoneMain) { + case BATTLEFIELD: + case STACK: + if (zoneMain == zoneLeft) { + needZoneLeft = zoneMain; + needZoneRight = Zone.OUTSIDE; + } else if (zoneMain == zoneRight) { + needZoneLeft = Zone.OUTSIDE; + needZoneRight = zoneMain; + } else { + // impossible + needZoneLeft = zoneMain; + needZoneRight = Zone.OUTSIDE; + } + break; + default: + needZoneLeft = zoneMain; + needZoneRight = zoneMain; + break; + } + + if (zoneLeft != needZoneLeft || zoneRight != needZoneRight) { + throw new IllegalStateException("Wrong code usage: MDF card uses wrong zones - " + card + + "\r\n" + String.format("* main zone: %s", zoneMain) + + "\r\n" + String.format("* left side: need %s, actual %s", needZoneLeft, zoneLeft) + + "\r\n" + String.format("* right side: need %s, actual %s", needZoneRight, zoneRight)); + } + } + + @Override + public boolean removeFromZone(Game game, Zone fromZone, Ability source) { + // zone contains only one main card + return super.removeFromZone(game, fromZone, source); + } + + @Override + public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) { + if (isCopy()) { // same as meld cards + super.updateZoneChangeCounter(game, event); + return; + } + super.updateZoneChangeCounter(game, event); + game.getState().updateZoneChangeCounter(leftHalfCard.getId()); + game.getState().updateZoneChangeCounter(rightHalfCard.getId()); + } + + @Override + public Counters getCounters(Game game) { + return getCounters(game.getState()); + } + + @Override + public Counters getCounters(GameState state) { + return state.getCardState(leftHalfCard.getId()).getCounters(); + } + + @Override + public boolean addCounters(Counter counter, UUID playerAddingCounters, Ability source, Game game, List appliedEffects, boolean isEffect, int maxCounters) { + return leftHalfCard.addCounters(counter, playerAddingCounters, source, game, appliedEffects, isEffect, maxCounters); + } + + @Override + public void removeCounters(String counterName, int amount, Ability source, Game game) { + leftHalfCard.removeCounters(counterName, amount, source, game); + } + + @Override + public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { + if (this.leftHalfCard.getSpellAbility() != null) { + this.leftHalfCard.getSpellAbility().setControllerId(controllerId); + } + if (this.rightHalfCard.getSpellAbility() != null) { + this.rightHalfCard.getSpellAbility().setControllerId(controllerId); + } + return super.cast(game, fromZone, ability, controllerId); + } + + + @Override + public List getSuperType(Game game) { + // CardImpl's constructor can call some code on init, so you must check left/right before + // it's a bad workaround + return leftHalfCard != null ? leftHalfCard.getSuperType(game) : supertype; + } + + @Override + public List getCardType(Game game) { + // CardImpl's constructor can call some code on init, so you must check left/right before + // it's a bad workaround + return leftHalfCard != null ? leftHalfCard.getCardType(game) : cardType; + } + + @Override + public SubTypes getSubtype() { + // rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face. + // CardImpl's constructor can call some code on init, so you must check left/right before + return leftHalfCard != null ? leftHalfCard.getSubtype() : subtype; + } + + @Override + public SubTypes getSubtype(Game game) { + // rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face. + // CardImpl's constructor can call some code on init, so you must check left/right before + return leftHalfCard != null ? leftHalfCard.getSubtype(game) : subtype; + } + + @Override + public boolean hasSubtype(SubType subtype, Game game) { + return leftHalfCard.hasSubtype(subtype, game); + } + + @Override + public Abilities getAbilities() { + return getInnerAbilities(true, true); + } + + @Override + public Abilities getInitAbilities() { + // must init only parent related abilities, spell card must be init separately + return getInnerAbilities(false, false); + } + + public Abilities getSharedAbilities(Game game) { + // no shared abilities for mdf cards (e.g. must be left or right only) + return new AbilitiesImpl<>(); + } + + @Override + public Abilities getAbilities(Game game) { + return getInnerAbilities(game, true, true); + } + + private boolean isIgnoreDefaultAbility(Ability ability) { + // ignore default play/spell ability from main card (only halves are actual) + // default abilities added on card creation from card type and can't be skipped + + // skip cast spell + if (ability instanceof SpellAbility) { + SpellAbilityType type = ((SpellAbility) ability).getSpellAbilityType(); + return type == SpellAbilityType.MODAL || type == SpellAbilityType.TRANSFORMED; + } + + // skip play land + return ability instanceof PlayLandAbility; + } + + private boolean isIgnoreTransformSpellAbility(Ability ability) { + return ability instanceof SpellAbility && ((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.TRANSFORMED_RIGHT; + } + + private Abilities getInnerAbilities(Game game, boolean showLeftSide, boolean showRightSide) { + Abilities allAbilites = new AbilitiesImpl<>(); + + for (Ability ability : super.getAbilities(game)) { + if (isIgnoreDefaultAbility(ability)) { + continue; + } + allAbilites.add(ability); + } + + if (showLeftSide) { + allAbilites.addAll(leftHalfCard.getAbilities(game)); + } + if (showRightSide) { + for (Ability ability: rightHalfCard.getAbilities(game)) { + if (isIgnoreTransformSpellAbility(ability)) { + continue; + } + allAbilites.add(ability); + } + } + + return allAbilites; + } + + private Abilities getInnerAbilities(boolean showLeftSide, boolean showRightSide) { + Abilities allAbilites = new AbilitiesImpl<>(); + + for (Ability ability : super.getAbilities()) { + if (isIgnoreDefaultAbility(ability)) { + continue; + } + allAbilites.add(ability); + } + + if (showLeftSide) { + allAbilites.addAll(leftHalfCard.getAbilities()); + } + + if (showRightSide) { + for (Ability ability: rightHalfCard.getAbilities()) { + if (isIgnoreTransformSpellAbility(ability)) { + continue; + } + allAbilites.add(ability); + } + } + + return allAbilites; + } + + @Override + public List getRules() { + // rules must show only main side (another side visible by toggle/transform button in GUI) + // card hints from both sides + return CardUtil.getCardRulesWithAdditionalInfo( + this, + this.getInnerAbilities(true, false), + this.getInnerAbilities(true, true) + ); + } + + @Override + public List getRules(Game game) { + // rules must show only main side (another side visible by toggle/transform button in GUI) + // card hints from both sides + return CardUtil.getCardRulesWithAdditionalInfo( + game, + this, + this.getInnerAbilities(game, true, false), + this.getInnerAbilities(game, true, true) + ); + } + + @Override + public boolean hasAbility(Ability ability, Game game) { + return super.hasAbility(ability, game); + } + + @Override + public ObjectColor getColor() { + return leftHalfCard.getColor(); + } + + @Override + public ObjectColor getColor(Game game) { + return leftHalfCard.getColor(game); + } + + @Override + public ObjectColor getFrameColor(Game game) { + return leftHalfCard.getFrameColor(game); + } + + @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 ManaCosts getManaCost() { + return leftHalfCard.getManaCost(); + } + + @Override + public int getManaValue() { + // 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 leftHalfCard.getManaValue(); + } + + @Override + public MageInt getPower() { + return leftHalfCard.getPower(); + } + + @Override + public MageInt getToughness() { + return leftHalfCard.getToughness(); + } +} diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalfImpl.java b/Mage/src/main/java/mage/cards/DoubleFacedCardHalf.java similarity index 67% rename from Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalfImpl.java rename to Mage/src/main/java/mage/cards/DoubleFacedCardHalf.java index 2521b78aee8..c6bd6a390c3 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalfImpl.java +++ b/Mage/src/main/java/mage/cards/DoubleFacedCardHalf.java @@ -1,25 +1,25 @@ package mage.cards; -import mage.MageInt; import mage.abilities.Ability; import mage.constants.*; import mage.game.Game; +import mage.game.events.ZoneChangeEvent; import java.util.Arrays; import java.util.List; import java.util.UUID; /** - * @author JayDi85 + * @author JayDi85 - originally from ModalDoubleFaceCardHalf */ -public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubleFacedCardHalf { +public abstract class DoubleFacedCardHalf extends CardImpl implements SubCard { - ModalDoubleFacedCard parentCard; + protected DoubleFacedCard parentCard; - public ModalDoubleFacedCardHalfImpl( + public DoubleFacedCardHalf( UUID ownerId, CardSetInfo setInfo, SuperType[] cardSuperTypes, CardType[] cardTypes, SubType[] cardSubTypes, - String costs, ModalDoubleFacedCard parentCard, SpellAbilityType spellAbilityType + String costs, DoubleFacedCard parentCard, SpellAbilityType spellAbilityType ) { super(ownerId, setInfo, cardTypes, costs, spellAbilityType); this.supertype.addAll(Arrays.asList(cardSuperTypes)); @@ -27,7 +27,7 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl this.parentCard = parentCard; } - protected ModalDoubleFacedCardHalfImpl(final ModalDoubleFacedCardHalfImpl card) { + protected DoubleFacedCardHalf(final DoubleFacedCardHalf card) { super(card); this.parentCard = card.parentCard; } @@ -49,6 +49,11 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl return parentCard.getCardNumber(); } + @Override + public boolean isTransformable() { + return getOtherSide().isPermanent(); + } + @Override public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List appliedEffects) { return parentCard.moveToZone(toZone, source, game, flag, appliedEffects); @@ -65,25 +70,23 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl } @Override - public ModalDoubleFacedCard getMainCard() { + public Card getMainCard() { return parentCard; } + @Override + public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) { + parentCard.updateZoneChangeCounter(game, event); + } + @Override public void setZone(Zone zone, Game game) { - // see ModalDoubleFacedCard.checkGoodZones for details + // see DoubleFacedCard.checkGoodZones for details game.setZone(parentCard.getId(), zone); game.setZone(this.getId(), zone); // find another side to sync - ModalDoubleFacedCardHalf otherSide; - if (!parentCard.getLeftHalfCard().getId().equals(this.getId())) { - otherSide = parentCard.getLeftHalfCard(); - } else if (!parentCard.getRightHalfCard().getId().equals(this.getId())) { - otherSide = parentCard.getRightHalfCard(); - } else { - throw new IllegalStateException("Wrong code usage: MDF halves must use different ids"); - } + Card otherSide = getOtherSide(); switch (zone) { case STACK: @@ -96,33 +99,39 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl break; } - ModalDoubleFacedCard.checkGoodZones(game, parentCard); + DoubleFacedCard.checkGoodZones(game, parentCard); + } + + public Card getOtherSide() { + Card otherSide; + if (!parentCard.getLeftHalfCard().getId().equals(this.getId())) { + otherSide = parentCard.getLeftHalfCard(); + } else if (!parentCard.getRightHalfCard().getId().equals(this.getId())) { + otherSide = parentCard.getRightHalfCard(); + } else { + throw new IllegalStateException("Wrong code usage: MDF halves must use different ids"); + } + return otherSide; + } + + public boolean isBackSide() { + if (parentCard.getLeftHalfCard().getId().equals(this.getId())) { + return false; + } else if (parentCard.getRightHalfCard().getId().equals(this.getId())) { + return true; + } else { + throw new IllegalStateException("Wrong code usage: MDF halves must use different ids"); + } } @Override - public ModalDoubleFacedCardHalfImpl copy() { - return new ModalDoubleFacedCardHalfImpl(this); - } - - @Override - public void setParentCard(ModalDoubleFacedCard card) { + public void setParentCard(DoubleFacedCard card) { this.parentCard = card; } @Override - public ModalDoubleFacedCard getParentCard() { - return this.parentCard; - } - - @Override - public void setPT(int power, int toughness) { - this.setPT(new MageInt(power), new MageInt(toughness)); - } - - @Override - public void setPT(MageInt power, MageInt toughness) { - this.power = power; - this.toughness = toughness; + public DoubleFacedCard getParentCard() { + return parentCard; } @Override diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java b/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java index eccfab302f2..cce1911e1bb 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java @@ -1,30 +1,15 @@ package mage.cards; -import mage.MageInt; -import mage.MageObject; -import mage.ObjectColor; import mage.abilities.*; -import mage.abilities.costs.mana.ManaCost; -import mage.abilities.costs.mana.ManaCosts; import mage.constants.*; -import mage.counters.Counter; -import mage.counters.Counters; import mage.game.Game; -import mage.game.GameState; -import mage.game.events.ZoneChangeEvent; -import mage.util.CardUtil; -import mage.util.SubTypes; -import java.util.List; import java.util.UUID; /** * @author JayDi85 */ -public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithHalves { - - protected Card leftHalfCard; // main card in all zone - protected Card rightHalfCard; // second side card, can be only in stack and battlefield zones +public abstract class ModalDoubleFacedCard extends DoubleFacedCard { public ModalDoubleFacedCard( UUID ownerId, CardSetInfo setInfo, @@ -48,184 +33,21 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH ) { super(ownerId, setInfo, typesLeft, costsLeft + costsRight, SpellAbilityType.MODAL); // main card name must be same as left side - leftHalfCard = new ModalDoubleFacedCardHalfImpl( + leftHalfCard = new ModalDoubleFacedCardHalf( this.getOwnerId(), setInfo.copy(), superTypesLeft, typesLeft, subTypesLeft, costsLeft, this, SpellAbilityType.MODAL_LEFT ); - rightHalfCard = new ModalDoubleFacedCardHalfImpl( + rightHalfCard = new ModalDoubleFacedCardHalf( this.getOwnerId(), new CardSetInfo(secondSideName, setInfo), superTypesRight, typesRight, subTypesRight, costsRight, this, SpellAbilityType.MODAL_RIGHT ); + this.secondSideCard = rightHalfCard; } - public ModalDoubleFacedCard(ModalDoubleFacedCard card) { + public ModalDoubleFacedCard(final ModalDoubleFacedCard card) { super(card); - // make sure all parts created and parent ref added - this.leftHalfCard = card.getLeftHalfCard().copy(); - ((ModalDoubleFacedCardHalf) leftHalfCard).setParentCard(this); - this.rightHalfCard = card.rightHalfCard.copy(); - ((ModalDoubleFacedCardHalf) rightHalfCard).setParentCard(this); - } - - public ModalDoubleFacedCardHalf getLeftHalfCard() { - return (ModalDoubleFacedCardHalf) leftHalfCard; - } - - public ModalDoubleFacedCardHalf getRightHalfCard() { - return (ModalDoubleFacedCardHalf) rightHalfCard; - } - - public void setParts(ModalDoubleFacedCardHalf leftHalfCard, ModalDoubleFacedCardHalf rightHalfCard) { - // for card copy only - set new parts - this.leftHalfCard = leftHalfCard; - leftHalfCard.setParentCard(this); - this.rightHalfCard = rightHalfCard; - rightHalfCard.setParentCard(this); - } - - @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); // TODO: must check copiedFrom and assign sides? (??? related to #8476 ???) - rightHalfCard.setCopy(isCopy, copiedFrom); - } - - private void setSideZones(Zone mainZone, Game game) { - switch (mainZone) { - case BATTLEFIELD: - case STACK: - throw new IllegalArgumentException("Wrong code usage: you must put to battlefield/stack only real side card (half), not main"); - default: - // must keep both sides in same zone cause xmage need access to cost reduction, spell - // and other abilities before put it to stack (in playable calcs) - game.setZone(leftHalfCard.getId(), mainZone); - game.setZone(rightHalfCard.getId(), mainZone); - break; - } - checkGoodZones(game, this); - } - - @Override - public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List appliedEffects) { - if (super.moveToZone(toZone, source, game, flag, appliedEffects)) { - Zone currentZone = game.getState().getZone(getId()); - setSideZones(currentZone, game); - return true; - } - return false; - } - - @Override - public void setZone(Zone zone, Game game) { - super.setZone(zone, game); - setSideZones(zone, game); - } - - @Override - public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List appliedEffects) { - if (super.moveToExile(exileId, name, source, game, appliedEffects)) { - Zone currentZone = game.getState().getZone(getId()); - setSideZones(currentZone, game); - return true; - } - return false; - } - - /** - * Runtime check for good zones and other MDF data - */ - public static void checkGoodZones(Game game, ModalDoubleFacedCard card) { - Card leftPart = card.getLeftHalfCard(); - Card rightPart = card.getRightHalfCard(); - - Zone zoneMain = game.getState().getZone(card.getId()); - Zone zoneLeft = game.getState().getZone(leftPart.getId()); - Zone zoneRight = game.getState().getZone(rightPart.getId()); - - // runtime check: - // * in battlefield and stack - card + one of the sides (another side in outside zone) - // * in other zones - card + both sides (need both sides due cost reductions, spell and other access before put to stack) - // - // 712.8a While a double-faced card is outside the game or in a zone other than the battlefield or stack, - // it has only the characteristics of its front face. - // - // 712.8f While a modal double-faced spell is on the stack or a modal double-faced permanent is on the battlefield, - // it has only the characteristics of the face that’s up. - Zone needZoneLeft; - Zone needZoneRight; - switch (zoneMain) { - case BATTLEFIELD: - case STACK: - if (zoneMain == zoneLeft) { - needZoneLeft = zoneMain; - needZoneRight = Zone.OUTSIDE; - } else if (zoneMain == zoneRight) { - needZoneLeft = Zone.OUTSIDE; - needZoneRight = zoneMain; - } else { - // impossible - needZoneLeft = zoneMain; - needZoneRight = Zone.OUTSIDE; - } - break; - default: - needZoneLeft = zoneMain; - needZoneRight = zoneMain; - break; - } - - if (zoneLeft != needZoneLeft || zoneRight != needZoneRight) { - throw new IllegalStateException("Wrong code usage: MDF card uses wrong zones - " + card - + "\r\n" + String.format("* main zone: %s", zoneMain) - + "\r\n" + String.format("* left side: need %s, actual %s", needZoneLeft, zoneLeft) - + "\r\n" + String.format("* right side: need %s, actual %s", needZoneRight, zoneRight)); - } - } - - @Override - public boolean removeFromZone(Game game, Zone fromZone, Ability source) { - // zone contains only one main card - return super.removeFromZone(game, fromZone, source); - } - - @Override - public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) { - if (isCopy()) { // same as meld cards - super.updateZoneChangeCounter(game, event); - return; - } - super.updateZoneChangeCounter(game, event); - leftHalfCard.updateZoneChangeCounter(game, event); - rightHalfCard.updateZoneChangeCounter(game, event); - } - - @Override - public Counters getCounters(Game game) { - return getCounters(game.getState()); - } - - @Override - public Counters getCounters(GameState state) { - return state.getCardState(leftHalfCard.getId()).getCounters(); - } - - @Override - public boolean addCounters(Counter counter, UUID playerAddingCounters, Ability source, Game game, List appliedEffects, boolean isEffect, int maxCounters) { - return leftHalfCard.addCounters(counter, playerAddingCounters, source, game, appliedEffects, isEffect, maxCounters); - } - - @Override - public void removeCounters(String counterName, int amount, Ability source, Game game) { - leftHalfCard.removeCounters(counterName, amount, source, game); } @Override @@ -236,201 +58,22 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH case MODAL_RIGHT: return this.rightHalfCard.cast(game, fromZone, ability, controllerId); default: - if (this.leftHalfCard.getSpellAbility() != null) { - this.leftHalfCard.getSpellAbility().setControllerId(controllerId); - } - if (this.rightHalfCard.getSpellAbility() != null) { - this.rightHalfCard.getSpellAbility().setControllerId(controllerId); - } return super.cast(game, fromZone, ability, controllerId); } } @Override - public List getSuperType(Game game) { - // CardImpl's constructor can call some code on init, so you must check left/right before - // it's a bad workaround - return leftHalfCard != null ? leftHalfCard.getSuperType(game) : supertype; + public boolean isTransformable() { + return this.getLeftHalfCard().isPermanent() && this.getRightHalfCard().isPermanent(); } @Override - public List getCardType(Game game) { - // CardImpl's constructor can call some code on init, so you must check left/right before - // it's a bad workaround - return leftHalfCard != null ? leftHalfCard.getCardType(game) : cardType; + public ModalDoubleFacedCardHalf getLeftHalfCard() { + return (ModalDoubleFacedCardHalf) leftHalfCard; } @Override - public SubTypes getSubtype() { - // rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face. - // CardImpl's constructor can call some code on init, so you must check left/right before - return leftHalfCard != null ? leftHalfCard.getSubtype() : subtype; - } - - @Override - public SubTypes getSubtype(Game game) { - // rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face. - // CardImpl's constructor can call some code on init, so you must check left/right before - return leftHalfCard != null ? leftHalfCard.getSubtype(game) : subtype; - } - - @Override - public boolean hasSubtype(SubType subtype, Game game) { - return leftHalfCard.hasSubtype(subtype, game); - } - - @Override - public Abilities getAbilities() { - return getInnerAbilities(true, true); - } - - @Override - public Abilities getInitAbilities() { - // must init only parent related abilities, spell card must be init separately - return getInnerAbilities(false, false); - } - - public Abilities getSharedAbilities(Game game) { - // no shared abilities for mdf cards (e.g. must be left or right only) - return new AbilitiesImpl<>(); - } - - @Override - public Abilities getAbilities(Game game) { - return getInnerAbilities(game, true, true); - } - - private boolean isIgnoreDefaultAbility(Ability ability) { - // ignore default play/spell ability from main card (only halfes are actual) - // default abilities added on card creation from card type and can't be skipped - - // skip cast spell - if (ability instanceof SpellAbility && ((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.MODAL) { - return true; - } - - // skip play land - return ability instanceof PlayLandAbility; - } - - private Abilities getInnerAbilities(Game game, boolean showLeftSide, boolean showRightSide) { - Abilities allAbilites = new AbilitiesImpl<>(); - - for (Ability ability : super.getAbilities(game)) { - if (isIgnoreDefaultAbility(ability)) { - continue; - } - allAbilites.add(ability); - } - - if (showLeftSide) { - allAbilites.addAll(leftHalfCard.getAbilities(game)); - } - if (showRightSide) { - allAbilites.addAll(rightHalfCard.getAbilities(game)); - } - - return allAbilites; - } - - private Abilities getInnerAbilities(boolean showLeftSide, boolean showRightSide) { - Abilities allAbilites = new AbilitiesImpl<>(); - - for (Ability ability : super.getAbilities()) { - if (isIgnoreDefaultAbility(ability)) { - continue; - } - allAbilites.add(ability); - } - - if (showLeftSide) { - allAbilites.addAll(leftHalfCard.getAbilities()); - } - - if (showRightSide) { - allAbilites.addAll(rightHalfCard.getAbilities()); - } - - return allAbilites; - } - - @Override - public List getRules() { - // rules must show only main side (another side visible by toggle/transform button in GUI) - // card hints from both sides - return CardUtil.getCardRulesWithAdditionalInfo( - this, - this.getInnerAbilities(true, false), - this.getInnerAbilities(true, true) - ); - } - - @Override - public List getRules(Game game) { - // rules must show only main side (another side visible by toggle/transform button in GUI) - // card hints from both sides - return CardUtil.getCardRulesWithAdditionalInfo( - game, - this, - this.getInnerAbilities(game, true, false), - this.getInnerAbilities(game, true, true) - ); - } - - @Override - public boolean hasAbility(Ability ability, Game game) { - return super.hasAbility(ability, game); - } - - @Override - public ObjectColor getColor() { - return leftHalfCard.getColor(); - } - - @Override - public ObjectColor getColor(Game game) { - return leftHalfCard.getColor(game); - } - - @Override - public ObjectColor getFrameColor(Game game) { - return leftHalfCard.getFrameColor(game); - } - - @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 ManaCosts getManaCost() { - return leftHalfCard.getManaCost(); - } - - @Override - public int getManaValue() { - // 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 leftHalfCard.getManaValue(); - } - - @Override - public MageInt getPower() { - return leftHalfCard.getPower(); - } - - @Override - public MageInt getToughness() { - return leftHalfCard.getToughness(); + public ModalDoubleFacedCardHalf getRightHalfCard() { + return (ModalDoubleFacedCardHalf) rightHalfCard; } } diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java b/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java index 78cba6bd606..0626b54807b 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java @@ -1,16 +1,34 @@ package mage.cards; -import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.constants.SubType; +import mage.constants.SuperType; -/** - * @author JayDi85 - */ -public interface ModalDoubleFacedCardHalf extends SubCard { +import java.util.UUID; + +public class ModalDoubleFacedCardHalf extends DoubleFacedCardHalf { + + public ModalDoubleFacedCardHalf( + UUID ownerId, CardSetInfo setInfo, + SuperType[] cardSuperTypes, CardType[] cardTypes, SubType[] cardSubTypes, + String costs, ModalDoubleFacedCard parentCard, SpellAbilityType spellAbilityType + ) { + super(ownerId, setInfo, cardSuperTypes, cardTypes, cardSubTypes, costs, parentCard, spellAbilityType); + } + + protected ModalDoubleFacedCardHalf(final ModalDoubleFacedCardHalf card) { + super(card); + this.parentCard = card.parentCard; + } @Override - ModalDoubleFacedCardHalf copy(); + public ModalDoubleFacedCardHalf copy() { + return new ModalDoubleFacedCardHalf(this); + } - void setPT(int power, int toughness); - - void setPT(MageInt power, MageInt toughness); + @Override + public ModalDoubleFacedCard getParentCard() { + return (ModalDoubleFacedCard) parentCard; + } } diff --git a/Mage/src/main/java/mage/cards/RoomCard.java b/Mage/src/main/java/mage/cards/RoomCard.java index 2b44bcad48e..8685b9c84f1 100644 --- a/Mage/src/main/java/mage/cards/RoomCard.java +++ b/Mage/src/main/java/mage/cards/RoomCard.java @@ -1,27 +1,20 @@ package mage.cards; -import java.util.UUID; - +import mage.ObjectColor; import mage.abilities.Abilities; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.common.RoomUnlockAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.UnlockThisDoorTriggeredAbility; -import mage.abilities.condition.common.RoomHalfLockedCondition; -import mage.abilities.costs.mana.ManaCosts; -import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.common.RoomAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.RoomCharacteristicsEffect; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SpellAbilityType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; -import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; + +import java.util.UUID; /** * @author oscscull @@ -43,6 +36,13 @@ public abstract class RoomCard extends SplitCard { this.getOwnerId(), new CardSetInfo(names[1], setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), types, costsRight, this, SpellAbilityType.SPLIT_RIGHT); + + // Add the one-shot effect to unlock a door on cast -> ETB + Ability entersAbility = new EntersBattlefieldAbility(new RoomEnterUnlockEffect()); + entersAbility.setRuleVisible(false); + this.addAbility(entersAbility); + + this.addAbility(new RoomAbility()); } protected RoomCard(RoomCard card) { @@ -58,56 +58,6 @@ public abstract class RoomCard extends SplitCard { this.lastCastHalf = lastCastHalf; } - protected void addRoomAbilities(Ability leftAbility, Ability rightAbility) { - getLeftHalfCard().addAbility(leftAbility); - getRightHalfCard().addAbility(rightAbility); - this.addAbility(leftAbility.copy()); - this.addAbility(rightAbility.copy()); - - // Add the one-shot effect to unlock a door on cast -> ETB - Ability entersAbility = new EntersBattlefieldAbility(new RoomEnterUnlockEffect()); - entersAbility.setRuleVisible(false); - this.addAbility(entersAbility); - - // Remove locked door abilities - keeping unlock triggers (or they won't trigger - // when unlocked) - if (leftAbility != null && !(leftAbility instanceof UnlockThisDoorTriggeredAbility)) { - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( - new LoseAbilitySourceEffect(leftAbility, Duration.WhileOnBattlefield), - RoomHalfLockedCondition.LEFT, "")).setRuleVisible(false); - this.addAbility(ability); - } - - if (rightAbility != null && !(rightAbility instanceof UnlockThisDoorTriggeredAbility)) { - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( - new LoseAbilitySourceEffect(rightAbility, Duration.WhileOnBattlefield), - RoomHalfLockedCondition.RIGHT, "")).setRuleVisible(false); - this.addAbility(ability); - } - - // Add the Special Action to unlock doors. - // These will ONLY be active if the corresponding half is LOCKED! - if (leftAbility != null) { - ManaCosts leftHalfManaCost = null; - if (this.getLeftHalfCard() != null && this.getLeftHalfCard().getSpellAbility() != null) { - leftHalfManaCost = this.getLeftHalfCard().getSpellAbility().getManaCosts(); - } - RoomUnlockAbility leftUnlockAbility = new RoomUnlockAbility(leftHalfManaCost, true); - this.addAbility(leftUnlockAbility.setRuleAtTheTop(true)); - } - - if (rightAbility != null) { - ManaCosts rightHalfManaCost = null; - if (this.getRightHalfCard() != null && this.getRightHalfCard().getSpellAbility() != null) { - rightHalfManaCost = this.getRightHalfCard().getSpellAbility().getManaCosts(); - } - RoomUnlockAbility rightUnlockAbility = new RoomUnlockAbility(rightHalfManaCost, false); - this.addAbility(rightUnlockAbility.setRuleAtTheTop(true)); - } - - this.addAbility(new RoomAbility()); - } - @Override public Abilities getAbilities() { return this.abilities; @@ -131,6 +81,41 @@ public abstract class RoomCard extends SplitCard { game.setZone(getLeftHalfCard().getId(), zone); game.setZone(getRightHalfCard().getId(), zone); } + + public static void setRoomCharacteristics(Permanent permanent, Game game) { + if (!(permanent.getMainCard() instanceof RoomCard)) { + return; + } + setRoomCharacteristics(permanent, (RoomCard) permanent.getMainCard(), game, permanent.isLeftDoorUnlocked(), permanent.isRightDoorUnlocked()); + } + + // Static method for setting room characteristics on permanents + public static void setRoomCharacteristics(Permanent permanent, RoomCard roomCard, Game game, boolean isLeftUnlocked, boolean isRightUnlocked) { + permanent.setName(roomCard.name); + + permanent.setManaCost(roomCard.getManaCost()); + + // Set color indicator based on unlocked halves + ObjectColor newColor = new ObjectColor(); + if (isLeftUnlocked && roomCard.getLeftHalfCard() != null) { + newColor.addColor(roomCard.getLeftHalfCard().getColor()); + } + if (isRightUnlocked && roomCard.getRightHalfCard() != null) { + newColor.addColor(roomCard.getRightHalfCard().getColor()); + } + permanent.getColor().setColor(roomCard.getColor()); + + // Get abilities from each half + Abilities leftAbilities = roomCard.getLeftHalfCard().getAbilities(); + for (Ability ability : leftAbilities) { + permanent.addAbility(ability, roomCard.getLeftHalfCard().getId(), game, true); + } + + Abilities rightAbilities = roomCard.getRightHalfCard().getAbilities(); + for (Ability ability : rightAbilities) { + permanent.addAbility(ability, roomCard.getRightHalfCard().getId(), game,true); + } + } } class RoomEnterUnlockEffect extends OneShotEffect { @@ -189,27 +174,3 @@ class RoomEnterUnlockEffect extends OneShotEffect { } } -// For the overall Room card flavor text and mana value effect. -class RoomAbility extends SimpleStaticAbility { - public RoomAbility() { - super(Zone.ALL, null); - this.setRuleVisible(true); - this.setRuleAtTheTop(true); - this.addEffect(new RoomCharacteristicsEffect()); - } - - protected RoomAbility(final RoomAbility ability) { - super(ability); - } - - @Override - public String getRule() { - return "(You may cast either half. That door unlocks on the battlefield. " + - "As a sorcery, you may pay the mana cost of a locked door to unlock it.)"; - } - - @Override - public RoomAbility copy() { - return new RoomAbility(this); - } -} \ No newline at end of file diff --git a/Mage/src/main/java/mage/cards/TransformingDoubleFacedCard.java b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCard.java new file mode 100644 index 00000000000..aa56e519844 --- /dev/null +++ b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCard.java @@ -0,0 +1,66 @@ +package mage.cards; + +import mage.abilities.SpellAbility; +import mage.constants.*; +import mage.game.Game; + +import java.util.UUID; + +public abstract class TransformingDoubleFacedCard extends DoubleFacedCard { + + public TransformingDoubleFacedCard( + UUID ownerId, CardSetInfo setInfo, + CardType[] typesLeft, SubType[] subTypesLeft, String costsLeft, + String secondSideName, + CardType[] typesRight, SubType[] subTypesRight, String colorRight + ) { + this( + ownerId, setInfo, + new SuperType[]{}, typesLeft, subTypesLeft, costsLeft, + secondSideName, + new SuperType[]{}, typesRight, subTypesRight, colorRight + ); + } + + public TransformingDoubleFacedCard( + UUID ownerId, CardSetInfo setInfo, + SuperType[] superTypesLeft, CardType[] typesLeft, SubType[] subTypesLeft, String costsLeft, + String secondSideName, + SuperType[] superTypesRight, CardType[] typesRight, SubType[] subTypesRight, String colorRight + ) { + super(ownerId, setInfo, typesLeft, costsLeft, SpellAbilityType.TRANSFORMED); + // main card name must be same as left side + leftHalfCard = new TransformingDoubleFacedCardHalf( + this.getOwnerId(), setInfo.copy(), + superTypesLeft, typesLeft, subTypesLeft, costsLeft, + this, SpellAbilityType.TRANSFORMED_LEFT + ); + rightHalfCard = new TransformingDoubleFacedCardHalf( + this.getOwnerId(), new CardSetInfo(secondSideName, setInfo), + superTypesRight, typesRight, subTypesRight, colorRight, this + ); + this.secondSideCard = rightHalfCard; + } + + public TransformingDoubleFacedCard(final TransformingDoubleFacedCard card) { + super(card); + } + + @Override + public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { + if (ability.getSpellAbilityType() == SpellAbilityType.BASE) { + return this.leftHalfCard.cast(game, fromZone, ability, controllerId); + } + return super.cast(game, fromZone, ability, controllerId); + } + + @Override + public TransformingDoubleFacedCardHalf getLeftHalfCard() { + return (TransformingDoubleFacedCardHalf) leftHalfCard; + } + + @Override + public TransformingDoubleFacedCardHalf getRightHalfCard() { + return (TransformingDoubleFacedCardHalf) rightHalfCard; + } +} diff --git a/Mage/src/main/java/mage/cards/TransformingDoubleFacedCardHalf.java b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCardHalf.java new file mode 100644 index 00000000000..f82a910d852 --- /dev/null +++ b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCardHalf.java @@ -0,0 +1,49 @@ +package mage.cards; + +import mage.ObjectColor; +import mage.abilities.SpellAbility; +import mage.constants.*; +import mage.game.Game; + +import java.util.UUID; + +public class TransformingDoubleFacedCardHalf extends DoubleFacedCardHalf { + + public TransformingDoubleFacedCardHalf( + UUID ownerId, CardSetInfo setInfo, + SuperType[] cardSuperTypes, CardType[] cardTypes, SubType[] cardSubTypes, + String costs, TransformingDoubleFacedCard parentCard, SpellAbilityType spellAbilityType + ) { + super(ownerId, setInfo, cardSuperTypes, cardTypes, cardSubTypes, costs, parentCard, spellAbilityType); + } + + protected TransformingDoubleFacedCardHalf(final TransformingDoubleFacedCardHalf card) { + super(card); + this.parentCard = card.parentCard; + } + + public TransformingDoubleFacedCardHalf( + UUID ownerId, CardSetInfo setInfo, + SuperType[] superTypesRight, CardType[] typesRight, SubType[] subTypesRight, String colorRight, TransformingDoubleFacedCard parentCard) { + super(ownerId, setInfo, superTypesRight, typesRight, subTypesRight, "", parentCard, SpellAbilityType.TRANSFORMED_RIGHT); + this.getColor().setColor(new ObjectColor(colorRight)); + } + + @Override + public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { + if (ability.getSpellAbilityCastMode() == SpellAbilityCastMode.DISTURB && !isBackSide()) { + return getOtherSide().cast(game, fromZone, ability, controllerId); + } + return super.cast(game, fromZone, ability, controllerId); + } + + @Override + public TransformingDoubleFacedCardHalf copy() { + return new TransformingDoubleFacedCardHalf(this); + } + + @Override + public TransformingDoubleFacedCard getParentCard() { + return (TransformingDoubleFacedCard) parentCard; + } +} diff --git a/Mage/src/main/java/mage/cards/mock/MockCard.java b/Mage/src/main/java/mage/cards/mock/MockCard.java index 6d768ef8b67..04e28b30a09 100644 --- a/Mage/src/main/java/mage/cards/mock/MockCard.java +++ b/Mage/src/main/java/mage/cards/mock/MockCard.java @@ -5,7 +5,7 @@ import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.cards.CardImpl; -import mage.cards.ModalDoubleFacedCard; +import mage.cards.DoubleFacedCard; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.util.CardUtil; @@ -35,7 +35,7 @@ public class MockCard extends CardImpl implements MockableCard { protected List manaCostRightStr; protected List manaCostStr; protected String spellOptionName; // adventure/omen spell name - protected boolean isModalDoubleFacedCard; + protected boolean isDoubleFacedCard; protected int manaValue; public MockCard(CardInfo card) { @@ -67,7 +67,7 @@ public class MockCard extends CardImpl implements MockableCard { this.nightCard = card.isNightCard(); - if (card.getSecondSideName() != null && !card.getSecondSideName().isEmpty()) { + if (card.getSecondSideName() != null && !card.getSecondSideName().isEmpty() && !card.isDoubleFacedCard()) { this.secondSideCard = new MockCard(CardRepository.instance.findCardWithPreferredSetAndNumber(card.getSecondSideName(), card.getSetCode(), card.getCardNumber())); } @@ -75,11 +75,11 @@ public class MockCard extends CardImpl implements MockableCard { this.spellOptionName = card.getSpellOptionCardName(); } - if (card.isModalDoubleFacedCard()) { - ModalDoubleFacedCard mdfCard = (ModalDoubleFacedCard) card.createCard(); + if (card.isDoubleFacedCard()) { + DoubleFacedCard mdfCard = (DoubleFacedCard) card.createCard(); CardInfo mdfSecondSide = new CardInfo(mdfCard.getRightHalfCard()); this.secondSideCard = new MockCard(mdfSecondSide); - this.isModalDoubleFacedCard = true; + this.isDoubleFacedCard = true; } this.startingLoyalty = CardUtil.convertLoyaltyOrDefense(card.getStartingLoyalty()); @@ -102,7 +102,7 @@ public class MockCard extends CardImpl implements MockableCard { this.manaCostRightStr = new ArrayList<>(card.manaCostRightStr); this.manaCostStr = new ArrayList<>(card.manaCostStr); this.spellOptionName = card.spellOptionName; - this.isModalDoubleFacedCard = card.isModalDoubleFacedCard; + this.isDoubleFacedCard = card.isDoubleFacedCard; this.manaValue = card.manaValue; } @@ -157,7 +157,7 @@ public class MockCard extends CardImpl implements MockableCard { if (spellOptionName != null) { return getName() + CARD_WITH_SPELL_OPTION_NAME_SEPARATOR + spellOptionName; - } else if (isModalDoubleFacedCard) { + } else if (isDoubleFacedCard) { return getName() + MODAL_DOUBLE_FACES_NAME_SEPARATOR + this.getSecondCardFace().getName(); } else { return getName(); @@ -181,6 +181,6 @@ public class MockCard extends CardImpl implements MockableCard { @Override public boolean isTransformable() { // must enable toggle mode in deck editor (switch between card sides); - return super.isTransformable() || this.isModalDoubleFacedCard || this.secondSideCard != null; + return super.isTransformable() || this.isDoubleFacedCard || this.secondSideCard != null; } } diff --git a/Mage/src/main/java/mage/cards/repository/CardInfo.java b/Mage/src/main/java/mage/cards/repository/CardInfo.java index 622df93e12a..3db32d2fdad 100644 --- a/Mage/src/main/java/mage/cards/repository/CardInfo.java +++ b/Mage/src/main/java/mage/cards/repository/CardInfo.java @@ -112,9 +112,9 @@ public class CardInfo { @DatabaseField protected String spellOptionCardName; @DatabaseField - protected boolean modalDoubleFacedCard; + protected boolean doubleFacedCard; @DatabaseField - protected String modalDoubleFacedSecondSideName; + protected String doubleFacedSecondSideName; @DatabaseField protected String meldsToCardName; @DatabaseField @@ -164,9 +164,9 @@ public class CardInfo { this.spellOptionCardName = ((CardWithSpellOption) card).getSpellCard().getName(); } - if (card instanceof ModalDoubleFacedCard) { - this.modalDoubleFacedCard = true; - this.modalDoubleFacedSecondSideName = ((ModalDoubleFacedCard) card).getRightHalfCard().getName(); + if (card instanceof DoubleFacedCard) { + this.doubleFacedCard = true; + this.doubleFacedSecondSideName = ((DoubleFacedCard) card).getRightHalfCard().getName(); } if (card.getFrameStyle() != null) { @@ -485,12 +485,12 @@ public class CardInfo { return spellOptionCardName; } - public boolean isModalDoubleFacedCard() { - return modalDoubleFacedCard; + public boolean isDoubleFacedCard() { + return doubleFacedCard; } - public String getModalDoubleFacedSecondSideName() { - return modalDoubleFacedSecondSideName; + public String getDoubleFacedSecondSideName() { + return doubleFacedSecondSideName; } @Override diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index fd3fab74dfc..37115721b84 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -128,7 +128,7 @@ public enum CardRepository { } private void addNewNames(CardInfo card, Set namesList) { - // require before call: qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName"...); + // require before call: qb.distinct().selectColumns("name", "doubleFacedSecondSideName"...); // normal names int result = card.getName().indexOf(" // "); @@ -143,8 +143,8 @@ public enum CardRepository { if (card.getSecondSideName() != null && !card.getSecondSideName().isEmpty()) { namesList.add(card.getSecondSideName()); } - if (card.getModalDoubleFacedSecondSideName() != null && !card.getModalDoubleFacedSecondSideName().isEmpty()) { - namesList.add(card.getModalDoubleFacedSecondSideName()); + if (card.getDoubleFacedSecondSideName() != null && !card.getDoubleFacedSecondSideName().isEmpty()) { + namesList.add(card.getDoubleFacedSecondSideName()); } if (card.getFlipCardName() != null && !card.getFlipCardName().isEmpty()) { namesList.add(card.getFlipCardName()); @@ -168,7 +168,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); List results = cardsDao.query(qb.prepare()); for (CardInfo card : results) { addNewNames(card, names); @@ -187,7 +187,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); qb.where().not().like("types", new SelectArg('%' + CardType.LAND.name() + '%')); List results = cardsDao.query(qb.prepare()); for (CardInfo card : results) { @@ -207,7 +207,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); Where where = qb.where(); where.and( where.not().like("supertypes", '%' + SuperType.BASIC.name() + '%'), @@ -231,7 +231,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); qb.where().not().like("supertypes", new SelectArg('%' + SuperType.BASIC.name() + '%')); List results = cardsDao.query(qb.prepare()); for (CardInfo card : results) { @@ -251,7 +251,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); qb.where().like("types", new SelectArg('%' + CardType.CREATURE.name() + '%')); List results = cardsDao.query(qb.prepare()); for (CardInfo card : results) { @@ -271,7 +271,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); qb.where().like("types", new SelectArg('%' + CardType.ARTIFACT.name() + '%')); List results = cardsDao.query(qb.prepare()); for (CardInfo card : results) { @@ -291,7 +291,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); Where where = qb.where(); where.and( where.not().like("types", '%' + CardType.CREATURE.name() + '%'), @@ -315,7 +315,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); Where where = qb.where(); where.and( where.not().like("types", '%' + CardType.ARTIFACT.name() + '%'), @@ -541,7 +541,7 @@ public enum CardRepository { .eq("flipCardName", new SelectArg(name)).or() .eq("secondSideName", new SelectArg(name)).or() .eq("spellOptionCardName", new SelectArg(name)).or() - .eq("modalDoubleFacedSecondSideName", new SelectArg(name)); + .eq("doubleFacedSecondSideName", new SelectArg(name)); results = cardsDao.query(queryBuilder.prepare()); } else { // Check that a full card was found and not a SplitCardHalf diff --git a/Mage/src/main/java/mage/constants/PutCards.java b/Mage/src/main/java/mage/constants/PutCards.java index 59ffc721e5f..2d93243ff52 100644 --- a/Mage/src/main/java/mage/constants/PutCards.java +++ b/Mage/src/main/java/mage/constants/PutCards.java @@ -2,9 +2,7 @@ package mage.constants; import mage.abilities.Ability; import mage.abilities.keyword.TransformAbility; -import mage.cards.Card; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -92,6 +90,9 @@ public enum PutCards { case SHUFFLE: return player.shuffleCardsToLibrary(card, game, source); case BATTLEFIELD_TRANSFORMED: + if (card instanceof TransformingDoubleFacedCard) { + card = ((TransformingDoubleFacedCard) card).getRightHalfCard(); + } game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId(), Boolean.TRUE); case BATTLEFIELD: case EXILED: diff --git a/Mage/src/main/java/mage/constants/SpellAbilityType.java b/Mage/src/main/java/mage/constants/SpellAbilityType.java index fac7a218aef..a0da5bcd762 100644 --- a/Mage/src/main/java/mage/constants/SpellAbilityType.java +++ b/Mage/src/main/java/mage/constants/SpellAbilityType.java @@ -11,6 +11,9 @@ public enum SpellAbilityType { SPLIT_FUSED("Split SpellAbility"), SPLIT_LEFT("LeftSplit SpellAbility"), SPLIT_RIGHT("RightSplit SpellAbility"), + TRANSFORMED("Transformed SpellAbility"), + TRANSFORMED_LEFT("TransformFront SpellAbility"), + TRANSFORMED_RIGHT("TransformBack SpellAbility"), MODAL("Modal SpellAbility"), // used for modal double faces cards MODAL_LEFT("LeftModal SpellAbility"), MODAL_RIGHT("RightModal SpellAbility"), diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 82d0ad5ce63..ff45386549a 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -56,6 +56,7 @@ import mage.game.mulligan.Mulligan; import mage.game.permanent.Battlefield; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; +import mage.game.permanent.PermanentToken; import mage.game.stack.Spell; import mage.game.stack.SpellStack; import mage.game.stack.StackAbility; @@ -129,8 +130,6 @@ public abstract class GameImpl implements Game { // For checking "becomes the target" triggers accurately. Cleared on short living LKI reset protected Map>> targetedMap = new HashMap<>(); - // Permanents entering the Battlefield while handling replacement effects before they are added to the battlefield - protected Map permanentsEntering = new HashMap<>(); // used to set the counters a permanent adds the battlefield (if no replacement effect is used e.g. Persist) protected Map enterWithCounters = new HashMap<>(); @@ -214,7 +213,6 @@ public abstract class GameImpl implements Game { this.lkiShortLiving = CardUtil.deepCopyObject(game.lkiShortLiving); this.targetedMap = CardUtil.deepCopyObject(game.targetedMap); - this.permanentsEntering = CardUtil.deepCopyObject(game.permanentsEntering); this.enterWithCounters = CardUtil.deepCopyObject(game.enterWithCounters); this.state = game.state.copy(); @@ -341,13 +339,13 @@ public abstract class GameImpl implements Game { Card rightCard = ((SplitCard) card).getRightHalfCard(); rightCard.setOwnerId(ownerId); addCardToState(rightCard); - } else if (card instanceof ModalDoubleFacedCard) { + } else if (card instanceof DoubleFacedCard) { // left - Card leftCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); + Card leftCard = ((DoubleFacedCard) card).getLeftHalfCard(); leftCard.setOwnerId(ownerId); addCardToState(leftCard); // right - Card rightCard = ((ModalDoubleFacedCard) card).getRightHalfCard(); + Card rightCard = ((DoubleFacedCard) card).getRightHalfCard(); rightCard.setOwnerId(ownerId); addCardToState(rightCard); } else if (card instanceof CardWithSpellOption) { @@ -764,12 +762,12 @@ public abstract class GameImpl implements Game { @Override public Permanent getPermanentEntering(UUID permanentId) { - return permanentsEntering.get(permanentId); + return state.getBattlefield().getPermanentsEntering().get(permanentId); } @Override public Map getPermanentsEntering() { - return permanentsEntering; + return state.getBattlefield().getPermanentsEntering(); } @Override @@ -2109,6 +2107,7 @@ public abstract class GameImpl implements Game { newBluePrint = copyFromPermanent.copy(); // reset to original characteristics + newBluePrint.resetLockedStatus(); // reset locked status so room characteristics are correct newBluePrint.reset(this); // workaround to find real copyable characteristics of transformed/facedown/etc permanents @@ -2118,7 +2117,9 @@ public abstract class GameImpl implements Game { BecomesFaceDownCreatureEffect.makeFaceDownObject(this, null, newBluePrint, faceDownType, null); } newBluePrint.assignNewId(); - if (copyFromPermanent.isTransformed()) { + // TODO: should be able to remove after tdfc rework + if (copyFromPermanent.isTransformed() && (copyFromPermanent instanceof PermanentToken || ((copyFromPermanent instanceof PermanentCard) && + !(((PermanentCard) copyFromPermanent).getCard() instanceof DoubleFacedCardHalf)))) { TransformAbility.transformPermanent(newBluePrint, this, source); } if (copyFromPermanent.isPrototyped()) { @@ -3818,7 +3819,7 @@ public abstract class GameImpl implements Game { loadCards(ownerId, hand); loadCards(ownerId, battlefield .stream() - .map(PutToBattlefieldInfo::getCard) + .map(PutToBattlefieldInfo::getMainCard) .collect(Collectors.toList()) ); loadCards(ownerId, graveyard); diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java index c9963203f9e..86b38e24117 100644 --- a/Mage/src/main/java/mage/game/GameState.java +++ b/Mage/src/main/java/mage/game/GameState.java @@ -670,9 +670,9 @@ public class GameState implements Serializable, Copyable { for (Player player : players.values()) { player.reset(); } + this.reset(); battlefield.reset(game); combat.reset(game); - this.reset(); effects.apply(game); combat.checkForRemoveFromCombat(game); } @@ -1627,19 +1627,19 @@ public class GameState implements Serializable, Copyable { copiedParts.add(rightCopied); // sync parts ((SplitCard) copiedCard).setParts(leftCopied, rightCopied); - } else if (copiedCard instanceof ModalDoubleFacedCard) { + } else if (copiedCard instanceof DoubleFacedCard) { // left - ModalDoubleFacedCardHalf leftOriginal = ((ModalDoubleFacedCard) copiedCard).getLeftHalfCard(); - ModalDoubleFacedCardHalf leftCopied = leftOriginal.copy(); + DoubleFacedCardHalf leftOriginal = ((DoubleFacedCard) copiedCard).getLeftHalfCard(); + DoubleFacedCardHalf leftCopied = (DoubleFacedCardHalf) leftOriginal.copy(); prepareCardForCopy(leftOriginal, leftCopied, newController); copiedParts.add(leftCopied); // right - ModalDoubleFacedCardHalf rightOriginal = ((ModalDoubleFacedCard) copiedCard).getRightHalfCard(); - ModalDoubleFacedCardHalf rightCopied = rightOriginal.copy(); + DoubleFacedCardHalf rightOriginal = ((DoubleFacedCard) copiedCard).getRightHalfCard(); + DoubleFacedCardHalf rightCopied = (DoubleFacedCardHalf) rightOriginal.copy(); prepareCardForCopy(rightOriginal, rightCopied, newController); copiedParts.add(rightCopied); // sync parts - ((ModalDoubleFacedCard) copiedCard).setParts(leftCopied, rightCopied); + ((DoubleFacedCard) copiedCard).setParts(leftCopied, rightCopied); } else if (copiedCard instanceof CardWithSpellOption) { // right SpellOptionCard rightOriginal = ((CardWithSpellOption) copiedCard).getSpellCard(); diff --git a/Mage/src/main/java/mage/game/PutToBattlefieldInfo.java b/Mage/src/main/java/mage/game/PutToBattlefieldInfo.java index 404cde602e6..912157935a8 100644 --- a/Mage/src/main/java/mage/game/PutToBattlefieldInfo.java +++ b/Mage/src/main/java/mage/game/PutToBattlefieldInfo.java @@ -21,6 +21,10 @@ public class PutToBattlefieldInfo { return card; } + public Card getMainCard() { + return card.getMainCard(); + } + public boolean isTapped() { return tapped; } diff --git a/Mage/src/main/java/mage/game/ZonesHandler.java b/Mage/src/main/java/mage/game/ZonesHandler.java index 9a1c26c8154..ad215f21baf 100644 --- a/Mage/src/main/java/mage/game/ZonesHandler.java +++ b/Mage/src/main/java/mage/game/ZonesHandler.java @@ -89,21 +89,31 @@ public final class ZonesHandler { ZoneChangeInfo info = itr.next(); if (info.event.getToZone().equals(Zone.BATTLEFIELD)) { Card card = game.getCard(info.event.getTargetId()); - if (card instanceof ModalDoubleFacedCard || card instanceof ModalDoubleFacedCardHalf) { + if (card instanceof DoubleFacedCard || card instanceof DoubleFacedCardHalf) { boolean forceToMainSide = false; + // TODO: move transform key or have some other identifier after tdfc rework + Boolean enterTransformed = (Boolean) game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()); + if (enterTransformed == null) { + enterTransformed = false; + } // if effect put half mdf card to battlefield then it must be the main side only (example: return targeted half card to battle) - if (card instanceof ModalDoubleFacedCardHalf && !source.getAbilityType().isPlayCardAbility()) { + if (card instanceof DoubleFacedCardHalf && !source.getAbilityType().isPlayCardAbility() && !enterTransformed) { forceToMainSide = true; } // if effect put mdf card to battlefield then it must be main side only - if (card instanceof ModalDoubleFacedCard) { + if (card instanceof DoubleFacedCard) { forceToMainSide = true; } if (forceToMainSide) { - info.event.setTargetId(((ModalDoubleFacedCard) card.getMainCard()).getLeftHalfCard().getId()); + info.event.setTargetId(((DoubleFacedCard) card.getMainCard()).getLeftHalfCard().getId()); + } + + // if left half is being moved, but entering transformed, change to transformed side + if (enterTransformed && card instanceof DoubleFacedCardHalf && !((DoubleFacedCardHalf) card).isBackSide()) { + info.event.setTargetId(((DoubleFacedCardHalf) card).getOtherSide().getId()); } } } @@ -154,10 +164,10 @@ public final class ZonesHandler { // meld/group cards must be independent (use can choose order) cardsToMove = ((MeldCard) targetCard).getHalves(); cardsToUpdate.get(toZone).addAll(cardsToMove); - } else if (targetCard instanceof ModalDoubleFacedCard - || targetCard instanceof ModalDoubleFacedCardHalf) { + } else if (targetCard instanceof DoubleFacedCard + || targetCard instanceof DoubleFacedCardHalf) { // mdf cards must be moved as single object, but each half must be updated separately - ModalDoubleFacedCard mdfCard = (ModalDoubleFacedCard) targetCard.getMainCard(); + DoubleFacedCard mdfCard = (DoubleFacedCard) targetCard.getMainCard(); cardsToMove = new CardsImpl(mdfCard); cardsToUpdate.get(toZone).add(mdfCard); // example: cast left side @@ -296,7 +306,7 @@ public final class ZonesHandler { } else { game.setZone(event.getTargetId(), event.getToZone()); } - + // update zone in other parts (meld cards, mdf half cards) cardsToUpdate.entrySet().forEach(entry -> { for (Card card : entry.getValue().getCards(game)) { @@ -373,8 +383,9 @@ public final class ZonesHandler { * that isn't a transforming double-faced card onto the battlefield transformed or converted, that card stays in * its current zone. */ + // TODO: remove after tdfc rework boolean wantToTransform = Boolean.TRUE.equals(game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId())); - if (wantToTransform) { + if (wantToTransform && !(card instanceof DoubleFacedCardHalf)) { isGoodToMove = card.isTransformable() && card.getSecondCardFace().isPermanent(game); } else { isGoodToMove = card.isPermanent(game); @@ -407,8 +418,7 @@ public final class ZonesHandler { } else if (card instanceof RoomCardHalf) { // Only the main room card can etb permanent = new PermanentCard(card.getMainCard(), event.getPlayerId(), game); - } - else if (card instanceof ModalDoubleFacedCard) { + } else if (card instanceof DoubleFacedCard) { // main mdf card must be processed before that call (e.g. only halves can be moved to battlefield) throw new IllegalStateException("Unexpected trying of move mdf card to battlefield instead half"); } else if (card instanceof Permanent) { @@ -533,4 +543,4 @@ public final class ZonesHandler { return card; } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/game/command/emblems/InzervaMasterOfInsightsEmblem.java b/Mage/src/main/java/mage/game/command/emblems/InzervaMasterOfInsightsEmblem.java index cf3f474532d..af72e38b5bc 100644 --- a/Mage/src/main/java/mage/game/command/emblems/InzervaMasterOfInsightsEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/InzervaMasterOfInsightsEmblem.java @@ -23,7 +23,7 @@ public final class InzervaMasterOfInsightsEmblem extends Emblem { )); // Whenever an opponent draws a card, this emblem deals 1 damage to them this.getAbilities().add(new DrawCardOpponentTriggeredAbility( - Zone.COMMAND, new DamageTargetEffect(1, true, "them") + Zone.COMMAND, new DamageTargetEffect(1) .setText("this emblem deals 1 damage to them"), false, true )); } diff --git a/Mage/src/main/java/mage/game/permanent/Battlefield.java b/Mage/src/main/java/mage/game/permanent/Battlefield.java index 7a57d75d044..094c03eecad 100644 --- a/Mage/src/main/java/mage/game/permanent/Battlefield.java +++ b/Mage/src/main/java/mage/game/permanent/Battlefield.java @@ -18,6 +18,7 @@ import java.util.stream.Collectors; public class Battlefield implements Serializable { private final Map field = new LinkedHashMap<>(); + private final Map permanentsEntering = new LinkedHashMap<>(); public Battlefield() { } @@ -26,6 +27,9 @@ public class Battlefield implements Serializable { for (Entry entry : battlefield.field.entrySet()) { field.put(entry.getKey(), entry.getValue().copy()); } + for (Entry entry : battlefield.permanentsEntering.entrySet()) { + permanentsEntering.put(entry.getKey(), entry.getValue().copy()); + } } public Battlefield copy() { @@ -36,10 +40,14 @@ public class Battlefield implements Serializable { for (Permanent perm : field.values()) { perm.reset(game); } + for (Permanent perm : permanentsEntering.values()) { + perm.reset(game); + } } public void clear() { field.clear(); + permanentsEntering.clear(); } /** @@ -156,6 +164,11 @@ public class Battlefield implements Serializable { return field.containsKey(key); } + public Map getPermanentsEntering() { + return permanentsEntering; + } + + public void beginningOfTurn(Game game) { for (Permanent perm : field.values()) { perm.beginningOfTurn(game); diff --git a/Mage/src/main/java/mage/game/permanent/Permanent.java b/Mage/src/main/java/mage/game/permanent/Permanent.java index f73c83bf1a0..97ef2ba3491 100644 --- a/Mage/src/main/java/mage/game/permanent/Permanent.java +++ b/Mage/src/main/java/mage/game/permanent/Permanent.java @@ -223,7 +223,10 @@ public interface Permanent extends Card, Controllable { boolean fight(Permanent fightTarget, Ability source, Game game); - boolean fight(Permanent fightTarget, Ability source, Game game, boolean batchTrigger); + /** + * Resolves a fight and returns the amount of excess damage dealt to fightTarget + */ + int fightWithExcess(Permanent fightTarget, Ability source, Game game, boolean batchTrigger); boolean entersBattlefield(Ability source, Game game, Zone fromZone, boolean fireEvent); @@ -475,7 +478,14 @@ public interface Permanent extends Card, Controllable { void setHarnessed(boolean value); boolean wasRoomUnlockedOnCast(); - + + /** + * used to reset the locked status of a room. Only used when copying a room + * or creating a token copy of a room permanent. Could most likely be removed + * after a designation class added. + */ + void resetLockedStatus(); + boolean isLeftDoorUnlocked(); boolean isRightDoorUnlocked(); @@ -483,7 +493,7 @@ public interface Permanent extends Card, Controllable { boolean unlockRoomOnCast(Game game); boolean unlockDoor(Game game, Ability source, boolean isLeftDoor); - + @Override Permanent copy(); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentCard.java b/Mage/src/main/java/mage/game/permanent/PermanentCard.java index 2d58da03e3f..9139caea669 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentCard.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentCard.java @@ -1,8 +1,10 @@ package mage.game.permanent; import mage.MageObject; +import mage.ObjectColor; import mage.abilities.Abilities; import mage.abilities.Ability; +import mage.abilities.common.RoomAbility; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.keyword.NightboundAbility; @@ -30,6 +32,8 @@ public class PermanentCard extends PermanentImpl { protected int maxLevelCounters; protected int zoneChangeCounter; + protected ObjectColor originalColor; + protected ObjectColor originalFrameColor; public PermanentCard(Card card, UUID controllerId, Game game) { super(card.getId(), card.getOwnerId(), controllerId, card.getName()); // card id @@ -46,7 +50,7 @@ public class PermanentCard extends PermanentImpl { // if you use it in test code or for permanent's copy effects then call CardUtil.getDefaultCardSideForBattlefield for default side // it's a basic check and still allows to create permanent from instant or sorcery boolean goodForBattlefield = true; - if (card instanceof ModalDoubleFacedCard) { + if (card instanceof DoubleFacedCard) { goodForBattlefield = false; } else if (card instanceof SplitCard) { // fused spells allowed (it uses main card) @@ -65,9 +69,24 @@ public class PermanentCard extends PermanentImpl { throw new IllegalArgumentException("Wrong code usage: can't create permanent card from split or mdf: " + card.getName()); } - this.card = card; + // if two permanent sides, set front and second side + if (card instanceof DoubleFacedCardHalf && card.isPermanent() && ((DoubleFacedCardHalf) card).getOtherSide().isPermanent()) { + if (((DoubleFacedCardHalf) card).isBackSide()) { + secondSideCard = card; + this.card = ((DoubleFacedCardHalf) card).getOtherSide().copy(); + this.transformed = true; + init(secondSideCard, game); + } else { + secondSideCard = ((DoubleFacedCardHalf) card).getOtherSide().copy(); + this.card = card; + init(card, game); + } + } else { + this.card = card; + init(card, game); + } + this.zoneChangeCounter = card.getZoneChangeCounter(game); // local value already set to the raised number - init(card, game); } private void init(Card card, Game game) { @@ -75,7 +94,7 @@ public class PermanentCard extends PermanentImpl { toughness = card.getToughness().copy(); startingLoyalty = card.getStartingLoyalty(); startingDefense = card.getStartingDefense(); - copyFromCard(card, game); + copyFromCard(card, game, false); // if temporary added abilities to the spell/card exist, you need to add it to the permanent derived from that card Abilities otherAbilities = game.getState().getAllOtherAbilities(card.getId()); if (otherAbilities != null) { @@ -86,10 +105,11 @@ public class PermanentCard extends PermanentImpl { } // if transformed on ETB - if (card.isTransformable()) { - if (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getId()) != null + // TODO: remove after tdfc rework + if (card.isTransformable() && !(card instanceof DoubleFacedCardHalf)) { + if (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()) != null || NightboundAbility.checkCard(this, game)) { - game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getId(), null); + game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId(), null); TransformAbility.transformPermanent(this, game, null); } } @@ -100,19 +120,37 @@ public class PermanentCard extends PermanentImpl { this.card = permanent.card.copy(); this.maxLevelCounters = permanent.maxLevelCounters; this.zoneChangeCounter = permanent.zoneChangeCounter; + this.originalColor = permanent.originalColor.copy(); + this.originalFrameColor = permanent.originalFrameColor.copy(); } @Override public void reset(Game game) { // when the permanent is reset, copy all original values from the card // must copy card each reset so that the original values don't get modified - copyFromCard(card, game); + if (transformed && secondSideCard != null && getCard() instanceof DoubleFacedCardHalf) { + copyFromCard(secondSideCard, game, true); + } else { + copyFromCard(card, game, true); + } power.resetToBaseValue(); toughness.resetToBaseValue(); super.reset(game); } - protected void copyFromCard(final Card card, final Game game) { + @Override + protected void initOtherFace(Game game) { + if (!(secondSideCard instanceof DoubleFacedCardHalf)) { + return; + } + if (transformed) { + copyFromCard(secondSideCard, game, false); + } else { + copyFromCard(card, game, false); + } + } + + protected void copyFromCard(final Card card, final Game game, boolean isReset) { // TODO: must research - is it copy all fields or something miss this.name = card.getName(); this.abilities.clear(); @@ -122,6 +160,11 @@ public class PermanentCard extends PermanentImpl { this.abilities.add(ability.copy()); } } + } else if (card.getId() != this.getId()) { + // if different id, abilities need to be added to game state for continuous/triggers + for (Ability ability : card.getAbilities()) { + this.addAbility(ability, card.getId(), game, true); + } } else { // copy only own abilities; all dynamic added abilities must be added in the parent call this.abilities = card.getAbilities().copy(); @@ -131,13 +174,23 @@ public class PermanentCard extends PermanentImpl { this.abilities.setSourceId(objectId); this.cardType.clear(); this.cardType.addAll(card.getCardType()); - this.color = card.getColor(game).copy(); - this.frameColor = card.getFrameColor(game).copy(); + if (!isReset) { + // save color from game state on first creation + this.color = card.getColor(game).copy(); + this.frameColor = card.getFrameColor(game).copy(); + this.originalColor = card.getColor(game).copy(); + this.originalFrameColor = card.getFrameColor(game).copy(); + } else { + this.color = originalColor.copy(); + this.frameColor = originalFrameColor.copy(); + } this.frameStyle = card.getFrameStyle(); this.manaCost = card.getManaCost().copy(); if (card instanceof PermanentCard) { this.maxLevelCounters = ((PermanentCard) card).maxLevelCounters; } + this.power = card.getPower().copy(); + this.toughness = card.getToughness().copy(); this.subtype.copyFrom(card.getSubtype()); this.supertype.clear(); this.supertype.addAll(card.getSuperType()); @@ -149,7 +202,7 @@ public class PermanentCard extends PermanentImpl { this.setImageFileName(card.getImageFileName()); this.setImageNumber(card.getImageNumber()); - if (card.getSecondCardFace() != null) { + if (card.getSecondCardFace() != null && !(card instanceof DoubleFacedCardHalf)) { this.secondSideCardClazz = card.getSecondCardFace().getClass(); } if (card.getMeldsToCard() != null) { @@ -158,6 +211,22 @@ public class PermanentCard extends PermanentImpl { this.nightCard = card.isNightCard(); this.flipCard = card.isFlipCard(); this.flipCardName = card.getFlipCardName(); + // Rooms set characteristics at the end so nothing gets overwritten + if (card instanceof RoomCard) { + RoomCard.setRoomCharacteristics(this, game); + if (!isReset) { + RoomAbility roomAbility = null; + for (Ability ability : this.abilities) { + if (ability instanceof RoomAbility) { + roomAbility = (RoomAbility) ability; + break; + } + } + if (roomAbility != null) { + roomAbility.applyCharacteristics(game, this); + } + } + } } @Override diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 1e094470adf..1b096877cdc 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -17,6 +17,7 @@ import mage.abilities.hint.HintUtils; import mage.abilities.keyword.*; import mage.cards.Card; import mage.cards.CardImpl; +import mage.abilities.common.RoomAbility; import mage.constants.*; import mage.counters.Counter; import mage.counters.CounterType; @@ -706,12 +707,15 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { + CardUtil.getSourceLogName(game, source, this.getId())); this.setTransformed(!this.transformed); this.transformCount++; + initOtherFace(game); game.applyEffects(); // not process action - no firing of simultaneous events yet this.replaceEvent(EventType.TRANSFORMING, game); game.addSimultaneousEvent(GameEvent.getEvent(EventType.TRANSFORMED, this.getId(), this.getControllerId())); return true; } + protected abstract void initOtherFace(Game game); + @Override public int getTransformCount() { return transformCount; @@ -2024,16 +2028,17 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean fight(Permanent fightTarget, Ability source, Game game) { - return this.fight(fightTarget, source, game, true); + this.fightWithExcess(fightTarget, source, game, true); + return true; } @Override - public boolean fight(Permanent fightTarget, Ability source, Game game, boolean batchTrigger) { + public int fightWithExcess(Permanent fightTarget, Ability source, Game game, boolean batchTrigger) { // double fight events for each creature game.fireEvent(GameEvent.getEvent(GameEvent.EventType.FIGHTED_PERMANENT, fightTarget.getId(), source, source.getControllerId())); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.FIGHTED_PERMANENT, getId(), source, source.getControllerId())); damage(fightTarget.getPower().getValue(), fightTarget.getId(), source, game); - fightTarget.damage(getPower().getValue(), getId(), source, game); + int excess = fightTarget.damageWithExcess(getPower().getValue(), getId(), source, game); if (batchTrigger) { Set morSet = new HashSet<>(); @@ -2044,7 +2049,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BATCH_FIGHT, getId(), source, source.getControllerId(), data, 0)); } - return true; + return excess; } @Override @@ -2098,6 +2103,12 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return roomWasUnlockedOnCast; } + @Override + public void resetLockedStatus() { + leftHalfUnlocked = false; + rightHalfUnlocked = false; + } + @Override public boolean isLeftDoorUnlocked() { return leftHalfUnlocked; @@ -2140,17 +2151,29 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { rightHalfUnlocked = true; } - // Fire door unlock event + // Update intrinsic stats/abilities from unlocking + // find the RoomCharacteristicsEffect applied by this permanent's ability + Abilities abilities = this.getAbilities(game); + for (Ability ability : abilities) { + if (ability instanceof RoomAbility) { + ((RoomAbility) ability).restoreUnlockedStats(game, this); + break; + } + } + + // Create door unlock event GameEvent event = new GameEvent(GameEvent.EventType.DOOR_UNLOCKED, getId(), source, source.getControllerId()); event.setFlag(isLeftDoor); - game.fireEvent(event); // Check if room is now fully unlocked boolean otherDoorUnlocked = isLeftDoor ? rightHalfUnlocked : leftHalfUnlocked; if (otherDoorUnlocked) { - game.fireEvent(new GameEvent(EventType.ROOM_FULLY_UNLOCKED, getId(), source, source.getControllerId())); + game.addSimultaneousEvent(event); + game.addSimultaneousEvent(new GameEvent(EventType.ROOM_FULLY_UNLOCKED, getId(), source, source.getControllerId())); + } else { + game.fireEvent(event); } return true; } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/game/permanent/PermanentToken.java b/Mage/src/main/java/mage/game/permanent/PermanentToken.java index 6ef20aff4de..024be2a2275 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentToken.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentToken.java @@ -5,8 +5,8 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; import mage.abilities.keyword.ChangelingAbility; -import mage.abilities.keyword.TransformAbility; import mage.cards.Card; +import mage.cards.RoomCard; import mage.constants.EmptyNames; import mage.game.Game; import mage.game.events.ZoneChangeEvent; @@ -30,13 +30,13 @@ public class PermanentToken extends PermanentImpl { this.token = token.copy(); this.token.getAbilities().newOriginalId(); // neccessary if token has ability like DevourAbility() this.token.getAbilities().setSourceId(objectId); - this.power = new MageInt(token.getPower().getModifiedBaseValue()); - this.toughness = new MageInt(token.getToughness().getModifiedBaseValue()); - this.copyFromToken(this.token, game, false); // needed to have at this time (e.g. for subtypes for entersTheBattlefield replacement effects) // if transformed on ETB if (this.token.isEntersTransformed()) { - TransformAbility.transformPermanent(this, game, null); + this.setTransformed(true); + this.copyFromToken(this.token.getBackFace(), game, false); + } else { + this.copyFromToken(this.token, game, false); // needed to have at this time (e.g. for subtypes for entersTheBattlefield replacement effects) } // token's ZCC must be synced with original token to keep abilities settings @@ -53,7 +53,11 @@ public class PermanentToken extends PermanentImpl { @Override public void reset(Game game) { - copyFromToken(token, game, true); + if (this.isTransformed()) { + copyFromToken(token.getBackFace(), game, true); + } else { + copyFromToken(token, game, true); + } super.reset(game); // Because the P/T objects have there own base value for reset we have to take it from there instead of from the basic token object this.power.resetToBaseValue(); @@ -110,8 +114,12 @@ public class PermanentToken extends PermanentImpl { if (this.abilities.containsClass(ChangelingAbility.class)) { this.subtype.setIsAllCreatureTypes(true); } - + this.power = new MageInt(token.getPower().getModifiedBaseValue()); + this.toughness = new MageInt(token.getToughness().getModifiedBaseValue()); CardUtil.copySetAndCardNumber(this, token); + if (token.getCopySourceCard() instanceof RoomCard) { + RoomCard.setRoomCharacteristics(this, game); + } } @Override @@ -161,4 +169,13 @@ public class PermanentToken extends PermanentImpl { public MageObject getOtherFace() { return this.transformed ? token : this.token.getBackFace(); } + + @Override + protected void initOtherFace(Game game) { + if (transformed) { + copyFromToken(token.getBackFace(), game, false); + } else { + copyFromToken(token, game, false); + } + } } diff --git a/Mage/src/main/java/mage/game/permanent/token/FaerieBlueBlackToken.java b/Mage/src/main/java/mage/game/permanent/token/FaerieBlueBlackToken.java index d5be3d0f3ee..dc2ba7b3d96 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FaerieBlueBlackToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FaerieBlueBlackToken.java @@ -6,17 +6,16 @@ import mage.constants.CardType; import mage.constants.SubType; /** - * @author spjspj + * @author TheElk801 */ public final class FaerieBlueBlackToken extends TokenImpl { public FaerieBlueBlackToken() { - super("Faerie Rogue Token", "1/1 blue and black Faerie Rogue creature token with flying"); + super("Faerie Token", "1/1 blue and black Faerie creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); color.setBlack(true); subtype.add(SubType.FAERIE); - subtype.add(SubType.ROGUE); power = new MageInt(1); toughness = new MageInt(1); this.addAbility(FlyingAbility.getInstance()); diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index b18d326117b..e9b54a60375 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -2,6 +2,7 @@ package mage.game.stack; import mage.*; import mage.abilities.*; +import mage.abilities.common.SpellTransformedAbility; import mage.abilities.costs.mana.ActivationManaAbilityStep; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; @@ -102,6 +103,11 @@ public class Spell extends StackObjectImpl implements Card { this.ability = ability; this.ability.setControllerId(controllerId); + // 712.8c TDFC spell "Its mana value is calculated using the mana cost of its front face" + if(ability instanceof SpellTransformedAbility && manaCost.isEmpty()) { + this.manaCost = card.getMainCard().getManaCost().copy(); + this.ability.setSourceId(affectedCard.getId()); // Maybe wrong? Permanent has incorrect id otherwise + } if (ability.getSpellAbilityCastMode().isFaceDown()) { // TODO: need research: // - why it use game param for color and subtype (possible bug?) @@ -1187,6 +1193,16 @@ public class Spell extends StackObjectImpl implements Card { throw new UnsupportedOperationException("Not supported."); } + @Override + public void setPT(int power, int toughness) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void setPT(MageInt power, MageInt toughness) { + throw new UnsupportedOperationException("Not supported."); + } + @Override public boolean cantBeAttachedBy(MageObject attachment, Ability source, Game game, boolean silentMode) { throw new UnsupportedOperationException("Not supported."); diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index ef0b43ea920..e2c6348cbaa 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -4106,7 +4106,11 @@ public abstract class PlayerImpl implements Player, Serializable { 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 CardWithSpellOption) { + } else if (object instanceof TransformingDoubleFacedCard) { + TransformingDoubleFacedCard mainCard = (TransformingDoubleFacedCard) object; + getPlayableFromObjectSingle(game, fromZone, mainCard.getLeftHalfCard(), mainCard.getLeftHalfCard().getAbilities(game), availableMana, output); + getPlayableFromObjectSingle(game, fromZone, mainCard, mainCard.getSharedAbilities(game), availableMana, output); + } else if (object instanceof CardWithSpellOption) { // adventure must use different card characteristics for different spells (main or adventure) CardWithSpellOption cardWithSpellOption = (CardWithSpellOption) object; getPlayableFromObjectSingle(game, fromZone, cardWithSpellOption.getSpellCard(), cardWithSpellOption.getSpellCard().getAbilities(game), availableMana, output); @@ -4258,6 +4262,12 @@ public abstract class PlayerImpl implements Player, Serializable { boolean isPlaySpell = (ability instanceof SpellAbility); boolean isPlayLand = (ability instanceof PlayLandAbility); + // ignore backside of TDFC + // TODO: maybe better way to ignore + if (isPlaySpell && ((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.TRANSFORMED_RIGHT) { + continue; + } + // play land restrictions if (isPlayLand && game.getContinuousEffects().preventedByRuleModification( GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), @@ -4946,8 +4956,9 @@ public abstract class PlayerImpl implements Player, Serializable { // or "converted," it enters the battlefield with its back face up. If a player is instructed to put a card // that isn't a transforming double-faced card onto the battlefield transformed or converted, that card stays in // its current zone. + // TODO: can probably remove/change after tdfc rework, should only be sending transformed side Boolean enterTransformed = (Boolean) game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()); - if (enterTransformed != null && enterTransformed && !card.isTransformable()) { + if (enterTransformed != null && enterTransformed && !card.isTransformable() && !(card instanceof TransformingDoubleFacedCardHalf)) { continue; } diff --git a/Mage/src/main/java/mage/target/TargetImpl.java b/Mage/src/main/java/mage/target/TargetImpl.java index e0a00773cc2..ffb46ca4c70 100644 --- a/Mage/src/main/java/mage/target/TargetImpl.java +++ b/Mage/src/main/java/mage/target/TargetImpl.java @@ -141,6 +141,7 @@ public abstract class TargetImpl implements Target { addTargetWord = false; } else if (targetName.endsWith("any target") || targetName.endsWith("any other target") + || targetName.endsWith("another target") || targetName.endsWith("targets")) { addTargetWord = false; } diff --git a/Mage/src/main/java/mage/target/common/TargetAttackingCreature.java b/Mage/src/main/java/mage/target/common/TargetAttackingCreature.java index 8a2661734cc..36824803080 100644 --- a/Mage/src/main/java/mage/target/common/TargetAttackingCreature.java +++ b/Mage/src/main/java/mage/target/common/TargetAttackingCreature.java @@ -21,7 +21,7 @@ public class TargetAttackingCreature extends TargetPermanent { } public TargetAttackingCreature(int minNumTargets, int maxNumTargets, boolean notTarget) { - super(minNumTargets, maxNumTargets, StaticFilters.FILTER_ATTACKING_CREATURE, notTarget); + super(minNumTargets, maxNumTargets, maxNumTargets > 1 ? StaticFilters.FILTER_ATTACKING_CREATURES : StaticFilters.FILTER_ATTACKING_CREATURE, notTarget); } protected TargetAttackingCreature(final TargetAttackingCreature target) { diff --git a/Mage/src/main/java/mage/target/targetpointer/EachTargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/EachTargetPointer.java index 3536e38a3f3..bbf6a007bad 100644 --- a/Mage/src/main/java/mage/target/targetpointer/EachTargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/EachTargetPointer.java @@ -120,7 +120,9 @@ public class EachTargetPointer extends TargetPointerImpl { @Override public String describeTargets(Targets targets, String defaultDescription) { - if (targetDescription != null) return targetDescription; + if (targetDescription != null) { + return targetDescription; + } if (targets.isEmpty()) { return defaultDescription; } diff --git a/Mage/src/main/java/mage/target/targetpointer/NthTargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/NthTargetPointer.java index d4da5b9f329..2cb6e0ebd4d 100644 --- a/Mage/src/main/java/mage/target/targetpointer/NthTargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/NthTargetPointer.java @@ -148,7 +148,9 @@ public abstract class NthTargetPointer extends TargetPointerImpl { @Override public String describeTargets(Targets targets, String defaultDescription) { - if (targetDescription != null) return targetDescription; + if (targetDescription != null) { + return targetDescription; + } if (targets.size() <= this.targetIndex) { // TODO: need research, is it used for non setup targets ?! // Typical usage example: trigger sets fixed target pointer diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index db9ff9e8543..2dcb5501ee3 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -84,7 +84,7 @@ public final class CardUtil { public static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS"); private static final List costWords = Arrays.asList( - "put", "return", "exile", "discard", "mill", "sacrifice", "remove", "tap", "reveal", "pay", "have", "collect", "forage" + "put", "return", "exile", "discard", "mill", "sacrifice", "remove", "tap", "reveal", "pay", "have", "collect", "forage", "transform" ); // search set code in commands like "set_code-card_name" @@ -979,7 +979,7 @@ public final class CardUtil { } if (!targetPlayerGets) { sb.append(add ? " on " : " from "); - if (description.contains("up to") && !description.contains("up to one")) { + if (description.contains("any number") || description.contains("up to") && !description.contains("up to one")) { sb.append("each of "); } sb.append(description); @@ -1261,8 +1261,8 @@ public final class CardUtil { permCard = card; } else if (card instanceof CardWithSpellOption) { permCard = card; - } else if (card instanceof ModalDoubleFacedCard) { - permCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); + } else if (card instanceof DoubleFacedCard) { + permCard = ((DoubleFacedCard) card).getLeftHalfCard(); } else { permCard = card; } @@ -1294,8 +1294,8 @@ public final class CardUtil { // 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 ModalDoubleFacedCard) { - return ((ModalDoubleFacedCard) card).getLeftHalfCard().getName(); + } else if (card instanceof DoubleFacedCard) { + return ((DoubleFacedCard) card).getLeftHalfCard().getName(); } else { return card.getName(); } @@ -1669,6 +1669,22 @@ public final class CardUtil { game.getState().setValue("PlayFromNotOwnHandZone" + rightHalfCard.getId(), Boolean.TRUE); } + // handle TDFC + if (card instanceof TransformingDoubleFacedCard) { + TransformingDoubleFacedCardHalf frontFace = ((TransformingDoubleFacedCard) card).getLeftHalfCard(); + TransformingDoubleFacedCardHalf backFace = ((TransformingDoubleFacedCard) card).getRightHalfCard(); + + if (manaCost != null) { + // get additional cost if any + Costs additionalCostsMDFCLeft = frontFace.getSpellAbility().getCosts(); + // set alternative cost and any additional cost + player.setCastSourceIdWithAlternateMana(frontFace.getId(), manaCost, additionalCostsMDFCLeft, MageIdentifier.Default); + } + + // allow just the front face + game.getState().setValue("PlayFromNotOwnHandZone" + frontFace.getId(), Boolean.TRUE); + } + // handle adventure cards if (card instanceof CardWithSpellOption) { Card creatureCard = card.getMainCard(); @@ -1706,9 +1722,9 @@ public final class CardUtil { game.getState().setValue("PlayFromNotOwnHandZone" + leftHalfCard.getId(), null); game.getState().setValue("PlayFromNotOwnHandZone" + rightHalfCard.getId(), null); } - if (card instanceof ModalDoubleFacedCard) { - ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); - ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard(); + if (card instanceof DoubleFacedCard) { + DoubleFacedCardHalf leftHalfCard = ((DoubleFacedCard) card).getLeftHalfCard(); + DoubleFacedCardHalf rightHalfCard = ((DoubleFacedCard) card).getRightHalfCard(); game.getState().setValue("PlayFromNotOwnHandZone" + leftHalfCard.getId(), null); game.getState().setValue("PlayFromNotOwnHandZone" + rightHalfCard.getId(), null); } @@ -2100,8 +2116,8 @@ public final class CardUtil { res.add(mainCard); res.add(mainCard.getLeftHalfCard()); res.add(mainCard.getRightHalfCard()); - } else if (object instanceof ModalDoubleFacedCard || object instanceof ModalDoubleFacedCardHalf) { - ModalDoubleFacedCard mainCard = (ModalDoubleFacedCard) ((Card) object).getMainCard(); + } else if (object instanceof DoubleFacedCard || object instanceof DoubleFacedCardHalf) { + DoubleFacedCard mainCard = (DoubleFacedCard) ((Card) object).getMainCard(); res.add(mainCard); res.add(mainCard.getLeftHalfCard()); res.add(mainCard.getRightHalfCard()); diff --git a/Mage/src/main/java/mage/util/ManaUtil.java b/Mage/src/main/java/mage/util/ManaUtil.java index f86f376a1d0..c232e4687fb 100644 --- a/Mage/src/main/java/mage/util/ManaUtil.java +++ b/Mage/src/main/java/mage/util/ManaUtil.java @@ -643,8 +643,8 @@ public final class ManaUtil { secondSide = ((SplitCard) card).getRightHalfCard(); } else if (card instanceof CardWithSpellOption) { secondSide = ((CardWithSpellOption) card).getSpellCard(); - } else if (card instanceof ModalDoubleFacedCard) { - secondSide = ((ModalDoubleFacedCard) card).getRightHalfCard(); + } else if (card instanceof DoubleFacedCard) { + secondSide = ((DoubleFacedCard) card).getRightHalfCard(); } else { secondSide = card.getSecondCardFace(); } diff --git a/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java b/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java index 3b159398037..a53bf0c135f 100644 --- a/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java +++ b/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java @@ -5,7 +5,7 @@ import mage.abilities.Abilities; import mage.abilities.Ability; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect; import mage.abilities.keyword.PrototypeAbility; -import mage.cards.Card; +import mage.cards.*; import mage.constants.CardType; import mage.constants.SuperType; import mage.game.Game; @@ -91,9 +91,13 @@ public class CopyTokenFunction { copyToToken(target, sourceObj, game); CardUtil.copySetAndCardNumber(target, sourceObj); // second side - if (sourceObj.isTransformable()) { + if (sourceObj.isTransformable() && !(sourceObj instanceof DoubleFacedCardHalf)) { copyToToken(target.getBackFace(), sourceObj.getSecondCardFace(), game); CardUtil.copySetAndCardNumber(target.getBackFace(), sourceObj.getSecondCardFace()); + } else if (sourceObj.isTransformable() && sourceObj instanceof DoubleFacedCardHalf) { + // double faced card + copyToToken(target.getBackFace(), ((DoubleFacedCardHalf) sourceObj).getOtherSide(), game); + CardUtil.copySetAndCardNumber(target.getBackFace(), ((DoubleFacedCardHalf) sourceObj).getOtherSide()); } // apply prototyped status @@ -108,6 +112,35 @@ public class CopyTokenFunction { return; } + // from double faced card spell + if (source instanceof DoubleFacedCardHalf) { + DoubleFacedCardHalf sourceCard = (DoubleFacedCardHalf) source; + Card frontSide; + Card backSide = null; + if (sourceCard.isTransformable()) { + if (sourceCard.isBackSide()) { + target.setEntersTransformed(true); + frontSide = sourceCard.getOtherSide(); + backSide = sourceCard; + } else { + frontSide = sourceCard; + backSide = sourceCard.getOtherSide(); + } + } else { + frontSide = sourceCard; + } + // main side + copyToToken(target, frontSide, game); + target.setCopySourceCard(sourceCard); + CardUtil.copySetAndCardNumber(target, frontSide); + // second side + if (backSide != null) { + copyToToken(target.getBackFace(), backSide, game); + CardUtil.copySetAndCardNumber(target, backSide); + } + return; + } + // from another card (example: Embalm ability) Card sourceObj = CardUtil.getDefaultCardSideForBattlefield(game, source.getMainCard()); target.setCopySourceCard(sourceObj); @@ -121,8 +154,14 @@ public class CopyTokenFunction { // must create back face?? throw new IllegalStateException("Wrong code usage: back face must be non null: " + target.getName() + " - " + target.getClass().getSimpleName()); } - copyToToken(target.getBackFace(), source.getSecondCardFace(), game); - CardUtil.copySetAndCardNumber(target.getBackFace(), source.getSecondCardFace()); + Card secondFace; + if (source instanceof DoubleFacedCard) { + secondFace = ((DoubleFacedCard) source).getRightHalfCard(); + } else { + secondFace = source.getSecondCardFace(); + } + copyToToken(target.getBackFace(), secondFace, game); + CardUtil.copySetAndCardNumber(target.getBackFace(), secondFace); } } diff --git a/Mage/src/main/java/mage/watchers/common/CreatureLeftBattlefieldWatcher.java b/Mage/src/main/java/mage/watchers/common/CreatureLeftBattlefieldWatcher.java new file mode 100644 index 00000000000..8fb44dac0a0 --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/CreatureLeftBattlefieldWatcher.java @@ -0,0 +1,51 @@ +package mage.watchers.common; + +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author Susucr + */ +public class CreatureLeftBattlefieldWatcher extends Watcher { + + // player -> number of creatures that left the battlefield under that player's control this turn + private final Map mapCreaturesLeft = new HashMap<>(); + + public CreatureLeftBattlefieldWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.ZONE_CHANGE) { + return; + } + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (Zone.BATTLEFIELD.match(zEvent.getFromZone()) && zEvent.getTarget().isCreature(game)) { + mapCreaturesLeft.compute(zEvent.getTarget().getControllerId(), CardUtil::setOrIncrementValue); + } + } + + @Override + public void reset() { + super.reset(); + mapCreaturesLeft.clear(); + } + + public static int getNumberCreatureLeft(UUID playerId, Game game) { + return game + .getState() + .getWatcher(CreatureLeftBattlefieldWatcher.class) + .mapCreaturesLeft + .getOrDefault(playerId, 0); + } +} diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt index 7e1ba03be1f..5d64c87398c 100644 --- a/Utils/known-sets.txt +++ b/Utils/known-sets.txt @@ -242,7 +242,7 @@ Sega Dreamcast Cards|SegaDreamcastCards| Scars of Mirrodin|ScarsOfMirrodin| Scourge|Scourge| Secret Lair Drop|SecretLairDrop| -Secret Lair Showdown|SecretLairShowdown| +Secret Lair Promo|SecretLairPromo| Seventh Edition|SeventhEdition| Shadowmoor|Shadowmoor| Shadows over Innistrad|ShadowsOverInnistrad|