diff --git a/Mage.Sets/src/mage/cards/a/Aethertow.java b/Mage.Sets/src/mage/cards/a/Aethertow.java index d2c060a9bba..4922cb71427 100644 --- a/Mage.Sets/src/mage/cards/a/Aethertow.java +++ b/Mage.Sets/src/mage/cards/a/Aethertow.java @@ -7,12 +7,14 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.ConspireAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.common.TargetCreaturePermanent; /** @@ -58,9 +60,9 @@ class AethertowEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent targetCreature = game.getPermanent(targetPointer.getFirst(game, source)); + Player controller = game.getPlayer(source.getControllerId()); if (targetCreature != null) { - targetCreature.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - return true; + return controller.putCardsOnTopOfLibrary(targetCreature, game, source, true); } return false; } diff --git a/Mage.Sets/src/mage/cards/a/AmassTheComponents.java b/Mage.Sets/src/mage/cards/a/AmassTheComponents.java index 5d7c24dbad8..c3cdc37eced 100644 --- a/Mage.Sets/src/mage/cards/a/AmassTheComponents.java +++ b/Mage.Sets/src/mage/cards/a/AmassTheComponents.java @@ -71,8 +71,7 @@ class AmassTheComponentsEffect extends OneShotEffect { if (player.choose(Outcome.Detriment, player.getHand(), target, game)) { Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { - player.removeFromHand(card, game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); + return player.putCardsOnBottomOfLibrary(card, game, source, true); } } } diff --git a/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java b/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java index de15f1581de..308ddc69c14 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java +++ b/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java @@ -83,13 +83,9 @@ class BrutalizerExarchEffect2 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - Player player = game.getPlayer(permanent.getOwnerId()); - if (player == null) { - return false; - } - - return permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); + Player controller = game.getPlayer(source.getControllerId()); + if (permanent != null && controller != null) { + return controller.putCardsOnBottomOfLibrary(permanent, game, source, true); } return false; } diff --git a/Mage.Sets/src/mage/cards/c/ConsignToDream.java b/Mage.Sets/src/mage/cards/c/ConsignToDream.java index 451c0819ea6..32946ea4ebd 100644 --- a/Mage.Sets/src/mage/cards/c/ConsignToDream.java +++ b/Mage.Sets/src/mage/cards/c/ConsignToDream.java @@ -11,6 +11,7 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.TargetPermanent; /** @@ -58,15 +59,15 @@ class ConsignToDreamEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - boolean applied = false; Permanent target = game.getPermanent(source.getFirstTarget()); - if (target != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (target != null && controller != null) { if (target.getColor(game).isRed() || target.getColor(game).isGreen()) { - applied = target.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + return controller.putCardsOnTopOfLibrary(target, game, source, true); } else { - applied = target.moveToZone(Zone.HAND, source.getSourceId(), game, false); + return controller.moveCards(target, Zone.HAND, source, game); } } - return applied; + return false; } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DarkRevenant.java b/Mage.Sets/src/mage/cards/d/DarkRevenant.java index 8f42634f7ee..8e404392eca 100644 --- a/Mage.Sets/src/mage/cards/d/DarkRevenant.java +++ b/Mage.Sets/src/mage/cards/d/DarkRevenant.java @@ -10,6 +10,7 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Outcome; @@ -67,9 +68,9 @@ class DarkRevenantEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getSourceId()); if (card != null && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { - Player owner = game.getPlayer(card.getOwnerId()); - if(owner != null) { - return card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + Player controller = game.getPlayer(source.getControllerId()); + if(controller != null) { + return controller.putCardsOnTopOfLibrary(card, game, source, true); } } return true; diff --git a/Mage.Sets/src/mage/cards/d/DeadReckoning.java b/Mage.Sets/src/mage/cards/d/DeadReckoning.java index 1e3843ae00c..a12b0bd82fb 100644 --- a/Mage.Sets/src/mage/cards/d/DeadReckoning.java +++ b/Mage.Sets/src/mage/cards/d/DeadReckoning.java @@ -7,6 +7,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -59,22 +60,22 @@ class DeadReckoningEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); TargetCardInYourGraveyard target1 = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card in your graveyard")); TargetCreaturePermanent target2 = new TargetCreaturePermanent(); - if (you != null) { + if (controller != null) { if (target1.canChoose(source.getControllerId(), game) - && you.choose(Outcome.Benefit, target1, source.getSourceId(), game) + && controller.choose(Outcome.Benefit, target1, source.getSourceId(), game) && target2.canChoose(source.getControllerId(), game) - && you.choose(Outcome.Damage, target2, source.getSourceId(), game)) { + && controller.choose(Outcome.Damage, target2, source.getSourceId(), game)) { Card creatureInGraveyard = game.getCard(target1.getFirstTarget()); if (creatureInGraveyard != null) { - if (creatureInGraveyard.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true)) { + if (controller.putCardsOnTopOfLibrary(creatureInGraveyard, game, source, true)) { int power = creatureInGraveyard.getPower().getValue(); Permanent creature = game.getPermanent(target2.getFirstTarget()); if (creature != null) { - creature.damage(power, source.getSourceId(), game, true, true); + creature.damage(power, source.getSourceId(), game, false, true); return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DiminishingReturns.java b/Mage.Sets/src/mage/cards/d/DiminishingReturns.java index cee47ba7676..f1c69c6f8ca 100644 --- a/Mage.Sets/src/mage/cards/d/DiminishingReturns.java +++ b/Mage.Sets/src/mage/cards/d/DiminishingReturns.java @@ -4,7 +4,8 @@ package mage.cards.d; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.DrawCardAllEffect; +import mage.abilities.effects.common.ShuffleHandGraveyardAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -23,7 +24,8 @@ public final class DiminishingReturns extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{U}{U}"); // Each player shuffles their hand and graveyard into their library. You exile the top ten cards of your library. Then each player draws up to seven cards. - this.getSpellAbility().addEffect(new DiminishingReturnsEffect()); + this.getSpellAbility().addEffect(new ShuffleHandGraveyardAllEffect()); + this.getSpellAbility().addEffect(new DiminishingReturnsEffect()); } public DiminishingReturns(final DiminishingReturns card) { @@ -40,7 +42,7 @@ class DiminishingReturnsEffect extends OneShotEffect { public DiminishingReturnsEffect() { super(Outcome.Neutral); - staticText = "Each player shuffles their hand and graveyard into their library. You exile the top ten cards of your library. Then each player draws up to seven cards."; + staticText = "You exile the top ten cards of your library. Then each player draws up to seven cards."; } public DiminishingReturnsEffect(final DiminishingReturnsEffect effect) { @@ -51,28 +53,13 @@ class DiminishingReturnsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { + controller.moveCards(controller.getLibrary().getTopCards(game, 10), Zone.EXILED, source, game); + game.getState().processAction(game); for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card: player.getHand().getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - for (Card card: player.getGraveyard().getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - player.shuffleLibrary(source, game); - } - } - - for (Card card: controller.getLibrary().getTopCards(game, 10)) { - controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.LIBRARY, true); - } - - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - int cardsToDrawCount = player.getAmount(0, 7, "How many cards to draw (up to 7)?", game); - player.drawCards(cardsToDrawCount, source.getSourceId(), game); + player.drawCards(player.getAmount(0, 7, "How many cards to draw (up to 7)?", game), + source.getSourceId(), game); } } } diff --git a/Mage.Sets/src/mage/cards/d/Doomsday.java b/Mage.Sets/src/mage/cards/d/Doomsday.java index 59f04c1df2d..15ed6ab58a3 100644 --- a/Mage.Sets/src/mage/cards/d/Doomsday.java +++ b/Mage.Sets/src/mage/cards/d/Doomsday.java @@ -58,47 +58,24 @@ class DoomsdayEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); - if (player != null) { + if (controller != null) { //Search your library and graveyard for five cards Cards allCards = new CardsImpl(); - Cards cards = new CardsImpl(); - allCards.addAll(player.getLibrary().getCardList()); - allCards.addAll(player.getGraveyard()); + allCards.addAll(controller.getLibrary().getCardList()); + allCards.addAll(controller.getGraveyard()); int number = Math.min(5, allCards.size()); TargetCard target = new TargetCard(number, number, Zone.ALL, new FilterCard()); - if (player.choose(Outcome.Benefit, allCards, target, game)) { - // exile the rest - for (UUID uuid : allCards) { - if (!target.getTargets().contains(uuid)) { - Card card = game.getCard(uuid); - if (card != null) { - card.moveToExile(null, "Doomsday", source.getSourceId(), game); - } - } else { - cards.add(uuid); - } - - } + if (controller.choose(Outcome.Benefit, allCards, target, game)) { + Cards toLibrary = new CardsImpl(target.getTargets()); + allCards.removeAll(toLibrary); + // Exile the rest + controller.moveCards(allCards, Zone.EXILED, source, game); //Put the chosen cards on top of your library in any order - target = new TargetCard(Zone.ALL, new FilterCard("Card to put on top")); - while (cards.size() > 1 && player.canRespond()) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } + controller.putCardsOnTopOfLibrary(toLibrary, game, source, true); } - return true; } return false; diff --git a/Mage.Sets/src/mage/cards/d/DwellOnThePast.java b/Mage.Sets/src/mage/cards/d/DwellOnThePast.java index 57164964d99..f57594e87ae 100644 --- a/Mage.Sets/src/mage/cards/d/DwellOnThePast.java +++ b/Mage.Sets/src/mage/cards/d/DwellOnThePast.java @@ -8,6 +8,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -61,23 +62,9 @@ class DwellOnThePastEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getFirstTarget()); - if (player != null) { - List targets = source.getTargets().get(1).getTargets(); - boolean shuffle = false; - for (UUID targetId : targets) { - Card card = game.getCard(targetId); - if (card != null) { - if (player.getGraveyard().contains(card.getId())) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - shuffle = true; - } - } - } - if (shuffle) { - player.shuffleLibrary(source, game); - } - return true; + Player controller = game.getPlayer(source.getFirstTarget()); + if (controller != null) { + return controller.shuffleCardsToLibrary(new CardsImpl(source.getTargets().get(1).getTargets()), game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/e/EpitaphGolem.java b/Mage.Sets/src/mage/cards/e/EpitaphGolem.java index 9751cffa5b5..19b60d1e562 100644 --- a/Mage.Sets/src/mage/cards/e/EpitaphGolem.java +++ b/Mage.Sets/src/mage/cards/e/EpitaphGolem.java @@ -7,7 +7,7 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; +import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; /** @@ -32,7 +33,7 @@ public final class EpitaphGolem extends CardImpl { // {2}: Put target card from your graveyard on the bottom of your library. Ability ability = new SimpleActivatedAbility( Zone.BATTLEFIELD, - new EpitaphGolemGraveyardToLibraryEffect(), + new PutOnLibraryTargetEffect(true), new ManaCostsImpl("{2}")); ability.addTarget(new TargetCardInYourGraveyard()); this.addAbility(ability); @@ -66,9 +67,9 @@ class EpitaphGolemGraveyardToLibraryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Card card = game.getCard(getTargetPointer().getFirst(game, source)); - if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { - return card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + return controller.putCardsOnBottomOfLibrary(game.getCard(getTargetPointer().getFirst(game, source)), game, source, true); } return false; } diff --git a/Mage.Sets/src/mage/cards/g/GaeasBlessing.java b/Mage.Sets/src/mage/cards/g/GaeasBlessing.java index 8f617b4bc23..e3de06d4a51 100644 --- a/Mage.Sets/src/mage/cards/g/GaeasBlessing.java +++ b/Mage.Sets/src/mage/cards/g/GaeasBlessing.java @@ -1,7 +1,6 @@ package mage.cards.g; -import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ZoneChangeTriggeredAbility; @@ -10,6 +9,7 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -68,23 +68,9 @@ class GaeasBlessingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getFirstTarget()); - if (player != null) { - List targets = source.getTargets().get(1).getTargets(); - boolean shuffle = false; - for (UUID targetId : targets) { - Card card = game.getCard(targetId); - if (card != null) { - if (player.getGraveyard().contains(card.getId())) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - shuffle = true; - } - } - } - if (shuffle) { - player.shuffleLibrary(source, game); - } - return true; + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + if (targetPlayer != null) { + return targetPlayer.shuffleCardsToLibrary(new CardsImpl(source.getTargets().get(1).getTargets()), game, source); } return false; } @@ -154,14 +140,7 @@ class GaeasBlessingGraveToLibraryEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - game.informPlayers(controller.getLogName() + " shuffle their graveyard into their library"); - for (Card card : controller.getGraveyard().getCards(game)) { - controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.GRAVEYARD, true, true); - } - controller.getLibrary().addAll(controller.getGraveyard().getCards(game), game); - controller.getGraveyard().clear(); - controller.shuffleLibrary(source, game); - return true; + return controller.shuffleCardsToLibrary(controller.getGraveyard(), game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/g/GravebaneZombie.java b/Mage.Sets/src/mage/cards/g/GravebaneZombie.java index 43d6a30779f..6717c313779 100644 --- a/Mage.Sets/src/mage/cards/g/GravebaneZombie.java +++ b/Mage.Sets/src/mage/cards/g/GravebaneZombie.java @@ -18,6 +18,7 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; +import mage.players.Player; /** * @@ -50,7 +51,7 @@ class GravebaneZombieEffect extends ReplacementEffectImpl { GravebaneZombieEffect() { super(Duration.WhileOnBattlefield, Outcome.Neutral); - staticText = "If {this} would die, put Gravebane Zombie on top of its owner's library instead"; + staticText = "If {this} would die, put {this} on top of its owner's library instead"; } GravebaneZombieEffect(final GravebaneZombieEffect effect) { @@ -60,11 +61,9 @@ class GravebaneZombieEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent permanent = ((ZoneChangeEvent) event).getTarget(); - if (permanent != null) { - if (permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true)) { - game.informPlayers(permanent.getName() + " was put on the top of its owner's library"); - return true; - } + Player controller = game.getPlayer(source.getControllerId()); + if (permanent != null && controller !=null) { + return controller.putCardsOnTopOfLibrary(permanent, game, source, true); } return false; } diff --git a/Mage.Sets/src/mage/cards/h/HarmonicConvergence.java b/Mage.Sets/src/mage/cards/h/HarmonicConvergence.java index 95dc56ddf90..5c33eb781a2 100644 --- a/Mage.Sets/src/mage/cards/h/HarmonicConvergence.java +++ b/Mage.Sets/src/mage/cards/h/HarmonicConvergence.java @@ -17,6 +17,9 @@ import mage.players.Player; import mage.target.TargetCard; import java.util.*; +import mage.cards.Cards; +import mage.filter.common.FilterEnchantmentPermanent; +import mage.filter.predicate.other.OwnerIdPredicate; /** * @@ -27,7 +30,6 @@ public final class HarmonicConvergence extends CardImpl { public HarmonicConvergence(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{G}"); - // Put all enchantments on top of their owners' libraries. this.getSpellAbility().addEffect(new HarmonicConvergenceEffect()); } @@ -60,44 +62,18 @@ class HarmonicConvergenceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List enchantments = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_ENCHANTMENT_PERMANENT, - source.getControllerId(), - source.getSourceId(), - game); - - Map> moveList = new HashMap<>(); - for (Permanent permanent : enchantments) { - List list = moveList.computeIfAbsent(permanent.getControllerId(), k -> new ArrayList<>()); - list.add(permanent); - } - - TargetCard target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("card to put on top of your library")); - for (UUID playerId : moveList.keySet()) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); - List list = moveList.get(playerId); - if (player == null) { - continue; - } - - CardsImpl cards = new CardsImpl(); - for (Permanent permanent : list) { - cards.add(permanent); - } - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Permanent permanent = game.getPermanent(target.getFirstTarget()); - if (permanent != null) { - cards.remove(permanent); - permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + if (player != null) { + FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent(); + filter.add(new OwnerIdPredicate(player.getId())); + Cards toLib = new CardsImpl(); + for(Permanent enchantment: game.getBattlefield().getActivePermanents(filter, playerId, source.getSourceId(), game)) { + toLib.add(enchantment); } - target.clearChosen(); - } - if (cards.size() == 1) { - Permanent permanent = game.getPermanent(cards.iterator().next()); - permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - } - + player.putCardsOnTopOfLibrary(toLib, game, source, true); + } + } return true; } } diff --git a/Mage.Sets/src/mage/cards/k/KrosanReclamation.java b/Mage.Sets/src/mage/cards/k/KrosanReclamation.java index 2ae901a246a..671b1144082 100644 --- a/Mage.Sets/src/mage/cards/k/KrosanReclamation.java +++ b/Mage.Sets/src/mage/cards/k/KrosanReclamation.java @@ -1,7 +1,6 @@ package mage.cards.k; -import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; @@ -10,6 +9,7 @@ import mage.abilities.keyword.FlashbackAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.TimingRule; @@ -66,23 +66,9 @@ class KrosanReclamationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getFirstTarget()); - if (player != null) { - List targets = source.getTargets().get(1).getTargets(); - boolean shuffle = false; - for (UUID targetId : targets) { - Card card = game.getCard(targetId); - if (card != null) { - if (player.getGraveyard().contains(card.getId())) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - shuffle = true; - } - } - } - if (shuffle) { - player.shuffleLibrary(source, game); - } - return true; + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + if (targetPlayer != null) { + return targetPlayer.shuffleCardsToLibrary(new CardsImpl(source.getTargets().get(1).getTargets()), game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/l/LichsMirror.java b/Mage.Sets/src/mage/cards/l/LichsMirror.java index 3bff7b7d4e7..d12065242e3 100644 --- a/Mage.Sets/src/mage/cards/l/LichsMirror.java +++ b/Mage.Sets/src/mage/cards/l/LichsMirror.java @@ -8,7 +8,10 @@ import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.*; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.other.OwnerIdPredicate; import mage.game.Game; @@ -64,32 +67,20 @@ class LichsMirrorEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player player = game.getPlayer(event.getPlayerId()); if (player != null) { + Cards toLib = new CardsImpl(); FilterControlledPermanent filter = new FilterControlledPermanent(); filter.add(new OwnerIdPredicate(player.getId())); - for (UUID uuid : player.getHand().copy()) { - Card card = game.getCard(uuid); - if (card != null) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - } - - for (UUID uuid : player.getGraveyard().copy()) { - Card card = game.getCard(uuid); - if (card != null) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - } - + toLib.addAll(player.getHand()); + toLib.addAll(player.getGraveyard()); for(Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)){ - permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - player.shuffleLibrary(source, game); - - player.drawCards(7, source.getSourceId(), game); - - player.setLife(20, game, source); + toLib.add(permanent); + } + player.shuffleCardsToLibrary(toLib, game, source); + game.getState().processAction(game); + player.drawCards(7, source.getSourceId(), game); + player.setLife(20, game, source); } - return true; + return true; // replace the loses event } @Override @@ -99,10 +90,7 @@ class LichsMirrorEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getPlayerId().equals(source.getControllerId())) { - return true; - } - return false; + return event.getPlayerId().equals(source.getControllerId()); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MemorysJourney.java b/Mage.Sets/src/mage/cards/m/MemorysJourney.java index 71b1f58fc37..4893700f1b1 100644 --- a/Mage.Sets/src/mage/cards/m/MemorysJourney.java +++ b/Mage.Sets/src/mage/cards/m/MemorysJourney.java @@ -10,6 +10,7 @@ import mage.abilities.keyword.FlashbackAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.TimingRule; @@ -65,23 +66,9 @@ class MemorysJourneyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getFirstTarget()); - if (player != null) { - List targets = source.getTargets().get(1).getTargets(); - boolean shuffle = false; - for (UUID targetId : targets) { - Card card = game.getCard(targetId); - if (card != null) { - if (player.getGraveyard().contains(card.getId())) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - shuffle = true; - } - } - } - if (shuffle) { - player.shuffleLibrary(source, game); - } - return true; + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + if (targetPlayer != null) { + return targetPlayer.shuffleCardsToLibrary(new CardsImpl(source.getTargets().get(1).getTargets()), game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/m/MirrorMadPhantasm.java b/Mage.Sets/src/mage/cards/m/MirrorMadPhantasm.java index 34511c34805..5d8a5207f38 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorMadPhantasm.java +++ b/Mage.Sets/src/mage/cards/m/MirrorMadPhantasm.java @@ -69,10 +69,7 @@ class MirrorMadPhantasmEffect extends OneShotEffect { if (owner == null) { return false; } - if (owner.moveCards(perm, Zone.LIBRARY, source, game)) { - owner.shuffleLibrary(source, game); - perm.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - owner.shuffleLibrary(source, game); + if (owner.shuffleCardsToLibrary(perm, game, source)) { Cards cards = new CardsImpl(); Card phantasmCard = null; for (Card card : owner.getLibrary().getCards(game)) { diff --git a/Mage.Sets/src/mage/cards/m/MirrorOfFate.java b/Mage.Sets/src/mage/cards/m/MirrorOfFate.java index bc8bd0e12fd..5eb29e5592d 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorOfFate.java +++ b/Mage.Sets/src/mage/cards/m/MirrorOfFate.java @@ -67,42 +67,20 @@ class MirrorOfFateEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } - + // Choose up to seven face-up exiled cards you own CardsImpl cards = new CardsImpl(); MirrorOfFateTarget targetExile = new MirrorOfFateTarget(); - if (player.choose(outcome, targetExile, source.getSourceId(), game)) { - for (UUID cardId : targetExile.getTargets()) { - Card card = game.getCard(cardId); - if (card != null) { - cards.add(card); - } - } + if (controller.choose(outcome, targetExile, source.getSourceId(), game)) { + cards.addAll(targetExile.getTargets()); } - - for (Card card : player.getLibrary().getCards(game)) { - card.moveToExile(null, null, source.getSourceId(), game); - } - - TargetCard target = new TargetCard(Zone.EXILED, new FilterCard("card to put on top of your library")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - - return true; + // Exile all the cards from your library + controller.moveCards(new CardsImpl(controller.getLibrary().getCardList()), Zone.EXILED, source, game); + // put the chosen cards on top of your library" + return controller.putCardsOnTopOfLibrary(cards, game, source, true); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index c937ce70d69..171038de3a2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -2659,6 +2659,21 @@ public class TestPlayer implements Player { return computerPlayer.putCardsOnTopOfLibrary(cards, game, source, anyOrder); } + @Override + public boolean putCardsOnTopOfLibrary(Card card, Game game, Ability source, boolean anyOrder) { + return computerPlayer.putCardsOnTopOfLibrary(card, game, source, anyOrder); + } + + @Override + public boolean shuffleCardsToLibrary(Cards cards, Game game, Ability source) { + return computerPlayer.shuffleCardsToLibrary(cards, game, source); + } + + @Override + public boolean shuffleCardsToLibrary(Card card, Game game, Ability source) { + return computerPlayer.shuffleCardsToLibrary(card, game, source); + } + @Override public void setCastSourceIdWithAlternateMana(UUID sourceId, ManaCosts manaCosts, Costs costs) { computerPlayer.setCastSourceIdWithAlternateMana(sourceId, manaCosts, costs); diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java index 7093c322591..652a654636c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java @@ -892,6 +892,21 @@ public class PlayerStub implements Player { return false; } + @Override + public boolean putCardsOnTopOfLibrary(Card card, Game game, Ability source, boolean anyOrder) { + return false; + } + + @Override + public boolean shuffleCardsToLibrary(Cards cards, Game game, Ability source) { + return false; + } + + @Override + public boolean shuffleCardsToLibrary(Card card, Game game, Ability source) { + return false; + } + @Override public boolean putCardOnTopXOfLibrary(Card card, Game game, Ability source, int xFromTheTop) { return true; diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 61e04700c69..cbf313bc28a 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -530,8 +530,11 @@ public interface Player extends MageItem, Copyable { * * @param cards - list of cards that have to be moved * @param game - game - * @param anyOrder - true if player can determine the order of the cards - * else random order + * @param anyOrder - true = if player can determine the order of the cards + * else false = random order + * 401.4. If an effect puts two or more cards in a specific position in a library + * at the same time, the owner of those cards may arrange them in any order. + * That library’s owner doesn’t reveal the order in which the cards go into the library. * @param source - source ability * @return */ @@ -560,7 +563,13 @@ public interface Player extends MageItem, Copyable { * @return */ boolean putCardsOnTopOfLibrary(Cards cards, Game game, Ability source, boolean anyOrder); + + boolean putCardsOnTopOfLibrary(Card card, Game game, Ability source, boolean anyOrder); + boolean shuffleCardsToLibrary(Cards cards, Game game, Ability source); + + boolean shuffleCardsToLibrary(Card card, Game game, Ability source); + // set the value for X mana spells and abilities default int announceXMana(int min, int max, String message, Game game, Ability ability) { return announceXMana(min, max, 1, message, game, ability); @@ -725,7 +734,7 @@ public interface Player extends MageItem, Copyable { /** * Universal method to move cards from one zone to another. Do not mix - * objects from different from zones to move. + * objects from different zones to move. * * @param cards * @param toZone diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index bbc47b11935..cdd42ea1886 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -613,9 +613,9 @@ public abstract class PlayerImpl implements Player, Serializable { && this.hasOpponent(sourceControllerId, game) && game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) == null && abilities.stream() - .filter(HexproofBaseAbility.class::isInstance) - .map(HexproofBaseAbility.class::cast) - .anyMatch(ability -> ability.checkObject(source, game))) { + .filter(HexproofBaseAbility.class::isInstance) + .map(HexproofBaseAbility.class::cast) + .anyMatch(ability -> ability.checkObject(source, game))) { return false; } @@ -655,7 +655,7 @@ public abstract class PlayerImpl implements Player, Serializable { game.informPlayers(getLogName() + " discards down to " + this.maxHandSize + (this.maxHandSize == 1 - ? " hand card" : " hand cards")); + ? " hand card" : " hand cards")); } discard(hand.size() - this.maxHandSize, false, null, game); } @@ -804,7 +804,7 @@ public abstract class PlayerImpl implements Player, Serializable { } GameEvent gameEvent = GameEvent.getEvent(GameEvent.EventType.DISCARD_CARD, card.getId(), source == null - ? null : source.getSourceId(), playerId); + ? null : source.getSourceId(), playerId); gameEvent.setFlag(source != null); // event from effect or from cost (source == null) if (game.replaceEvent(gameEvent, source)) { return false; @@ -966,6 +966,27 @@ public abstract class PlayerImpl implements Player, Serializable { return true; } + @Override + public boolean shuffleCardsToLibrary(Cards cards, Game game, Ability source) { + if (cards.isEmpty()) { + return true; + } + game.informPlayers(getName() + " shuffels " + CardUtil.numberToText(cards.size(), "a") + + " card" + (cards.size() == 1 ? "" : "s") + + " into their library."); + boolean status = moveCards(cards, Zone.LIBRARY, source, game); + shuffleLibrary(source, game); + return status; + } + + @Override + public boolean shuffleCardsToLibrary(Card card, Game game, Ability source) { + if (card == null) { + return true; + } + return shuffleCardsToLibrary(new CardsImpl(card), game, source); + } + @Override public boolean putCardOnTopXOfLibrary(Card card, Game game, Ability source, int xFromTheTop) { if (card.isOwnedBy(getId())) { @@ -1005,7 +1026,6 @@ public abstract class PlayerImpl implements Player, Serializable { public boolean putCardsOnTopOfLibrary(Cards cardsToLibrary, Game game, Ability source, boolean anyOrder) { if (cardsToLibrary != null && !cardsToLibrary.isEmpty()) { Cards cards = new CardsImpl(cardsToLibrary); // prevent possible ConcurrentModificationException - UUID sourceId = (source == null ? null : source.getSourceId()); if (!anyOrder) { // random order List ids = new ArrayList<>(cards); @@ -1039,6 +1059,14 @@ public abstract class PlayerImpl implements Player, Serializable { return true; } + @Override + public boolean putCardsOnTopOfLibrary(Card cardToLibrary, Game game, Ability source, boolean anyOrder) { + if (cardToLibrary != null) { + return putCardsOnTopOfLibrary(new CardsImpl(cardToLibrary), game, source, anyOrder); + } + return true; + } + private boolean moveObjectToLibrary(UUID objectId, UUID sourceId, Game game, boolean toTop, boolean withName) { MageObject mageObject = game.getObject(objectId); if (mageObject != null) { @@ -1813,9 +1841,9 @@ public abstract class PlayerImpl implements Player, Serializable { } private List getPermanentsThatCanBeUntapped(Game game, - List canBeUntapped, - RestrictionUntapNotMoreThanEffect handledEffect, - Map>, Integer> notMoreThanEffectsUsage) { + List canBeUntapped, + RestrictionUntapNotMoreThanEffect handledEffect, + Map>, Integer> notMoreThanEffectsUsage) { List leftForUntap = new ArrayList<>(); // select permanents that can still be untapped for (Permanent permanent : canBeUntapped) { @@ -2524,7 +2552,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId, - boolean triggerEvents) { + boolean triggerEvents) { //20091005 - 701.14c Library searchedLibrary = null; String searchInfo = null; @@ -2726,7 +2754,7 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param game * @param appliedEffects - * @param numSides Number of sides the dice has + * @param numSides Number of sides the dice has * @return the number that the player rolled */ @Override @@ -2763,16 +2791,16 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param game * @param appliedEffects - * @param numberChaosSides The number of chaos sides the planar die - * currently has (normally 1 but can be 5) + * @param numberChaosSides The number of chaos sides the planar die + * currently has (normally 1 but can be 5) * @param numberPlanarSides The number of chaos sides the planar die - * currently has (normally 1) + * currently has (normally 1) * @return the outcome that the player rolled. Either ChaosRoll, PlanarRoll * or NilRoll */ @Override public PlanarDieRoll rollPlanarDie(Game game, List appliedEffects, int numberChaosSides, - int numberPlanarSides) { + int numberPlanarSides) { int result = RandomUtil.nextInt(9) + 1; PlanarDieRoll roll = PlanarDieRoll.NIL_ROLL; if (numberChaosSides + numberPlanarSides > 9) { @@ -2929,7 +2957,7 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param ability - * @param available if null, it won't be checked if enough mana is available + * @param available if null, it won't be checked if enough mana is available * @param sourceObject * @param game * @return @@ -3652,7 +3680,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId, - UUID controllerId, Game game + UUID controllerId, Game game ) { return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game); } @@ -3805,8 +3833,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Card card, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { Set cardList = new HashSet<>(); if (card != null) { @@ -3817,22 +3845,22 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Cards cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return moveCards(cards.getCards(game), toZone, source, game); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return moveCards(cards, toZone, source, game, false, false, false, null); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { if (cards.isEmpty()) { return true; @@ -3934,8 +3962,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardsToExile(Card card, Ability source, - Game game, boolean withName, UUID exileId, - String exileZoneName + Game game, boolean withName, UUID exileId, + String exileZoneName ) { Set cards = new HashSet<>(); cards.add(card); @@ -3944,8 +3972,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardsToExile(Set cards, Ability source, - Game game, boolean withName, UUID exileId, - String exileZoneName + Game game, boolean withName, UUID exileId, + String exileZoneName ) { if (cards.isEmpty()) { return true; @@ -3961,14 +3989,14 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, - Game game + Game game ) { return this.moveCardToHandWithInfo(card, sourceId, game, true); } @Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, - Game game, boolean withName + Game game, boolean withName ) { boolean result = false; Zone fromZone = game.getState().getZone(card.getId()); @@ -3993,7 +4021,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public Set moveCardsToGraveyardWithInfo(Set allCards, Ability source, - Game game, Zone fromZone + Game game, Zone fromZone ) { UUID sourceId = source == null ? null : source.getSourceId(); Set movedCards = new LinkedHashSet<>(); @@ -4001,7 +4029,7 @@ public abstract class PlayerImpl implements Player, Serializable { // identify cards from one owner Cards cards = new CardsImpl(); UUID ownerId = null; - for (Iterator it = allCards.iterator(); it.hasNext(); ) { + for (Iterator it = allCards.iterator(); it.hasNext();) { Card card = it.next(); if (cards.isEmpty()) { ownerId = card.getOwnerId(); @@ -4064,7 +4092,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, - Game game, Zone fromZone + Game game, Zone fromZone ) { if (card == null) { return false; @@ -4093,8 +4121,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, - Game game, Zone fromZone, - boolean toTop, boolean withName + Game game, Zone fromZone, + boolean toTop, boolean withName ) { if (card == null) { return false; @@ -4159,7 +4187,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, - Game game, Zone fromZone, boolean withName) { + Game game, Zone fromZone, boolean withName) { if (card == null) { return false; } @@ -4182,7 +4210,7 @@ public abstract class PlayerImpl implements Player, Serializable { game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() + (card.isCopy() ? " (Copy)" : "") : "a card face down") + ' ' + (fromZone != null ? "from " + fromZone.toString().toLowerCase(Locale.ENGLISH) - + ' ' : "") + "to the exile zone"); + + ' ' : "") + "to the exile zone"); } result = true; diff --git a/Mage/src/main/java/mage/players/StubPlayer.java b/Mage/src/main/java/mage/players/StubPlayer.java index 6b1fe798d37..c9d959e34a5 100644 --- a/Mage/src/main/java/mage/players/StubPlayer.java +++ b/Mage/src/main/java/mage/players/StubPlayer.java @@ -35,6 +35,7 @@ import static com.google.common.collect.Iterables.getOnlyElement; public class StubPlayer extends PlayerImpl implements Player { + @Override public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { if (target instanceof TargetPlayer) { for (Player player : game.getPlayers().values()) { @@ -47,6 +48,7 @@ public class StubPlayer extends PlayerImpl implements Player { return false; } + @Override public boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game) { cards.getCards(game).stream().map(MageItem::getId).forEach(cardId -> target.add(cardId, game)); return true;