[SNC] Implemented Endless Detour

This commit is contained in:
Evan Kranzler 2022-04-19 18:40:45 -04:00
parent 342eabbfa7
commit 9ead88bacb
19 changed files with 261 additions and 428 deletions

View file

@ -542,7 +542,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
// Angel of Serenity trigger
if (target.getOriginalTarget() instanceof TargetCardInGraveyardOrBattlefield) {
if (target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack) {
Cards cards = new CardsImpl(possibleTargets);
List<Card> possibleCards = new ArrayList<>(cards.getCards(game));
for (Card card : possibleCards) {
@ -1043,7 +1043,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return target.isChosen();
}
if (target.getOriginalTarget() instanceof TargetCardInGraveyardOrBattlefield) {
if (target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack) {
List<Card> cards = new ArrayList<>();
for (Player player : game.getPlayers().values()) {
cards.addAll(player.getGraveyard().getCards(game));

View file

@ -1,19 +1,15 @@
package mage.cards.a;
import mage.MageObject;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.common.FilterSpellOrPermanent;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetSpellOrPermanent;
import java.util.UUID;
@ -25,7 +21,7 @@ public final class AetherGust extends CardImpl {
private static final FilterSpellOrPermanent filter
= new FilterSpellOrPermanent("spell or permanent that's red or green");
private static final Predicate predicate = Predicates.or(
private static final Predicate<MageObject> predicate = Predicates.or(
new ColorPredicate(ObjectColor.RED),
new ColorPredicate(ObjectColor.GREEN)
);
@ -39,8 +35,11 @@ public final class AetherGust extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}");
// Choose target spell or permanent that's red or green. Its owner puts it on the top or bottom of their library.
this.getSpellAbility().addEffect(new AetherGustEffect());
this.getSpellAbility().addTarget(new TargetSpellOrPermanent(1, 1, filter, false));
this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(
"choose target spell or permanent that's red or green. " +
"Its owner puts it on the top or bottom of their library"
));
this.getSpellAbility().addTarget(new TargetSpellOrPermanent(filter));
}
private AetherGust(final AetherGust card) {
@ -52,34 +51,3 @@ public final class AetherGust extends CardImpl {
return new AetherGust(this);
}
}
class AetherGustEffect extends OneShotEffect {
AetherGustEffect() {
super(Outcome.Removal);
staticText = "Choose target spell or permanent that's red or green. " +
"Its owner puts it on the top or bottom of their library.";
}
private AetherGustEffect(final AetherGustEffect effect) {
super(effect);
}
@Override
public AetherGustEffect copy() {
return new AetherGustEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget()));
if (player == null) {
return false;
}
if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?",
"", "Top", "Bottom", source, game)) {
return new PutOnLibraryTargetEffect(true).apply(game, source);
}
return new PutOnLibraryTargetEffect(false).apply(game, source);
}
}

View file

@ -13,7 +13,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.target.common.TargetCardInGraveyardOrBattlefield;
import mage.target.common.TargetCardInGraveyardBattlefieldOrStack;
import java.util.UUID;
import mage.filter.common.FilterCreatureCard;
@ -49,7 +49,7 @@ public final class AngelOfSerenity extends CardImpl {
Ability ability = new EntersBattlefieldTriggeredAbility(
new ExileTargetForSourceEffect().setText(rule), true
);
ability.addTarget(new TargetCardInGraveyardOrBattlefield(
ability.addTarget(new TargetCardInGraveyardBattlefieldOrStack(
0, 3, filterCreatureCard, filterCreaturePermanent
));
this.addAbility(ability);

View file

@ -17,7 +17,7 @@ import mage.filter.StaticFilters;
import mage.filter.predicate.Predicates;
import mage.game.permanent.token.DarettiConstructToken;
import mage.target.TargetPermanent;
import mage.target.common.TargetCardInGraveyardOrBattlefield;
import mage.target.common.TargetCardInGraveyardBattlefieldOrStack;
import mage.target.common.TargetControlledPermanent;
import java.util.UUID;
@ -65,7 +65,7 @@ public final class DarettiIngeniousIconoclast extends CardImpl {
.setText("Choose target artifact card in a graveyard or artifact on the battlefield. " +
"Create three tokens that are copies of it"), -6
);
ability.addTarget(new TargetCardInGraveyardOrBattlefield(1, 1,
ability.addTarget(new TargetCardInGraveyardBattlefieldOrStack(1, 1,
StaticFilters.FILTER_CARD_ARTIFACT, StaticFilters.FILTER_PERMANENT_ARTIFACT));
this.addAbility(ability);
}

View file

@ -3,16 +3,12 @@ package mage.cards.d;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.ExploitCreatureTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect;
import mage.abilities.keyword.ExploitAbility;
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.players.Player;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
@ -33,7 +29,9 @@ public final class DiverSkaab extends CardImpl {
this.addAbility(new ExploitAbility());
// When Diver Skaab exploits a creature, target creature's owner puts it on the top or bottom of their library.
Ability ability = new ExploitCreatureTriggeredAbility(new DiverSkaabEffect());
Ability ability = new ExploitCreatureTriggeredAbility(new PutOnTopOrBottomLibraryTargetEffect(
"target creature's owner puts it on the top or bottom of their library"
));
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
@ -47,33 +45,3 @@ public final class DiverSkaab extends CardImpl {
return new DiverSkaab(this);
}
}
class DiverSkaabEffect extends OneShotEffect {
DiverSkaabEffect() {
super(Outcome.Removal);
staticText = "target creature's owner puts it on the top or bottom of their library";
}
private DiverSkaabEffect(final DiverSkaabEffect effect) {
super(effect);
}
@Override
public DiverSkaabEffect copy() {
return new DiverSkaabEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget()));
if (player == null) {
return false;
}
if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?",
"", "Top", "Bottom", source, game)) {
return new PutOnLibraryTargetEffect(true).apply(game, source);
}
return new PutOnLibraryTargetEffect(false).apply(game, source);
}
}

