new ExileReturnBattlefieldNextEndStepTargetEffect (#11251)

* adjust ExileThenReturnTargetEffect

* initial rework ExileReturnBattlefieldNextEndStepTargetEffect

(test coverage provided by CloudshiftTest)

* refactor some more cards

* refactor more straightforward cards

* add params and more refactoring

* text fixes

* maintain order in set

* fix Lae'zel's Acrobatics and add test
This commit is contained in:
xenohedron 2023-10-05 22:04:12 -04:00 committed by GitHub
parent c8e2282a79
commit 6e18dbd2e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 402 additions and 1182 deletions

View file

@ -3,27 +3,19 @@ package mage.cards.a;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.costs.common.ExertSourceCost; import mage.abilities.costs.common.ExertSourceCost;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; import mage.abilities.effects.common.ExileUntilSourceLeavesEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -47,7 +39,7 @@ public final class AngelOfCondemnation extends CardImpl {
// {2}{W}, {T}: Exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step. // {2}{W}, {T}: Exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step.
Ability ability = new SimpleActivatedAbility( Ability ability = new SimpleActivatedAbility(
new AngelOfCondemnationExileUntilEOTEffect(), new ManaCostsImpl<>("{2}{W}") new ExileReturnBattlefieldNextEndStepTargetEffect(), new ManaCostsImpl<>("{2}{W}")
); );
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE));
@ -70,37 +62,3 @@ public final class AngelOfCondemnation extends CardImpl {
return new AngelOfCondemnation(this); return new AngelOfCondemnation(this);
} }
} }
class AngelOfCondemnationExileUntilEOTEffect extends OneShotEffect {
AngelOfCondemnationExileUntilEOTEffect() {
super(Outcome.Detriment);
staticText = "exile another target creature. Return that card to the battlefield " +
"under its owner's control at the beginning of the next end step";
}
private AngelOfCondemnationExileUntilEOTEffect(final AngelOfCondemnationExileUntilEOTEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source));
Player controller = game.getPlayer(source.getControllerId());
if (controller == null || permanent == null) {
return false;
}
controller.moveCards(permanent, Zone.EXILED, source, game);
//create delayed triggered ability
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false)
.setTargetPointer(new FixedTarget(source.getFirstTarget(), game))
), source);
return true;
}
@Override
public AngelOfCondemnationExileUntilEOTEffect copy() {
return new AngelOfCondemnationExileUntilEOTEffect(this);
}
}

View file

@ -3,24 +3,20 @@ package mage.cards.b;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate; 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.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -56,7 +52,7 @@ public final class BlizzardStrix extends CardImpl {
// When Blizzard Strix enters the battlefield, if you control another snow permanent, exile target permanent other than Blizzard Strix. Return that card to the battlefield under its owner's control at the beginning of the next end step. // When Blizzard Strix enters the battlefield, if you control another snow permanent, exile target permanent other than Blizzard Strix. Return that card to the battlefield under its owner's control at the beginning of the next end step.
Ability ability = new ConditionalInterveningIfTriggeredAbility( Ability ability = new ConditionalInterveningIfTriggeredAbility(
new EntersBattlefieldTriggeredAbility(new BlizzardStrixEffect()), condition, new EntersBattlefieldTriggeredAbility(new ExileReturnBattlefieldNextEndStepTargetEffect()), condition,
"When {this} enters the battlefield, if you control another snow permanent, " + "When {this} enters the battlefield, if you control another snow permanent, " +
"exile target permanent other than {this}. Return that card to the battlefield " + "exile target permanent other than {this}. Return that card to the battlefield " +
"under its owner's control at the beginning of the next end step." "under its owner's control at the beginning of the next end step."
@ -74,35 +70,3 @@ public final class BlizzardStrix extends CardImpl {
return new BlizzardStrix(this); return new BlizzardStrix(this);
} }
} }
class BlizzardStrixEffect extends OneShotEffect {
BlizzardStrixEffect() {
super(Outcome.Detriment);
}
private BlizzardStrixEffect(final BlizzardStrixEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
Player controller = game.getPlayer(source.getControllerId());
if (controller == null || permanent == null) {
return false;
}
controller.moveCards(permanent, Zone.EXILED, source, game);
//create delayed triggered ability
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false)
.setTargetPointer(new FixedTarget(source.getFirstTarget(), game))
), source);
return true;
}
@Override
public BlizzardStrixEffect copy() {
return new BlizzardStrixEffect(this);
}
}

View file

