refactored card.moveToExile usages A through D

heavily reworked Dark Impostor and Dimensional Breach
This commit is contained in:
Evan Kranzler 2021-02-28 16:10:23 -05:00
parent 129a477f56
commit 4a09654743
8 changed files with 248 additions and 247 deletions

View file

@ -1,22 +1,22 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt; import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.condition.common.MetalcraftCondition; import mage.abilities.condition.common.MetalcraftCondition;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect;
import mage.abilities.hint.common.MetalcraftHint; import mage.abilities.hint.common.MetalcraftHint;
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.*; import mage.constants.*;
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.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -37,7 +37,10 @@ public final class ArgentSphinx extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// <i>Metalcraft</i> &mdash; {U}: Exile Argent Sphinx. Return it to the battlefield under your control at the beginning of the next end step. Activate this ability only if you control three or more artifacts. // <i>Metalcraft</i> &mdash; {U}: Exile Argent Sphinx. Return it to the battlefield under your control at the beginning of the next end step. Activate this ability only if you control three or more artifacts.
Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new ArgentSphinxEffect(), new ManaCostsImpl("{U}"), MetalcraftCondition.instance); Ability ability = new ActivateIfConditionActivatedAbility(
Zone.BATTLEFIELD, new ArgentSphinxEffect(),
new ManaCostsImpl("{U}"), MetalcraftCondition.instance
);
ability.setAbilityWord(AbilityWord.METALCRAFT); ability.setAbilityWord(AbilityWord.METALCRAFT);
ability.addHint(MetalcraftHint.instance); ability.addHint(MetalcraftHint.instance);
this.addAbility(ability); this.addAbility(ability);
@ -56,37 +59,38 @@ public final class ArgentSphinx extends CardImpl {
class ArgentSphinxEffect extends OneShotEffect { class ArgentSphinxEffect extends OneShotEffect {
private static final String effectText = "Exile {this}. Return it to the battlefield under your control at the beginning of the next end step"; private static final String effectText = "Exile {this}. Return it to the battlefield " +
"under your control at the beginning of the next end step";
ArgentSphinxEffect() { ArgentSphinxEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
staticText = effectText; staticText = effectText;
} }
ArgentSphinxEffect(ArgentSphinxEffect effect) { private ArgentSphinxEffect(ArgentSphinxEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId()); Player player = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId()); Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent != null && sourceObject != null) { if (player == null || permanent == null) {
if (permanent.moveToExile(source.getSourceId(), sourceObject.getIdName(), 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(source.getSourceId(), game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}
}
return false; return false;
} }
Card card = permanent.getMainCard();
player.moveCards(permanent, Zone.EXILED, source, game);
//create delayed triggered ability
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
new ReturnToBattlefieldUnderYourControlTargetEffect().setText(
"Return it to the battlefield under your control at the beginning of the next end step"
).setTargetPointer(new FixedTarget(card, game))
), source);
return true;
}
@Override @Override
public ArgentSphinxEffect copy() { public ArgentSphinxEffect copy() {
return new ArgentSphinxEffect(this); return new ArgentSphinxEffect(this);
} }
} }

View file

