diff --git a/Mage.Sets/src/mage/cards/a/Aetherspouts.java b/Mage.Sets/src/mage/cards/a/Aetherspouts.java index 506d81aed8ae..12d2da9e8621 100644 --- a/Mage.Sets/src/mage/cards/a/Aetherspouts.java +++ b/Mage.Sets/src/mage/cards/a/Aetherspouts.java @@ -6,18 +6,21 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.filter.FilterPermanent; import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; import mage.players.Player; import mage.players.PlayerList; -import mage.target.TargetCard; +import mage.target.TargetPermanent; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; /** * @author LevelX2 @@ -85,6 +88,11 @@ public boolean apply(Game game, Ability source) { List permanentsToBottom = new ArrayList<>(); for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source, game)) { if (permanent.isOwnedBy(player.getId())) { + // it doesn't matter if tokens go to top or bottom of library, so don't bother asking the player + if (permanent instanceof PermanentToken) { + permanentsToTop.add(permanent); + continue; + } if (player.chooseUse(outcome, "Put " + permanent.getLogName() + " to the top? (else it goes to bottom)", source, game)) { permanentsToTop.add(permanent); game.informPlayers(permanent.getLogName() + " goes to the top of " + player.getLogName() + "'s library"); @@ -95,82 +103,50 @@ public boolean apply(Game game, Ability source) { } } // cards to top - Cards cards = new CardsImpl(); - List toLibrary = new ArrayList<>(); - for (Permanent permanent : permanentsToTop) { - if (permanent instanceof PermanentToken) { - toLibrary.add(permanent); - } else { - Card card = game.getCard(permanent.getId()); - if (card != null) { - cards.add(card); - } - } - } - TargetCard target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on the top of library (last chosen will be the top most)")); - while (cards.size() > 1) { + final Map> orderedToTop = permanentsToTop.stream().collect( + Collectors.partitioningBy(permanent -> permanent instanceof PermanentToken)); + while (orderedToTop.get(false).size() > 1) { if (!player.canRespond()) { return false; } - player.choose(Outcome.Neutral, cards, target, source, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - toLibrary.add(permanent); - } - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - Permanent permanent = game.getPermanent(card.getId()); + final FilterPermanent filter = new FilterPermanent("order to put on the top of library (last chosen will be the top most)"); + filter.add(new PermanentReferenceInCollectionPredicate(orderedToTop.get(false), game)); + final TargetPermanent target = new TargetPermanent(1, 1, filter, true); + player.chooseTarget(Outcome.Neutral, target, source, game); + final Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { - toLibrary.add(permanent); + orderedToTop.get(false).remove(permanent); + orderedToTop.get(true).add(permanent); } } + if (orderedToTop.get(false).size() == 1) { + orderedToTop.get(true).add(orderedToTop.get(false).get(0)); + } // move all permanents to lib at the same time - for (Permanent permanent : toLibrary) { + for (Permanent permanent : orderedToTop.get(true)) { player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, true, false); } // cards to bottom - cards.clear(); - toLibrary.clear(); - for (Permanent permanent : permanentsToBottom) { - if (permanent instanceof PermanentToken) { - toLibrary.add(permanent); - } else { - Card card = game.getCard(permanent.getId()); - if (card != null) { - cards.add(card); - } - } - } - target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on bottom of library (last chosen will be bottommost card)")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, source, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - toLibrary.add(permanent); - } - target.clearChosen(); + final Map> orderedToBottom = permanentsToBottom.stream().collect( + Collectors.partitioningBy(permanent -> permanent instanceof PermanentToken)); + while (player.canRespond() && orderedToBottom.get(false).size() > 1) { + final FilterPermanent filter = new FilterPermanent("order to put on bottom of library (last chosen will be bottommost card)"); + filter.add(new PermanentReferenceInCollectionPredicate(orderedToBottom.get(false), game)); + final TargetPermanent target = new TargetPermanent(1, 1, filter, true); + player.chooseTarget(Outcome.Neutral, target, source, game); + final Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + orderedToBottom.get(false).remove(permanent); + orderedToBottom.get(true).add(permanent); } else { break; } } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - toLibrary.add(permanent); - } + if (orderedToBottom.get(false).size() == 1) { + orderedToBottom.get(true).add(orderedToBottom.get(false).get(0)); } // move all permanents to lib at the same time - for (Permanent permanent : toLibrary) { + for (Permanent permanent : orderedToBottom.get(true)) { player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, false, false); } player = playerList.getNext(game, false); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mic/AetherspoutsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mic/AetherspoutsTest.java new file mode 100644 index 000000000000..ff4ad2aa73e3 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mic/AetherspoutsTest.java @@ -0,0 +1,81 @@ +package org.mage.test.cards.single.mic; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class AetherspoutsTest extends CardTestPlayerBase { + + // https://github.com/magefree/mage/issues/14351 + @Test + public void testAllToTop() { + addCard(Zone.HAND, playerB, "Aetherspouts"); + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears"); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); + addCard(Zone.BATTLEFIELD, playerA, "Kalonian Behemoth"); + addCard(Zone.BATTLEFIELD, playerB, "Island", 5); + addCard(Zone.HAND, playerA, "Beast Attack"); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Beast Attack"); + attack(3, playerA, "Balduvian Bears", playerB); + attack(3, playerA, "Grizzly Bears", playerB); + attack(3, playerA, "Beast Token", playerB); + attack(3, playerA, "Kalonian Behemoth", playerB); + castSpell(3, PhaseStep.DECLARE_BLOCKERS, playerB, "Aetherspouts"); + setChoice(playerA, true); // yes, send Balduvian Bears to top + setChoice(playerA, true); // yes, send Grizzly Bears to top + setChoice(playerA, true); // yes, send Kalonian Behemoth to top + addTarget(playerA, "Balduvian Bears"); + addTarget(playerA, "Grizzly Bears"); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Balduvian Bears", 0); + assertPermanentCount(playerA, "Grizzly Bears", 0); + assertPermanentCount(playerA, "Kalonian Behemoth", 0); + assertPermanentCount(playerA, "Beast Token", 0); + assertLibraryCount(playerA, "Balduvian Bears", 1); + assertLibraryCount(playerA, "Grizzly Bears", 1); + assertLibraryCount(playerA, "Kalonian Behemoth", 1); + assertLibraryCount(playerA, "Beast Token", 0); + } + + @Test + public void testSomeToBottom() { + addCard(Zone.HAND, playerB, "Aetherspouts"); + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears"); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); + addCard(Zone.BATTLEFIELD, playerA, "Kalonian Behemoth"); + addCard(Zone.BATTLEFIELD, playerB, "Island", 5); + addCard(Zone.HAND, playerA, "Beast Attack"); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Beast Attack"); + attack(3, playerA, "Balduvian Bears", playerB); + attack(3, playerA, "Grizzly Bears", playerB); + attack(3, playerA, "Beast Token", playerB); + attack(3, playerA, "Kalonian Behemoth", playerB); + castSpell(3, PhaseStep.DECLARE_BLOCKERS, playerB, "Aetherspouts"); + setChoice(playerA, true); // yes, send Balduvian Bears to top + setChoice(playerA, false); // no, send Grizzly Bears to bottom + setChoice(playerA, false); // no, send Kalonian Behemoth to bottom + addTarget(playerA, "Grizzly Bears"); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Balduvian Bears", 0); + assertPermanentCount(playerA, "Grizzly Bears", 0); + assertPermanentCount(playerA, "Kalonian Behemoth", 0); + assertPermanentCount(playerA, "Beast Token", 0); + assertLibraryCount(playerA, "Balduvian Bears", 1); + assertLibraryCount(playerA, "Grizzly Bears", 1); + assertLibraryCount(playerA, "Kalonian Behemoth", 1); + assertLibraryCount(playerA, "Beast Token", 0); + } +}