diff --git a/Mage.Sets/src/mage/cards/m/MycoidMaze.java b/Mage.Sets/src/mage/cards/m/MycoidMaze.java new file mode 100644 index 00000000000..04fa111f543 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MycoidMaze.java @@ -0,0 +1,51 @@ +package mage.cards.m; + +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.common.LookLibraryAndPickControllerEffect; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PutCards; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author xenohedron + */ +public final class MycoidMaze extends CardImpl { + + public MycoidMaze(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.CAVE); + + // (Transforms from Twists and Turns.) + this.nightCard = true; + + // {T}: Add {G}. + this.addAbility(new GreenManaAbility()); + + // {3}{G}, {T}: Look at the top four cards of your library. You may reveal a creature card from among them and put that card into your hand. Put the rest on the bottom of your library in a random order. + Ability ability = new SimpleActivatedAbility(new LookLibraryAndPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM + ), new ManaCostsImpl<>("{3}{G}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + } + + private MycoidMaze(final MycoidMaze card) { + super(card); + } + + @Override + public MycoidMaze copy() { + return new MycoidMaze(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TwistsAndTurns.java b/Mage.Sets/src/mage/cards/t/TwistsAndTurns.java new file mode 100644 index 00000000000..6906e243c73 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TwistsAndTurns.java @@ -0,0 +1,93 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.keyword.ExploreTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author xenohedron + */ +public final class TwistsAndTurns extends CardImpl { + + public TwistsAndTurns(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); + + // If a creature you control would explore, instead you scry 1, then that creature explores. + this.addAbility(new SimpleStaticAbility(new TwistsAndTurnsReplacementEffect())); + + // When Twists and Turns enters the battlefield, target creature you control explores. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExploreTargetEffect(false)); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + + // When a land enters the battlefield under your control, if you control seven or more lands, transform Twists and Turns. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldControlledTriggeredAbility(new TransformSourceEffect(), StaticFilters.FILTER_LAND), + new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_LANDS, ComparisonType.MORE_THAN, 6, true), + "When a land enters the battlefield under your control, if you control seven or more lands, transform {this}." + )); + + } + + private TwistsAndTurns(final TwistsAndTurns card) { + super(card); + } + + @Override + public TwistsAndTurns copy() { + return new TwistsAndTurns(this); + } +} + +class TwistsAndTurnsReplacementEffect extends ReplacementEffectImpl { + + TwistsAndTurnsReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "If a creature you control would explore, instead you scry 1, then that creature explores"; + } + + private TwistsAndTurnsReplacementEffect(final TwistsAndTurnsReplacementEffect effect) { + super(effect); + } + + @Override + public TwistsAndTurnsReplacementEffect copy() { + return new TwistsAndTurnsReplacementEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.EXPLORE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return source.getControllerId().equals(event.getPlayerId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + controller.scry(1, source, game); + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java index c5759c3ec72..0727a9c6066 100644 --- a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java @@ -118,6 +118,7 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Mischievous Pup", 25, Rarity.UNCOMMON, mage.cards.m.MischievousPup.class)); cards.add(new SetCardInfo("Mountain", 290, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mountain", 399, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mycoid Maze", 217, Rarity.UNCOMMON, mage.cards.m.MycoidMaze.class)); cards.add(new SetCardInfo("Nicanzil, Current Conductor", 236, Rarity.UNCOMMON, mage.cards.n.NicanzilCurrentConductor.class)); cards.add(new SetCardInfo("Nurturing Bristleback", 203, Rarity.COMMON, mage.cards.n.NurturingBristleback.class)); cards.add(new SetCardInfo("Ojer Axonil, Deepest Might", 158, Rarity.MYTHIC, mage.cards.o.OjerAxonilDeepestMight.class)); @@ -185,6 +186,7 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Treasure Cove", 267, Rarity.RARE, mage.cards.t.TreasureCove.class)); cards.add(new SetCardInfo("Treasure Map", 267, Rarity.RARE, mage.cards.t.TreasureMap.class)); cards.add(new SetCardInfo("Trumpeting Carnosaur", 324, Rarity.RARE, mage.cards.t.TrumpetingCarnosaur.class)); + cards.add(new SetCardInfo("Twists and Turns", 217, Rarity.UNCOMMON, mage.cards.t.TwistsAndTurns.class)); cards.add(new SetCardInfo("Uchbenbak, the Great Mistake", 242, Rarity.UNCOMMON, mage.cards.u.UchbenbakTheGreatMistake.class)); cards.add(new SetCardInfo("Vanguard of the Rose", 42, Rarity.UNCOMMON, mage.cards.v.VanguardOfTheRose.class)); cards.add(new SetCardInfo("Vito, Fanatic of Aclazotz", 243, Rarity.MYTHIC, mage.cards.v.VitoFanaticOfAclazotz.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ExploreTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ExploreTest.java index 776fd85fef2..b014614a749 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ExploreTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ExploreTest.java @@ -4,6 +4,7 @@ import mage.constants.PhaseStep; import mage.constants.Zone; import mage.counters.CounterType; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** @@ -26,6 +27,9 @@ public class ExploreTest extends CardTestPlayerBase { private static final String mb = "Merfolk Branchwalker"; // 1G 2/1 ETB explores private static final String ww = "Wildgrowth Walker"; // 1G 1/3 // Whenever a creature you control explores, put a +1/+1 counter on Wildgrowth Walker and you gain 3 life. + private static final String nicanzil = "Nicanzil, Current Conductor"; + // Whenever a creature you control explores a land card, you may put a land card from your hand onto the battlefield tapped. + // Whenever a creature you control explores a nonland card, put a +1/+1 counter on Nicanzil, Current Conductor. private static final String enter = "Enter the Unknown"; // G Sorcery - Target creature you control explores. private static final String quicksand = "Quicksand"; // Land private static final String gg = "Giant Growth"; // Nonland @@ -81,6 +85,7 @@ public class ExploreTest extends CardTestPlayerBase { @Test public void exploreNonlandToGraveyard() { addCard(Zone.BATTLEFIELD, playerA, ww); + addCard(Zone.BATTLEFIELD, playerA, nicanzil); addCard(Zone.HAND, playerA, mb); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); removeAllCardsFromLibrary(playerA); @@ -89,6 +94,7 @@ public class ExploreTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, mb); setChoice(playerA, true); // yes to graveyard + setChoice(playerA, "Whenever a creature you control explores a nonland card,"); // order trigger setStopAt(1, PhaseStep.BEGIN_COMBAT); setStrictChooseMode(true); @@ -96,17 +102,46 @@ public class ExploreTest extends CardTestPlayerBase { assertCounterCount(mb, CounterType.P1P1, 1); assertCounterCount(ww, CounterType.P1P1, 1); + assertCounterCount(nicanzil, CounterType.P1P1, 1); assertLife(playerA, 23); assertHandCount(playerA, 0); assertGraveyardCount(playerA, gg,1); assertLibraryCount(playerA, 0); } + @Test + public void exploreLandToBattlefield() { + addCard(Zone.BATTLEFIELD, playerA, ww); + addCard(Zone.BATTLEFIELD, playerA, nicanzil); + addCard(Zone.HAND, playerA, mb); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + removeAllCardsFromLibrary(playerA); + skipInitShuffling(); + addCard(Zone.LIBRARY, playerA, quicksand); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, mb); + setChoice(playerA, "Whenever a creature you control explores a land card,"); // order trigger + setChoice(playerA, true); // yes to put land to battlefield tapped + setChoice(playerA, quicksand); // choose land + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + setStrictChooseMode(true); + execute(); + + assertCounterCount(mb, CounterType.P1P1, 0); + assertCounterCount(ww, CounterType.P1P1, 1); + assertLife(playerA, 23); + assertTapped(quicksand, true); + assertGraveyardCount(playerA, 0); + assertLibraryCount(playerA, 0); + } + @Test public void exploreEmptyLibrary() { // If no card is revealed, most likely because that player's library is empty, // the exploring creature receives a +1/+1 counter. addCard(Zone.BATTLEFIELD, playerA, ww); + addCard(Zone.BATTLEFIELD, playerA, nicanzil); addCard(Zone.HAND, playerA, mb); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); removeAllCardsFromLibrary(playerA); @@ -120,6 +155,7 @@ public class ExploreTest extends CardTestPlayerBase { assertCounterCount(mb, CounterType.P1P1, 1); assertCounterCount(ww, CounterType.P1P1, 1); + assertCounterCount(nicanzil, CounterType.P1P1, 0); assertLife(playerA, 23); assertHandCount(playerA, 0); assertGraveyardCount(playerA, 0); @@ -204,5 +240,33 @@ public class ExploreTest extends CardTestPlayerBase { assertGraveyardCount(playerA, gg, 1); assertLibraryCount(playerA, gg, 2); } + + @Test + public void exploreReplacement() { + String twists = "Twists and Turns"; + // If a creature you control would explore, instead you scry 1, then that creature explores. + + addCard(Zone.BATTLEFIELD, playerA, ww); + addCard(Zone.BATTLEFIELD, playerA, twists); + addCard(Zone.HAND, playerA, mb); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + removeAllCardsFromLibrary(playerA); + skipInitShuffling(); + addCard(Zone.LIBRARY, playerA, quicksand); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, mb); + addTarget(playerA, TestPlayer.TARGET_SKIP); // scry to top (no targets to bottom) + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + setStrictChooseMode(true); + execute(); + + assertCounterCount(mb, CounterType.P1P1, 0); + assertCounterCount(ww, CounterType.P1P1, 1); + assertLife(playerA, 23); + assertHandCount(playerA, quicksand, 1); + assertGraveyardCount(playerA, 0); + assertLibraryCount(playerA, 0); + } } diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index 8aa6c3784b0..72520863782 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -75,7 +75,7 @@ public class GameEvent implements Serializable { ZONE_CHANGE_GROUP, DRAW_CARDS, // event calls for multi draws only (if player draws 2+ cards at once) DRAW_CARD, DREW_CARD, - EXPLORE, EXPLORED, // targetId is exploring permanent + EXPLORE, EXPLORED, // targetId is exploring permanent, playerId is its controller ECHO_PAID, MIRACLE_CARD_REVEALED, /* MADNESS_CARD_EXILED,