@ -1,27 +1,23 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.effects.common.ExileTargetEffect;
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.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
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 java.util.UUID;
/** /**
*
* @author jeffwadsworth * @author jeffwadsworth
*/ */
public final class AshesToAshes extends CardImpl { public final class AshesToAshes extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonartifact creature"); private static final FilterPermanent filter = new FilterCreaturePermanent("nonartifact creatures");
static { static {
filter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); filter.add(Predicates.not(CardType.ARTIFACT.getPredicate()));
@ -30,9 +26,8 @@ public final class AshesToAshes extends CardImpl {
public AshesToAshes(UUID ownerId, CardSetInfo setInfo) { public AshesToAshes(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}");
// Exile two target nonartifact creatures. Ashes to Ashes deals 5 damage to you. // Exile two target nonartifact creatures. Ashes to Ashes deals 5 damage to you.
this.getSpellAbility().addEffect(new AshesToAshesEffect()); this.getSpellAbility().addEffect(new ExileTargetEffect());
this.getSpellAbility().addTarget(new TargetPermanent(2, filter)); this.getSpellAbility().addTarget(new TargetPermanent(2, filter));
this.getSpellAbility().addEffect(new DamageControllerEffect(5)); this.getSpellAbility().addEffect(new DamageControllerEffect(5));
} }
@ -46,32 +41,3 @@ public final class AshesToAshes extends CardImpl {
return new AshesToAshes(this); return new AshesToAshes(this);
} }
} }
class AshesToAshesEffect extends OneShotEffect {
public AshesToAshesEffect() {
super(Outcome.Benefit);
staticText = "Exile two target nonartifact creatures";
}
public AshesToAshesEffect(final AshesToAshesEffect effect) {
super(effect);
}
@Override
public AshesToAshesEffect copy() {
return new AshesToAshesEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
UUID exileId = source.getSourceId();
for (UUID permanentId : targetPointer.getTargets(game, source)) {
Permanent target = game.getPermanent(permanentId);
if (target != null) {
target.moveToExile(exileId, "Ashes to Ashes", source, game);
}
}
return true;
}
}

View file

@ -115,7 +115,9 @@ class BaneAlleyBrokerDrawExileEffect extends OneShotEffect {
if (card == null || sourceObject == null) { if (card == null || sourceObject == null) {
return false; return false;
} }
if (!card.moveToExile(CardUtil.getExileZoneId(game, source), sourceObject.getName(), source, game)) { if (!controller.moveCardsToExile(
card, source, game, false, CardUtil.getExileZoneId(game, source), sourceObject.getIdName()
)) {
return false; return false;
} }
card.setFaceDown(true, game); card.setFaceDown(true, game);

View file

@ -1,20 +1,22 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; 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.constants.Zone;
import mage.filter.StaticFilters; 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 java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class CryptIncursion extends CardImpl { public final class CryptIncursion extends CardImpl {
@ -23,9 +25,8 @@ public final class CryptIncursion extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}");
// Exile all creature cards from target player's graveyard. You gain 3 life for each card exiled this way. // Exile all creature cards from target player's graveyard. You gain 3 life for each card exiled this way.
this.getSpellAbility().addTarget(new TargetPlayer());
this.getSpellAbility().addEffect(new CryptIncursionEffect()); this.getSpellAbility().addEffect(new CryptIncursionEffect());
this.getSpellAbility().addTarget(new TargetPlayer());
} }
private CryptIncursion(final CryptIncursion card) { private CryptIncursion(final CryptIncursion card) {
@ -36,17 +37,17 @@ public final class CryptIncursion extends CardImpl {
public CryptIncursion copy() { public CryptIncursion copy() {
return new CryptIncursion(this); return new CryptIncursion(this);
} }
} }
class CryptIncursionEffect extends OneShotEffect { class CryptIncursionEffect extends OneShotEffect {
public CryptIncursionEffect() { CryptIncursionEffect() {
super(Outcome.Detriment); super(Outcome.Detriment);
staticText = "Exile all creature cards from target player's graveyard. You gain 3 life for each card exiled this way"; staticText = "Exile all creature cards from target player's graveyard. " +
"You gain 3 life for each card exiled this way";
} }
public CryptIncursionEffect(final CryptIncursionEffect effect) { private CryptIncursionEffect(final CryptIncursionEffect effect) {
super(effect); super(effect);
} }
@ -54,24 +55,20 @@ class CryptIncursionEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
Player targetPlayer = game.getPlayer(source.getFirstTarget()); Player targetPlayer = game.getPlayer(source.getFirstTarget());
if (player != null && targetPlayer != null) { Cards cards = new CardsImpl(targetPlayer.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, game));
int exiledCards = 0; player.moveCards(cards, Zone.EXILED, source, game);
for (Card card : targetPlayer.getGraveyard().getCards(game)) { int count = cards
if (StaticFilters.FILTER_CARD_CREATURE.match(card, game)) { .stream()
if (card.moveToExile(null, "", source, game)) { .map(game.getState()::getZone)
exiledCards++; .map(Zone.EXILED::equals)
} .mapToInt(x -> x ? 1 : 0)
} .sum();
} player.gainLife(3 * count, game, source);
player.gainLife(exiledCards * 3, game, source);
return true; return true;
} }
return false;
}
@Override @Override
public CryptIncursionEffect copy() { public CryptIncursionEffect copy() {
return new CryptIncursionEffect(this); return new CryptIncursionEffect(this);
} }
} }

