mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 05:09:16 -08:00
Refactor: improved choose cards method to use source param (fixed NPE like #10233, #9974 and other bugs with choose cards)
This commit is contained in:
parent
5474787641
commit
689b93d005
280 changed files with 341 additions and 342 deletions
|
|
@ -69,7 +69,7 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
TargetCard target = new TargetCard(Zone.OUTSIDE, filterCard);
|
||||
if (player.choose(Outcome.Benefit, filteredCards, target, game)) {
|
||||
if (player.choose(Outcome.Benefit, filteredCards, target, source, game)) {
|
||||
Card card = player.getSideboard().get(target.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class DrawDiscardOneOfThemEffect extends OneShotEffect {
|
|||
if (!drawnCards.isEmpty()) {
|
||||
TargetCard cardToDiscard = new TargetCard(Zone.HAND, new FilterCard("card to discard"));
|
||||
cardToDiscard.setNotTarget(true);
|
||||
if (controller.choose(Outcome.Discard, drawnCards, cardToDiscard, game)) {
|
||||
if (controller.choose(Outcome.Discard, drawnCards, cardToDiscard, source, game)) {
|
||||
Card card = controller.getHand().get(cardToDiscard.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
return controller.discard(card, false, source, game);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public class ExileCardYouChooseTargetOpponentEffect extends OneShotEffect {
|
|||
return true;
|
||||
}
|
||||
TargetCard target = new TargetCard(Zone.HAND, filter);
|
||||
controller.choose(Outcome.Exile, opponent.getHand(), target, game);
|
||||
controller.choose(Outcome.Exile, opponent.getHand(), target, source, game);
|
||||
Card card = opponent.getHand().get(target.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
controller.moveCards(card, Zone.EXILED, source, game);
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public class MillThenPutInHandEffect extends OneShotEffect {
|
|||
return applyOtherwiseEffect(game, source);
|
||||
}
|
||||
TargetCard target = new TargetCard(0, 1, Zone.ALL, filter);
|
||||
player.choose(Outcome.DrawCard, cards, target, game);
|
||||
player.choose(Outcome.DrawCard, cards, target, source, game);
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card == null) {
|
||||
return applyOtherwiseEffect(game, source);
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ public class PutCardFromOneOfTwoZonesOntoBattlefieldEffect extends OneShotEffect
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
controller.choose(outcome, cards, targetCard, game);
|
||||
controller.choose(outcome, cards, targetCard, source, game);
|
||||
Card card = game.getCard(targetCard.getFirstTarget());
|
||||
if (card == null || !controller.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, false, null)) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ public class RevealAndSeparatePilesEffect extends OneShotEffect {
|
|||
Player separatingPlayer = this.getExecutingPlayer(controller, game, source, playerWhoSeparates, "separate the revealed cards");
|
||||
TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, filter);
|
||||
List<Card> pile1 = new ArrayList<>();
|
||||
separatingPlayer.choose(Outcome.Neutral, cards, target, game);
|
||||
separatingPlayer.choose(Outcome.Neutral, cards, target, source, game);
|
||||
target.getTargets()
|
||||
.stream()
|
||||
.map(game::getCard)
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ public class WishEffect extends OneShotEffect {
|
|||
|
||||
TargetCard target = new TargetCard(Zone.ALL, filter);
|
||||
target.setNotTarget(true);
|
||||
if (controller.choose(Outcome.Benefit, filteredCards, target, game)) {
|
||||
if (controller.choose(Outcome.Benefit, filteredCards, target, source, game)) {
|
||||
Card card = controller.getSideboard().get(target.getFirstTarget(), game);
|
||||
if (card == null && alsoFromExile) {
|
||||
card = game.getCard(target.getFirstTarget());
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ public class DiscardCardYouChooseTargetEffect extends OneShotEffect {
|
|||
return result;
|
||||
}
|
||||
TargetCard target = new TargetCard(optional ? 0 : numberToDiscard, numberToDiscard, Zone.HAND, filter);
|
||||
if (!controller.choose(Outcome.Benefit, revealedCards, target, game)) {
|
||||
if (!controller.choose(Outcome.Benefit, revealedCards, target, source, game)) {
|
||||
return result;
|
||||
}
|
||||
result = !player.discard(new CardsImpl(target.getTargets()), false, source, game).isEmpty();
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public class SearchLibraryGraveyardPutInHandEffect extends OneShotEffect {
|
|||
if (cardFound == null && controller.chooseUse(outcome, "Search your graveyard for a card named " + filter.getMessage() + '?', source, game)) {
|
||||
TargetCard target = new TargetCardInYourGraveyard(0, 1, filter, true);
|
||||
target.clearChosen();
|
||||
if (controller.choose(outcome, controller.getGraveyard(), target, game)) {
|
||||
if (controller.choose(outcome, controller.getGraveyard(), target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
cardFound = game.getCard(target.getFirstTarget());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public class SearchLibraryGraveyardPutOntoBattlefieldEffect extends OneShotEffec
|
|||
if (cardFound == null && controller.chooseUse(outcome, "Search your graveyard for a " + filter.getMessage() + '?', source, game)) {
|
||||
TargetCard target = new TargetCardInYourGraveyard(0, 1, filter, true);
|
||||
target.clearChosen();
|
||||
if (controller.choose(outcome, controller.getGraveyard(), target, game)) {
|
||||
if (controller.choose(outcome, controller.getGraveyard(), target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
cardFound = game.getCard(target.getFirstTarget());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public class SearchLibraryGraveyardWithLessMVPutIntoPlay extends OneShotEffect {
|
|||
if (cardFound == null && controller.chooseUse(outcome, "Search your graveyard for a " + filter.getMessage() + " with mana value X or less" + '?', source, game)) {
|
||||
TargetCard target = new TargetCard(0, 1, Zone.GRAVEYARD, advancedFilter);
|
||||
target.clearChosen();
|
||||
if (controller.choose(outcome, controller.getGraveyard(), target, game)) {
|
||||
if (controller.choose(outcome, controller.getGraveyard(), target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
cardFound = game.getCard(target.getFirstTarget());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public abstract class SearchTargetGraveyardHandLibraryForCardNameAndExileEffect
|
|||
if (cardsCount > 0) {
|
||||
filter.setMessage("card named " + cardName + " in the graveyard of " + targetPlayer.getName());
|
||||
TargetCard target = new TargetCard((graveyardExileOptional ? 0 : cardsCount), cardsCount, Zone.GRAVEYARD, filter);
|
||||
if (controller.choose(Outcome.Exile, targetPlayer.getGraveyard(), target, game)) {
|
||||
if (controller.choose(Outcome.Exile, targetPlayer.getGraveyard(), target, source, game)) {
|
||||
controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game);
|
||||
}
|
||||
}
|
||||
|
|
@ -78,7 +78,7 @@ public abstract class SearchTargetGraveyardHandLibraryForCardNameAndExileEffect
|
|||
cardsCount = (cardName.isEmpty() ? 0 : targetPlayer.getHand().count(filter, game));
|
||||
filter.setMessage("card named " + cardName + " in the hand of " + targetPlayer.getName());
|
||||
TargetCard target = new TargetCard(0, cardsCount, Zone.HAND, filter);
|
||||
if (controller.choose(Outcome.Exile, targetPlayer.getHand(), target, game)) {
|
||||
if (controller.choose(Outcome.Exile, targetPlayer.getHand(), target, source, game)) {
|
||||
controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game);
|
||||
}
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ public abstract class SearchTargetGraveyardHandLibraryForCardNameAndExileEffect
|
|||
cardsCount = (cardName.isEmpty() ? 0 : cardsInLibrary.count(filter, game));
|
||||
filter.setMessage("card named " + cardName + " in the library of " + targetPlayer.getLogName());
|
||||
TargetCardInLibrary targetLib = new TargetCardInLibrary(0, cardsCount, filter);
|
||||
if (controller.choose(Outcome.Exile, cardsInLibrary, targetLib, game)) {
|
||||
if (controller.choose(Outcome.Exile, cardsInLibrary, targetLib, source, game)) {
|
||||
controller.moveCards(new CardsImpl(targetLib.getTargets()), Zone.EXILED, source, game);
|
||||
}
|
||||
targetPlayer.shuffleLibrary(source, game);
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class FatesealEffect extends OneShotEffect {
|
|||
TargetCard target1 = new TargetCard(Zone.LIBRARY, filter1);
|
||||
target1.setRequired(false);
|
||||
// move cards to the bottom of the library
|
||||
while (!cards.isEmpty() && controller.choose(Outcome.Detriment, cards, target1, game)) {
|
||||
while (!cards.isEmpty() && controller.choose(Outcome.Detriment, cards, target1, source, game)) {
|
||||
if (!controller.canRespond() || !opponent.canRespond()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ class CascadeEffect extends OneShotEffect {
|
|||
if (event.getAmount() > 0) {
|
||||
TargetCardInExile target = new TargetCardInExile(0, event.getAmount(), StaticFilters.FILTER_CARD_LAND, null, true);
|
||||
target.withChooseHint("land to put onto battlefield tapped");
|
||||
controller.choose(Outcome.PutCardInPlay, cardsToExile, target, game);
|
||||
controller.choose(Outcome.PutCardInPlay, cardsToExile, target, source, game);
|
||||
controller.moveCards(
|
||||
new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD,
|
||||
source, game, true, false, false, null
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ class HideawayExileEffect extends OneShotEffect {
|
|||
}
|
||||
TargetCard target = new TargetCard(Zone.LIBRARY, filter);
|
||||
target.setNotTarget(true);
|
||||
controller.choose(Outcome.Detriment, cards, target, game);
|
||||
controller.choose(Outcome.Detriment, cards, target, source, game);
|
||||
Card card = cards.get(target.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
controller.moveCardsToExile(
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class RippleEffect extends OneShotEffect {
|
|||
target1.setRequired(false);
|
||||
|
||||
// choose cards to play for free
|
||||
while (player.canRespond() && cards.count(sameNameFilter, game) > 0 && player.choose(Outcome.PlayForFree, cards, target1, game)) {
|
||||
while (player.canRespond() && cards.count(sameNameFilter, game) > 0 && player.choose(Outcome.PlayForFree, cards, target1, source, game)) {
|
||||
Card card = cards.get(target1.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
ZoneChangeEvent event = new ZoneChangeEvent(mainCard.getId(), ability, controllerId, fromZone, Zone.STACK);
|
||||
Spell spell = new Spell(this, ability.getSpellAbilityToResolve(game), controllerId, event.getFromZone(), game);
|
||||
ZoneChangeInfo.Stack info = new ZoneChangeInfo.Stack(event, spell);
|
||||
return ZonesHandler.cast(info, game, ability);
|
||||
return ZonesHandler.cast(info, ability, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ import java.util.*;
|
|||
*/
|
||||
public final class ZonesHandler {
|
||||
|
||||
public static boolean cast(ZoneChangeInfo info, Game game, Ability source) {
|
||||
public static boolean cast(ZoneChangeInfo info, Ability source, Game game) {
|
||||
if (maybeRemoveFromSourceZone(info, game, source)) {
|
||||
placeInDestinationZone(info, game, 0);
|
||||
placeInDestinationZone(info,0, source, game);
|
||||
// create a group zone change event if a card is moved to stack for casting (it's always only one card, but some effects check for group events (one or more xxx))
|
||||
Set<Card> cards = new HashSet<>();
|
||||
Set<PermanentToken> tokens = new HashSet<>();
|
||||
|
|
@ -54,10 +54,10 @@ public final class ZonesHandler {
|
|||
public static boolean moveCard(ZoneChangeInfo info, Game game, Ability source) {
|
||||
List<ZoneChangeInfo> list = new ArrayList<>();
|
||||
list.add(info);
|
||||
return !moveCards(list, game, source).isEmpty();
|
||||
return !moveCards(list, source, game).isEmpty();
|
||||
}
|
||||
|
||||
public static List<ZoneChangeInfo> moveCards(List<ZoneChangeInfo> zoneChangeInfos, Game game, Ability source) {
|
||||
public static List<ZoneChangeInfo> moveCards(List<ZoneChangeInfo> zoneChangeInfos, Ability source, Game game) {
|
||||
// Handle Unmelded Meld Cards
|
||||
for (ListIterator<ZoneChangeInfo> itr = zoneChangeInfos.listIterator(); itr.hasNext(); ) {
|
||||
ZoneChangeInfo info = itr.next();
|
||||
|
|
@ -110,7 +110,7 @@ public final class ZonesHandler {
|
|||
// All permanents go to battlefield at the same time (=create order)
|
||||
createOrder = game.getState().getNextPermanentOrderNumber();
|
||||
}
|
||||
placeInDestinationZone(zoneChangeInfo, game, createOrder);
|
||||
placeInDestinationZone(zoneChangeInfo, createOrder, source, game);
|
||||
if (game.getPhase() != null) { // moving cards to zones before game started does not need events
|
||||
game.addSimultaneousEvent(zoneChangeInfo.event);
|
||||
}
|
||||
|
|
@ -118,14 +118,14 @@ public final class ZonesHandler {
|
|||
return zoneChangeInfos;
|
||||
}
|
||||
|
||||
private static void placeInDestinationZone(ZoneChangeInfo info, Game game, int createOrder) {
|
||||
private static void placeInDestinationZone(ZoneChangeInfo info, int createOrder, Ability source, Game game) {
|
||||
// Handle unmelded cards
|
||||
if (info instanceof ZoneChangeInfo.Unmelded) {
|
||||
ZoneChangeInfo.Unmelded unmelded = (ZoneChangeInfo.Unmelded) info;
|
||||
Zone toZone = null;
|
||||
for (ZoneChangeInfo subInfo : unmelded.subInfo) {
|
||||
toZone = subInfo.event.getToZone();
|
||||
placeInDestinationZone(subInfo, game, createOrder);
|
||||
placeInDestinationZone(subInfo, createOrder, source, game);
|
||||
}
|
||||
// We arbitrarily prefer the bottom half card. This should never be relevant.
|
||||
if (toZone != null) {
|
||||
|
|
@ -199,7 +199,8 @@ public final class ZonesHandler {
|
|||
break;
|
||||
case GRAVEYARD:
|
||||
for (Card card : chooseOrder(
|
||||
"order to put in graveyard (last chosen will be on top)", cardsToMove, owner, game)) {
|
||||
"order to put in graveyard (last chosen will be on top)",
|
||||
cardsToMove, owner, source, game)) {
|
||||
game.getPlayer(card.getOwnerId()).getGraveyard().add(card);
|
||||
}
|
||||
break;
|
||||
|
|
@ -207,13 +208,15 @@ public final class ZonesHandler {
|
|||
if (info instanceof ZoneChangeInfo.Library && ((ZoneChangeInfo.Library) info).top) {
|
||||
// on top
|
||||
for (Card card : chooseOrder(
|
||||
"order to put on top of library (last chosen will be topmost)", cardsToMove, owner, game)) {
|
||||
"order to put on top of library (last chosen will be topmost)",
|
||||
cardsToMove, owner, source, game)) {
|
||||
game.getPlayer(card.getOwnerId()).getLibrary().putOnTop(card, game);
|
||||
}
|
||||
} else {
|
||||
// on bottom
|
||||
for (Card card : chooseOrder(
|
||||
"order to put on bottom of library (last chosen will be bottommost)", cardsToMove, owner, game)) {
|
||||
"order to put on bottom of library (last chosen will be bottommost)",
|
||||
cardsToMove, owner, source, game)) {
|
||||
game.getPlayer(card.getOwnerId()).getLibrary().putOnBottom(card, game);
|
||||
}
|
||||
}
|
||||
|
|
@ -404,7 +407,7 @@ public final class ZonesHandler {
|
|||
return success;
|
||||
}
|
||||
|
||||
public static List<Card> chooseOrder(String message, Cards cards, Player player, Game game) {
|
||||
public static List<Card> chooseOrder(String message, Cards cards, Player player, Ability source, Game game) {
|
||||
List<Card> order = new ArrayList<>();
|
||||
if (cards.isEmpty()) {
|
||||
return order;
|
||||
|
|
@ -412,7 +415,7 @@ public final class ZonesHandler {
|
|||
TargetCard target = new TargetCard(Zone.ALL, new FilterCard(message));
|
||||
target.setRequired(true);
|
||||
while (player.canRespond() && cards.size() > 1) {
|
||||
player.choose(Outcome.Neutral, cards, target, game);
|
||||
player.choose(Outcome.Neutral, cards, target, source, game);
|
||||
UUID targetObjectId = target.getFirstTarget();
|
||||
order.add(cards.get(targetObjectId, game));
|
||||
cards.remove(targetObjectId);
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ class MadWizardsLairEffect extends OneShotEffect {
|
|||
}
|
||||
player.revealCards(source, cards, game);
|
||||
TargetCardInHand target = new TargetCardInHand(0, 1, StaticFilters.FILTER_CARD_NON_LAND);
|
||||
player.choose(Outcome.PlayForFree, cards, target, game);
|
||||
player.choose(Outcome.PlayForFree, cards, target, source, game);
|
||||
Card card = player.getHand().get(target.getFirstTarget(), game);
|
||||
if (card == null) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ class ThroneOfTheDeadThreeEffect extends OneShotEffect {
|
|||
break;
|
||||
default:
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_CREATURE);
|
||||
player.choose(outcome, cards, target, game);
|
||||
player.choose(outcome, cards, target, source, game);
|
||||
card = cards.get(target.getFirstTarget(), game);
|
||||
}
|
||||
if (card != null) {
|
||||
|
|
|
|||
|
|
@ -625,10 +625,6 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
|
||||
boolean choose(Outcome outcome, Target target, Ability source, Game game, Map<String, Serializable> options);
|
||||
|
||||
// TODO: remove to use choose with "Ability source"
|
||||
default boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game) {
|
||||
return choose(outcome, cards, target, null, game);
|
||||
}
|
||||
boolean choose(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game);
|
||||
|
||||
boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game);
|
||||
|
|
|
|||
|
|
@ -937,7 +937,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
new FilterCard("card ORDER to put on the BOTTOM of your library (last one chosen will be bottommost)"));
|
||||
target.setRequired(true);
|
||||
while (cards.size() > 1 && this.canRespond()
|
||||
&& this.choose(Outcome.Neutral, cards, target, game)) {
|
||||
&& this.choose(Outcome.Neutral, cards, target, source, game)) {
|
||||
UUID targetObjectId = target.getFirstTarget();
|
||||
if (targetObjectId == null) {
|
||||
break;
|
||||
|
|
@ -1031,7 +1031,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
target.setRequired(true);
|
||||
while (cards.size() > 1
|
||||
&& this.canRespond()
|
||||
&& this.choose(Outcome.Neutral, cards, target, game)) {
|
||||
&& this.choose(Outcome.Neutral, cards, target, source, game)) {
|
||||
UUID targetObjectId = target.getFirstTarget();
|
||||
if (targetObjectId == null) {
|
||||
break;
|
||||
|
|
@ -2691,7 +2691,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
// handling Panglacial Wurm - cast cards while searching from own library
|
||||
if (targetPlayer.getId().equals(searchingPlayer.getId())) {
|
||||
if (handleCastableCardsWhileLibrarySearching(library, game, targetPlayer)) {
|
||||
if (handleCastableCardsWhileLibrarySearching(library, targetPlayer, source, game)) {
|
||||
// clear all choices to start from scratch (casted cards must be removed from library)
|
||||
newTarget.clearChosen();
|
||||
continue;
|
||||
|
|
@ -2748,7 +2748,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean handleCastableCardsWhileLibrarySearching(Library library, Game game, Player targetPlayer) {
|
||||
private boolean handleCastableCardsWhileLibrarySearching(Library library, Player targetPlayer, Ability source, Game game) {
|
||||
// must return true after cast try (to restart searching process without casted cards)
|
||||
// uses for handling Panglacial Wurm:
|
||||
// * While you're searching your library, you may cast Panglacial Wurm from your library.
|
||||
|
|
@ -2776,7 +2776,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
targetCard.setNotTarget(true);
|
||||
while (castableCards.size() > 0) {
|
||||
targetCard.clearChosen();
|
||||
if (!targetPlayer.choose(Outcome.AIDontUseIt, new CardsImpl(castableCards), targetCard, game)) {
|
||||
if (!targetPlayer.choose(Outcome.AIDontUseIt, new CardsImpl(castableCards), targetCard, source, game)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -4539,7 +4539,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
byOwner ? card.getOwnerId() : getId(), fromZone, Zone.BATTLEFIELD, appliedEffects);
|
||||
infoList.add(new ZoneChangeInfo.Battlefield(event, faceDown, tapped, source));
|
||||
}
|
||||
infoList = ZonesHandler.moveCards(infoList, game, source);
|
||||
infoList = ZonesHandler.moveCards(infoList, source, game);
|
||||
for (ZoneChangeInfo info : infoList) {
|
||||
Permanent permanent = game.getPermanent(info.event.getTargetId());
|
||||
if (permanent != null) {
|
||||
|
|
|
|||
|
|
@ -1282,7 +1282,7 @@ public final class CardUtil {
|
|||
Cards castableCards = new CardsImpl(cardMap.keySet());
|
||||
TargetCard target = new TargetCard(0, 1, Zone.ALL, defaultFilter);
|
||||
target.setNotTarget(true);
|
||||
player.choose(Outcome.PlayForFree, castableCards, target, game);
|
||||
player.choose(Outcome.PlayForFree, castableCards, target, source, game);
|
||||
cardToCast = castableCards.get(target.getFirstTarget(), game);
|
||||
}
|
||||
if (cardToCast == null) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue