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

@ -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.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author xenohedron
@ -50,15 +50,15 @@ public class ExileThenReturnTargetEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Set<Card> toFlicker = new LinkedHashSet<>();
for (UUID targetId : getTargetPointer().getTargets(game, source)) {
Permanent permanent = game.getPermanent(targetId);
if (permanent == null) {
continue;
}
toFlicker.add(permanent);
if (controller == null) {
return false;
}
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;
}
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;
}
}