View file

@ -1,11 +1,8 @@
package mage.cards.d; package mage.cards.d;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.ActivatedAbility; import mage.abilities.ActivatedAbility;
import mage.abilities.Mode;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
@ -17,14 +14,18 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.StaticFilters;
import mage.game.ExileZone;
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.util.CardUtil;
import java.util.UUID;
/** /**
*
* @author noxx * @author noxx
*
*/ */
public final class DarkImpostor extends CardImpl { public final class DarkImpostor extends CardImpl {
@ -37,12 +38,16 @@ public final class DarkImpostor extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// {4}{B}{B}: Exile target creature and put a +1/+1 counter on Dark Impostor. // {4}{B}{B}: Exile target creature and put a +1/+1 counter on Dark Impostor.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DarkImpostorExileTargetEffect(), new ManaCostsImpl("{4}{B}{B}")); Ability ability = new SimpleActivatedAbility(
new DarkImpostorExileTargetEffect(), new ManaCostsImpl("{4}{B}{B}")
);
ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance())
.setText("and put a +1/+1 counter on {this}"));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);
// Dark Impostor has all activated abilities of all creature cards exiled with it. // Dark Impostor has all activated abilities of all creature cards exiled with it.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DarkImpostorContinuousEffect())); this.addAbility(new SimpleStaticAbility(new DarkImpostorContinuousEffect()));
} }
private DarkImpostor(final DarkImpostor card) { private DarkImpostor(final DarkImpostor card) {
@ -57,11 +62,12 @@ public final class DarkImpostor extends CardImpl {
class DarkImpostorExileTargetEffect extends OneShotEffect { class DarkImpostorExileTargetEffect extends OneShotEffect {
public DarkImpostorExileTargetEffect() { DarkImpostorExileTargetEffect() {
super(Outcome.Exile); super(Outcome.Exile);
staticText = "exile target creature";
} }
public DarkImpostorExileTargetEffect(final DarkImpostorExileTargetEffect effect) { private DarkImpostorExileTargetEffect(final DarkImpostorExileTargetEffect effect) {
super(effect); super(effect);
} }
@ -72,46 +78,43 @@ class DarkImpostorExileTargetEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); Player player = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game); Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null) { if (player == null || permanent == null) {
permanent.moveToExile(null, null, source, game); return false;
if (sourceObject instanceof Permanent) {
((Permanent) sourceObject).imprint(permanent.getId(), game);
} }
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
if (sourcePermanent == null) {
return player.moveCards(permanent, Zone.EXILED, source, game);
} }
return new AddCountersSourceEffect(CounterType.P1P1.createInstance()).apply(game, source); return player.moveCardsToExile(
} permanent, source, game, true, CardUtil.getExileZoneId(game, source), sourcePermanent.getIdName()
);
@Override
public String getText(Mode mode) {
return "exile target creature and put a +1/+1 counter on {this}";
} }
} }
class DarkImpostorContinuousEffect extends ContinuousEffectImpl { class DarkImpostorContinuousEffect extends ContinuousEffectImpl {
public DarkImpostorContinuousEffect() { DarkImpostorContinuousEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
staticText = "{this} has all activated abilities of all creature cards exiled with it"; staticText = "{this} has all activated abilities of all creature cards exiled with it";
} }
public DarkImpostorContinuousEffect(final DarkImpostorContinuousEffect effect) { private DarkImpostorContinuousEffect(final DarkImpostorContinuousEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent perm = game.getPermanent(source.getSourceId()); Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (perm != null) { ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source));
for (UUID imprintedId : perm.getImprinted()) { if (permanent == null || exileZone == null || exileZone.isEmpty()) {
Card card = game.getCard(imprintedId); return false;
if (card != null) { }
for (Card card : exileZone.getCards(StaticFilters.FILTER_CARD_CREATURE, game)) {
for (Ability ability : card.getAbilities(game)) { for (Ability ability : card.getAbilities(game)) {
if (ability instanceof ActivatedAbility) { if (ability instanceof ActivatedAbility) {
perm.addAbility(ability.copy(), source.getSourceId(), game); permanent.addAbility(ability, source.getSourceId(), game);
}
}
} }
} }
} }
@ -122,5 +125,4 @@ class DarkImpostorContinuousEffect extends ContinuousEffectImpl {
public DarkImpostorContinuousEffect copy() { public DarkImpostorContinuousEffect copy() {
return new DarkImpostorContinuousEffect(this); return new DarkImpostorContinuousEffect(this);
} }
} }