@ -1,27 +1,21 @@
package mage.cards.c; package mage.cards.c;
import mage.MageInt; import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect;
import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.effects.keyword.ScryEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AnotherPredicate; 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.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -30,8 +24,7 @@ import java.util.UUID;
*/ */
public final class CharmingPrince extends CardImpl { public final class CharmingPrince extends CardImpl {
private static final FilterPermanent filter = new FilterCreaturePermanent("another target creature you own");
private static final FilterPermanent filter = new FilterCreaturePermanent("another creature you own");
static { static {
filter.add(TargetController.YOU.getOwnerPredicate()); filter.add(TargetController.YOU.getOwnerPredicate());
@ -54,7 +47,7 @@ public final class CharmingPrince extends CardImpl {
ability.addMode(new Mode(new GainLifeEffect(3))); ability.addMode(new Mode(new GainLifeEffect(3)));
// Exile another target creature you own. Return it to the battlefield under your control at the beginning of the next end step. // Exile another target creature you own. Return it to the battlefield under your control at the beginning of the next end step.
Mode mode = new Mode(new CharmingPrinceEffect()); Mode mode = new Mode(new ExileReturnBattlefieldNextEndStepTargetEffect().underYourControl(true).withTextThatCard(false));
mode.addTarget(new TargetPermanent(filter)); mode.addTarget(new TargetPermanent(filter));
ability.addMode(mode); ability.addMode(mode);
this.addAbility(ability); this.addAbility(ability);
@ -69,42 +62,3 @@ public final class CharmingPrince extends CardImpl {
return new CharmingPrince(this); return new CharmingPrince(this);
} }
} }
class CharmingPrinceEffect extends OneShotEffect {
CharmingPrinceEffect() {
super(Outcome.Benefit);
staticText = "Exile another target creature you own. " +
"Return it to the battlefield under your control at the beginning of the next end step.";
}
private CharmingPrinceEffect(final CharmingPrinceEffect effect) {
super(effect);
}
@Override
public CharmingPrinceEffect copy() {
return new CharmingPrinceEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source);
if (controller == null || sourceObject == null) {
return false;
}
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent == null) {
return false;
}
controller.moveCards(permanent, Zone.EXILED, source, game);
//create delayed triggered ability
Effect effect = new ReturnToBattlefieldUnderYourControlTargetEffect();
effect.setText("Return it to the battlefield under your control at the beginning of the next end step");
effect.setTargetPointer(new FixedTarget(permanent.getId(), game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}
}

View file

@ -1,25 +1,12 @@
package mage.cards.e; package mage.cards.e;
import mage.MageObject; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.Ability; import mage.cards.CardImpl;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.cards.CardSetInfo;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.cards.*;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.targetpointer.FixedTargets;
import mage.util.CardUtil;
import mage.util.ExileUtil;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
@ -32,8 +19,8 @@ public final class EerieInterlude extends CardImpl {
// Exile any number of target creatures you control. Return those cards to the // Exile any number of target creatures you control. Return those cards to the
// battlefield under their owner's control at the beginning of the next end step. // battlefield under their owner's control at the beginning of the next end step.
this.getSpellAbility().addEffect(new EerieInterludeEffect()); this.getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect());
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, new FilterControlledCreaturePermanent(), false)); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, StaticFilters.FILTER_CONTROLLED_CREATURES, false));
} }
private EerieInterlude(final EerieInterlude card) { private EerieInterlude(final EerieInterlude card) {
@ -45,46 +32,3 @@ public final class EerieInterlude extends CardImpl {
return new EerieInterlude(this); return new EerieInterlude(this);
} }
} }
class EerieInterludeEffect extends OneShotEffect {
public EerieInterludeEffect() {
super(Outcome.Neutral);
staticText = "Exile any number of target creatures you control. Return those cards to the battlefield under their owner's control at the beginning of the next end step";
}
private EerieInterludeEffect(final EerieInterludeEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (sourceObject != null && controller != null) {
Set<Card> toExile = new HashSet<>();
for (UUID targetId : getTargetPointer().getTargets(game, source)) {
Permanent targetCreature = game.getPermanent(targetId);
if (targetCreature != null) {
toExile.add(targetCreature);
}
}
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
controller.moveCardsToExile(toExile, source, game, true, exileId, sourceObject.getIdName());
Cards cardsToReturn = ExileUtil.returnCardsFromExile(toExile, game);
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setTargetPointer(new FixedTargets(cardsToReturn, game));
AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
return false;
}
@Override
public EerieInterludeEffect copy() {
return new EerieInterludeEffect(this);
}
}

View file

@ -3,24 +3,15 @@ package mage.cards.f;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate; 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.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -46,7 +37,7 @@ public final class Flickerwisp extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// When Flickerwisp enters the battlefield, exile another target permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step. // When Flickerwisp enters the battlefield, exile another target permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step.
Ability ability = new EntersBattlefieldTriggeredAbility(new FlickerwispEffect()); Ability ability = new EntersBattlefieldTriggeredAbility(new ExileReturnBattlefieldNextEndStepTargetEffect());
ability.addTarget(new TargetPermanent(filter)); ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability); this.addAbility(ability);
} }
@ -60,38 +51,3 @@ public final class Flickerwisp extends CardImpl {
return new Flickerwisp(this); return new Flickerwisp(this);
} }
} }
class FlickerwispEffect extends OneShotEffect {
public FlickerwispEffect() {
super(Outcome.Detriment);
staticText = "exile another target permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step";
}
private FlickerwispEffect(final FlickerwispEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (controller != null && permanent != null && sourcePermanent != null) {
if (controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourcePermanent.getIdName(), source, game, Zone.BATTLEFIELD, true)) {
//create delayed triggered ability
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setText("Return that card to the battlefield under its owner's control at the beginning of the next end step");
effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}
}
return false;
}
@Override
public FlickerwispEffect copy() {
return new FlickerwispEffect(this);
}
}

View file

@ -1,27 +1,16 @@
package mage.cards.g; package mage.cards.g;
import mage.MageInt; import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -41,7 +30,7 @@ public final class GalepowderMage extends CardImpl {
// Flying // Flying
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// Whenever Galepowder Mage attacks, exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step. // Whenever Galepowder Mage attacks, exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step.
Ability ability = new AttacksTriggeredAbility(new GalepowderMageEffect(), false); Ability ability = new AttacksTriggeredAbility(new ExileReturnBattlefieldNextEndStepTargetEffect(), false);
ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE));
this.addAbility(ability); this.addAbility(ability);
} }
@ -55,45 +44,3 @@ public final class GalepowderMage extends CardImpl {
return new GalepowderMage(this); return new GalepowderMage(this);
} }
} }
class GalepowderMageEffect extends OneShotEffect {
public GalepowderMageEffect() {
super(Outcome.Benefit);
this.staticText = "exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step";
}
private GalepowderMageEffect(final GalepowderMageEffect effect) {
super(effect);
}
@Override
public GalepowderMageEffect copy() {
return new GalepowderMageEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source);
if (controller != null && sourceObject != null) {
if (getTargetPointer().getFirst(game, source) != null) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
UUID exileId = UUID.randomUUID();
if (controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName(), source, game, Zone.BATTLEFIELD, true)) {
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (card != null) {
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId())));
AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
game.addDelayedTriggeredAbility(delayedAbility, source);
}
}
}
}
return true;
}
return false;
}
}

View file

@ -3,24 +3,15 @@ package mage.cards.g;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate; 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.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -46,7 +37,7 @@ public final class GlimmerpointStag extends CardImpl {
this.addAbility(VigilanceAbility.getInstance()); this.addAbility(VigilanceAbility.getInstance());
// When Glimmerpoint Stag enters the battlefield, exile another target permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step. // When Glimmerpoint Stag enters the battlefield, exile another target permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step.
Ability etbAbility = new EntersBattlefieldTriggeredAbility(new GlimmerpointStagEffect()); Ability etbAbility = new EntersBattlefieldTriggeredAbility(new ExileReturnBattlefieldNextEndStepTargetEffect());
etbAbility.addTarget(new TargetPermanent(filter)); etbAbility.addTarget(new TargetPermanent(filter));
this.addAbility(etbAbility); this.addAbility(etbAbility);
} }
@ -60,42 +51,3 @@ public final class GlimmerpointStag extends CardImpl {
return new GlimmerpointStag(this); return new GlimmerpointStag(this);
} }
} }
class GlimmerpointStagEffect extends OneShotEffect {
private static final String effectText = "exile another target permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step";
GlimmerpointStagEffect() {
super(Outcome.Detriment);
staticText = effectText;
}
private GlimmerpointStagEffect(final GlimmerpointStagEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null) {
int zcc = permanent.getZoneChangeCounter(game);
controller.moveCards(permanent, Zone.EXILED, source, game);
//create delayed triggered ability
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setTargetPointer(new FixedTarget(permanent.getId(), zcc + 1));
AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
game.addDelayedTriggeredAbility(delayedAbility, source);
}
return true;
}
return false;
}
@Override
public GlimmerpointStagEffect copy() {
return new GlimmerpointStagEffect(this);
}
}

View file

