From 8bd3109c879657f3e391ff1176d74113ba41fe3d Mon Sep 17 00:00:00 2001 From: LevelX2 <ludwig.hirth@online.de> Date: Thu, 29 May 2014 10:27:52 +0200 Subject: [PATCH] * Fixed some game locking loops if a player concedes while resolving an effect (e.g. Scry, Discard). Some changes to game log for info about moving cards to library. --- .../mage/sets/alarareborn/MaelstromNexus.java | 7 +++++-- .../journeyintonyx/AjaniMentorOfHeroes.java | 2 -- .../src/mage/sets/mirage/PainfulMemories.java | 2 +- .../JaceArchitectOfThought.java | 4 ++-- .../seventhedition/AgonizingMemories.java | 3 +-- Mage.Sets/src/mage/sets/zendikar/Gomazoa.java | 4 ++-- ...utTopCardOfYourLibraryToGraveyardCost.java | 2 +- .../common/LookLibraryControllerEffect.java | 2 +- .../effects/common/ReturnFromExileEffect.java | 2 +- .../RevealLibraryPutIntoHandEffect.java | 2 +- .../abilities/effects/common/ScryEffect.java | 19 +++++++------------ .../discard/DiscardEachPlayerEffect.java | 2 +- .../abilities/keyword/CascadeAbility.java | 11 +++++++---- .../abilities/keyword/HideawayAbility.java | 2 +- .../mage/abilities/keyword/KickerAbility.java | 2 +- .../abilities/keyword/ReplicateAbility.java | 2 +- Mage/src/mage/cards/Sets.java | 2 +- Mage/src/mage/players/Player.java | 3 ++- Mage/src/mage/players/PlayerImpl.java | 14 +++++++------- 19 files changed, 43 insertions(+), 44 deletions(-) diff --git a/Mage.Sets/src/mage/sets/alarareborn/MaelstromNexus.java b/Mage.Sets/src/mage/sets/alarareborn/MaelstromNexus.java index 748c3d4bb2..22f78ee5d7 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/MaelstromNexus.java +++ b/Mage.Sets/src/mage/sets/alarareborn/MaelstromNexus.java @@ -167,6 +167,9 @@ class CascadeEffect extends OneShotEffect<CascadeEffect> { public boolean apply(Game game, Ability source) { Card card; Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } ExileZone exile = game.getExile().createZone(source.getSourceId(), player.getName() + " Cascade"); Card stackCard = game.getCard(targetPointer.getFirst(game, source)); if (stackCard == null) { @@ -179,7 +182,7 @@ class CascadeEffect extends OneShotEffect<CascadeEffect> { break; } - card.moveToExile(exile.getId(), exile.getName(), source.getId(), game); + player.moveCardToExileWithInfo(card, source.getId(), exile.getName(), source.getSourceId(), game, Zone.LIBRARY); } while (card.getCardType().contains(CardType.LAND) || card.getManaCost().convertedManaCost() >= sourceCost); if (card != null) { @@ -192,7 +195,7 @@ class CascadeEffect extends OneShotEffect<CascadeEffect> { while (exile.size() > 0) { card = exile.getRandom(game); exile.remove(card.getId()); - card.moveToZone(Zone.LIBRARY, source.getId(), game, false); + player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.EXILED, false, false); } return true; diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/AjaniMentorOfHeroes.java b/Mage.Sets/src/mage/sets/journeyintonyx/AjaniMentorOfHeroes.java index d0c9bc7835..dc66e7b180 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/AjaniMentorOfHeroes.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/AjaniMentorOfHeroes.java @@ -42,12 +42,10 @@ import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.Filter; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; diff --git a/Mage.Sets/src/mage/sets/mirage/PainfulMemories.java b/Mage.Sets/src/mage/sets/mirage/PainfulMemories.java index e2d6a3f3b8..05fcb32e2f 100644 --- a/Mage.Sets/src/mage/sets/mirage/PainfulMemories.java +++ b/Mage.Sets/src/mage/sets/mirage/PainfulMemories.java @@ -98,7 +98,7 @@ class PainfulMemoriesEffect extends OneShotEffect<PainfulMemoriesEffect> { if (you.choose(Outcome.Benefit, targetPlayer.getHand(), target, game)) { Card card = targetPlayer.getHand().get(target.getFirstTarget(), game); if (card != null) { - return targetPlayer.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, true); + return targetPlayer.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, true, true); } } } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java b/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java index 4bc6cfcf6e..c15efab1c8 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java @@ -311,13 +311,13 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect<JaceArchitectOfThought Card card = cardsToLibrary.get(targetCard.getFirstTarget(), game); if (card != null) { cardsToLibrary.remove(card); - player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false); + player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); } target.clearChosen(); } if (cardsToLibrary.size() == 1) { Card card = cardsToLibrary.get(cardsToLibrary.iterator().next(), game); - player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false); + player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); } return true; } diff --git a/Mage.Sets/src/mage/sets/seventhedition/AgonizingMemories.java b/Mage.Sets/src/mage/sets/seventhedition/AgonizingMemories.java index 6be1dc393e..980ceda6aa 100644 --- a/Mage.Sets/src/mage/sets/seventhedition/AgonizingMemories.java +++ b/Mage.Sets/src/mage/sets/seventhedition/AgonizingMemories.java @@ -99,14 +99,13 @@ class AgonizingMemoriesEffect extends OneShotEffect<AgonizingMemoriesEffect> { } private void chooseCardInHandAndPutOnTopOfLibrary(Game game, Ability source, Player you, Player targetPlayer) { - MageObject sourceObject = game.getObject(source.getSourceId()); if (targetPlayer.getHand().size() > 0) { TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the top of library (last chosen will be on top)")); target.setRequired(true); if (you.choose(Outcome.Benefit, targetPlayer.getHand(), target, game)) { Card card = targetPlayer.getHand().get(target.getFirstTarget(), game); if (card != null) { - targetPlayer.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, true); + targetPlayer.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, true, false); } } } diff --git a/Mage.Sets/src/mage/sets/zendikar/Gomazoa.java b/Mage.Sets/src/mage/sets/zendikar/Gomazoa.java index 65d5356785..678a73c11a 100644 --- a/Mage.Sets/src/mage/sets/zendikar/Gomazoa.java +++ b/Mage.Sets/src/mage/sets/zendikar/Gomazoa.java @@ -110,7 +110,7 @@ class GomazoaEffect extends OneShotEffect<GomazoaEffect> { List<UUID> players = new ArrayList<>(); Permanent gomazoa = game.getPermanent(source.getSourceId()); if (gomazoa != null) { - controller.moveCardToLibraryWithInfo(gomazoa, source.getSourceId(), game, Zone.BATTLEFIELD, true); + controller.moveCardToLibraryWithInfo(gomazoa, source.getSourceId(), game, Zone.BATTLEFIELD, true, true); players.add(gomazoa.getOwnerId()); } @@ -123,7 +123,7 @@ class GomazoaEffect extends OneShotEffect<GomazoaEffect> { players.add(blockedByGomazoa.getOwnerId()); Player owner = game.getPlayer(blockedByGomazoa.getOwnerId()); if (owner != null) { - owner.moveCardToLibraryWithInfo(blockedByGomazoa, source.getSourceId(), game, Zone.BATTLEFIELD, true); + owner.moveCardToLibraryWithInfo(blockedByGomazoa, source.getSourceId(), game, Zone.BATTLEFIELD, true, true); } } } diff --git a/Mage/src/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java b/Mage/src/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java index c4868044f1..0409e43427 100644 --- a/Mage/src/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java +++ b/Mage/src/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java @@ -67,7 +67,7 @@ public class PutTopCardOfYourLibraryToGraveyardCost extends CostImpl<PutTopCardO if (player != null && player.getLibrary().size() >= numberOfCards) { int i = 0; paid = true; - while (i < numberOfCards) { + while (player.isInGame() && i < numberOfCards) { Card card = player.getLibrary().removeFromTop(game); if (card != null) { // all cards must reach the graveyard to pay the costs diff --git a/Mage/src/mage/abilities/effects/common/LookLibraryControllerEffect.java b/Mage/src/mage/abilities/effects/common/LookLibraryControllerEffect.java index 0dea2dc95f..882ed8cc42 100644 --- a/Mage/src/mage/abilities/effects/common/LookLibraryControllerEffect.java +++ b/Mage/src/mage/abilities/effects/common/LookLibraryControllerEffect.java @@ -165,7 +165,7 @@ public class LookLibraryControllerEffect extends OneShotEffect<LookLibraryContro case LIBRARY: TargetCard target = new TargetCard(Zone.PICK, new FilterCard(this.getPutBackText())); target.setRequired(true); - while (cards.size() > 1) { + while (player.isInGame() && cards.size() > 1) { player.choose(Outcome.Neutral, cards, target, game); Card card = cards.get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage/src/mage/abilities/effects/common/ReturnFromExileEffect.java b/Mage/src/mage/abilities/effects/common/ReturnFromExileEffect.java index 9c0c1fefd3..f657a615e2 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnFromExileEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnFromExileEffect.java @@ -102,7 +102,7 @@ public class ReturnFromExileEffect extends OneShotEffect<ReturnFromExileEffect> controller.moveCardToGraveyardWithInfo(card, source.getSourceId(), game, Zone.EXILED); break; case LIBRARY: - controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.EXILED, true); + controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.EXILED, true, true); break; default: card.moveToZone(zone, source.getSourceId(), game, tapped); diff --git a/Mage/src/mage/abilities/effects/common/RevealLibraryPutIntoHandEffect.java b/Mage/src/mage/abilities/effects/common/RevealLibraryPutIntoHandEffect.java index 8626531f07..e9d08be89d 100644 --- a/Mage/src/mage/abilities/effects/common/RevealLibraryPutIntoHandEffect.java +++ b/Mage/src/mage/abilities/effects/common/RevealLibraryPutIntoHandEffect.java @@ -98,7 +98,7 @@ public class RevealLibraryPutIntoHandEffect extends OneShotEffect<RevealLibraryP } } - while (cards.size() > 1) { + while (player.isInGame() && cards.size() > 1) { Card card; if (anyOrder) { TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); diff --git a/Mage/src/mage/abilities/effects/common/ScryEffect.java b/Mage/src/mage/abilities/effects/common/ScryEffect.java index d4b1da613a..afafd87ddd 100644 --- a/Mage/src/mage/abilities/effects/common/ScryEffect.java +++ b/Mage/src/mage/abilities/effects/common/ScryEffect.java @@ -28,13 +28,13 @@ package mage.abilities.effects.common; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.Outcome; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.game.events.GameEvent; @@ -81,37 +81,32 @@ public class ScryEffect extends OneShotEffect<ScryEffect> { } TargetCard target1 = new TargetCard(Zone.LIBRARY, filter1); // move cards to the bottom of the library - while (cards.size() > 0 && player.choose(Outcome.Detriment, cards, target1, game)) { + while (player.isInGame() && cards.size() > 0 && player.choose(Outcome.Detriment, cards, target1, game)) { Card card = cards.get(target1.getFirstTarget(), game); if (card != null) { cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); + player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); } target1.clearChosen(); } // move cards to the top of the library - int onBottom = scryNumber - cards.size(); if (cards.size() > 1) { TargetCard target2 = new TargetCard(Zone.LIBRARY, filter2); target2.setRequired(true); - while (cards.size() > 1) { + while (player.isInGame() && cards.size() > 1) { player.choose(Outcome.Benefit, cards, target2, game); Card card = cards.get(target2.getFirstTarget(), game); if (card != null) { cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, true, false); } target2.clearChosen(); } } if (cards.size() == 1) { Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, true, false); } - game.informPlayers(new StringBuilder(player.getName()).append(" puts ") - .append(onBottom).append(onBottom == 1 ?" card":" cards") - .append(" on the bottom of his or her library (scry ") - .append(scryNumber).append(")").toString()); game.fireEvent(new GameEvent(GameEvent.EventType.SCRY, source.getControllerId(), source.getSourceId(), source.getControllerId())); player.setTopCardRevealed(revealed); return true; diff --git a/Mage/src/mage/abilities/effects/common/discard/DiscardEachPlayerEffect.java b/Mage/src/mage/abilities/effects/common/discard/DiscardEachPlayerEffect.java index b8b1d020dc..072eeed643 100644 --- a/Mage/src/mage/abilities/effects/common/discard/DiscardEachPlayerEffect.java +++ b/Mage/src/mage/abilities/effects/common/discard/DiscardEachPlayerEffect.java @@ -82,7 +82,7 @@ public class DiscardEachPlayerEffect extends OneShotEffect<DiscardEachPlayerEffe int numberOfCardsToDiscard = Math.min(amount.calculate(game, source), player.getHand().size()); Cards cards = new CardsImpl(); if (randomDiscard) { - while (cards.size() < numberOfCardsToDiscard) { + while (player.isInGame() && cards.size() < numberOfCardsToDiscard) { Card card = player.getHand().getRandom(game); if (!cards.contains(card.getId())) { cards.add(card); diff --git a/Mage/src/mage/abilities/keyword/CascadeAbility.java b/Mage/src/mage/abilities/keyword/CascadeAbility.java index 9de7ef91de..491f3e75c2 100644 --- a/Mage/src/mage/abilities/keyword/CascadeAbility.java +++ b/Mage/src/mage/abilities/keyword/CascadeAbility.java @@ -110,15 +110,18 @@ class CascadeEffect extends OneShotEffect<CascadeEffect> { public boolean apply(Game game, Ability source) { Card card; Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } ExileZone exile = game.getExile().createZone(source.getSourceId(), player.getName() + " Cascade"); int sourceCost = game.getCard(source.getSourceId()).getManaCost().convertedManaCost(); do { card = player.getLibrary().getFromTop(game); if (card == null) { break; - } - card.moveToExile(exile.getId(), exile.getName(), source.getId(), game); - } while (card.getCardType().contains(CardType.LAND) || card.getManaCost().convertedManaCost() >= sourceCost); + } + player.moveCardToExileWithInfo(card, source.getId(), exile.getName(), source.getSourceId(), game, Zone.LIBRARY); + } while (player.isInGame() && card.getCardType().contains(CardType.LAND) || card.getManaCost().convertedManaCost() >= sourceCost); if (card != null) { if (player.chooseUse(outcome, "Use cascade effect on " + card.getName() + "?", game)) { @@ -130,7 +133,7 @@ class CascadeEffect extends OneShotEffect<CascadeEffect> { while (exile.size() > 0) { card = exile.getRandom(game); exile.remove(card.getId()); - card.moveToZone(Zone.LIBRARY, source.getId(), game, false); + player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.EXILED, false, false); } return true; diff --git a/Mage/src/mage/abilities/keyword/HideawayAbility.java b/Mage/src/mage/abilities/keyword/HideawayAbility.java index e9e54af982..27698060ca 100644 --- a/Mage/src/mage/abilities/keyword/HideawayAbility.java +++ b/Mage/src/mage/abilities/keyword/HideawayAbility.java @@ -141,7 +141,7 @@ class HideawayExileEffect extends OneShotEffect<HideawayExileEffect> { if (cards.size() > 0) { TargetCard target2 = new TargetCard(Zone.PICK, filter2); target2.setRequired(true); - while (cards.size() > 1) { + while (player.isInGame() && cards.size() > 1) { player.choose(Outcome.Benefit, cards, target2, game); Card card = cards.get(target2.getFirstTarget(), game); if (card != null) { diff --git a/Mage/src/mage/abilities/keyword/KickerAbility.java b/Mage/src/mage/abilities/keyword/KickerAbility.java index b5ce4e9214..84b4a26d4d 100644 --- a/Mage/src/mage/abilities/keyword/KickerAbility.java +++ b/Mage/src/mage/abilities/keyword/KickerAbility.java @@ -201,7 +201,7 @@ public class KickerAbility extends StaticAbility<KickerAbility> implements Optio this.resetKicker(); for (OptionalAdditionalCost kickerCost: kickerCosts) { boolean again = true; - while (again) { + while (player.isInGame() && again) { String times = ""; if (kickerCost.isRepeatable()) { int activated = kickerCost.getActivateCount(); diff --git a/Mage/src/mage/abilities/keyword/ReplicateAbility.java b/Mage/src/mage/abilities/keyword/ReplicateAbility.java index 3c00d57fd2..86e0ea75a5 100644 --- a/Mage/src/mage/abilities/keyword/ReplicateAbility.java +++ b/Mage/src/mage/abilities/keyword/ReplicateAbility.java @@ -114,7 +114,7 @@ public class ReplicateAbility extends StaticAbility<ReplicateAbility> implements this.resetReplicate(); boolean again = true; - while (again) { + while (player.isInGame() && again) { String times = ""; if (additionalCost.isRepeatable()) { int activated = additionalCost.getActivateCount(); diff --git a/Mage/src/mage/cards/Sets.java b/Mage/src/mage/cards/Sets.java index cf547560cf..3b894e9347 100644 --- a/Mage/src/mage/cards/Sets.java +++ b/Mage/src/mage/cards/Sets.java @@ -104,7 +104,7 @@ public class Sets extends HashMap<String, ExpansionSet> { int count = 0; int tries = 0; - List<Card> cardPool = new ArrayList<Card>(); + List<Card> cardPool = new ArrayList<>(); while (count < cardsCount) { CardInfo cardInfo = cards.get(rnd.nextInt(cards.size())); Card card = cardInfo != null ? cardInfo.getCard() : null; diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index fc822b4200..c3b5e4e6b1 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -439,9 +439,10 @@ public interface Player extends MageItem, Copyable<Player> { * @param game * @param fromZone if null, this info isn't postet * @param toTop to the top of the library else to the bottom + * @param withName show the card name in the log * @return */ - boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop); + boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop, boolean withName); /** diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 48620159ca..dee922208f 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -563,7 +563,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser public void discardToMax(Game game) { if (hand.size() > this.maxHandSize) { game.informPlayers(new StringBuilder(getName()).append(" discards down to ").append(this.maxHandSize).append(this.maxHandSize == 1?" hand card":" hand cards").toString()); - while (hand.size() > this.maxHandSize) { + while (isInGame() && hand.size() > this.maxHandSize) { TargetDiscard target = new TargetDiscard(playerId); target.setTargetName(new StringBuilder(" card to discard (").append(hand.size() - this.maxHandSize).append(" in total)").toString()); choose(Outcome.Discard, target, null, game); @@ -607,7 +607,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser return; } int numDiscarded = 0; - while (numDiscarded < amount) { + while (isInGame() && numDiscarded < amount) { if (hand.size() == 0) { break; } @@ -713,7 +713,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser } else { TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); target.setRequired(true); - while (cards.size() > 1) { + while (isInGame() && cards.size() > 1) { this.choose(Outcome.Neutral, cards, target, game); Card chosenCard = cards.get(target.getFirstTarget(), game); if (chosenCard != null) { @@ -1130,7 +1130,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser filter.add(Predicates.not(new PermanentIdPredicate(permanent.getId()))); } // while targets left and there is still allowed to untap - while (leftForUntap.size() > 0 && numberToUntap > 0) { + while (isInGame() && leftForUntap.size() > 0 && numberToUntap > 0) { // player has to select the permanent he wants to untap for this restriction Ability ability = handledEntry.getKey().getValue().iterator().next(); if (ability != null) { @@ -1180,7 +1180,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser } } - } while (playerCanceledSelection); + } while (isInGame() && playerCanceledSelection); // show in log which permanents were selected to untap for(Permanent permanent :selectedToUntap) { @@ -2237,11 +2237,11 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser } @Override - public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop) { + public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop, boolean withName) { boolean result = false; if (card.moveToZone(Zone.LIBRARY, sourceId, game, toTop)) { game.informPlayers(new StringBuilder(this.getName()) - .append(" puts ").append(card.getName()).append(" ") + .append(" puts ").append(withName ? card.getName():"a card").append(" ") .append(fromZone != null ? new StringBuilder("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" "):"") .append("to the ").append(toTop ? "top":"bottom").append(" of his or her library").toString()); result = true;