View file

@ -1,18 +1,18 @@
package mage.cards.d; package mage.cards.d;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.CycleTriggeredAbility; import mage.abilities.common.CycleTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.DestroyAllEffect;
import mage.abilities.keyword.CyclingAbility; import mage.abilities.keyword.CyclingAbility;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; 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.constants.Zone;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
@ -20,8 +20,9 @@ import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author fireshoes * @author fireshoes
*/ */
public final class DecreeOfAnnihilation extends CardImpl { public final class DecreeOfAnnihilation extends CardImpl {
@ -36,8 +37,7 @@ public final class DecreeOfAnnihilation extends CardImpl {
this.addAbility(new CyclingAbility(new ManaCostsImpl("{5}{R}{R}"))); this.addAbility(new CyclingAbility(new ManaCostsImpl("{5}{R}{R}")));
// When you cycle Decree of Annihilation, destroy all lands. // When you cycle Decree of Annihilation, destroy all lands.
Ability ability = new CycleTriggeredAbility(new DestroyAllEffect(StaticFilters.FILTER_LANDS), false); this.addAbility(new CycleTriggeredAbility(new DestroyAllEffect(StaticFilters.FILTER_LANDS), false));
this.addAbility(ability);
} }
private DecreeOfAnnihilation(final DecreeOfAnnihilation card) { private DecreeOfAnnihilation(final DecreeOfAnnihilation card) {
@ -52,21 +52,23 @@ public final class DecreeOfAnnihilation extends CardImpl {
class DecreeOfAnnihilationEffect extends OneShotEffect { class DecreeOfAnnihilationEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterPermanent(""); private static final FilterPermanent filter = new FilterPermanent();
static { static {
filter.add(Predicates.or( filter.add(Predicates.or(
CardType.ARTIFACT.getPredicate(), CardType.ARTIFACT.getPredicate(),
CardType.CREATURE.getPredicate(), CardType.CREATURE.getPredicate(),
CardType.LAND.getPredicate())); CardType.LAND.getPredicate()
));
} }
public DecreeOfAnnihilationEffect() { DecreeOfAnnihilationEffect() {
super(Outcome.Detriment); super(Outcome.Detriment);
staticText = "Exile all artifacts, creatures, and lands from the battlefield, all cards from all graveyards, and all cards from all hands"; staticText = "Exile all artifacts, creatures, and lands from the battlefield, " +
"all cards from all graveyards, and all cards from all hands";
} }
public DecreeOfAnnihilationEffect(final DecreeOfAnnihilationEffect effect) { private DecreeOfAnnihilationEffect(final DecreeOfAnnihilationEffect effect) {
super(effect); super(effect);
} }
@ -77,26 +79,24 @@ class DecreeOfAnnihilationEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { Player controller = game.getPlayer(source.getControllerId());
permanent.moveToExile(null, "", source, game); if (controller == null) {
return false;
}
Cards cards = new CardsImpl();
for (Permanent permanent : game.getBattlefield().getActivePermanents(
filter, source.getControllerId(), source.getSourceId(), game
)) {
cards.add(permanent);
} }
for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
if (player != null) { if (player == null) {
for (UUID cid : player.getHand().copy()) { continue;
Card c = game.getCard(cid); }
if (c != null) { cards.addAll(player.getHand());
c.moveToExile(null, null, source, game); cards.addAll(player.getGraveyard());
} }
} return controller.moveCards(cards, Zone.EXILED, source, game);
for (UUID cid : player.getGraveyard().copy()) {
Card c = game.getCard(cid);
if (c != null) {
c.moveToExile(null, null, source, game);
}
}
}
}
return true;
} }
} }