View file

@ -0,0 +1,36 @@
package mage.cards.e;
import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.StaticFilters;
import mage.target.common.TargetCardInGraveyardBattlefieldOrStack;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class EndlessDetour extends CardImpl {
public EndlessDetour(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}{W}{U}");
// The owner of target spell, nonland permanent, or card in a graveyard puts it on the top or bottom of their library.
this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect());
this.getSpellAbility().addTarget(new TargetCardInGraveyardBattlefieldOrStack(
1, 1, StaticFilters.FILTER_CARD, StaticFilters.FILTER_PERMANENT_NON_LAND,
StaticFilters.FILTER_SPELL, "spell, nonland permanent, or card in a graveyard"
));
}
private EndlessDetour(final EndlessDetour card) {
super(card);
}
@Override
public EndlessDetour copy() {
return new EndlessDetour(this);
}
}

View file

@ -2,19 +2,15 @@ package mage.cards.m;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapTargetCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect;
import mage.abilities.keyword.ChannelAbility;
import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetNonlandPermanent;
@ -45,7 +41,7 @@ public final class MoonsnarePrototype extends CardImpl {
this.addAbility(ability);
// Channel {4}{U}, Discard Moonsnare Prototype: The owner of target nonland permanent puts it on the top or bottom of their library.
ability = new ChannelAbility("{4}{U}", new MoonsnarePrototypeEffect());
ability = new ChannelAbility("{4}{U}", new PutOnTopOrBottomLibraryTargetEffect());
ability.addTarget(new TargetNonlandPermanent());
this.addAbility(ability);
}
@ -59,33 +55,3 @@ public final class MoonsnarePrototype extends CardImpl {
return new MoonsnarePrototype(this);
}
}
class MoonsnarePrototypeEffect extends OneShotEffect {
MoonsnarePrototypeEffect() {
super(Outcome.Benefit);
staticText = "the owner of target nonland permanent puts it on the top or bottom of their library";
}
private MoonsnarePrototypeEffect(final MoonsnarePrototypeEffect effect) {
super(effect);
}
@Override
public MoonsnarePrototypeEffect copy() {
return new MoonsnarePrototypeEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget()));
if (player == null) {
return false;
}
if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?",
"", "Top", "Bottom", source, game)) {
return new PutOnLibraryTargetEffect(true).apply(game, source);
}
return new PutOnLibraryTargetEffect(false).apply(game, source);
}
}

View file

