diff --git a/Mage.Sets/src/mage/cards/e/EssenceFlux.java b/Mage.Sets/src/mage/cards/e/EssenceFlux.java index f7d31cff633..5e167bc2a77 100644 --- a/Mage.Sets/src/mage/cards/e/EssenceFlux.java +++ b/Mage.Sets/src/mage/cards/e/EssenceFlux.java @@ -1,22 +1,14 @@ package mage.cards.e; -import mage.abilities.Ability; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.abilities.condition.common.TargetHasSubtypeCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.ExileThenReturnTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.*; 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.common.TargetControlledCreaturePermanent; -import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; import java.util.UUID; @@ -30,8 +22,10 @@ public final class EssenceFlux extends CardImpl { // Exile target creature you control, then return that card to the battlefield under its owner's control. If it's a Spirit, put a +1/+1 counter on it. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addEffect(new ExileTargetForSourceEffect()); - this.getSpellAbility().addEffect(new EssenceFluxEffect()); + this.getSpellAbility().addEffect(new ExileThenReturnTargetEffect(false, false).withAfterEffect( + new ConditionalOneShotEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), + new TargetHasSubtypeCondition(SubType.SPIRIT), "If it's a Spirit, put a +1/+1 counter on it") + )); } private EssenceFlux(final EssenceFlux card) { @@ -42,62 +36,4 @@ public final class EssenceFlux extends CardImpl { public EssenceFlux copy() { return new EssenceFlux(this); } -} - -class EssenceFluxEffect extends OneShotEffect { - - EssenceFluxEffect() { - super(Outcome.Benefit); - staticText = ", then return that card to the battlefield under its owner's control. If it's a Spirit, put a +1/+1 counter on it"; - } - - private EssenceFluxEffect(final EssenceFluxEffect effect) { - super(effect); - } - - @Override - public EssenceFluxEffect copy() { - return new EssenceFluxEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Cards cardsToBattlefield = new CardsImpl(); - for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { - UUID mainCardId = CardUtil.getMainCardId(game, targetId); - if (game.getExile().containsId(mainCardId, game)) { - cardsToBattlefield.add(mainCardId); - } else { - Card card = game.getCard(targetId); - if (card instanceof MeldCard) { - MeldCard meldCard = (MeldCard) card; - Card topCard = meldCard.getTopHalfCard(); - Card bottomCard = meldCard.getBottomHalfCard(); - if (topCard.getZoneChangeCounter(game) == meldCard.getTopLastZoneChangeCounter() && game.getExile().containsId(topCard.getId(), game)) { - cardsToBattlefield.add(topCard); - } - if (bottomCard.getZoneChangeCounter(game) == meldCard.getBottomLastZoneChangeCounter() && game.getExile().containsId(bottomCard.getId(), game)) { - cardsToBattlefield.add(bottomCard); - } - } - } - } - - if (!cardsToBattlefield.isEmpty()) { - controller.moveCards(cardsToBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); - for (UUID cardId : cardsToBattlefield) { - Permanent permanent = game.getPermanent(cardId); - if (permanent != null && permanent.hasSubtype(SubType.SPIRIT, game)) { - Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); - effect.setTargetPointer(new FixedTarget(permanent, game)); - return effect.apply(game, source); - } - } - } - return true; - } - return false; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SplashPortal.java b/Mage.Sets/src/mage/cards/s/SplashPortal.java new file mode 100644 index 00000000000..60e5ad63701 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SplashPortal.java @@ -0,0 +1,71 @@ +package mage.cards.s; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileThenReturnTargetEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author jimga150 + */ +public final class SplashPortal extends CardImpl { + + public SplashPortal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); + + + // Exile target creature you control, then return it to the battlefield under its owner's control. + // If that creature is a Bird, Frog, Otter, or Rat, draw a card. + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addEffect(new ExileThenReturnTargetEffect(false, false).withAfterEffect( + new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), new SplashPortalCondition()) + )); + } + + private SplashPortal(final SplashPortal card) { + super(card); + } + + @Override + public SplashPortal copy() { + return new SplashPortal(this); + } +} + +// Based on TargetHasSubtypeCondition +class SplashPortalCondition implements Condition { + + private static final List checkedSubTypes = Arrays.asList( + SubType.BIRD, SubType.FROG, SubType.OTTER, SubType.RAT + ); + + @Override + public boolean apply(Game game, Ability source) { + if (source.getTargets().isEmpty()) { + return false; + } + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + return checkedSubTypes.stream() + .anyMatch(subType -> permanent.hasSubtype(subType, game)); + } + + @Override + public String toString() { + return "If that creature is a Bird, Frog, Otter, or Rat"; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/Bloomburrow.java b/Mage.Sets/src/mage/sets/Bloomburrow.java index cacc5b9c3c8..366e2315b16 100644 --- a/Mage.Sets/src/mage/sets/Bloomburrow.java +++ b/Mage.Sets/src/mage/sets/Bloomburrow.java @@ -216,6 +216,7 @@ public final class Bloomburrow extends ExpansionSet { cards.add(new SetCardInfo("Sonar Strike", 32, Rarity.COMMON, mage.cards.s.SonarStrike.class)); cards.add(new SetCardInfo("Spellgyre", 72, Rarity.UNCOMMON, mage.cards.s.Spellgyre.class)); cards.add(new SetCardInfo("Splash Lasher", 73, Rarity.UNCOMMON, mage.cards.s.SplashLasher.class)); + cards.add(new SetCardInfo("Splash Portal", 74, Rarity.UNCOMMON, mage.cards.s.SplashPortal.class)); cards.add(new SetCardInfo("Star Charter", 33, Rarity.UNCOMMON, mage.cards.s.StarCharter.class)); cards.add(new SetCardInfo("Starforged Sword", 249, Rarity.UNCOMMON, mage.cards.s.StarforgedSword.class)); cards.add(new SetCardInfo("Stargaze", 114, Rarity.UNCOMMON, mage.cards.s.Stargaze.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/blb/SplashPortalTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/blb/SplashPortalTest.java new file mode 100644 index 00000000000..49fdde6e3c7 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/blb/SplashPortalTest.java @@ -0,0 +1,42 @@ +package org.mage.test.cards.single.blb; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author jimga150 + */ +public class SplashPortalTest extends CardTestPlayerBase { + + /** + * {@link mage.cards.s.SplashPortal Splash Portal} {U} + * Sorcery + * Exile target creature you control, then return it to the battlefield under its owner's control. + * If that creature is a Bird, Frog, Otter, or Rat, draw a card. + */ + private static final String splashPortal = "Splash Portal"; + + @Test + public void test_ExileOtterNonOtter() { + + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Memnite"); + // When Alania's Pathmaker enters, exile the top card of your library. Until the end of your next turn, you may play that card. + addCard(Zone.BATTLEFIELD, playerA, "Alania's Pathmaker"); + addCard(Zone.HAND, playerA, splashPortal, 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, splashPortal, true); + addTarget(playerA, "Memnite"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, splashPortal, true); + addTarget(playerA, "Alania's Pathmaker"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/EssenceFluxTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/EssenceFluxTest.java new file mode 100644 index 00000000000..092ce8b1a54 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/EssenceFluxTest.java @@ -0,0 +1,43 @@ +package org.mage.test.cards.single.soi; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author jimga150 + */ +public class EssenceFluxTest extends CardTestPlayerBase { + + /** + * {@link mage.cards.e.EssenceFlux Essence Flux} {U} + * Sorcery + * Exile target creature you control, then return that card to the battlefield under its owner's control. + * If it's a Spirit, put a +1/+1 counter on it. + */ + private static final String essenceFlux = "Essence Flux"; + + @Test + public void test_ExileSpiritNonSpirit() { + + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Memnite"); + addCard(Zone.BATTLEFIELD, playerA, "Abuelo, Ancestral Echo"); + addCard(Zone.HAND, playerA, essenceFlux, 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, essenceFlux, true); + addTarget(playerA, "Memnite"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, essenceFlux, true); + addTarget(playerA, "Abuelo, Ancestral Echo"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertCounterCount("Memnite", CounterType.P1P1, 0); + assertCounterCount("Abuelo, Ancestral Echo", CounterType.P1P1, 1); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileThenReturnTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileThenReturnTargetEffect.java index 46bd8d2ebfe..737d783e8c1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileThenReturnTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileThenReturnTargetEffect.java @@ -2,6 +2,7 @@ package mage.abilities.effects.common; import mage.abilities.Ability; import mage.abilities.Mode; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.constants.Outcome; @@ -9,6 +10,8 @@ import mage.constants.PutCards; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import mage.target.targetpointer.FixedTargets; +import mage.util.CardUtil; import java.util.LinkedHashSet; import java.util.Objects; @@ -23,6 +26,7 @@ public class ExileThenReturnTargetEffect extends OneShotEffect { private final boolean yourControl; private final boolean textThatCard; private final PutCards putCards; + private OneShotEffect afterEffect = null; public ExileThenReturnTargetEffect(boolean yourControl, boolean textThatCard) { this(yourControl, textThatCard, PutCards.BATTLEFIELD); @@ -40,6 +44,7 @@ public class ExileThenReturnTargetEffect extends OneShotEffect { this.putCards = effect.putCards; this.yourControl = effect.yourControl; this.textThatCard = effect.textThatCard; + this.afterEffect = effect.afterEffect; } @Override @@ -47,6 +52,11 @@ public class ExileThenReturnTargetEffect extends OneShotEffect { return new ExileThenReturnTargetEffect(this); } + public ExileThenReturnTargetEffect withAfterEffect(OneShotEffect afterEffect) { + this.afterEffect = afterEffect; + return this; + } + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -68,6 +78,10 @@ public class ExileThenReturnTargetEffect extends OneShotEffect { yourControl ? controller : game.getPlayer(card.getOwnerId()), card.getMainCard(), source, game, "card"); } + if (afterEffect != null){ + afterEffect.setTargetPointer(new FixedTargets(toFlicker, game)); + afterEffect.apply(game, source); + } return true; } @@ -91,6 +105,9 @@ public class ExileThenReturnTargetEffect extends OneShotEffect { sb.append(this.yourControl ? "your" : "its owner's"); } sb.append(" control"); + if (afterEffect != null){ + sb.append(". ").append(CardUtil.getTextWithFirstCharUpperCase(afterEffect.getText(mode))); + } return sb.toString(); }