From 420a12524377403a1759a80934d1d25eb897faad Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 13 Nov 2020 19:41:25 -0500 Subject: [PATCH] two more search effects refactored --- .../src/mage/cards/c/ClarionUltimatum.java | 125 ++++++++++++------ Mage.Sets/src/mage/cards/d/DoublingChant.java | 122 ++++++++++------- 2 files changed, 157 insertions(+), 90 deletions(-) diff --git a/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java b/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java index 460d2879790..6eaa88c4503 100644 --- a/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java +++ b/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java @@ -1,31 +1,32 @@ - package mage.cards.c; -import java.util.*; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetControlledPermanent; +import java.util.*; +import java.util.stream.Collectors; + /** - * * @author North */ public final class ClarionUltimatum extends CardImpl { public ClarionUltimatum(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{G}{G}{W}{W}{W}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}{G}{W}{W}{W}{U}{U}"); // Choose five permanents you control. For each of those permanents, you may search your library for a card with the same name as that permanent. Put those cards onto the battlefield tapped, then shuffle your library. this.getSpellAbility().addEffect(new ClarionUltimatumEffect()); @@ -45,7 +46,9 @@ class ClarionUltimatumEffect extends OneShotEffect { public ClarionUltimatumEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "Choose five permanents you control. For each of those permanents, you may search your library for a card with the same name as that permanent. Put those cards onto the battlefield tapped, then shuffle your library"; + this.staticText = "Choose five permanents you control. For each of those permanents, " + + "you may search your library for a card with the same name as that permanent. " + + "Put those cards onto the battlefield tapped, then shuffle your library"; } public ClarionUltimatumEffect(final ClarionUltimatumEffect effect) { @@ -59,41 +62,79 @@ class ClarionUltimatumEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - - Player controller = game.getPlayer(source.getControllerId()); - int permanentsCount = game.getBattlefield().getAllActivePermanents(source.getControllerId()).size(); - if (controller == null || permanentsCount < 1) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { return false; } - - TargetControlledPermanent permanentsTarget = new TargetControlledPermanent(Math.min(permanentsCount, 5)); - controller.choose(Outcome.Benefit, permanentsTarget, source.getSourceId(), game); - - Set chosenCards = new LinkedHashSet<>(); - List namesFiltered = new ArrayList<>(); - List permanents = permanentsTarget.getTargets(); - for (UUID permanentId : permanents) { - Permanent permanent = game.getPermanent(permanentId); - final String cardName = permanent.getName(); - if (!namesFiltered.contains(cardName)) { - if (controller.chooseUse(Outcome.PutCardInPlay, "Search for " + cardName + " in your library?", source, game)) { - FilterCard filter = new FilterCard("card named " + cardName); - filter.add(new NamePredicate(cardName)); - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, source, game)) { - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - chosenCards.add(card); - } - } - } else { - namesFiltered.add(cardName); - } - } - } - - controller.moveCards(chosenCards, Zone.BATTLEFIELD, source, game, true, false, false, null); - controller.shuffleLibrary(source, game); + int permCount = game.getBattlefield().count( + StaticFilters.FILTER_CONTROLLED_PERMANENT, + source.getSourceId(), source.getControllerId(), game + ); + TargetPermanent targetPermanent = new TargetControlledPermanent(Math.max(permCount, 5)); + targetPermanent.setNotTarget(true); + player.choose(outcome, targetPermanent, source.getSourceId(), game); + Set names = targetPermanent + .getTargets() + .stream() + .map(game::getCard) + .filter(Objects::nonNull) + .map(MageObject::getName) + .collect(Collectors.toSet()); + TargetCardInLibrary targetCardInLibrary = new ClarionUltimatumTarget(names); + player.searchLibrary(targetCardInLibrary, source, game); + Cards cards = new CardsImpl(targetCardInLibrary.getTargets()); + player.moveCards(cards.getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); + player.shuffleLibrary(source, game); return true; } } + +class ClarionUltimatumTarget extends TargetCardInLibrary { + + private final Map nameMap = new HashMap<>(); + + ClarionUltimatumTarget(Set names) { + super(0, names.size(), makeFilter(names)); + this.populateNameMap(names); + } + + private ClarionUltimatumTarget(final ClarionUltimatumTarget target) { + super(target); + this.nameMap.putAll(target.nameMap); + } + + @Override + public ClarionUltimatumTarget copy() { + return new ClarionUltimatumTarget(this); + } + + private static FilterCard makeFilter(Set names) { + FilterCard filter = new FilterCard(); + filter.add(Predicates.or(names.stream().map(name -> new NamePredicate(name)).collect(Collectors.toSet()))); + return filter; + } + + private void populateNameMap(Set names) { + names.stream().forEach(name -> this.nameMap.compute(name, (s, i) -> i == null ? 1 : Integer.sum(i, 1))); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; + } + Card card = game.getCard(id); + if (card == null) { + return false; + } + Map alreadyChosen = new HashMap<>(); + this.getTargets() + .stream() + .map(game::getCard) + .filter(Objects::nonNull) + .map(MageObject::getName) + .forEach(name -> alreadyChosen.compute(name, (s, i) -> i == null ? 1 : Integer.sum(i, 1))); + return nameMap.getOrDefault(card.getName(), 0) + > alreadyChosen.getOrDefault(card.getName(), 0); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DoublingChant.java b/Mage.Sets/src/mage/cards/d/DoublingChant.java index 1a459bce347..0c93a5c168b 100644 --- a/Mage.Sets/src/mage/cards/d/DoublingChant.java +++ b/Mage.Sets/src/mage/cards/d/DoublingChant.java @@ -1,31 +1,25 @@ - package mage.cards.d; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; +import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.*; +import java.util.stream.Collectors; + /** - * * @author North */ public final class DoublingChant extends CardImpl { @@ -52,7 +46,9 @@ class DoublingChantEffect extends OneShotEffect { public DoublingChantEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "For each creature you control, you may search your library for a creature card with the same name as that creature. Put those cards onto the battlefield, then shuffle your library"; + this.staticText = "For each creature you control, " + + "you may search your library for a creature card with the same name as that creature. " + + "Put those cards onto the battlefield, then shuffle your library"; } public DoublingChantEffect(final DoublingChantEffect effect) { @@ -66,43 +62,73 @@ class DoublingChantEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { return false; } - Set chosenCards = new HashSet<>(); - List creatures = game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game); - if (creatures.isEmpty()) { - //9/22/2011: If you control no creatures when Doubling Chant resolves, you may still search your library and you must shuffle your library. - if (controller.chooseUse(Outcome.PutCreatureInPlay, "Search in your library?", source, game)) { - FilterCreatureCard filter = new FilterCreatureCard("nothing (no valid card available)"); - filter.add(new NamePredicate("creatureName")); - TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); - controller.searchLibrary(target, source, game); - } - } - for (Permanent creature : creatures) { - final String creatureName = creature.getName(); - List uuidPredicates = new ArrayList<>(); - if (controller.chooseUse(Outcome.PutCreatureInPlay, "Search for " + creatureName + " in your library?", source, game)) { - FilterCreatureCard filter = new FilterCreatureCard("creature card named " + creatureName); - filter.add(new NamePredicate(creatureName)); - if (!uuidPredicates.isEmpty()) { // Prevent to select a card twice - filter.add(Predicates.not(Predicates.or(uuidPredicates))); - } - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, source, game)) { - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - chosenCards.add(card); - uuidPredicates.add(new CardIdPredicate(card.getId())); - } - } - } - - } - controller.moveCards(chosenCards, Zone.BATTLEFIELD, source, game); - controller.shuffleLibrary(source, game); + Set names = game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getControllerId(), source.getSourceId(), game + ) + .stream() + .filter(Objects::nonNull) + .map(MageObject::getName) + .collect(Collectors.toSet()); + TargetCardInLibrary targetCardInLibrary = new DoublingChantTarget(names); + player.searchLibrary(targetCardInLibrary, source, game); + Cards cards = new CardsImpl(targetCardInLibrary.getTargets()); + player.moveCards(cards, Zone.BATTLEFIELD, source, game); + player.shuffleLibrary(source, game); return true; } } + +class DoublingChantTarget extends TargetCardInLibrary { + + private final Map nameMap = new HashMap<>(); + + DoublingChantTarget(Set names) { + super(0, names.size(), makeFilter(names)); + this.populateNameMap(names); + } + + private DoublingChantTarget(final DoublingChantTarget target) { + super(target); + this.nameMap.putAll(target.nameMap); + } + + @Override + public DoublingChantTarget copy() { + return new DoublingChantTarget(this); + } + + private static FilterCard makeFilter(Set names) { + FilterCard filter = new FilterCreatureCard(); + filter.add(Predicates.or(names.stream().map(name -> new NamePredicate(name)).collect(Collectors.toSet()))); + return filter; + } + + private void populateNameMap(Set names) { + names.stream().forEach(name -> this.nameMap.compute(name, (s, i) -> i == null ? 1 : Integer.sum(i, 1))); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; + } + Card card = game.getCard(id); + if (card == null) { + return false; + } + Map alreadyChosen = new HashMap<>(); + this.getTargets() + .stream() + .map(game::getCard) + .filter(Objects::nonNull) + .map(MageObject::getName) + .forEach(name -> alreadyChosen.compute(name, (s, i) -> i == null ? 1 : Integer.sum(i, 1))); + return nameMap.getOrDefault(card.getName(), 0) + > alreadyChosen.getOrDefault(card.getName(), 0); + } +}