@ -3,22 +3,16 @@ package mage.cards.g;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent;
import mage.filter.StaticFilters; import mage.filter.predicate.Predicates;
import mage.game.Game; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -27,6 +21,15 @@ import java.util.UUID;
*/ */
public final class GuardianOfGhirapur extends CardImpl { public final class GuardianOfGhirapur extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledPermanent("other target creature or artifact you control");
static {
filter.add(Predicates.or(
CardType.CREATURE.getPredicate(),
CardType.ARTIFACT.getPredicate()
));
filter.add(AnotherPredicate.instance);
}
public GuardianOfGhirapur(UUID ownerId, CardSetInfo setInfo) { public GuardianOfGhirapur(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
@ -38,10 +41,8 @@ public final class GuardianOfGhirapur extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// When Guardian of Ghirapur enters the battlefield, exile up to one other target creature or artifact you control. Return it to the battlefield under its owner's control at the beginning of the next end step. // When Guardian of Ghirapur enters the battlefield, exile up to one other target creature or artifact you control. Return it to the battlefield under its owner's control at the beginning of the next end step.
Ability ability = new EntersBattlefieldTriggeredAbility(new GuardianOfGhirapurEffect()); Ability ability = new EntersBattlefieldTriggeredAbility(new ExileReturnBattlefieldNextEndStepTargetEffect().withTextThatCard(false));
ability.addTarget(new TargetPermanent( ability.addTarget(new TargetPermanent(0, 1, filter));
0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_ARTIFACT_OR_CREATURE
));
this.addAbility(ability); this.addAbility(ability);
} }
@ -54,36 +55,3 @@ public final class GuardianOfGhirapur extends CardImpl {
return new GuardianOfGhirapur(this); return new GuardianOfGhirapur(this);
} }
} }
class GuardianOfGhirapurEffect extends OneShotEffect {
GuardianOfGhirapurEffect() {
super(Outcome.Benefit);
staticText = "exile up to one other target creature or artifact you control. " +
"Return it to the battlefield under its owner's control at the beginning of the next end step";
}
private GuardianOfGhirapurEffect(final GuardianOfGhirapurEffect effect) {
super(effect);
}
@Override
public GuardianOfGhirapurEffect copy() {
return new GuardianOfGhirapurEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (player == null || permanent == null) {
return false;
}
player.moveCards(permanent, Zone.EXILED, source, game);
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false)
.setTargetPointer(new FixedTarget(permanent.getId(), game))
), source);
return true;
}
}

View file

@ -1,139 +1,97 @@
package mage.cards.l; package mage.cards.l;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.*;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.cards.*;
import mage.abilities.effects.common.RollDieWithResultTableEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.PutCards;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.filter.predicate.permanent.TokenPredicate; import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.targetpointer.FixedTargets; import mage.target.targetpointer.FixedTargets;
import mage.util.CardUtil;
import mage.util.ExileUtil;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
* @author TheElk801 * @author xenohedron
*/ */
public final class LaezelsAcrobatics extends CardImpl { public final class LaezelsAcrobatics extends CardImpl {
public LaezelsAcrobatics(UUID ownerId, CardSetInfo setInfo) { public LaezelsAcrobatics(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[] { CardType.INSTANT }, "{3}{W}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}");
this.getSpellAbility().addEffect(new LaezelsAcrobaticsEffect()); this.getSpellAbility().addEffect(new LaezelsAcrobaticsEffect());
} }
private LaezelsAcrobatics(final LaezelsAcrobatics card) { private LaezelsAcrobatics(final LaezelsAcrobatics card) {
super(card); super(card);
} }
@Override @Override
public LaezelsAcrobatics copy() { public LaezelsAcrobatics copy() {
return new LaezelsAcrobatics(this); return new LaezelsAcrobatics(this);
} }
} }
class LaezelsAcrobaticsEffect extends RollDieWithResultTableEffect { class LaezelsAcrobaticsEffect extends RollDieWithResultTableEffect {
LaezelsAcrobaticsEffect() { private static final FilterControlledCreaturePermanent creatureFilter = new FilterControlledCreaturePermanent();
super(20, "Exile all nontoken creatures you control, then roll a d20");
this.addTableEntry(
1, 9,
new InfoEffect("Return those cards to the battlefield under their owner's control at the " +
"beginning of the next end step."));
this.addTableEntry(
10, 20,
new InfoEffect(
"Return those cards to the battlefield under their owner's control, then exile them again. Return those cards to the battlefield under their owner's control at the beginning of the next end step."));
}
private LaezelsAcrobaticsEffect(final LaezelsAcrobaticsEffect effect) { static {
super(effect); creatureFilter.add(TokenPredicate.FALSE);
}
@Override
public LaezelsAcrobaticsEffect copy() {
return new LaezelsAcrobaticsEffect(this);
}
private static final FilterControlledCreaturePermanent creatureFilter = new FilterControlledCreaturePermanent();
static {
creatureFilter.add(TokenPredicate.FALSE);
}
private Set<Card> getNontokenCreatureCards(Game game, Player player) {
List<Permanent> playerPermanents = game
.getState()
.getBattlefield()
.getActivePermanents(creatureFilter, player.getId(), game);
Set<Card> toExile = new HashSet<>();
for (Permanent permanent : playerPermanents) {
if (permanent != null) {
toExile.add(permanent);
}
} }
return toExile; LaezelsAcrobaticsEffect() {
} super(20, "Exile all nontoken creatures you control, then roll a d20");
this.addTableEntry(
@Override 1, 9,
public boolean apply(Game game, Ability source) { new InfoEffect("Return those cards to the battlefield under their owner's control at the " +
Player player = game.getPlayer(source.getControllerId()); "beginning of the next end step."));
MageObject sourceObject = source.getSourceObject(game); this.addTableEntry(
10, 20,
if (player == null) { new InfoEffect(
return false; "Return those cards to the battlefield under their owner's control, then exile them again. Return those cards to the battlefield under their owner's control at the beginning of the next end step."));
} }
Set<Card> toExile = getNontokenCreatureCards(game, player); private LaezelsAcrobaticsEffect(final LaezelsAcrobaticsEffect effect) {
super(effect);
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
player.moveCardsToExile(toExile, source, game, true, exileId, sourceObject.getIdName());
Integer result = player.rollDice(outcome, source, game, 20);
Cards cardsToReturn = ExileUtil.returnCardsFromExile(toExile, game);
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setTargetPointer(new FixedTargets(cardsToReturn, game));
if (result < 10) {
AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
effect);
game.addDelayedTriggeredAbility(delayedAbility, source);
} else {
effect.apply(game, source);
toExile = getNontokenCreatureCards(game, player);
exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
player.moveCardsToExile(toExile, source, game, true, exileId, sourceObject.getIdName());
cardsToReturn = ExileUtil.returnCardsFromExile(toExile, game);
effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setTargetPointer(new FixedTargets(cardsToReturn, game));
AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
effect);
game.addDelayedTriggeredAbility(delayedAbility, source);
} }
return true; @Override
} public LaezelsAcrobaticsEffect copy() {
return new LaezelsAcrobaticsEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Cards toFlicker = new CardsImpl(game.getBattlefield().getActivePermanents(creatureFilter, controller.getId(), game));
controller.moveCards(toFlicker, Zone.EXILED, source, game);
game.getState().processAction(game);
int result = controller.rollDice(outcome, source, game, 20);
if (result >= 1 && result <= 9) {
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setTargetPointer(new FixedTargets(new CardsImpl(toFlicker), game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
} else if (result >= 10 && result <= 20) {
for (UUID cardId : toFlicker) {
Card card = game.getCard(cardId);
if (card != null) {
PutCards.BATTLEFIELD.moveCard(game.getPlayer(card.getOwnerId()), card.getMainCard(), source, game, "card");
}
}
game.getState().processAction(game);
Effect effect = new ExileReturnBattlefieldNextEndStepTargetEffect();
effect.setTargetPointer(new FixedTargets(toFlicker, game));
effect.apply(game, source);
}
return true;
}
} }

View file