View file

@ -1,31 +1,32 @@
package mage.cards.d; package mage.cards.d;
import java.util.UUID; import mage.MageObjectReference;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.StaticFilters;
import mage.filter.predicate.card.OwnerIdPredicate;
import mage.game.ExileZone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInExile;
import mage.util.CardUtil;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* * @author TheElk801
* @author jeffwadsworth
*/ */
public final class DimensionalBreach extends CardImpl { public final class DimensionalBreach extends CardImpl {
@ -34,8 +35,6 @@ public final class DimensionalBreach extends CardImpl {
// Exile all permanents. For as long as any of those cards remain exiled, at the beginning of each player's upkeep, that player returns one of the exiled cards they own to the battlefield. // Exile all permanents. For as long as any of those cards remain exiled, at the beginning of each player's upkeep, that player returns one of the exiled cards they own to the battlefield.
this.getSpellAbility().addEffect(new DimensionalBreachExileEffect()); this.getSpellAbility().addEffect(new DimensionalBreachExileEffect());
this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfUpkeepTriggeredAbility(Zone.ALL, new DimensionalBreachReturnFromExileEffect(), TargetController.ANY, false, true, null), new CardsStillInExileCondition(), null));
} }
private DimensionalBreach(final DimensionalBreach card) { private DimensionalBreach(final DimensionalBreach card) {
@ -50,12 +49,14 @@ public final class DimensionalBreach extends CardImpl {
class DimensionalBreachExileEffect extends OneShotEffect { class DimensionalBreachExileEffect extends OneShotEffect {
public DimensionalBreachExileEffect() { DimensionalBreachExileEffect() {
super(Outcome.Exile); super(Outcome.Exile);
staticText = "Exile all permanents."; staticText = "Exile all permanents. For as long as any of those cards remain exiled, " +
"at the beginning of each player's upkeep, that player returns " +
"one of the exiled cards they own to the battlefield.";
} }
public DimensionalBreachExileEffect(final DimensionalBreachExileEffect effect) { private DimensionalBreachExileEffect(final DimensionalBreachExileEffect effect) {
super(effect); super(effect);
} }
@ -66,75 +67,107 @@ class DimensionalBreachExileEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
MageObject sourceObject = source.getSourceObject(game); Player player = game.getPlayer(source.getControllerId());
Player controller = game.getPlayer(source.getControllerId()); if (player == null) {
if (sourceObject != null return false;
&& controller != null) { }
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), 0); Cards cards = new CardsImpl();
if (exileId != null) { game.getBattlefield().getActivePermanents(source.getControllerId(), game).stream().forEach(cards::add);
game.getBattlefield().getAllActivePermanents().forEach((permanent) -> { player.moveCards(cards, Zone.EXILED, source, game);
permanent.moveToExile(exileId, sourceObject.getName(), source, game); Set<MageObjectReference> morSet = cards
}); .getCards(game)
.stream()
.filter(c -> game.getState().getZone(c.getId()) == Zone.EXILED)
.map(c -> new MageObjectReference(c, game))
.collect(Collectors.toSet());
game.addDelayedTriggeredAbility(new DimensionalBreachDelayedTriggeredAbility(morSet), source);
return true; return true;
} }
} }
return false;
} class DimensionalBreachDelayedTriggeredAbility extends DelayedTriggeredAbility {
private final Set<MageObjectReference> morSet = new HashSet<>();
DimensionalBreachDelayedTriggeredAbility(Set<MageObjectReference> morSet) {
super(new DimensionalBreachReturnEffect(morSet), Duration.Custom, false, false);
this.morSet.addAll(morSet);
} }
class DimensionalBreachReturnFromExileEffect extends OneShotEffect { private DimensionalBreachDelayedTriggeredAbility(final DimensionalBreachDelayedTriggeredAbility ability) {
super(ability);
public DimensionalBreachReturnFromExileEffect() { this.morSet.addAll(ability.morSet);
super(Outcome.PutCardInPlay);
staticText = "For as long as any of those cards remain exiled, at the beginning of each player's upkeep, that player returns one of the exiled cards they own to the battlefield.";
}
public DimensionalBreachReturnFromExileEffect(final DimensionalBreachReturnFromExileEffect effect) {
super(effect);
} }
@Override @Override
public DimensionalBreachReturnFromExileEffect copy() { public boolean checkEventType(GameEvent event, Game game) {
return new DimensionalBreachReturnFromExileEffect(this); return event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return morSet.stream().map(mor -> mor.getCard(game)).anyMatch(Objects::nonNull);
}
@Override
public DimensionalBreachDelayedTriggeredAbility copy() {
return new DimensionalBreachDelayedTriggeredAbility(this);
}
@Override
public boolean isInactive(Game game) {
return morSet.stream().map(mor -> mor.getCard(game)).noneMatch(Objects::nonNull);
}
@Override
public String getRule() {
return "For as long as any of those cards remain exiled, at the beginning of each player's upkeep, " +
"that player returns one of the exiled cards they own to the battlefield.";
}
}
class DimensionalBreachReturnEffect extends OneShotEffect {
private final Set<MageObjectReference> morSet = new HashSet<>();
DimensionalBreachReturnEffect(Set<MageObjectReference> morSet) {
super(Outcome.PutCardInPlay);
this.morSet.addAll(morSet);
}
private DimensionalBreachReturnEffect(final DimensionalBreachReturnEffect effect) {
super(effect);
this.morSet.addAll(effect.morSet);
}
@Override
public DimensionalBreachReturnEffect copy() {
return new DimensionalBreachReturnEffect(this);
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
if (player != null) {
FilterCard filter = new FilterCard("card you own from the Dimensional Breach exile");
filter.add(new OwnerIdPredicate(player.getId()));
TargetCardInExile target = new TargetCardInExile(filter, CardUtil.getExileZoneId(game, source.getSourceId(), 0));
target.setNotTarget(true);
if (target.canChoose(source.getSourceId(), player.getId(), game)) {
if (player.chooseTarget(Outcome.PutCardInPlay, target, source, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null
&& player.moveCards(card, Zone.BATTLEFIELD, source, game)) {
return true;
}
}
}
}
return false;
}
}
class CardsStillInExileCondition implements Condition {
@Override
public final boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getActivePlayerId()); Player player = game.getPlayer(game.getActivePlayerId());
if (player != null) { if (player == null) {
FilterCard filter = new FilterCard();
filter.add(new OwnerIdPredicate(player.getId()));
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), 0);
ExileZone exileZone = game.getExile().getExileZone(exileId);
return (exileZone != null
&& !exileZone.getCards(filter, game).isEmpty());
}
return false; return false;
} }
Cards cards = new CardsImpl(
morSet.stream()
.map(mor -> mor.getCard(game))
.filter(Objects::nonNull)
.filter(c -> c.isOwnedBy(game.getActivePlayerId()))
.collect(Collectors.toSet())
);
if (cards.isEmpty()) {
return false;
}
if (cards.size() > 1) {
TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD);
target.setNotTarget(true);
player.choose(outcome, cards, target, game);
cards.clear();
cards.add(target.getFirstTarget());
}
return player.moveCards(cards, Zone.BATTLEFIELD, source, game);
}
} }

