implement [LCI] Twists and Turns

expand explore tests
This commit is contained in:
xenohedron 2023-11-01 23:22:21 -04:00
parent d3cc3aa96d
commit 5275c87a41
5 changed files with 211 additions and 1 deletions

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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));

View file

@ -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);
}
}

View file

@ -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,