From d2f1a9851158b4121b843d3b3de59c3a5588545d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 17 Oct 2012 14:29:13 +0200 Subject: [PATCH] Redesign of SearchTargetGraveyardHandLibraryForCardNameAndExileEffect for reusablility. --- .../sets/betrayersofkamigawa/Eradicate.java | 2 +- .../mage/sets/betrayersofkamigawa/Scour.java | 2 +- .../sets/betrayersofkamigawa/SowingSalt.java | 2 +- .../sets/betrayersofkamigawa/Splinter.java | 2 +- ...etAndSearchGraveyardHandLibraryEffect.java | 100 +++-------- ...etAndSearchGraveyardHandLibraryEffect.java | 152 +++++----------- ...dHandLibraryForCardNameAndExileEffect.java | 165 ++++++++++++++++++ 7 files changed, 239 insertions(+), 186 deletions(-) create mode 100644 Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/Eradicate.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/Eradicate.java index 5e4cead175..a6eec843ef 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/Eradicate.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/Eradicate.java @@ -58,7 +58,7 @@ public class Eradicate extends CardImpl { // Exile target nonblack creature. Search its controller's graveyard, hand, and library for all cards // with the same name as that creature and exile them. Then that player shuffles his or her library. this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); - this.getSpellAbility().addEffect(new ExileTargetAndSearchGraveyardHandLibraryEffect()); + this.getSpellAbility().addEffect(new ExileTargetAndSearchGraveyardHandLibraryEffect(false, "its controller's","all cards with the same name as that creature")); } public Eradicate(final Eradicate card) { diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/Scour.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/Scour.java index a379032e70..faf6cf3e3d 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/Scour.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/Scour.java @@ -56,7 +56,7 @@ public class Scour extends CardImpl { // Exile target enchantment. // Search its controller's graveyard, hand, and library for all cards with the same name as that enchantment and exile them. Then that player shuffles his or her library. this.getSpellAbility().addTarget(new TargetPermanent(filter)); - this.getSpellAbility().addEffect(new ExileTargetAndSearchGraveyardHandLibraryEffect()); + this.getSpellAbility().addEffect(new ExileTargetAndSearchGraveyardHandLibraryEffect(false, "its controller's","all cards with the same name as that enchantment")); } public Scour(final Scour card) { diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/SowingSalt.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/SowingSalt.java index 7cb80f5b60..c2abfb135f 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/SowingSalt.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/SowingSalt.java @@ -58,7 +58,7 @@ public class SowingSalt extends CardImpl { // Exile target nonbasic land. Search its controller's graveyard, hand, and library for all cards with // the same name as that land and exile them. Then that player shuffles his or her library. this.getSpellAbility().addTarget(new TargetPermanent(filter)); - this.getSpellAbility().addEffect(new ExileTargetAndSearchGraveyardHandLibraryEffect()); + this.getSpellAbility().addEffect(new ExileTargetAndSearchGraveyardHandLibraryEffect(false, "its controller's","all cards with the same name as that land")); } public SowingSalt(final SowingSalt card) { diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/Splinter.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/Splinter.java index 8663df9093..ba41843d4d 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/Splinter.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/Splinter.java @@ -52,7 +52,7 @@ public class Splinter extends CardImpl { // Exile target artifact. Search its controller's graveyard, hand, and library for all cards // with the same name as that artifact and exile them. Then that player shuffles his or her library. this.getSpellAbility().addTarget(new TargetPermanent(filter)); - this.getSpellAbility().addEffect(new ExileTargetAndSearchGraveyardHandLibraryEffect()); + this.getSpellAbility().addEffect(new ExileTargetAndSearchGraveyardHandLibraryEffect(false, "its controller's","all cards with the same name as that artifact")); } public Splinter(final Splinter card) { diff --git a/Mage/src/mage/abilities/effects/common/CounterTargetAndSearchGraveyardHandLibraryEffect.java b/Mage/src/mage/abilities/effects/common/CounterTargetAndSearchGraveyardHandLibraryEffect.java index e93378fb8f..df496e68d4 100644 --- a/Mage/src/mage/abilities/effects/common/CounterTargetAndSearchGraveyardHandLibraryEffect.java +++ b/Mage/src/mage/abilities/effects/common/CounterTargetAndSearchGraveyardHandLibraryEffect.java @@ -29,19 +29,13 @@ package mage.abilities.effects.common; import java.util.UUID; -import mage.Constants; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.SpellAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; import mage.cards.Card; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.game.stack.StackObject; -import mage.players.Player; import mage.target.TargetSpell; /** @@ -49,24 +43,19 @@ import mage.target.TargetSpell; * @author LevelX2 */ -public class CounterTargetAndSearchGraveyardHandLibraryEffect extends OneShotEffect { +public class CounterTargetAndSearchGraveyardHandLibraryEffect extends SearchTargetGraveyardHandLibraryForCardNameAndExileEffect { - private String exileZone = null; - private UUID exileId = null; public CounterTargetAndSearchGraveyardHandLibraryEffect() { - super(Constants.Outcome.Exile); + this(false,"its controller's", "all cards with the same name as that spell" ); } - public CounterTargetAndSearchGraveyardHandLibraryEffect(UUID exileId, String exileZone) { - this(); - this.exileId = exileId; - this.exileZone = exileZone; + public CounterTargetAndSearchGraveyardHandLibraryEffect(Boolean graveyardExileOptional, String searchWhatText, String searchForText) { + super(graveyardExileOptional, searchWhatText, searchForText); } + public CounterTargetAndSearchGraveyardHandLibraryEffect(final CounterTargetAndSearchGraveyardHandLibraryEffect effect) { super(effect); - this.exileZone = effect.exileZone; - this.exileId = effect.exileId; } @Override @@ -77,22 +66,9 @@ public class CounterTargetAndSearchGraveyardHandLibraryEffect extends OneShotEff @Override public boolean apply(Game game, Ability source) { boolean result = false; - String sourceName = null; - if (source instanceof SpellAbility) { - Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null) { - sourceName = sourceCard.getName(); - } - } else { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null) { - sourceName = sourcePermanent.getName(); - } - } - - Card chosenCard = null; - Player you = game.getPlayer(source.getControllerId()); - Player searchPlayer = null; + + String cardName = ""; + UUID searchPlayerId = null; if (source.getTargets().get(0) instanceof TargetSpell) { UUID objectId = source.getFirstTarget(); @@ -100,57 +76,25 @@ public class CounterTargetAndSearchGraveyardHandLibraryEffect extends OneShotEff if (stackObject != null) { MageObject targetObject = game.getObject(stackObject.getSourceId()); if (targetObject instanceof Card) { - chosenCard = (Card) targetObject; + cardName = targetObject.getName(); } - searchPlayer = game.getPlayer(stackObject.getControllerId()); + searchPlayerId = stackObject.getControllerId(); result = game.getStack().counter(objectId, source.getSourceId(), game); } - } - - if (searchPlayer != null && you != null && chosenCard != null) { - game.informPlayers("Searched for cards with the name: " + chosenCard.getName()); - //cards in Library - Cards cardsInLibrary = new CardsImpl(Constants.Zone.LIBRARY); - cardsInLibrary.addAll(searchPlayer.getLibrary().getCards(game)); - you.lookAtCards(sourceName + " search of Library", cardsInLibrary, game); - - // cards in Graveyard - Cards cardsInGraveyard = new CardsImpl(Constants.Zone.GRAVEYARD); - cardsInGraveyard.addAll(searchPlayer.getGraveyard()); - - // cards in Hand - Cards cardsInHand = new CardsImpl(Constants.Zone.HAND); - cardsInHand.addAll(searchPlayer.getHand()); - you.lookAtCards(sourceName + " search of Hand", cardsInHand, game); - - // exile same named cards from zones - for (Card checkCard : cardsInLibrary.getCards(game)) { - if (checkCard.getName().equals(chosenCard.getName())) { - checkCard.moveToExile(id, "Library", id, game); - } - } - for (Card checkCard : cardsInGraveyard.getCards(game)) { - if (checkCard.getName().equals(chosenCard.getName())) { - checkCard.moveToExile(id, "Graveyard", id, game); - } - } - for (Card checkCard : cardsInHand.getCards(game)) { - if (checkCard.getName().equals(chosenCard.getName())) { - checkCard.moveToExile(id, "Hand", id, game); - } - } - - searchPlayer.shuffleLibrary(game); } + // 5/1/2008: If the targeted spell can't be countered (it's Vexing Shusher, for example), + // that spell will remain on the stack. Counterbore will continue to resolve. You still + // get to search for and exile all other cards with that name. + this.applySearchAndExile(game, source, cardName, searchPlayerId); + return result; } - - @Override - public String getText(Mode mode) { + + @Override + public String getText(Mode mode) { StringBuilder sb = new StringBuilder(); - sb.append("Counter target ").append(mode.getTargets().get(0).getTargetName()).append(". "); - sb.append("Search its controller's graveyard, hand, and library for all cards with the same name as that spell and exile them. "); - sb.append("Then that player shuffles his or her library"); + sb.append("Counter target ").append(mode.getTargets().get(0).getFilter().getMessage()).append(". "); + sb.append(super.getText(mode)); return sb.toString(); - } + } } diff --git a/Mage/src/mage/abilities/effects/common/ExileTargetAndSearchGraveyardHandLibraryEffect.java b/Mage/src/mage/abilities/effects/common/ExileTargetAndSearchGraveyardHandLibraryEffect.java index 554ba92580..c97b557794 100644 --- a/Mage/src/mage/abilities/effects/common/ExileTargetAndSearchGraveyardHandLibraryEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileTargetAndSearchGraveyardHandLibraryEffect.java @@ -29,46 +29,69 @@ package mage.abilities.effects.common; import java.util.UUID; -import mage.Constants; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.SpellAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; import mage.cards.Card; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; -import mage.target.common.TargetArtifactPermanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPlayer; /** * * @author LevelX2 */ -public class ExileTargetAndSearchGraveyardHandLibraryEffect extends OneShotEffect { +public class ExileTargetAndSearchGraveyardHandLibraryEffect extends SearchTargetGraveyardHandLibraryForCardNameAndExileEffect { - private String exileZone = null; - private UUID exileId = null; - - public ExileTargetAndSearchGraveyardHandLibraryEffect() { - super(Constants.Outcome.Exile); + public ExileTargetAndSearchGraveyardHandLibraryEffect(Boolean graveyardExileOptional, String searchWhatText, String searchForText) { + super(graveyardExileOptional, searchWhatText, searchForText); } - public ExileTargetAndSearchGraveyardHandLibraryEffect(UUID exileId, String exileZone) { - this(); - this.exileId = exileId; - this.exileZone = exileZone; - } - public ExileTargetAndSearchGraveyardHandLibraryEffect(final ExileTargetAndSearchGraveyardHandLibraryEffect effect) { super(effect); - this.exileZone = effect.exileZone; - this.exileId = effect.exileId; + } + + @Override + public boolean apply(Game game, Ability source) { + boolean result = false; + String cardName = ""; + UUID targetPlayerId = null; + // define cardName + if (source instanceof SpellAbility) { + Card sourceCard = game.getCard(source.getSourceId()); + if (sourceCard != null) { + cardName = sourceCard.getName(); + } + } else { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent != null) { + cardName = sourcePermanent.getName(); + } + } + // get Target to exile + Target exileTarget = null; + for (Target target : source.getTargets()) { + if (!(target instanceof TargetPlayer)) { + exileTarget = target; + break; + } + } + + if (exileTarget != null && exileTarget instanceof TargetPermanent) { + Permanent permanentToExile = game.getPermanent(exileTarget.getFirstTarget()); + if (permanentToExile != null) { + targetPlayerId = permanentToExile.getControllerId(); + result = permanentToExile.moveToExile(null, "", source.getSourceId(), game); + } + } + + this.applySearchAndExile(game, source, cardName, targetPlayerId); + + return result; } @Override @@ -76,90 +99,11 @@ public class ExileTargetAndSearchGraveyardHandLibraryEffect extends OneShotEffec return new ExileTargetAndSearchGraveyardHandLibraryEffect(this); } - @Override - public boolean apply(Game game, Ability source) { - boolean result = false; - String sourceName = null; - if (source instanceof SpellAbility) { - Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null) { - sourceName = sourceCard.getName(); - } - } else { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null) { - sourceName = sourcePermanent.getName(); - } - } - - Card chosenCard = null; - Player you = game.getPlayer(source.getControllerId()); - Player searchPlayer = null; - Target target = source.getTargets().get(0); - if (target != null && target instanceof TargetPermanent) { - Permanent permanentToExile = game.getPermanent(targetPointer.getFirst(game, source)); - if (permanentToExile != null) { - chosenCard = permanentToExile; - searchPlayer = game.getPlayer(permanentToExile.getOwnerId()); - result = permanentToExile.moveToExile(exileId, exileZone, source.getSourceId(), game); - } - } - - if (searchPlayer != null && you != null && chosenCard != null) { - game.informPlayers("Searched for cards with the name: " + chosenCard.getName()); - //cards in Library - Cards cardsInLibrary = new CardsImpl(Constants.Zone.LIBRARY); - cardsInLibrary.addAll(searchPlayer.getLibrary().getCards(game)); - you.lookAtCards(sourceName + " search of Library", cardsInLibrary, game); - - // cards in Graveyard - Cards cardsInGraveyard = new CardsImpl(Constants.Zone.GRAVEYARD); - cardsInGraveyard.addAll(searchPlayer.getGraveyard()); - - // cards in Hand - Cards cardsInHand = new CardsImpl(Constants.Zone.HAND); - cardsInHand.addAll(searchPlayer.getHand()); - you.lookAtCards(sourceName + " search of Hand", cardsInHand, game); - - // exile same named cards from zones - for (Card checkCard : cardsInLibrary.getCards(game)) { - if (checkCard.getName().equals(chosenCard.getName())) { - checkCard.moveToExile(id, "Library", id, game); - } - } - for (Card checkCard : cardsInGraveyard.getCards(game)) { - if (checkCard.getName().equals(chosenCard.getName())) { - checkCard.moveToExile(id, "Graveyard", id, game); - } - } - for (Card checkCard : cardsInHand.getCards(game)) { - if (checkCard.getName().equals(chosenCard.getName())) { - checkCard.moveToExile(id, "Hand", id, game); - } - } - - searchPlayer.shuffleLibrary(game); - } - return result; - } - @Override public String getText(Mode mode) { StringBuilder sb = new StringBuilder(); - Target target = mode.getTargets().get(0); - sb.append("Exile target ").append(target.getTargetName()).append(". "); - sb.append("Search its controller's graveyard, hand, and library for all cards with the same name as that "); - - if (target instanceof TargetCreaturePermanent) { - sb.append("creature"); - } else if (target instanceof TargetCreaturePermanent) { - sb.append("land"); - } else if (target instanceof TargetArtifactPermanent) { - sb.append("artifact"); - } else { - sb.append(target.getTargetName()); - } - sb.append(" and exile them. Then that player shuffles his or her library"); + sb.append("Exile target ").append(mode.getTargets().get(0).getTargetName()).append(". "); + sb.append(super.getText(mode)); return sb.toString(); - } -} + } +} \ No newline at end of file diff --git a/Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java b/Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java new file mode 100644 index 0000000000..6b4d2677b4 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java @@ -0,0 +1,165 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.abilities.effects.common.search; + +import java.util.List; +import java.util.UUID; +import mage.Constants.Outcome; +import mage.Constants.Zone; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author LevelX2 + */ + +public abstract class SearchTargetGraveyardHandLibraryForCardNameAndExileEffect extends OneShotEffect { + + protected String searchWhatText; + protected String searchForText; + + /* Slaughter Games + * 10/1/2012: You can leave any cards with that name in the zone they are in. You don’t have to exile them. + * + * Sowing Salt + * 2/1/2005: The copies must be found if they are in publicly viewable zones. Finding copies while searching private zones is optional. + */ + protected Boolean graveyardExileOptional; + + public SearchTargetGraveyardHandLibraryForCardNameAndExileEffect(Boolean graveyardExileOptional, String searchWhatText, String searchForText) { + super(Outcome.Exile); + this.searchWhatText = searchWhatText; + this.searchForText = searchForText; + this.graveyardExileOptional = graveyardExileOptional; + } + + public SearchTargetGraveyardHandLibraryForCardNameAndExileEffect(final SearchTargetGraveyardHandLibraryForCardNameAndExileEffect effect) { + super(effect); + this.searchWhatText = effect.searchWhatText; + this.searchForText = effect.searchForText; + this.graveyardExileOptional = effect.graveyardExileOptional; + } + + public boolean applySearchAndExile(Game game, Ability source, String cardName, UUID targetPlayerId) { + Player player = game.getPlayer(source.getControllerId()); + if (cardName != null && player != null) { + Player targetPlayer = game.getPlayer(targetPlayerId); + if (targetPlayer != null) { + FilterCard filter = new FilterCard("card named " + cardName); + filter.add(new NamePredicate(cardName)); + + // cards in Graveyard + int cardsCount = (cardName.isEmpty() ? 0 :targetPlayer.getGraveyard().count(filter, game)); + if (cardsCount > 0) { + filter.setMessage("card named " + cardName + " in the graveyard of " + targetPlayer.getName()); + TargetCardInGraveyard target = new TargetCardInGraveyard((graveyardExileOptional ? 0 :cardsCount), cardsCount, filter); + if (player.choose(Outcome.Exile, targetPlayer.getGraveyard(), target, game)) { + List targets = target.getTargets(); + for (UUID targetId : targets) { + Card targetCard = targetPlayer.getGraveyard().get(targetId, game); + if (targetCard != null) { + targetPlayer.getGraveyard().remove(targetCard); + targetCard.moveToZone(Zone.EXILED, source.getId(), game, false); + } + } + } + } + + // cards in Hand + cardsCount = (cardName.isEmpty() ? 0 :targetPlayer.getHand().count(filter, game)); + if (cardsCount > 0) { + filter.setMessage("card named " + cardName + " in the hand of " + targetPlayer.getName()); + TargetCardInHand target = new TargetCardInHand(0, cardsCount, filter); + if (player.choose(Outcome.Exile, targetPlayer.getHand(), target, game)) { + List targets = target.getTargets(); + for (UUID targetId : targets) { + Card targetCard = targetPlayer.getHand().get(targetId, game); + if (targetCard != null) { + targetPlayer.getHand().remove(targetCard); + targetCard.moveToZone(Zone.EXILED, source.getId(), game, false); + } + } + } + } else { + if (targetPlayer.getHand().size() > 0) { + player.lookAtCards(targetPlayer.getName() + " hand", targetPlayer.getHand(), game); + } + } + + // cards in Library + Cards cardsInLibrary = new CardsImpl(Zone.LIBRARY); + cardsInLibrary.addAll(targetPlayer.getLibrary().getCards(game)); + cardsCount = (cardName.isEmpty() ? 0 :cardsInLibrary.count(filter, game)); + if (cardsCount > 0) { + filter.setMessage("card named " + cardName + " in the library of " + targetPlayer.getName()); + TargetCardInLibrary target = new TargetCardInLibrary(0, cardsCount, filter); + if (player.choose(Outcome.Exile, cardsInLibrary, target, game)) { + List targets = target.getTargets(); + for (UUID targetId : targets) { + Card targetCard = targetPlayer.getLibrary().remove(targetId, game); + if (targetCard != null) { + targetCard.moveToZone(Zone.EXILED, source.getId(), game, false); + } + } + } + } else { + player.lookAtCards(targetPlayer.getName() + " library", cardsInLibrary, game); + } + } + + targetPlayer.shuffleLibrary(game); + + return true; + } + + return false; + } + + @Override + public String getText(Mode mode) { + StringBuilder sb = new StringBuilder(); + sb.append("Search ").append(this.searchWhatText); + sb.append(" graveyard, hand, and library for "); + sb.append(this.searchForText); + sb.append(" and exile them. Then that player shuffles his or her library"); + return sb.toString(); + } +}