[GRN] fixed Mnemonic Betrayal not allowing exiled cards to be cast correctly

This commit is contained in:
Evan Kranzler 2021-05-05 09:32:20 -04:00
parent 28dfaaffa1
commit 373a7f689e

View file

@ -1,21 +1,25 @@
package mage.cards.m; package mage.cards.m;
import mage.MageObjectReference;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility; import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.AsThoughManaEffect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileSpellEffect; import mage.abilities.effects.common.ExileSpellEffect;
import mage.cards.*; import mage.cards.*;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.players.ManaPoolItem;
import mage.players.Player; import mage.players.Player;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.HashMap;
import java.util.Map; import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* @author TheElk801 * @author TheElk801
@ -32,7 +36,7 @@ public final class MnemonicBetrayal extends CardImpl {
this.getSpellAbility().addEffect(new MnemonicBetrayalExileEffect()); this.getSpellAbility().addEffect(new MnemonicBetrayalExileEffect());
// Exile Mnemonic Betrayal. // Exile Mnemonic Betrayal.
this.getSpellAbility().addEffect(new ExileSpellEffect()); this.getSpellAbility().addEffect(new ExileSpellEffect().concatBy("<br>"));
} }
private MnemonicBetrayal(final MnemonicBetrayal card) { private MnemonicBetrayal(final MnemonicBetrayal card) {
@ -49,12 +53,11 @@ class MnemonicBetrayalExileEffect extends OneShotEffect {
public MnemonicBetrayalExileEffect() { public MnemonicBetrayalExileEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
this.staticText = "Exile all cards from all opponents' graveyards. " this.staticText = "exile all cards from all opponents graveyards. " +
+ "You may cast those cards this turn, " "You may cast spells from among those cards this turn, " +
+ "and you may spend mana as though it were mana of any type " "and you may spend mana as though it were mana of any type to cast those spells. " +
+ "to cast those spells. At the beginning of the next end step, " "At the beginning of the next end step, if any of those cards remain exiled, " +
+ "if any of those cards remain exiled, " "return them to their owners graveyards";
+ "return them to their owner's graveyards";
} }
public MnemonicBetrayalExileEffect(final MnemonicBetrayalExileEffect effect) { public MnemonicBetrayalExileEffect(final MnemonicBetrayalExileEffect effect) {
@ -73,131 +76,46 @@ class MnemonicBetrayalExileEffect extends OneShotEffect {
return false; return false;
} }
Cards cards = new CardsImpl(); Cards cards = new CardsImpl();
Map<UUID, Integer> cardMap = new HashMap<>(); game.getOpponents(source.getControllerId())
game.getOpponents(source.getControllerId()).stream().map((playerId) .stream()
-> game.getPlayer(playerId)).filter((player) -> (player != null)).forEachOrdered((player) -> { .map(game::getPlayer)
cards.addAll(player.getGraveyard()); .filter(Objects::nonNull)
}); .map(Player::getGraveyard)
cards.getCards(game).stream().map((card) -> { .map(g -> g.getCards(game))
cardMap.put(card.getId(), card.getZoneChangeCounter(game)); .forEach(cards::addAll);
return card; controller.moveCardsToExile(
}).map((card) -> { cards.getCards(game), source, game, true,
game.addEffect(new MnemonicBetrayalCastFromExileEffect(card, game), source); source.getSourceId(), CardUtil.getSourceLogName(game, source)
return card; );
}).forEachOrdered((card) -> { for (Card card : cards.getCards(game)) {
game.addEffect(new MnemonicBetrayalAnyColorEffect(card, game), source); if (card.isLand()) {
}); continue;
controller.moveCardsToExile(cards.getCards(game), source, game, true,
source.getSourceId(), source.getSourceObjectIfItStillExists(game).getName());
game.addDelayedTriggeredAbility(new MnemonicBetrayalDelayedTriggeredAbility(cards, cardMap), source);
return true;
}
}
class MnemonicBetrayalCastFromExileEffect extends AsThoughEffectImpl {
private final Card card;
private final int zoneCounter;
public MnemonicBetrayalCastFromExileEffect(Card card, Game game) {
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit);
this.card = card;
this.zoneCounter = card.getZoneChangeCounter(game) + 1;
}
public MnemonicBetrayalCastFromExileEffect(final MnemonicBetrayalCastFromExileEffect effect) {
super(effect);
this.card = effect.card;
this.zoneCounter = effect.zoneCounter;
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public MnemonicBetrayalCastFromExileEffect copy() {
return new MnemonicBetrayalCastFromExileEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
if (card.getZoneChangeCounter(game) != zoneCounter) {
this.discard();
return false;
}
return objectId.equals(card.getId())
&& card.getZoneChangeCounter(game) == zoneCounter
&& source.isControlledBy(affectedControllerId)
&& !card.isLand(); // cast only not play
}
}
class MnemonicBetrayalAnyColorEffect extends AsThoughEffectImpl implements AsThoughManaEffect {
private final Card card;
private final int zoneCounter;
public MnemonicBetrayalAnyColorEffect(Card card, Game game) {
super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit);
this.card = card;
this.zoneCounter = card.getZoneChangeCounter(game) + 1;
}
public MnemonicBetrayalAnyColorEffect(final MnemonicBetrayalAnyColorEffect effect) {
super(effect);
this.card = effect.card;
this.zoneCounter = effect.zoneCounter;
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public MnemonicBetrayalAnyColorEffect copy() {
return new MnemonicBetrayalAnyColorEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
objectId = CardUtil.getMainCardId(game, objectId); // for split cards
if (objectId.equals(card.getId())
&& card.getZoneChangeCounter(game) <= zoneCounter + 1
&& source.isControlledBy(affectedControllerId)) {
return true;
} else {
if (objectId.equals(card.getId())) {
this.discard();
} }
CardUtil.makeCardPlayable(game, source, card, Duration.EndOfTurn, true);
} }
return false; cards.retainZone(Zone.EXILED, game);
} game.addDelayedTriggeredAbility(new MnemonicBetrayalDelayedTriggeredAbility(
cards.stream()
@Override .map(uuid -> new MageObjectReference(uuid, game))
public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { .collect(Collectors.toSet())
return mana.getFirstAvailable(); ), source);
return true;
} }
} }
class MnemonicBetrayalDelayedTriggeredAbility extends DelayedTriggeredAbility { class MnemonicBetrayalDelayedTriggeredAbility extends DelayedTriggeredAbility {
private final Cards cards; private final Set<MageObjectReference> morSet = new HashSet<>();
private final Map<UUID, Integer> cardMap = new HashMap<>();
public MnemonicBetrayalDelayedTriggeredAbility(Cards cards, Map<UUID, Integer> cardMap) { public MnemonicBetrayalDelayedTriggeredAbility(Set<MageObjectReference> morSet) {
super(new MnemonicBetrayalReturnEffect(cards, cardMap)); super(new MnemonicBetrayalReturnEffect(morSet));
this.triggerOnlyOnce = true; this.triggerOnlyOnce = true;
this.cards = cards; this.morSet.addAll(morSet);
this.cardMap.putAll(cardMap);
} }
public MnemonicBetrayalDelayedTriggeredAbility(final MnemonicBetrayalDelayedTriggeredAbility ability) { public MnemonicBetrayalDelayedTriggeredAbility(final MnemonicBetrayalDelayedTriggeredAbility ability) {
super(ability); super(ability);
this.cards = ability.cards.copy(); this.morSet.addAll(ability.morSet);
this.cardMap.putAll(ability.cardMap);
} }
@Override @Override
@ -217,8 +135,7 @@ class MnemonicBetrayalDelayedTriggeredAbility extends DelayedTriggeredAbility {
@Override @Override
public boolean checkInterveningIfClause(Game game) { public boolean checkInterveningIfClause(Game game) {
return cards.stream().anyMatch((cardId) -> (game.getState().getZone(cardId) == Zone.EXILED return morSet.stream().map(mor -> mor.getCard(game)).anyMatch(Objects::nonNull);
&& game.getState().getZoneChangeCounter(cardId) == cardMap.getOrDefault(cardId, -5) + 1));
} }
@Override @Override
@ -231,19 +148,16 @@ class MnemonicBetrayalDelayedTriggeredAbility extends DelayedTriggeredAbility {
class MnemonicBetrayalReturnEffect extends OneShotEffect { class MnemonicBetrayalReturnEffect extends OneShotEffect {
private final Cards cards; private final Set<MageObjectReference> morSet = new HashSet<>();
private final Map<UUID, Integer> cardMap = new HashMap<>();
public MnemonicBetrayalReturnEffect(Cards cards, Map<UUID, Integer> cardMap) { public MnemonicBetrayalReturnEffect(Set<MageObjectReference> morSet) {
super(Outcome.Benefit); super(Outcome.Benefit);
this.cards = cards; this.morSet.addAll(morSet);
this.cardMap.putAll(cardMap);
} }
public MnemonicBetrayalReturnEffect(final MnemonicBetrayalReturnEffect effect) { public MnemonicBetrayalReturnEffect(final MnemonicBetrayalReturnEffect effect) {
super(effect); super(effect);
this.cards = effect.cards.copy(); this.morSet.addAll(effect.morSet);
this.cardMap.putAll(effect.cardMap);
} }
@Override @Override
@ -257,11 +171,11 @@ class MnemonicBetrayalReturnEffect extends OneShotEffect {
if (player == null) { if (player == null) {
return false; return false;
} }
Cards cardsToReturn = new CardsImpl(); return player != null && player.moveCards(new CardsImpl(
cards.getCards(game).stream().filter((card) -> (game.getState().getZone(card.getId()) == Zone.EXILED morSet.stream()
&& card.getZoneChangeCounter(game) == cardMap.getOrDefault(card.getId(), -5) + 1)).forEachOrdered((card) -> { .map(mor -> mor.getCard(game))
cardsToReturn.add(card); .filter(Objects::nonNull)
}); .collect(Collectors.toList())
return player.moveCards(cardsToReturn, Zone.GRAVEYARD, source, game); ), Zone.GRAVEYARD, source, game);
} }
} }