View file

@ -1,14 +1,10 @@
package mage.cards.d; package mage.cards.d;
import java.util.UUID;
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.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToHandSourceEffect;
import mage.abilities.keyword.DevoidAbility; import mage.abilities.keyword.DevoidAbility;
import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
@ -16,15 +12,17 @@ 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.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
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 mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.UUID;
/** /**
*
* @author fireshoes * @author fireshoes
*/ */
public final class DimensionalInfiltrator extends CardImpl { public final class DimensionalInfiltrator extends CardImpl {
@ -45,7 +43,7 @@ public final class DimensionalInfiltrator extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// {1}{C}: Exile the top card of target opponent's library. If it's a land card, you may return Dimensional Infiltrator to its owner's hand. // {1}{C}: Exile the top card of target opponent's library. If it's a land card, you may return Dimensional Infiltrator to its owner's hand.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DimensionalInfiltratorEffect(), new ManaCostsImpl("{1}{C}")); Ability ability = new SimpleActivatedAbility(new DimensionalInfiltratorEffect(), new ManaCostsImpl("{1}{C}"));
ability.addTarget(new TargetOpponent()); ability.addTarget(new TargetOpponent());
this.addAbility(ability); this.addAbility(ability);
} }
@ -62,12 +60,13 @@ public final class DimensionalInfiltrator extends CardImpl {
class DimensionalInfiltratorEffect extends OneShotEffect { class DimensionalInfiltratorEffect extends OneShotEffect {
public DimensionalInfiltratorEffect() { DimensionalInfiltratorEffect() {
super(Outcome.PutCreatureInPlay); super(Outcome.ReturnToHand);
this.staticText = "Exile the top card of target opponent's library. If it's a land card, you may return Dimensional Infiltrator to its owner's hand"; this.staticText = "exile the top card of target opponent's library. " +
"If it's a land card, you may return {this} to its owner's hand";
} }
public DimensionalInfiltratorEffect(final DimensionalInfiltratorEffect effect) { private DimensionalInfiltratorEffect(final DimensionalInfiltratorEffect effect) {
super(effect); super(effect);
} }
@ -78,24 +77,22 @@ class DimensionalInfiltratorEffect 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.getControllerId());
Player opponent = game.getPlayer(source.getFirstTarget()); Player opponent = game.getPlayer(source.getFirstTarget());
MageObject sourceObject = game.getObject(source.getSourceId()); if (player == null || opponent == null) {
if (opponent == null || controller == null || sourceObject == null) {
return false; return false;
} }
if (opponent.getLibrary().hasCards()) {
Card card = opponent.getLibrary().getFromTop(game); Card card = opponent.getLibrary().getFromTop(game);
if (card != null) { if (card == null) {
card.moveToExile(null, "Dimensional Infiltrator", source, game); return false;
if (card.isLand()) {
if (controller.chooseUse(Outcome.Neutral, "Return " + sourceObject.getIdName() + " to its owner's hand?", source, game)) {
new ReturnToHandSourceEffect(true).apply(game, source);
}
}
}
} }
player.moveCards(card, Zone.EXILED, source, game);
if (!card.isLand()) {
return true; return true;
} }
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
return permanent != null
&& player.chooseUse(outcome, "Return " + permanent.getName() + " to its owner's hand?", source, game)
&& player.moveCards(permanent, Zone.HAND, source, game);
}
} }