@ -1,20 +1,11 @@
package mage.cards.l; package mage.cards.l;
import mage.abilities.Ability; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.filter.StaticFilters;
import mage.constants.Zone; import mage.target.TargetPermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -27,8 +18,8 @@ public final class Liberate extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}");
// Exile target creature you control. Return that card to the battlefield under its owner's control at the beginning of the next end step. // Exile target creature you control. Return that card to the battlefield under its owner's control at the beginning of the next end step.
this.getSpellAbility().addEffect(new LiberateEffect()); this.getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect());
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED));
} }
private Liberate(final Liberate card) { private Liberate(final Liberate card) {
@ -40,38 +31,3 @@ public final class Liberate extends CardImpl {
return new Liberate(this); return new Liberate(this);
} }
} }
class LiberateEffect extends OneShotEffect {
LiberateEffect() {
super(Outcome.Detriment);
staticText = "exile target creature you control. Return that card to the battlefield " +
"under its owner's control at the beginning of the next end step";
}
private LiberateEffect(final LiberateEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (player == null || permanent == null) {
return false;
}
Card card = permanent.getMainCard();
player.moveCards(permanent, Zone.EXILED, source, game);
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false)
.setText("Return that card to the battlefield under its owner's control at the beginning of the next end step")
.setTargetPointer(new FixedTarget(card, game))
), source);
return true;
}
@Override
public LiberateEffect copy() {
return new LiberateEffect(this);
}
}

View file

@ -3,20 +3,15 @@ package mage.cards.m;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BecomesTappedSourceTriggeredAbility; import mage.abilities.common.BecomesTappedSourceTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterNonlandPermanent; import mage.filter.common.FilterNonlandPermanent;
import mage.filter.predicate.permanent.TokenPredicate; import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -40,7 +35,7 @@ public final class MistmeadowVanisher extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// Whenever Mistmeadow Vanisher becomes tapped, exile up to one target nonland, nontoken permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step. // Whenever Mistmeadow Vanisher becomes tapped, exile up to one target nonland, nontoken permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step.
Ability ability = new BecomesTappedSourceTriggeredAbility(new MistmeadowVanisherEffect()); Ability ability = new BecomesTappedSourceTriggeredAbility(new ExileReturnBattlefieldNextEndStepTargetEffect());
ability.addTarget(new TargetPermanent(0, 1, filter)); ability.addTarget(new TargetPermanent(0, 1, filter));
this.addAbility(ability); this.addAbility(ability);
} }
@ -54,37 +49,3 @@ public final class MistmeadowVanisher extends CardImpl {
return new MistmeadowVanisher(this); return new MistmeadowVanisher(this);
} }
} }
class MistmeadowVanisherEffect extends OneShotEffect {
MistmeadowVanisherEffect() {
super(Outcome.Benefit);
staticText = "exile up to one target nonland, nontoken permanent. Return that card to the battlefield " +
"under its owner's control at the beginning of the next end step";
}
private MistmeadowVanisherEffect(final MistmeadowVanisherEffect effect) {
super(effect);
}
@Override
public MistmeadowVanisherEffect copy() {
return new MistmeadowVanisherEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (player == null || permanent == null) {
return false;
}
player.moveCards(permanent, Zone.EXILED, source, game);
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false)
.setTargetPointer(new FixedTarget(permanent, game)),
TargetController.ANY
), source);
return true;
}
}

View file

@ -1,4 +1,3 @@
package mage.cards.m; package mage.cards.m;
import java.util.UUID; import java.util.UUID;
@ -6,7 +5,7 @@ import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.MistmeadowWitchEffect; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
@ -29,7 +28,7 @@ public final class MistmeadowWitch extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// {2}{W}{U}: Exile target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step. // {2}{W}{U}: Exile target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MistmeadowWitchEffect(), new ManaCostsImpl<>("{2}{W}{U}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileReturnBattlefieldNextEndStepTargetEffect(), new ManaCostsImpl<>("{2}{W}{U}"));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);
} }
@ -43,4 +42,3 @@ public final class MistmeadowWitch extends CardImpl {
return new MistmeadowWitch(this); return new MistmeadowWitch(this);
} }
} }

View file

@ -3,20 +3,15 @@ package mage.cards.o;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -31,7 +26,7 @@ public final class OathOfTeferi extends CardImpl {
this.supertype.add(SuperType.LEGENDARY); this.supertype.add(SuperType.LEGENDARY);
// When Oath of Teferi enters the battlefield, exile another target permanent you control. Return it to the battlefield under its owner's control at the beginning of the next end step. // When Oath of Teferi enters the battlefield, exile another target permanent you control. Return it to the battlefield under its owner's control at the beginning of the next end step.
Ability ability = new EntersBattlefieldTriggeredAbility(new OathOfTeferiBlinkEffect()); Ability ability = new EntersBattlefieldTriggeredAbility(new ExileReturnBattlefieldNextEndStepTargetEffect().withTextThatCard(false));
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_PERMANENT)); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_PERMANENT));
this.addAbility(ability); this.addAbility(ability);
@ -49,45 +44,6 @@ public final class OathOfTeferi extends CardImpl {
} }
} }
class OathOfTeferiBlinkEffect extends OneShotEffect {
private static final String effectText = "exile another target permanent you control. Return it to the battlefield under its owner's control at the beginning of the next end step";
OathOfTeferiBlinkEffect() {
super(Outcome.Detriment);
staticText = effectText;
}
private OathOfTeferiBlinkEffect(final OathOfTeferiBlinkEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null) {
int zcc = permanent.getZoneChangeCounter(game);
controller.moveCards(permanent, Zone.EXILED, source, game);
//create delayed triggered ability
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setTargetPointer(new FixedTarget(permanent.getId(), zcc + 1));
AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
game.addDelayedTriggeredAbility(delayedAbility, source);
}
return true;
}
return false;
}
@Override
public OathOfTeferiBlinkEffect copy() {
return new OathOfTeferiBlinkEffect(this);
}
}
class OathOfTeferiLoyaltyEffect extends ContinuousEffectImpl { class OathOfTeferiLoyaltyEffect extends ContinuousEffectImpl {
public OathOfTeferiLoyaltyEffect() { public OathOfTeferiLoyaltyEffect() {

View file

@ -1,26 +1,21 @@
package mage.cards.r; package mage.cards.r;
import mage.MageInt; import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.TrampleAbility;
import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -43,7 +38,7 @@ public final class RoonOfTheHiddenRealm extends CardImpl {
// Trample // Trample
this.addAbility(TrampleAbility.getInstance()); this.addAbility(TrampleAbility.getInstance());
// {2}, {tap}: Exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step. // {2}, {tap}: Exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RoonOfTheHiddenRealmEffect(), new GenericManaCost(2)); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileReturnBattlefieldNextEndStepTargetEffect(), new GenericManaCost(2));
ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
this.addAbility(ability); this.addAbility(ability);
@ -59,43 +54,3 @@ public final class RoonOfTheHiddenRealm extends CardImpl {
return new RoonOfTheHiddenRealm(this); return new RoonOfTheHiddenRealm(this);
} }
} }
class RoonOfTheHiddenRealmEffect extends OneShotEffect {
public RoonOfTheHiddenRealmEffect() {
super(Outcome.Benefit);
this.staticText = "Exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step";
}
private RoonOfTheHiddenRealmEffect(final RoonOfTheHiddenRealmEffect effect) {
super(effect);
}
@Override
public RoonOfTheHiddenRealmEffect copy() {
return new RoonOfTheHiddenRealmEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source);
if (controller != null && sourceObject != null) {
if (getTargetPointer().getFirst(game, source) != null) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
int zcc = permanent.getZoneChangeCounter(game);
if (controller.moveCards(permanent, Zone.EXILED, source, game)) {
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setTargetPointer(new FixedTarget(permanent.getId(), zcc + 1));
AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility
= new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
game.addDelayedTriggeredAbility(delayedAbility, source);
}
}
}
return true;
}
return false;
}
}