@ -1,8 +1,6 @@
package mage.cards.p;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.abilities.effects.common.RollDieWithResultTableEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
@ -10,9 +8,6 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetOpponentsCreaturePermanent;
import java.util.UUID;
@ -36,7 +31,9 @@ public final class PowerOfPersuasion extends CardImpl {
effect.addTableEntry(1, 9, new ReturnToHandTargetEffect().setText("return it to its owner's hand"));
// 10-19 | Its owner puts it on the top of bottom of their library.
effect.addTableEntry(10, 19, new PowerOfPersuasionEffect());
effect.addTableEntry(10, 19, new PutOnTopOrBottomLibraryTargetEffect(
"its owner puts it on the top of bottom of their library"
));
// 20 | Gain control of it until the end of your next turn.
effect.addTableEntry(20, 20, new GainControlTargetEffect(
@ -53,33 +50,3 @@ public final class PowerOfPersuasion extends CardImpl {
return new PowerOfPersuasion(this);
}
}
class PowerOfPersuasionEffect extends OneShotEffect {
PowerOfPersuasionEffect() {
super(Outcome.Benefit);
staticText = "its owner puts it on the top or bottom of their library";
}
private PowerOfPersuasionEffect(final PowerOfPersuasionEffect effect) {
super(effect);
}
@Override
public PowerOfPersuasionEffect copy() {
return new PowerOfPersuasionEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget()));
if (player == null) {
return false;
}
if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?",
"", "Top", "Bottom", source, game)) {
return new PutOnLibraryTargetEffect(true).apply(game, source);
}
return new PutOnLibraryTargetEffect(false).apply(game, source);
}
}

View file

@ -1,16 +1,11 @@
package mage.cards.r;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.permanent.token.ZombieDecayedToken;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
@ -24,7 +19,9 @@ public final class RevengeOfTheDrowned extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}");
// Target creature's owner puts it on the top or bottom of their library. You create a 2/2 black Zombie creature token with decayed.
this.getSpellAbility().addEffect(new RevengeOfTheDrownedEffect());
this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(
"target creature's owner puts it on the top or bottom of their library"
));
this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieDecayedToken()).concatBy("You"));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}
@ -38,33 +35,3 @@ public final class RevengeOfTheDrowned extends CardImpl {
return new RevengeOfTheDrowned(this);
}
}
class RevengeOfTheDrownedEffect extends OneShotEffect {
RevengeOfTheDrownedEffect() {
super(Outcome.Benefit);
staticText = "target creature's owner puts it on the top or bottom of their library.";
}
private RevengeOfTheDrownedEffect(final RevengeOfTheDrownedEffect effect) {
super(effect);
}
@Override
public RevengeOfTheDrownedEffect copy() {
return new RevengeOfTheDrownedEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget()));
if (player == null) {
return false;
}
if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?",
"", "Top", "Bottom", source, game)) {
return new PutOnLibraryTargetEffect(true).apply(game, source);
}
return new PutOnLibraryTargetEffect(false).apply(game, source);
}
}

View file

@ -1,16 +1,11 @@
package mage.cards.r;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetNonlandPermanent;
import java.util.UUID;
@ -28,7 +23,7 @@ public final class RunAshore extends CardImpl {
this.getSpellAbility().getModes().setMaxModes(2);
// The owner of target nonland permanent puts it on the top or bottom of their library.
this.getSpellAbility().addEffect(new RunAshoreEffect());
this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect());
this.getSpellAbility().addTarget(new TargetNonlandPermanent());
// Return target nonland permanent to its owner's hand.
@ -46,33 +41,3 @@ public final class RunAshore extends CardImpl {
return new RunAshore(this);
}
}
class RunAshoreEffect extends OneShotEffect {
RunAshoreEffect() {
super(Outcome.Benefit);
staticText = "The owner of target nonland permanent puts it on the top or bottom of their library.";
}
private RunAshoreEffect(final RunAshoreEffect effect) {
super(effect);
}
@Override
public RunAshoreEffect copy() {
return new RunAshoreEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget()));
if (player == null) {
return false;
}
if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?",
"", "Top", "Bottom", source, game)) {
return new PutOnLibraryTargetEffect(true).apply(game, source);
}
return new PutOnLibraryTargetEffect(false).apply(game, source);
}
}

View file

