diff --git a/Mage.Sets/src/mage/cards/n/NashiMoonSagesScion.java b/Mage.Sets/src/mage/cards/n/NashiMoonSagesScion.java index 9b6a9325143..076116e003d 100644 --- a/Mage.Sets/src/mage/cards/n/NashiMoonSagesScion.java +++ b/Mage.Sets/src/mage/cards/n/NashiMoonSagesScion.java @@ -1,49 +1,30 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.cards.n; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; import mage.abilities.costs.CostsImpl; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.asthought.CanPlayCardControllerEffect; import mage.abilities.keyword.NinjutsuAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.cards.*; +import mage.constants.*; import mage.game.Game; -import mage.players.Player; -import mage.target.targetpointer.FixedTarget; -import mage.abilities.decorator.ConditionalAsThoughEffect; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.constants.AsThoughEffectType; -import mage.constants.WatcherScope; import mage.game.events.GameEvent; import mage.game.stack.Spell; +import mage.players.Player; import mage.util.CardUtil; import mage.watchers.Watcher; +import java.util.*; +import java.util.stream.Collectors; + /** - * - * @author jeffwadsworth + * @author TheElk801 */ public final class NashiMoonSagesScion extends CardImpl { @@ -60,8 +41,9 @@ public final class NashiMoonSagesScion extends CardImpl { this.addAbility(new NinjutsuAbility("{3}{B}")); // Whenever Nashi, Moon Sage's Scion deals combat damage to a player, exile the top card of each player's library. Until end of turn, you may play one of those cards. If you cast a spell this way, pay life equal to its mana value rather than paying its mana cost. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new NashiMoonSagesScionEffect(), false), new NashiMoonSagesScionWatcher(super.getId())); - + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new NashiMoonSagesScionEffect(), false + ), new NashiMoonSagesScionWatcher()); } private NashiMoonSagesScion(final NashiMoonSagesScion card) { @@ -76,12 +58,11 @@ public final class NashiMoonSagesScion extends CardImpl { class NashiMoonSagesScionEffect extends OneShotEffect { - Cards storeCardsThatWereInExile = new CardsImpl(); - Set cardsToExile = new HashSet<>(); - public NashiMoonSagesScionEffect() { super(Outcome.Benefit); - this.staticText = "exile the top card of each player's library. Until end of turn, you may play one of those cards. If you cast a spell this way, pay life equal to its mana value rather than paying its mana cost"; + this.staticText = "exile the top card of each player's library. Until end of turn, " + + "you may play one of those cards. If you cast a spell this way, " + + "pay life equal to its mana value rather than paying its mana cost"; } public NashiMoonSagesScionEffect(final NashiMoonSagesScionEffect effect) { @@ -95,121 +76,103 @@ class NashiMoonSagesScionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - storeCardsThatWereInExile.clear(); - cardsToExile.clear(); Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), game.getTurnNum()); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - Card topCard = player.getLibrary().getFromTop(game); - cardsToExile.add(topCard); - } - } - controller.moveCardsToExile(cardsToExile, source, game, true, exileId, game.getObject(source.getSourceId()).getIdName()); - NashiMoonSagesScionPlayEffect effect = new NashiMoonSagesScionPlayEffect(); - ConditionalAsThoughEffect conditionalEffect = new ConditionalAsThoughEffect(effect, new NashiMoonSagesScionCondition()); - conditionalEffect.setDuration(Duration.EndOfTurn); - game.getState().setValue("Result" + source.getSourceId().toString() + game.getTurn().toString(), Boolean.TRUE); - for (Card exiledCard : cardsToExile) { - if (game.getState().getZone(exiledCard.getId()) == Zone.EXILED) { - storeCardsThatWereInExile.add(exiledCard); - conditionalEffect.setTargetPointer(new FixedTarget(exiledCard.getId(), game)); - game.addEffect(conditionalEffect, source); - } - } - game.getState().setValue("Cards Exile" + source.getSourceId().toString() + game.getTurn().toString(), storeCardsThatWereInExile); - return true; + if (controller == null) { + return false; } - return false; - } -} - -class NashiMoonSagesScionCondition implements Condition { - - @Override - public boolean apply(Game game, Ability source) { - Watcher watcher = game.getState().getWatcher(NashiMoonSagesScionWatcher.class); - return (watcher != null - && watcher.conditionMet()); + Cards cards = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + cards.add(player.getLibrary().getFromTop(game)); + } + } + Set cardSet = cards.getCards(game); + controller.moveCardsToExile( + cardSet, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + NashiMoonSagesScionWatcher.addCards(source, cardSet, game); + for (Card card : cardSet) { + game.addEffect(new NashiMoonSagesScionPlayEffect(game, card), source); + } + return true; } } class NashiMoonSagesScionWatcher extends Watcher { - UUID sourceCardId; + private final Map>> morMap = new HashMap<>(); - public NashiMoonSagesScionWatcher(UUID sourceCardId) { + public NashiMoonSagesScionWatcher() { super(WatcherScope.GAME); - this.sourceCardId = sourceCardId; } @Override public void watch(GameEvent event, Game game) { - if (game.getState().getValue("Result" + sourceCardId.toString() + game.getTurn().toString()) != null) { - condition = (Boolean) game.getState().getValue("Result" + sourceCardId.toString() + game.getTurn().toString()); + if (event.getType() == GameEvent.EventType.CLEANUP_STEP_POST) { + morMap.entrySet().removeIf(e -> !e.getKey().zoneCounterIsCurrent(game)); + morMap.values() + .stream() + .flatMap(Collection::stream) + .map(set -> set.removeIf(mor -> !mor.zoneCounterIsCurrent(game))); + morMap.values().removeIf(Set::isEmpty); + return; } - UUID exileId = CardUtil.getExileZoneId(game, sourceCardId, game.getTurnNum()); - if (game.getState().getExile().getExileZone(exileId) != null - && game.getState().getExile().getExileZone(exileId).size() > 0) { - Cards cards = (Cards) game.getState().getValue("Cards Exile" + sourceCardId.toString() + game.getTurn().toString()); - // Cast spell - if (event.getType() == GameEvent.EventType.CAST_SPELL) { - Spell spell = (Spell) game.getObject(event.getSourceId()); - if (spell != null - && cards != null - && !cards.isEmpty() - && cards.contains(spell.getSourceId())) { - Ability approvingAbility = event.getAdditionalReference().getApprovingAbility(); - if (approvingAbility != null - && approvingAbility.getSourceId().equals(sourceCardId)) { - condition = false; - game.getState().setValue("Result" + sourceCardId.toString() + game.getTurn().toString(), Boolean.FALSE); - } - } - } - // Play land - if (event.getType() == GameEvent.EventType.PLAY_LAND) { - Card land = game.getCard(event.getSourceId()); - if (land != null - && cards != null - && !cards.isEmpty() - && cards.contains(land.getId())) { - Ability approvingAbility = event.getAdditionalReference().getApprovingAbility(); - if (approvingAbility != null - && approvingAbility.getSourceId().equals(sourceCardId)) { - condition = false; - game.getState().setValue("Result" + sourceCardId.toString() + game.getTurn().toString(), Boolean.FALSE); - } - } - } + if (event.getType() != GameEvent.EventType.SPELL_CAST || event.getAdditionalReference() == null) { + return; } + Spell spell = game.getSpell(event.getTargetId()); + if (spell == null) { + return; + } + morMap.getOrDefault( + event.getAdditionalReference().getApprovingMageObjectReference(), Collections.emptySet() + ).removeIf(set -> set + .stream() + .anyMatch(mor -> mor.getSourceId().equals(spell.getMainCard().getId()) + && mor.getZoneChangeCounter() + 1 == spell.getZoneChangeCounter(game))); } @Override public void reset() { super.reset(); + morMap.clear(); + } + + static void addCards(Ability source, Set cards, Game game) { + game.getState() + .getWatcher(NashiMoonSagesScionWatcher.class) + .morMap + .computeIfAbsent(new MageObjectReference(source), x -> new HashSet<>()) + .add(cards + .stream() + .map(card -> new MageObjectReference(card, game)) + .collect(Collectors.toSet())); + } + + static boolean checkCard(Game game, Ability source, MageObjectReference mor) { + return game.getState() + .getWatcher(NashiMoonSagesScionWatcher.class) + .morMap + .getOrDefault(new MageObjectReference(source), Collections.emptySet()) + .stream() + .flatMap(Collection::stream) + .anyMatch(mor::equals); } } -class NashiMoonSagesScionPlayEffect extends AsThoughEffectImpl { +class NashiMoonSagesScionPlayEffect extends CanPlayCardControllerEffect { - NashiMoonSagesScionPlayEffect() { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, - Duration.EndOfTurn, Outcome.Benefit); - staticText = ""; + NashiMoonSagesScionPlayEffect(Game game, Card card) { + super(game, card.getMainCard().getId(), card.getZoneChangeCounter(game), Duration.EndOfTurn); } private NashiMoonSagesScionPlayEffect(final NashiMoonSagesScionPlayEffect effect) { super(effect); } - @Override - public boolean apply(Game game, Ability source) { - return true; - } - @Override public NashiMoonSagesScionPlayEffect copy() { return new NashiMoonSagesScionPlayEffect(this); @@ -217,60 +180,21 @@ class NashiMoonSagesScionPlayEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - - Player controller = game.getPlayer(affectedControllerId); - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), game.getTurnNum()); - - Set cards = game.getState().getExile().getExileZone(exileId).getCards(game); - List targetsTest = getTargetPointer().getTargets(game, source); - if (cards != null - && targetsTest != null) { - for (UUID uuid : targetsTest) { - if (!cards.contains(game.getCard(uuid))) { - getTargetPointer().getTargets(game, source).remove(uuid); - } - } - } - - if (game.getState().getValue("Result" + source.getSourceId().toString() + game.getTurn().toString()) == Boolean.FALSE) { - this.discard(); + if (!super.applies(objectId, source, affectedControllerId, game) + || !NashiMoonSagesScionWatcher.checkCard(game, source, mor)) { return false; } - - List targets = getTargetPointer().getTargets(game, source); - if (targets.isEmpty()) { - this.discard(); - return false; + Card cardToCheck = mor.getCard(game); + if (cardToCheck.isLand(game)) { + return true; } - - UUID objectIdToCast = CardUtil.getMainCardId(game, objectId); - if (!targets.contains(objectIdToCast)) { - return false; - } - - Card cardToCheck = game.getCard(objectId); - if (cardToCheck == null) { - return false; - } - - // must be you - if (!affectedControllerId.equals(source.getControllerId())) { - return false; - } - - // must be in exile - if (game.getState().getZone(objectId) != Zone.EXILED) { - return false; - } - // allows to play/cast with alternative life cost - if (!cardToCheck.isLand(game)) { - PayLifeCost lifeCost = new PayLifeCost(cardToCheck.getSpellAbility().getManaCosts().manaValue()); - Costs newCosts = new CostsImpl(); - newCosts.add(lifeCost); - newCosts.addAll(cardToCheck.getSpellAbility().getCosts()); - controller.setCastSourceIdWithAlternateMana(cardToCheck.getId(), null, newCosts); - } + Player controller = game.getPlayer(source.getControllerId()); + PayLifeCost lifeCost = new PayLifeCost(cardToCheck.getSpellAbility().getManaCosts().manaValue()); + Costs newCosts = new CostsImpl<>(); + newCosts.add(lifeCost); + newCosts.addAll(cardToCheck.getSpellAbility().getCosts()); + controller.setCastSourceIdWithAlternateMana(cardToCheck.getId(), null, newCosts); return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java index 2e21df01784..4826c1d419b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java @@ -23,9 +23,9 @@ import java.util.UUID; */ public class CanPlayCardControllerEffect extends AsThoughEffectImpl { - private final MageObjectReference mor; - private final UUID playerId; - private final Condition condition; + protected final MageObjectReference mor; + protected final UUID playerId; + protected final Condition condition; public CanPlayCardControllerEffect(Game game, UUID cardId, int cardZCC, Duration duration) { this(game, cardId, cardZCC, duration, null, null);