View file

@ -2,20 +2,13 @@ package mage.cards.s;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.abilityword.ConstellationAbility; import mage.abilities.abilityword.ConstellationAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -34,7 +27,7 @@ public final class Skybind extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{W}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{W}");
// Constellation When Skybind or another enchantment enters the battlefield under your control, exile target nonenchantment permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step. // Constellation When Skybind or another enchantment enters the battlefield under your control, exile target nonenchantment permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step.
Ability ability = new ConstellationAbility(new SkybindEffect(), false); Ability ability = new ConstellationAbility(new ExileReturnBattlefieldNextEndStepTargetEffect(), false);
ability.addTarget(new TargetPermanent(filter)); ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability); this.addAbility(ability);
} }
@ -48,36 +41,3 @@ public final class Skybind extends CardImpl {
return new Skybind(this); return new Skybind(this);
} }
} }
class SkybindEffect extends OneShotEffect {
public SkybindEffect() {
super(Outcome.Detriment);
staticText = "exile target nonenchantment permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step";
}
private SkybindEffect(final SkybindEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (permanent != null && sourcePermanent != null) {
if (permanent.moveToExile(source.getSourceId(), sourcePermanent.getName(), source, game)) {
//create delayed triggered ability
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source), game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}
}
return false;
}
@Override
public SkybindEffect copy() {
return new SkybindEffect(this);
}
}

View file

@ -1,22 +1,21 @@
package mage.cards.s; package mage.cards.s;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.cards.*; import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.filter.common.FilterNonlandPermanent; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetPlayer; import mage.target.TargetPlayer;
import mage.target.targetpointer.FixedTargets; import mage.target.targetpointer.FixedTargets;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
@ -45,9 +44,7 @@ public final class SuddenDisappearance extends CardImpl {
class SuddenDisappearanceEffect extends OneShotEffect { class SuddenDisappearanceEffect extends OneShotEffect {
private static FilterNonlandPermanent filter = new FilterNonlandPermanent(); SuddenDisappearanceEffect() {
public SuddenDisappearanceEffect() {
super(Outcome.Exile); super(Outcome.Exile);
staticText = "Exile all nonland permanents target player controls. Return the exiled cards to the battlefield under their owner's control at the beginning of the next end step"; staticText = "Exile all nonland permanents target player controls. Return the exiled cards to the battlefield under their owner's control at the beginning of the next end step";
} }
@ -58,25 +55,17 @@ class SuddenDisappearanceEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getFirstTarget());
MageObject sourceObject = source.getSourceObject(game); if (player == null) {
if (controller != null && sourceObject != null) { return false;
Set<Card> permsSet = new HashSet<>(game.getBattlefield().getAllActivePermanents(filter, source.getFirstTarget(), game));
if (!permsSet.isEmpty()) {
controller.moveCardsToExile(permsSet, source, game, true, source.getSourceId(), sourceObject.getIdName());
Cards targets = new CardsImpl();
for (Card card : permsSet) {
targets.add(card.getId());
}
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, true);
effect.setText("Return the exiled cards to the battlefield under their owner's control");
effect.setTargetPointer(new FixedTargets(targets, game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
}
return true;
} }
Cards targets = new CardsImpl(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENTS_NON_LAND, player.getId(), game));
return false; if (targets.isEmpty()) {
return false;
}
Effect effect = new ExileReturnBattlefieldNextEndStepTargetEffect().returnExiledOnly(true);
effect.setTargetPointer(new FixedTargets(targets, game));
return effect.apply(game, source);
} }
@Override @Override

View file

@ -1,26 +1,17 @@
package mage.cards.t; package mage.cards.t;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; import mage.abilities.effects.common.ExileUntilSourceLeavesEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.abilities.keyword.ChannelAbility; import mage.abilities.keyword.ChannelAbility;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil; import java.util.UUID;
/** /**
* *
@ -39,7 +30,8 @@ public final class TouchTheSpiritRealm extends CardImpl {
// Channel - {1}{W}, Discard Touch the Spirit Realm: Exile target artifact or creature. // Channel - {1}{W}, Discard Touch the Spirit Realm: Exile target artifact or creature.
// Return it to the battlefield under its owner's control at the beginning of the next end step. // Return it to the battlefield under its owner's control at the beginning of the next end step.
Ability channelAbility = new ChannelAbility("{1}{W}", new TouchTheSpiritRealmEffect()); Ability channelAbility = new ChannelAbility("{1}{W}",
new ExileReturnBattlefieldNextEndStepTargetEffect().withTextThatCard(false));
channelAbility.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE)); channelAbility.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE));
this.addAbility(channelAbility); this.addAbility(channelAbility);
} }
@ -53,35 +45,3 @@ public final class TouchTheSpiritRealm extends CardImpl {
return new TouchTheSpiritRealm(this); return new TouchTheSpiritRealm(this);
} }
} }
class TouchTheSpiritRealmEffect extends OneShotEffect {
public TouchTheSpiritRealmEffect() {
super(Outcome.Detriment);
staticText = "Exile target artifact or creature. Return it to the battlefield under its owner's control at the beginning of the next end step";
}
private TouchTheSpiritRealmEffect(final TouchTheSpiritRealmEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (player == null || permanent == null) {
return false;
}
Card card = permanent.getMainCard();
player.moveCardsToExile(permanent, source, game, true, CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source));
ReturnToBattlefieldUnderOwnerControlTargetEffect returnEffect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
returnEffect.setTargetPointer(new FixedTarget(card,game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(returnEffect), source);
return true;
}
@Override
public TouchTheSpiritRealmEffect copy() {
return new TouchTheSpiritRealmEffect(this);
}
}

View file

@ -2,7 +2,7 @@
package mage.cards.t; package mage.cards.t;
import java.util.UUID; import java.util.UUID;
import mage.abilities.effects.common.MistmeadowWitchEffect; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
@ -19,7 +19,7 @@ public final class TurnToMist extends CardImpl {
// Exile target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step. // Exile target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step.
this.getSpellAbility().addEffect(new MistmeadowWitchEffect()); this.getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetCreaturePermanent());
} }

View file

@ -1,27 +1,18 @@
package mage.cards.t; package mage.cards.t;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.VigilanceAbility;
import mage.abilities.keyword.WardAbility; import mage.abilities.keyword.WardAbility;
import mage.cards.AdventureCard; import mage.cards.AdventureCard;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game; import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
import java.util.UUID; import java.util.UUID;
@ -30,6 +21,11 @@ import java.util.UUID;
*/ */
public final class TwiningTwins extends AdventureCard { public final class TwiningTwins extends AdventureCard {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature");
static {
filter.add(TokenPredicate.FALSE);
}
public TwiningTwins(UUID ownerId, CardSetInfo setInfo) { public TwiningTwins(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{2}{U}{U}", "Swift Spiral", "{1}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{2}{U}{U}", "Swift Spiral", "{1}{W}");
@ -49,8 +45,8 @@ public final class TwiningTwins extends AdventureCard {
// Swift Spiral // Swift Spiral
// Exile target nontoken creature. Return it to the battlefield under its owners control at the beginning of the next end step. // Exile target nontoken creature. Return it to the battlefield under its owners control at the beginning of the next end step.
this.getSpellCard().getSpellAbility().addEffect(new TwiningTwinsEffect()); this.getSpellCard().getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect().withTextThatCard(false));
this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_NON_TOKEN)); this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
this.finalizeAdventure(); this.finalizeAdventure();
} }
@ -64,36 +60,3 @@ public final class TwiningTwins extends AdventureCard {
return new TwiningTwins(this); return new TwiningTwins(this);
} }
} }
class TwiningTwinsEffect extends OneShotEffect {
TwiningTwinsEffect() {
super(Outcome.Detriment);
staticText = "Exile target nontoken creature. Return it to the battlefield under its "
+ "owner's control at the beginning of the next end step";
}
private TwiningTwinsEffect(final TwiningTwinsEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (player == null || permanent == null) {
return false;
}
player.moveCardsToExile(permanent, source, game, true, CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source));
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setText("Return the exiled card to the battlefield under its owner's control");
effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}
@Override
public TwiningTwinsEffect copy() {
return new TwiningTwinsEffect(this);
}
}