@ -1,20 +1,14 @@
package mage.cards.r;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetNonlandPermanent;
import java.util.UUID;
/**
*
* @author weirddan455
*/
public final class RunOutOfTown extends CardImpl {
@ -23,7 +17,7 @@ public final class RunOutOfTown extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}");
// The owner of target nonland permanent puts it on the top or bottom of their library.
this.getSpellAbility().addEffect(new RunOutOfTownEffect());
this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect());
this.getSpellAbility().addTarget(new TargetNonlandPermanent());
}
@ -36,33 +30,3 @@ public final class RunOutOfTown extends CardImpl {
return new RunOutOfTown(this);
}
}
class RunOutOfTownEffect extends OneShotEffect {
public RunOutOfTownEffect() {
super(Outcome.Removal);
this.staticText = "The owner of target nonland permanent puts it on the top or bottom of their library";
}
private RunOutOfTownEffect(final RunOutOfTownEffect effect) {
super(effect);
}
@Override
public RunOutOfTownEffect copy() {
return new RunOutOfTownEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget()));
if (player == null) {
return false;
}
if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?",
"", "Top", "Bottom", source, game)) {
return new PutOnLibraryTargetEffect(true).apply(game, source);
}
return new PutOnLibraryTargetEffect(false).apply(game, source);
}
}

View file

@ -18,7 +18,7 @@ import mage.game.ExileZone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.common.TargetCardInGraveyardOrBattlefield;
import mage.target.common.TargetCardInGraveyardBattlefieldOrStack;
import mage.util.CardUtil;
import java.util.UUID;
@ -60,7 +60,7 @@ class SaviorOfOllenbockTriggeredAbility extends TriggeredAbilityImpl {
SaviorOfOllenbockTriggeredAbility() {
super(Zone.BATTLEFIELD, new ExileTargetForSourceEffect());
this.addTarget(new TargetCardInGraveyardOrBattlefield(
this.addTarget(new TargetCardInGraveyardBattlefieldOrStack(
0, 1,
StaticFilters.FILTER_CARD_CREATURE,
StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE

View file

@ -5,22 +5,18 @@ import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.costs.common.ExileFromHandCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect;
import mage.abilities.keyword.EvokeAbility;
import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetSpell;
import mage.target.common.TargetCardInHand;
@ -57,7 +53,10 @@ public final class Subtlety extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When Subtlety enters the battlefield, choose up to one target creature spell or planeswalker spell. Its owner puts it on the top or bottom of their library.
Ability ability = new EntersBattlefieldTriggeredAbility(new SubtletyEffect());
Ability ability = new EntersBattlefieldTriggeredAbility(new PutOnTopOrBottomLibraryTargetEffect(
"choose up to one target creature spell or planeswalker spell. " +
"Its owner puts it on the top or bottom of their library"
));
ability.addTarget(new TargetSpell(0, 1, filter));
this.addAbility(ability);
@ -74,34 +73,3 @@ public final class Subtlety extends CardImpl {
return new Subtlety(this);
}
}
class SubtletyEffect extends OneShotEffect {
SubtletyEffect() {
super(Outcome.Removal);
staticText = "choose up to one target creature spell or planeswalker spell. " +
"Its owner puts it on the top or bottom of their library";
}
private SubtletyEffect(final SubtletyEffect effect) {
super(effect);
}
@Override
public SubtletyEffect copy() {
return new SubtletyEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget()));
if (player == null) {
return false;
}
if (player.chooseUse(Outcome.Detriment, "Put the targeted spell on the top or bottom of your library?",
"", "Top", "Bottom", source, game)) {
return new PutOnLibraryTargetEffect(true).apply(game, source);
}
return new PutOnLibraryTargetEffect(false).apply(game, source);
}
}

View file

@ -97,6 +97,7 @@ public final class StreetsOfNewCapenna extends ExpansionSet {
cards.add(new SetCardInfo("Echo Inspector", 40, Rarity.COMMON, mage.cards.e.EchoInspector.class));
cards.add(new SetCardInfo("Elegant Entourage", 143, Rarity.UNCOMMON, mage.cards.e.ElegantEntourage.class));
cards.add(new SetCardInfo("Elspeth Resplendent", 11, Rarity.MYTHIC, mage.cards.e.ElspethResplendent.class));
cards.add(new SetCardInfo("Endless Detour", 183, Rarity.RARE, mage.cards.e.EndlessDetour.class));
cards.add(new SetCardInfo("Errant, Street Artist", 41, Rarity.RARE, mage.cards.e.ErrantStreetArtist.class));
cards.add(new SetCardInfo("Evolving Door", 144, Rarity.RARE, mage.cards.e.EvolvingDoor.class));
cards.add(new SetCardInfo("Exhibition Magician", 106, Rarity.COMMON, mage.cards.e.ExhibitionMagician.class));

View file

@ -1,5 +1,3 @@
package org.mage.test.cards.single.m20;
import mage.constants.PhaseStep;
@ -8,10 +6,8 @@ import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author jgray1206
*/
public class AetherGustTest extends CardTestPlayerBase {
/* Aether Gust - Instant {1}{U}
@ -70,5 +66,4 @@ public class AetherGustTest extends CardTestPlayerBase {
assertLibraryCount(playerA, 1);
assertAllCommandsUsed();
}
}

View file

@ -2461,7 +2461,7 @@ public class TestPlayer implements Player {
}
// card in battlefield
if (target instanceof TargetCardInGraveyardOrBattlefield) {
if (target instanceof TargetCardInGraveyardBattlefieldOrStack) {
TargetCard targetFull = (TargetCard) target;
for (String targetDefinition : targets) {
checkTargetDefinitionMarksSupport(target, targetDefinition, "^");
@ -2489,7 +2489,7 @@ public class TestPlayer implements Player {
if (target.getOriginalTarget() instanceof TargetCardInOpponentsGraveyard
|| target.getOriginalTarget() instanceof TargetCardInYourGraveyard
|| target.getOriginalTarget() instanceof TargetCardInGraveyard
|| target.getOriginalTarget() instanceof TargetCardInGraveyardOrBattlefield
|| target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack
|| (target.getOriginalTarget() instanceof TargetCard && target.getOriginalTarget().getZone() == Zone.GRAVEYARD)) {
targetCardZonesChecked.add(Zone.GRAVEYARD);
TargetCard targetFull = (TargetCard) target.getOriginalTarget();

View file

@ -0,0 +1,54 @@
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
/**
* @author TheElk801
*/
public class PutOnTopOrBottomLibraryTargetEffect extends OneShotEffect {
public PutOnTopOrBottomLibraryTargetEffect() {
this("");
}
public PutOnTopOrBottomLibraryTargetEffect(String text) {
super(Outcome.Benefit);
staticText = text;
}
private PutOnTopOrBottomLibraryTargetEffect(final PutOnTopOrBottomLibraryTargetEffect effect) {
super(effect);
}
@Override
public PutOnTopOrBottomLibraryTargetEffect copy() {
return new PutOnTopOrBottomLibraryTargetEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget()));
if (player == null) {
return false;
}
boolean onTop = player.chooseUse(
Outcome.Detriment, "Put the targeted object on the top or bottom of your library?",
null, "Top", "Bottom", source, game
);
return new PutOnLibraryTargetEffect(onTop).apply(game, source);
}
@Override
public String getText(Mode mode) {
if (staticText != null && !staticText.isEmpty()) {
return staticText;
}
return "the owner of target " + mode.getTargets().get(0).getTargetName() +
" puts it on the top or bottom of their library";
}
}

View file

@ -0,0 +1,127 @@
package mage.target.common;
import mage.MageObject;
import mage.abilities.Ability;
import mage.constants.ComparisonType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.FilterSpell;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.target.TargetCard;
import java.util.Set;
import java.util.UUID;
/**
* @author LevelX2
*/
public class TargetCardInGraveyardBattlefieldOrStack extends TargetCard {
private static final FilterSpell defaultSpellFilter = new FilterSpell();
static {
defaultSpellFilter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, -1));
}
protected final FilterPermanent filterPermanent;
protected final FilterSpell filterSpell;
public TargetCardInGraveyardBattlefieldOrStack(int minNumTargets, int maxNumTargets, FilterCard filterGraveyard, FilterPermanent filterBattlefield) {
this(minNumTargets, maxNumTargets, filterGraveyard, filterBattlefield, defaultSpellFilter, null);
}
public TargetCardInGraveyardBattlefieldOrStack(int minNumTargets, int maxNumTargets, FilterCard filterGraveyard, FilterPermanent filterBattlefield, FilterSpell filterSpell, String targetName) {
super(minNumTargets, maxNumTargets, Zone.GRAVEYARD, filterGraveyard); // zone for card in graveyard, don't change
this.filterPermanent = filterBattlefield;
this.filterSpell = filterSpell;
this.targetName = targetName != null ? targetName : filter.getMessage()
+ " in a graveyard "
+ (maxNumTargets > 1 ? " and/or " : " or ")
+ this.filterPermanent.getMessage()
+ " on the battlefield";
}
public TargetCardInGraveyardBattlefieldOrStack(final TargetCardInGraveyardBattlefieldOrStack target) {
super(target);
this.filterPermanent = target.filterPermanent;
this.filterSpell = target.filterSpell;
}
@Override
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
if (super.canChoose(sourceControllerId, source, game)) {
return true;
}
MageObject targetSource = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanent, sourceControllerId, source, game)) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
return true;
}
}
for (StackObject stackObject : game.getStack()) {
if (stackObject instanceof Spell
&& game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId())
&& filterSpell.match(stackObject, sourceControllerId, source, game)) {
return true;
}
}
return false;
}
@Override
public boolean canTarget(UUID id, Ability source, Game game) {
return this.canTarget(source.getControllerId(), id, source, game);
}
@Override
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
if (super.canTarget(playerId, id, source, game)) { // in graveyard first
return true;
}
Permanent permanent = game.getPermanent(id);
if (permanent != null) {
return filterPermanent.match(permanent, playerId, source, game);
}
Spell spell = game.getSpell(id);
return spell != null && filterSpell.match(spell, playerId, source, game);
}
@Override
public boolean canTarget(UUID id, Game game) {
return this.canTarget(null, id, null, game);
}
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
return this.possibleTargets(sourceControllerId, (Ability) null, game);
}
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game); // in graveyard first
MageObject targetSource = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanent, sourceControllerId, source, game)) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
possibleTargets.add(permanent.getId());
}
}
for (StackObject stackObject : game.getStack()) {
if (stackObject instanceof Spell
&& game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId())
&& filterSpell.match(stackObject, sourceControllerId, source, game)) {
possibleTargets.add(stackObject.getId());
}
}
return possibleTargets;
}
@Override
public TargetCardInGraveyardBattlefieldOrStack copy() {
return new TargetCardInGraveyardBattlefieldOrStack(this);
}
}