View file

@ -1,28 +1,19 @@
package mage.cards.v; package mage.cards.v;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility; import mage.abilities.LoyaltyAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.GetEmblemEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect;
import mage.abilities.effects.common.combat.CantBeBlockedAllEffect; import mage.abilities.effects.common.combat.CantBeBlockedAllEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.command.emblems.VenserTheSojournerEmblem; import mage.game.command.emblems.VenserTheSojournerEmblem;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/** /**
* @author nantuko * @author nantuko
@ -43,7 +34,7 @@ public final class VenserTheSojourner extends CardImpl {
this.setStartingLoyalty(3); this.setStartingLoyalty(3);
// +2: Exile target permanent you own. Return it to the battlefield under your control at the beginning of the next end step. // +2: Exile target permanent you own. Return it to the battlefield under your control at the beginning of the next end step.
LoyaltyAbility ability1 = new LoyaltyAbility(new VenserTheSojournerEffect(), 2); LoyaltyAbility ability1 = new LoyaltyAbility(new ExileReturnBattlefieldNextEndStepTargetEffect().underYourControl(true).withTextThatCard(false), 2);
Target target = new TargetPermanent(filter); Target target = new TargetPermanent(filter);
ability1.addTarget(target); ability1.addTarget(target);
this.addAbility(ability1); this.addAbility(ability1);
@ -66,46 +57,3 @@ public final class VenserTheSojourner extends CardImpl {
} }
} }
class VenserTheSojournerEffect extends OneShotEffect {
private static final String effectText = "Exile target permanent you own. Return it to the battlefield under your control at the beginning of the next end step";
VenserTheSojournerEffect() {
super(Outcome.Benefit);
staticText = effectText;
}
private VenserTheSojournerEffect(final VenserTheSojournerEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source);
if (controller != null && sourceObject != null) {
if (getTargetPointer().getFirst(game, source) != null) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
if (controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourceObject.getIdName(), source, game, Zone.BATTLEFIELD, true)) {
//create delayed triggered ability
Effect effect = new ReturnToBattlefieldUnderYourControlTargetEffect();
effect.setText("Return it to the battlefield under your control at the beginning of the next end step");
effect.setTargetPointer(new FixedTarget(permanent.getId(), game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}
}
}
}
return false;
}
@Override
public VenserTheSojournerEffect copy() {
return new VenserTheSojournerEffect(this);
}
}

View file

@ -3,20 +3,17 @@ package mage.cards.v;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FlashAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.AttackedThisTurnWatcher; import mage.watchers.common.AttackedThisTurnWatcher;
@ -60,7 +57,7 @@ public final class VizierOfDeferment extends CardImpl {
class VizierOfDefermentEffect extends OneShotEffect { class VizierOfDefermentEffect extends OneShotEffect {
public VizierOfDefermentEffect() { VizierOfDefermentEffect() {
super(Outcome.Detriment); super(Outcome.Detriment);
staticText = "you may exile target creature if it attacked or blocked this turn. " + staticText = "you may exile target creature if it attacked or blocked this turn. " +
"Return that card to the battlefield under its owner's control at the beginning of the next end step"; "Return that card to the battlefield under its owner's control at the beginning of the next end step";
@ -73,8 +70,6 @@ class VizierOfDefermentEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget()); Permanent permanent = game.getPermanent(source.getFirstTarget());
Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
AttackedThisTurnWatcher watcherAttacked = game.getState().getWatcher(AttackedThisTurnWatcher.class); AttackedThisTurnWatcher watcherAttacked = game.getState().getWatcher(AttackedThisTurnWatcher.class);
BlockedThisTurnWatcher watcherBlocked = game.getState().getWatcher(BlockedThisTurnWatcher.class); BlockedThisTurnWatcher watcherBlocked = game.getState().getWatcher(BlockedThisTurnWatcher.class);
boolean attackedOrBlocked = false; boolean attackedOrBlocked = false;
@ -84,18 +79,12 @@ class VizierOfDefermentEffect extends OneShotEffect {
if (watcherBlocked != null && watcherBlocked.checkIfBlocked(permanent, game)) { if (watcherBlocked != null && watcherBlocked.checkIfBlocked(permanent, game)) {
attackedOrBlocked = true; attackedOrBlocked = true;
} }
if (controller != null if (!attackedOrBlocked) {
&& attackedOrBlocked return false;
&& sourcePermanent != null) {
if (controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourcePermanent.getIdName(), source, game, Zone.BATTLEFIELD, true)) {
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setText("Return that card to the battlefield under its owner's control at the beginning of the next end step");
effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}
} }
return false; Effect effect = new ExileReturnBattlefieldNextEndStepTargetEffect();
effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game));
return effect.apply(game, source);
} }
@Override @Override

View file

@ -1,22 +1,11 @@
package mage.cards.v; package mage.cards.v;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CipherEffect; import mage.abilities.effects.common.CipherEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -29,7 +18,7 @@ public final class Voidwalk extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}");
// Exile target creature. Return it to the battlefield under its owner's control at the beginning of the next end step. // Exile target creature. Return it to the battlefield under its owner's control at the beginning of the next end step.
this.getSpellAbility().addEffect(new VoidwalkEffect()); this.getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect().withTextThatCard(false));
this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetCreaturePermanent());
// Cipher // Cipher
@ -45,38 +34,3 @@ public final class Voidwalk extends CardImpl {
return new Voidwalk(this); return new Voidwalk(this);
} }
} }
class VoidwalkEffect extends OneShotEffect {
public VoidwalkEffect() {
super(Outcome.Detriment);
staticText = "Exile target creature. Return it to the battlefield under its owner's control at the beginning of the next end step";
}
private VoidwalkEffect(final VoidwalkEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source);
if (controller != null && permanent != null && sourceObject != null) {
if (controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourceObject.getIdName(), source, game, Zone.BATTLEFIELD, true)) {
//create delayed triggered ability
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setText("Return that card to the battlefield under its owner's control at the beginning of the next end step");
effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}
}
return false;
}
@Override
public VoidwalkEffect copy() {
return new VoidwalkEffect(this);
}
}

View file

@ -2,22 +2,14 @@ package mage.cards.v;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -30,7 +22,9 @@ public final class VoyagerStaff extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}");
// {2}, Sacrifice Voyager Staff: Exile target creature. Return the exiled card to the battlefield under its owner's control at the beginning of the next end step. // {2}, Sacrifice Voyager Staff: Exile target creature. Return the exiled card to the battlefield under its owner's control at the beginning of the next end step.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new VoyagerStaffEffect(), new GenericManaCost(2)); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new ExileReturnBattlefieldNextEndStepTargetEffect().returnExiledOnly(true),
new GenericManaCost(2));
ability.addCost(new SacrificeSourceCost()); ability.addCost(new SacrificeSourceCost());
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);
@ -45,38 +39,3 @@ public final class VoyagerStaff extends CardImpl {
return new VoyagerStaff(this); return new VoyagerStaff(this);
} }
} }
class VoyagerStaffEffect extends OneShotEffect {
public VoyagerStaffEffect() {
super(Outcome.Detriment);
staticText = "exile target creature. Return the exiled card to the battlefield under its owner's control at the beginning of the next end step";
}
private VoyagerStaffEffect(final VoyagerStaffEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (controller != null && creature != null && sourcePermanent != null) {
if (controller.moveCardToExileWithInfo(creature, source.getSourceId(), sourcePermanent.getIdName(), source, game, Zone.BATTLEFIELD, true)) {
//create delayed triggered ability
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, true);
effect.setText("Return the exiled card to the battlefield under its owner's control at the beginning of the next end step");
effect.setTargetPointer(new FixedTarget(creature.getId(), game.getState().getZoneChangeCounter(creature.getId())));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}
}
return false;
}
@Override
public VoyagerStaffEffect copy() {
return new VoyagerStaffEffect(this);
}
}

View file

@ -1,38 +1,42 @@
package mage.cards.y; package mage.cards.y;
import mage.MageInt; import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.abilities.keyword.CompanionAbility; import mage.abilities.keyword.CompanionAbility;
import mage.abilities.keyword.CompanionCondition; import mage.abilities.keyword.CompanionCondition;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.*; import mage.cards.Card;
import mage.constants.*; import mage.cards.CardImpl;
import mage.filter.FilterPermanent; import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTargets;
import mage.util.CardUtil;
import mage.util.ExileUtil;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
public final class YorionSkyNomad extends CardImpl { public final class YorionSkyNomad extends CardImpl {
private static final FilterControlledPermanent filter =
new FilterControlledPermanent("other nonland permanents you own and control");
static {
filter.add(Predicates.not(CardType.LAND.getPredicate()));
filter.add(TargetController.YOU.getOwnerPredicate());
filter.add(AnotherPredicate.instance);
}
private static final String ruleText = "exile any number of other nonland permanents you own and control. " +
"Return those cards to the battlefield at the beginning of the next end step.";
public YorionSkyNomad(UUID ownerId, CardSetInfo setInfo) { public YorionSkyNomad(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[] {CardType.CREATURE}, "{3}{W/U}{W/U}"); super(ownerId, setInfo, new CardType[] {CardType.CREATURE}, "{3}{W/U}{W/U}");
@ -50,7 +54,10 @@ public final class YorionSkyNomad extends CardImpl {
// When Yorion enters the battlefield, exile any number of other nonland permanents you own // When Yorion enters the battlefield, exile any number of other nonland permanents you own
// and control. Return those cards to the battlefield at the beginning of the next end step. // and control. Return those cards to the battlefield at the beginning of the next end step.
this.addAbility(new EntersBattlefieldTriggeredAbility(new YorionSkyNomadEffect())); Ability ability = new EntersBattlefieldTriggeredAbility(
new ExileReturnBattlefieldNextEndStepTargetEffect().setText(ruleText));
ability.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, filter, true));
this.addAbility(ability);
} }
private YorionSkyNomad(final YorionSkyNomad card) { private YorionSkyNomad(final YorionSkyNomad card) {
@ -76,51 +83,3 @@ enum YorionSkyNomadCompanionCondition implements CompanionCondition {
return deck.size() >= minimumDeckSize + 20; return deck.size() >= minimumDeckSize + 20;
} }
} }
class YorionSkyNomadEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterControlledPermanent("other nonland permanents you own and control");
static {
filter.add(Predicates.not(CardType.LAND.getPredicate()));
filter.add(TargetController.YOU.getOwnerPredicate());
filter.add(AnotherPredicate.instance);
}
YorionSkyNomadEffect() {
super(Outcome.Benefit);
staticText = "exile any number of other nonland permanents you own and control. " +
"Return those cards to the battlefield at the beginning of the next end step.";
}
private YorionSkyNomadEffect(final YorionSkyNomadEffect effect) {
super(effect);
}
@Override
public YorionSkyNomadEffect copy() {
return new YorionSkyNomadEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (sourceObject == null || controller == null) {
return false;
}
TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true);
controller.choose(outcome, target, source, game);
Set<Card> toExile = target.getTargets().stream().map(game::getPermanent).collect(Collectors.toSet());
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
controller.moveCardsToExile(toExile, source, game, true, exileId, sourceObject.getIdName());
Cards cardsToReturn = ExileUtil.returnCardsFromExile(toExile, game);
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setTargetPointer(new FixedTargets(cardsToReturn, game));
AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
}

View file

@ -0,0 +1,83 @@
package org.mage.test.cards.single.clb;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class LaezelsAcrobaticsTest extends CardTestPlayerBase {
// {3}{W} Instant
// Exile all nontoken creatures you control, then roll a d20.
// 19 | Return those cards to the battlefield under their owners control at the beginning of the next end step.
// 1020 | Return those cards to the battlefield under their owners control, then exile them again. Return those cards to the battlefield under their owners control at the beginning of the next end step.
private static final String acrobatics = "Lae'zel's Acrobatics";
// {2}{W} Creature Human Knight
// First strike
// When Attended Knight enters the battlefield, create a 1/1 white Soldier creature token.
private static final String knight = "Attended Knight";
// When Auramancer enters the battlefield, you may return target enchantment card from your graveyard to your hand.
private static final String auramancer = "Auramancer";
private static final String wings = "Nimbus Wings"; // aura
// Whenever you roll one or more dice, Brazen Dwarf deals 1 damage to each opponent.
private static final String dwarf = "Brazen Dwarf"; // not on the battlefield when die rolled, so should not trigger
@Test
public void testRollLow() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 7);
addCard(Zone.BATTLEFIELD, playerA, auramancer);
addCard(Zone.BATTLEFIELD, playerA, dwarf);
addCard(Zone.HAND, playerA, knight);
addCard(Zone.HAND, playerA, acrobatics);
addCard(Zone.GRAVEYARD, playerA, wings, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, knight);
setDieRollResult(playerA, 9);
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, acrobatics);
setChoice(playerA, "When {this} enters the battlefield, create"); // order triggers
setChoice(playerA, true); // Auramancer: yes to return
addTarget(playerA, wings); // enchantment to return
setStrictChooseMode(true);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertGraveyardCount(playerA, wings, 1);
assertHandCount(playerA, wings, 1);
assertPermanentCount(playerA, "Soldier Token", 2);
assertLife(playerA, 20);
assertLife(playerB, 20);
}
@Test
public void testRollHigh() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 7);
addCard(Zone.BATTLEFIELD, playerA, auramancer);
addCard(Zone.BATTLEFIELD, playerA, dwarf);
addCard(Zone.HAND, playerA, knight);
addCard(Zone.HAND, playerA, acrobatics);
addCard(Zone.GRAVEYARD, playerA, wings, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, knight);
setDieRollResult(playerA, 10);
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, acrobatics);
setChoice(playerA, "When {this} enters the battlefield, create"); // order triggers
setChoice(playerA, true); // Auramancer: yes to return
addTarget(playerA, wings); // enchantment to return
setChoice(playerA, "When {this} enters the battlefield, create"); // order triggers
setChoice(playerA, true); // Auramancer: yes to return
addTarget(playerA, wings); // enchantment to return
setStrictChooseMode(true);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertGraveyardCount(playerA, wings, 0);
assertHandCount(playerA, wings, 2);
assertPermanentCount(playerA, "Soldier Token", 3);
assertLife(playerA, 20);
assertLife(playerB, 20);
}
}

View file

@ -0,0 +1,110 @@
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardsImpl;
import mage.constants.Outcome;
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;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author xenohedron
*/
public class ExileReturnBattlefieldNextEndStepTargetEffect extends OneShotEffect {
private boolean yourControl;
private boolean textThatCard;
private boolean exiledOnly;
public ExileReturnBattlefieldNextEndStepTargetEffect() {
super(Outcome.Neutral);
this.yourControl = false;
this.textThatCard = true;
this.exiledOnly = false;
}
protected ExileReturnBattlefieldNextEndStepTargetEffect(final ExileReturnBattlefieldNextEndStepTargetEffect effect) {
super(effect);
this.yourControl = effect.yourControl;
this.textThatCard = effect.textThatCard;
this.exiledOnly = effect.exiledOnly;
}
public ExileReturnBattlefieldNextEndStepTargetEffect underYourControl(boolean yourControl) {
this.yourControl = yourControl;
return this;
}
public ExileReturnBattlefieldNextEndStepTargetEffect withTextThatCard(boolean textThatCard) {
this.textThatCard = textThatCard;
return this;
}
public ExileReturnBattlefieldNextEndStepTargetEffect returnExiledOnly(boolean exiledOnly) {
this.exiledOnly = exiledOnly;
return this;
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Set<Card> toExile = getTargetPointer().getTargets(game, source)
.stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.collect(Collectors.toCollection(LinkedHashSet::new));
if (toExile.isEmpty()) {
return false;
}
controller.moveCardsToExile(toExile, source, game, true, CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source));
Effect effect = yourControl
? new ReturnToBattlefieldUnderYourControlTargetEffect(exiledOnly)
: new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, exiledOnly);
effect.setTargetPointer(new FixedTargets(new CardsImpl(toExile), game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}
@Override
public ExileReturnBattlefieldNextEndStepTargetEffect copy() {
return new ExileReturnBattlefieldNextEndStepTargetEffect(this);
}
@Override
public String getText(Mode mode) {
if (staticText != null && !staticText.isEmpty()) {
return staticText;
}
String text = "exile " + getTargetPointer().describeTargets(mode.getTargets(), "that creature") + ". Return ";
boolean plural = getTargetPointer().isPlural(mode.getTargets());
if (exiledOnly) {
text += plural ? "the exiled cards" : "the exiled card";
} else if (textThatCard) {
text += plural ? "those cards" : "that card";
} else {
text += plural ? "them" : "it";
}
text += " to the battlefield";
if (yourControl) {
text += " under your control";
} else {
text += " under " + (plural ? "their" : "its") + " owner's control";
}
return text + " at the beginning of the next end step";
}
}