View file

@ -1,113 +0,0 @@
package mage.target.common;
import mage.MageObject;
import mage.abilities.Ability;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetCard;
import java.util.Set;
import java.util.UUID;
/**
* @author LevelX2
*/
public class TargetCardInGraveyardOrBattlefield extends TargetCard {
protected final FilterPermanent filterBattlefield;
public TargetCardInGraveyardOrBattlefield(int minNumTargets, int maxNumTargets, FilterCard filterGraveyard, FilterPermanent filterBattlefield) {
super(minNumTargets, maxNumTargets, Zone.GRAVEYARD, filterGraveyard); // zone for card in graveyard, don't change
this.filterBattlefield = filterBattlefield;
this.targetName = filter.getMessage()
+ " in a graveyard "
+ (maxNumTargets > 1 ? " and/or " : " or ")
+ this.filterBattlefield.getMessage()
+ " on the battlefield";
}
public TargetCardInGraveyardOrBattlefield(final TargetCardInGraveyardOrBattlefield target) {
super(target);
this.filterBattlefield = target.filterBattlefield;
}
@Override
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
if (!super.canChoose(sourceControllerId, source, game)) {
MageObject targetSource = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterBattlefield, sourceControllerId, game)) {
if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game))
&& filterBattlefield.match(permanent, sourceControllerId, source, game)) {
return true;
}
}
return false;
}
return true;
}
@Override
public boolean canTarget(UUID id, Ability source, Game game) {
if (!super.canTarget(id, source, game)) { // in graveyard first
Permanent permanent = game.getPermanent(id);
if (permanent != null) {
return filterBattlefield.match(permanent, source.getControllerId(), source, game);
}
}
return true;
}
@Override
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
if (!super.canTarget(playerId, id, source, game)) { // in graveyard first
Permanent permanent = game.getPermanent(id);
if (permanent != null) {
return filterBattlefield.match(permanent, playerId, source, game);
}
}
return true;
}
@Override
public boolean canTarget(UUID id, Game game) {
if (!super.canTarget(id, game)) { // in graveyard first
Permanent permanent = game.getPermanent(id);
if (permanent != null) {
return filterBattlefield.match(permanent, game);
}
}
return true;
}
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, game); // in graveyard first
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterBattlefield, sourceControllerId, game)) {
if (filterBattlefield.match(permanent, sourceControllerId, null, game)) {
possibleTargets.add(permanent.getId());
}
}
return possibleTargets;
}
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game); // in graveyard first
MageObject targetSource = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterBattlefield, sourceControllerId, source, game)) {
if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) && filterBattlefield.match(permanent, sourceControllerId, source, game)) {
possibleTargets.add(permanent.getId());
}
}
return possibleTargets;
}
@Override
public TargetCardInGraveyardOrBattlefield copy() {
return new TargetCardInGraveyardOrBattlefield(this);
}
}