View file

@ -8,12 +8,12 @@ import mage.constants.Outcome;
import mage.constants.PutCards; import mage.constants.PutCards;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.stream.Collectors;
/** /**
* @author xenohedron * @author xenohedron
@ -50,15 +50,15 @@ public class ExileThenReturnTargetEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Set<Card> toFlicker = new LinkedHashSet<>(); if (controller == null) {
for (UUID targetId : getTargetPointer().getTargets(game, source)) { return false;
Permanent permanent = game.getPermanent(targetId);
if (permanent == null) {
continue;
}
toFlicker.add(permanent);
} }
if (controller == null || toFlicker.isEmpty()) { Set<Card> toFlicker = getTargetPointer().getTargets(game, source)
.stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.collect(Collectors.toCollection(LinkedHashSet::new));
if (toFlicker.isEmpty()) {
return false; return false;
} }
controller.moveCards(toFlicker, Zone.EXILED, source, game); controller.moveCards(toFlicker, Zone.EXILED, source, game);

View file

@ -1,47 +0,0 @@
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
/**
* Created by Eric on 9/24/2016.
*/
public class MistmeadowWitchEffect extends OneShotEffect {
public MistmeadowWitchEffect() {
super(Outcome.Detriment);
staticText = "Exile target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step";
}
private MistmeadowWitchEffect(final MistmeadowWitchEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (player == null || permanent == null) {
return false;
}
player.moveCardsToExile(permanent, source, game, true, CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source));
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
effect.setText("Return the exiled card to the battlefield under its owner's control");
effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}
@Override
public MistmeadowWitchEffect copy() {
return new MistmeadowWitchEffect(this);
}
}

View file

@ -1,34 +0,0 @@
package mage.util;
import java.util.Set;
import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.cards.MeldCard;
import mage.game.Game;
import mage.game.permanent.PermanentCard;
import mage.game.permanent.PermanentMeld;
public class ExileUtil {
public static Cards returnCardsFromExile(Set<Card> cards, Game game) {
Cards cardsToReturn = new CardsImpl();
for (Card exiled : cards) {
if (exiled instanceof PermanentMeld) {
MeldCard meldCard = (MeldCard) ((PermanentCard) exiled).getCard();
Card topCard = meldCard.getTopHalfCard();
Card bottomCard = meldCard.getBottomHalfCard();
if (topCard.getZoneChangeCounter(game) == meldCard.getTopLastZoneChangeCounter()) {
cardsToReturn.add(topCard);
}
if (bottomCard.getZoneChangeCounter(game) == meldCard.getBottomLastZoneChangeCounter()) {
cardsToReturn.add(bottomCard);
}
} else if (exiled.getZoneChangeCounter(game) == game.getState().getZoneChangeCounter(exiled.getId()) - 1) {
cardsToReturn.add(exiled);
}
}
return cardsToReturn;
}
}