diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 77ae01408f5..d590eee35e7 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -127,35 +127,26 @@ public class GameAction { return c; } + CardCollectionView lastBattlefield = getLastState(AbilityKey.LastStateBattlefield, cause, params, false); + CardCollectionView lastGraveyard = getLastState(AbilityKey.LastStateGraveyard, cause, params, false); + // Aura entering indirectly // need to check before it enters if (c.isAura() && !c.isAttachedToEntity() && toBattlefield && (zoneFrom == null || !zoneFrom.is(ZoneType.Stack))) { boolean found = false; - try { - if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(c, null))) { + if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(c, null))) { + found = true; + } + + if (!found) { + if (Iterables.any(lastBattlefield, CardPredicates.canBeAttached(c, null))) { found = true; } - } catch (Exception e1) { - found = false; } if (!found) { - try { - if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(c, null))) { - found = true; - } - } catch (Exception e2) { - found = false; - } - } - - if (!found) { - try { - if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(c, null))) { - found = true; - } - } catch (Exception e3) { - found = false; + if (Iterables.any(lastGraveyard, CardPredicates.canBeAttached(c, null))) { + found = true; } } if (!found) { @@ -184,8 +175,6 @@ public class GameAction { lastKnownInfo = (Card) cause.getReplacingObject(AbilityKey.CardLKI); } } - CardCollectionView lastBattlefield = getLastState(AbilityKey.LastStateBattlefield, cause, params); - CardCollectionView lastGraveyard = getLastState(AbilityKey.LastStateGraveyard, cause, params); if (c.isSplitCard()) { boolean resetToOriginal = false; @@ -403,10 +392,10 @@ public class GameAction { if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(copied, null))) { found = true; } - if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(copied, null))) { + if (Iterables.any(lastBattlefield, CardPredicates.canBeAttached(copied, null))) { found = true; } - if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(copied, null))) { + if (Iterables.any(lastGraveyard, CardPredicates.canBeAttached(copied, null))) { found = true; } if (!found) { @@ -2608,12 +2597,13 @@ public class GameAction { } } - private CardCollectionView getLastState(final AbilityKey key, final SpellAbility cause, final Map params) { + public CardCollectionView getLastState(final AbilityKey key, final SpellAbility cause, final Map params, final boolean refreshIfEmpty) { CardCollectionView lastState = null; if (params != null) { lastState = (CardCollectionView) params.get(key); } if (lastState == null && cause != null) { + // inside RE if (key == AbilityKey.LastStateBattlefield) { lastState = cause.getLastStateBattlefield(); } @@ -2622,11 +2612,20 @@ public class GameAction { } } if (lastState == null) { + // this fallback should be rare unless called when creating a new CardZoneTable if (key == AbilityKey.LastStateBattlefield) { - lastState = game.getLastStateBattlefield(); + if (refreshIfEmpty) { + lastState = game.copyLastStateBattlefield(); + } else { + lastState = game.getLastStateBattlefield(); + } } if (key == AbilityKey.LastStateGraveyard) { - lastState = game.getLastStateGraveyard(); + if (refreshIfEmpty) { + lastState = game.copyLastStateGraveyard(); + } else { + lastState = game.getLastStateGraveyard(); + } } } return lastState; diff --git a/forge-game/src/main/java/forge/game/ability/AbilityKey.java b/forge-game/src/main/java/forge/game/ability/AbilityKey.java index 0c658e533ff..100836b90d9 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityKey.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityKey.java @@ -1,6 +1,5 @@ package forge.game.ability; -import forge.game.Game; import forge.game.GameEntity; import forge.game.card.Card; import forge.game.card.CardZoneTable; @@ -207,19 +206,14 @@ public enum AbilityKey { return runParams; } - public static void addCardZoneTableParams(Map map, CardZoneTable table) { - map.put(AbilityKey.LastStateBattlefield, table.getLastStateBattlefield()); - map.put(AbilityKey.LastStateGraveyard, table.getLastStateGraveyard()); - map.put(AbilityKey.InternalTriggerTable, table); - } - public static CardZoneTable addCardZoneTableParams(Map map, SpellAbility sa) { - CardZoneTable table = new CardZoneTable(sa.getLastStateBattlefield(), sa.getLastStateGraveyard()); - addCardZoneTableParams(map, table); + public static CardZoneTable addCardZoneTableParams(Map params, SpellAbility sa) { + CardZoneTable table = CardZoneTable.getSimultaneousInstance(sa); + addCardZoneTableParams(params, table); return table; } - public static CardZoneTable addCardZoneTableParams(Map map, Game game) { - CardZoneTable table = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateGraveyard()); - addCardZoneTableParams(map, table); - return table; + public static void addCardZoneTableParams(Map params, CardZoneTable table) { + params.put(AbilityKey.LastStateBattlefield, table.getLastStateBattlefield()); + params.put(AbilityKey.LastStateGraveyard, table.getLastStateGraveyard()); + params.put(AbilityKey.InternalTriggerTable, table); } } diff --git a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java index 7d2bfe30f79..6fe537132c1 100644 --- a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java +++ b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java @@ -17,7 +17,6 @@ import forge.game.player.PlayerCollection; import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementHandler; import forge.game.replacement.ReplacementLayer; -import forge.game.replacement.ReplacementType; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; import forge.game.trigger.Trigger; @@ -971,15 +970,6 @@ public abstract class SpellAbilityEffect { movedCard.setExiledBy(cause.getActivatingPlayer()); } - public CardZoneTable getChangeZoneTable(SpellAbility sa, CardCollectionView lastStateBattlefield, CardCollectionView lastStateGraveyard) { - if (sa.isReplacementAbility() && sa.getReplacementEffect().getMode() == ReplacementType.Moved - && sa.getReplacingObject(AbilityKey.InternalTriggerTable) != null) { - // if a RE changes the destination zone try to make it simultaneous - return (CardZoneTable) sa.getReplacingObject(AbilityKey.InternalTriggerTable); - } - return new CardZoneTable(lastStateBattlefield, lastStateGraveyard); - } - public static GameCommand exileEffectCommand(final Game game, final Card effect) { return new GameCommand() { private static final long serialVersionUID = 1L; diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java index 28e04c615cf..dd8a5d00f80 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java @@ -12,7 +12,6 @@ import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CardCollection; -import forge.game.card.CardCollectionView; import forge.game.card.CardFactoryUtil; import forge.game.card.CardLists; import forge.game.card.CardPredicates; @@ -55,8 +54,6 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect { CardCollection cards; List tgtPlayers = getTargetPlayers(sa); final Game game = sa.getActivatingPlayer().getGame(); - CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield(); - CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard(); if ((!sa.usesTargeting() && !sa.hasParam("Defined")) || sa.hasParam("UseAllOriginZones")) { cards = new CardCollection(game.getCardsIn(origin)); @@ -154,7 +151,8 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect { CardLists.shuffle(cards); } - final CardZoneTable triggerList = getChangeZoneTable(sa, lastStateBattlefield, lastStateGraveyard); + final CardZoneTable triggerList = CardZoneTable.getSimultaneousInstance(sa); + for (final Card c : cards) { final Zone originZone = game.getZoneOf(c); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index 7fb2d6a4dd2..f545343d127 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -470,11 +470,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect { libraryPosition = pair.getValue(); } - CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield(); - CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard(); + final GameEntityCounterTable counterTable = new GameEntityCounterTable(); + final CardZoneTable triggerList = CardZoneTable.getSimultaneousInstance(sa); + final CardCollectionView lastStateBattlefield = triggerList.getLastStateBattlefield(); - final CardZoneTable triggerList = getChangeZoneTable(sa, lastStateBattlefield, lastStateGraveyard); - GameEntityCounterTable counterTable = new GameEntityCounterTable(); // changing zones for spells on the stack for (final SpellAbility tgtSA : getTargetSpells(sa)) { if (!tgtSA.isSpell()) { // Catch any abilities or triggers that slip through somehow @@ -1260,10 +1259,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { final boolean imprint = sa.hasParam("Imprint"); boolean combatChanged = false; - - CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield(); - CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard(); - final CardZoneTable triggerList = getChangeZoneTable(sa, lastStateBattlefield, lastStateGraveyard); + final CardZoneTable triggerList = CardZoneTable.getSimultaneousInstance(sa); for (Player player : HiddenOriginChoicesMap.keySet()) { boolean searchedLibrary = HiddenOriginChoicesMap.get(player).searchedLibrary; @@ -1281,6 +1277,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { Map moveParams = AbilityKey.newMap(); moveParams.put(AbilityKey.FoundSearchingLibrary, searchedLibrary); AbilityKey.addCardZoneTableParams(moveParams, triggerList); + if (destination.equals(ZoneType.Library)) { movedCard = game.getAction().moveToLibrary(c, libraryPos, sa, moveParams); } @@ -1330,7 +1327,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (sa.hasParam("AttachedTo") && c.isAttachment()) { CardCollection list = AbilityUtils.getDefinedCards(source, sa.getParam("AttachedTo"), sa); if (list.isEmpty()) { - list = CardLists.getValidCards(lastStateBattlefield, sa.getParam("AttachedTo"), source.getController(), source, sa); + list = CardLists.getValidCards(triggerList.getLastStateBattlefield(), sa.getParam("AttachedTo"), source.getController(), source, sa); } // only valid choices are when they could be attached // TODO for multiple Auras entering attached this way, need to use LKI info diff --git a/forge-game/src/main/java/forge/game/ability/effects/ConniveEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ConniveEffect.java index 68bce82a92a..805edf78ca0 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ConniveEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ConniveEffect.java @@ -65,13 +65,12 @@ public class ConniveEffect extends SpellAbilityEffect { } for (final Player p : controllers) { - CardCollection connivers = CardLists.filterControlledBy(toConnive, p); + final CardCollection connivers = CardLists.filterControlledBy(toConnive, p); while (!connivers.isEmpty()) { - GameEntityCounterTable table = new GameEntityCounterTable(); - final CardZoneTable triggerList = new CardZoneTable(game.copyLastStateBattlefield(), game.copyLastStateGraveyard()); - Map discardedMap = Maps.newHashMap(); - Map moveParams = AbilityKey.newMap(); - AbilityKey.addCardZoneTableParams(moveParams, triggerList); + final Map discardedMap = Maps.newHashMap(); + final Map moveParams = AbilityKey.newMap(); + final CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(moveParams, sa); + final GameEntityCounterTable counterPlacements = new GameEntityCounterTable(); Card conniver = connivers.size() > 1 ? p.getController().chooseSingleEntityForEffect(connivers, sa, Localizer.getInstance().getMessage("lblChooseConniver"), null) : connivers.get(0); @@ -96,12 +95,12 @@ public class ConniveEffect extends SpellAbilityEffect { Card gamec = game.getCardState(conniver); // if the card is not in the game anymore, this might still return true, but it's no problem if (game.getZoneOf(gamec).is(ZoneType.Battlefield) && gamec.equalsWithTimestamp(conniver)) { - conniver.addCounter(CounterEnumType.P1P1, numCntrs, p, table); + conniver.addCounter(CounterEnumType.P1P1, numCntrs, p, counterPlacements); } discardedMap.put(p, CardCollection.getView(toBeDiscarded)); discard(sa, true, discardedMap, moveParams); - table.replaceCounterEffect(game, sa, true); - triggerList.triggerChangesZoneAll(game, sa); + counterPlacements.replaceCounterEffect(game, sa, true); + zoneMovements.triggerChangesZoneAll(game, sa); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java index 6a6aae8a6e1..876a6b705ca 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java @@ -53,7 +53,7 @@ public class CounterEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final Game game = sa.getActivatingPlayer().getGame(); Map params = AbilityKey.newMap(); - final CardZoneTable table = AbilityKey.addCardZoneTableParams(params, game); + final CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(params, sa); for (final SpellAbility tgtSA : getTargetSpells(sa)) { final Card tgtSACard = tgtSA.getHostCard(); @@ -103,8 +103,8 @@ public class CounterEffect extends SpellAbilityEffect { sa.getHostCard().addRemembered(tgtSACard); } } - table.triggerChangesZoneAll(game, sa); - } // end counterResolve + zoneMovements.triggerChangesZoneAll(game, sa); + } public static boolean checkForConditionWouldDestroy(SpellAbility sa, SpellAbility tgtSA) { List testChain = Lists.newArrayList(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DestroyAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DestroyAllEffect.java index 4cbe7813ff8..58dd62291c8 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DestroyAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DestroyAllEffect.java @@ -2,8 +2,6 @@ package forge.game.ability.effects; import java.util.Map; -import com.google.common.collect.Maps; - import forge.game.Game; import forge.game.GameActionUtil; import forge.game.ability.AbilityKey; @@ -13,7 +11,6 @@ import forge.game.card.Card; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; import forge.game.card.CardPredicates; -import forge.game.card.CardUtil; import forge.game.card.CardZoneTable; import forge.game.player.Player; import forge.game.spellability.SpellAbility; @@ -90,16 +87,15 @@ public class DestroyAllEffect extends SpellAbilityEffect { list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard, sa); Map params = AbilityKey.newMap(); - CardZoneTable table = new CardZoneTable(game.copyLastStateBattlefield(), game.getLastStateGraveyard()); - AbilityKey.addCardZoneTableParams(params, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(params, sa); - Map cachedMap = Maps.newHashMap(); for (Card c : list) { if (game.getAction().destroy(c, sa, !noRegen, params) && remDestroyed) { - card.addRemembered(CardUtil.getLKICopy(c, cachedMap)); + card.addRemembered(zoneMovements.getLastStateBattlefield().get(c)); } } - table.triggerChangesZoneAll(game, sa); + + zoneMovements.triggerChangesZoneAll(game, sa); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java index 192d6c87be5..9d24fb4066a 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java @@ -3,14 +3,11 @@ package forge.game.ability.effects; import java.util.List; import java.util.Map; -import com.google.common.collect.Maps; - import forge.game.Game; import forge.game.GameActionUtil; import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; -import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; import forge.game.card.CardUtil; import forge.game.card.CardZoneTable; @@ -47,23 +44,22 @@ public class DestroyEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { - final Card card = sa.getHostCard(); - final Game game = card.getGame(); + final Card host = sa.getHostCard(); + final Game game = host.getGame(); if (sa.hasParam("RememberDestroyed")) { - card.clearRemembered(); + host.clearRemembered(); } - CardCollectionView tgtCards = getTargetCards(sa); CardCollectionView untargetedCards = CardUtil.getRadiance(sa); + CardCollectionView tgtCards = getTargetCards(sa); tgtCards = GameActionUtil.orderCardsByTheirOwners(game, tgtCards, ZoneType.Graveyard, sa); + untargetedCards = GameActionUtil.orderCardsByTheirOwners(game, untargetedCards, ZoneType.Graveyard, sa); Map params = AbilityKey.newMap(); - CardZoneTable table = getChangeZoneTable(sa, game.copyLastStateBattlefield(), CardCollection.EMPTY); - AbilityKey.addCardZoneTableParams(params, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(params, sa); - Map cachedMap = Maps.newHashMap(); for (final Card tgtC : tgtCards) { if (!tgtC.isInPlay()) { continue; @@ -75,29 +71,26 @@ public class DestroyEffect extends SpellAbilityEffect { if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard)) { continue; } - internalDestroy(gameCard, sa, cachedMap, params); + internalDestroy(gameCard, sa, params, zoneMovements); } - untargetedCards = GameActionUtil.orderCardsByTheirOwners(game, untargetedCards, ZoneType.Graveyard, sa); - for (final Card unTgtC : untargetedCards) { if (unTgtC.isInPlay()) { - internalDestroy(unTgtC, sa, cachedMap, params); + internalDestroy(unTgtC, sa, params, zoneMovements); } } - table.triggerChangesZoneAll(game, sa); + zoneMovements.triggerChangesZoneAll(game, sa); } - protected void internalDestroy(Card gameCard, SpellAbility sa, Map cachedMap, Map params) { - final Card card = sa.getHostCard(); - final Game game = card.getGame(); + protected void internalDestroy(Card gameCard, SpellAbility sa, Map params, CardZoneTable zoneMovements) { + final Card host = sa.getHostCard(); + final Game game = host.getGame(); final boolean remDestroyed = sa.hasParam("RememberDestroyed"); final boolean noRegen = sa.hasParam("NoRegen"); final boolean sac = sa.hasParam("Sacrifice"); final boolean alwaysRem = sa.hasParam("AlwaysRemember"); boolean destroyed = false; - final Card lki = sa.hasParam("RememberLKI") ? CardUtil.getLKICopy(gameCard, cachedMap) : null; SpellAbility cause = sa; if (sa.isReplacementAbility()) { @@ -110,10 +103,10 @@ public class DestroyEffect extends SpellAbilityEffect { destroyed = game.getAction().destroy(gameCard, cause, !noRegen, params); } if (destroyed && remDestroyed) { - card.addRemembered(gameCard); + host.addRemembered(gameCard); } if ((destroyed || alwaysRem) && sa.hasParam("RememberLKI")) { - card.addRemembered(lki); + host.addRemembered(zoneMovements.getLastStateBattlefield().get(gameCard)); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java index 03b982c0317..23da51b5873 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java @@ -117,12 +117,13 @@ public class DigEffect extends SpellAbilityEffect { final ZoneType destZone1 = sa.hasParam("DestinationZone") ? ZoneType.smartValueOf(sa.getParam("DestinationZone")) : ZoneType.Hand; final ZoneType destZone2 = sa.hasParam("DestinationZone2") ? ZoneType.smartValueOf(sa.getParam("DestinationZone2")) : ZoneType.Library; - int libraryPosition = sa.hasParam("LibraryPosition") ? Integer.parseInt(sa.getParam("LibraryPosition")) : -1; + final int libraryPosition = sa.hasParam("LibraryPosition") ? Integer.parseInt(sa.getParam("LibraryPosition")) : -1; + final int libraryPosition2 = sa.hasParam("LibraryPosition2") ? Integer.parseInt(sa.getParam("LibraryPosition2")) : -1; + int destZone1ChangeNum = 1; String changeValid = sa.getParamOrDefault("ChangeValid", ""); final boolean anyNumber = sa.hasParam("AnyNumber"); - final int libraryPosition2 = sa.hasParam("LibraryPosition2") ? Integer.parseInt(sa.getParam("LibraryPosition2")) : -1; final boolean optional = sa.hasParam("Optional"); final boolean noMove = sa.hasParam("NoMove"); final boolean skipReorder = sa.hasParam("SkipReorder"); @@ -161,7 +162,7 @@ public class DigEffect extends SpellAbilityEffect { } } - CardZoneTable table = new CardZoneTable(game.copyLastStateBattlefield(), game.copyLastStateGraveyard()); + CardZoneTable zoneMovements = new CardZoneTable(game.copyLastStateBattlefield(), game.copyLastStateGraveyard()); GameEntityCounterTable counterTable = new GameEntityCounterTable(); boolean combatChanged = false; @@ -375,7 +376,7 @@ public class DigEffect extends SpellAbilityEffect { } Map moveParams = AbilityKey.newMap(); - AbilityKey.addCardZoneTableParams(moveParams, table); + AbilityKey.addCardZoneTableParams(moveParams, zoneMovements); for (Card c : movedCards) { if (destZone1.equals(ZoneType.Library) || destZone1.equals(ZoneType.PlanarDeck) || destZone1.equals(ZoneType.SchemeDeck)) { @@ -499,7 +500,7 @@ public class DigEffect extends SpellAbilityEffect { game.fireEvent(new GameEventCombatChanged()); } - table.triggerChangesZoneAll(game, sa); + zoneMovements.triggerChangesZoneAll(game, sa); counterTable.replaceCounterEffect(game, sa, true); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/EncodeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/EncodeEffect.java index 8a0977def7b..cabc65a83a3 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/EncodeEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/EncodeEffect.java @@ -32,36 +32,33 @@ public class EncodeEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { final Card host = sa.getHostCard(); - final Player player = sa.getActivatingPlayer(); - final Game game = player.getGame(); + final Player activator = sa.getActivatingPlayer(); + final Game game = activator.getGame(); if (host.isToken()) { return; } - // make list of creatures that controller has on Battlefield CardCollectionView choices = host.getController().getCreaturesInPlay(); // if no creatures on battlefield, cannot encoded if (choices.isEmpty()) { return; } - // Handle choice of whether or not to encoded - if (!player.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantExileCardAndEncodeOntoYouCreature", CardTranslation.getTranslatedName(host.getName())), null)) { + // Handle choice of whether or not to encoded + if (!activator.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantExileCardAndEncodeOntoYouCreature", CardTranslation.getTranslatedName(host.getName())), null)) { return; } Map moveParams = AbilityKey.newMap(); - CardZoneTable table = new CardZoneTable(sa.getLastStateBattlefield(), sa.getLastStateGraveyard()); - AbilityKey.addCardZoneTableParams(moveParams, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(moveParams, sa); - // move host card to exile - Card movedCard = game.getAction().exile(host, sa, moveParams); - table.triggerChangesZoneAll(game, sa); + Card moved = game.getAction().exile(host, sa, moveParams); - // choose a creature - Card choice = player.getController().chooseSingleEntityForEffect(choices, sa, Localizer.getInstance().getMessage("lblChooseACreatureYouControlToEncode") + " ", false, null); + zoneMovements.triggerChangesZoneAll(game, sa); + + Card choice = activator.getController().chooseSingleEntityForEffect(choices, sa, Localizer.getInstance().getMessage("lblChooseACreatureYouControlToEncode") + " ", false, null); if (choice == null) { return; @@ -72,8 +69,8 @@ public class EncodeEffect extends SpellAbilityEffect { game.getGameLog().add(GameLogEntryType.STACK_RESOLVE, codeLog.toString()); // store hostcard in encoded array - choice.addEncodedCard(movedCard); - movedCard.setEncodingCard(choice); + choice.addEncodedCard(moved); + moved.setEncodingCard(choice); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/EndCombatPhaseEffect.java b/forge-game/src/main/java/forge/game/ability/effects/EndCombatPhaseEffect.java index 245d96af568..f91e3572647 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/EndCombatPhaseEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/EndCombatPhaseEffect.java @@ -30,11 +30,11 @@ public class EndCombatPhaseEffect extends SpellAbilityEffect { // 1) All spells and abilities on the stack are exiled. Map moveParams = AbilityKey.newMap(); - CardZoneTable table = new CardZoneTable(sa.getLastStateBattlefield(), sa.getLastStateGraveyard()); - AbilityKey.addCardZoneTableParams(moveParams, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(moveParams, sa); game.getAction().exile(new CardCollection(game.getStackZone().getCards()), sa, moveParams); - table.triggerChangesZoneAll(game, sa); + + zoneMovements.triggerChangesZoneAll(game, sa); game.getStack().clear(); game.getStack().clearSimultaneousStack(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/EndTurnEffect.java b/forge-game/src/main/java/forge/game/ability/effects/EndTurnEffect.java index 76722de0437..1abcb9944f5 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/EndTurnEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/EndTurnEffect.java @@ -38,11 +38,10 @@ public class EndTurnEffect extends SpellAbilityEffect { // Time Stop, though it will continue to resolve. It also includes // spells and abilities that can't be countered. Map moveParams = AbilityKey.newMap(); - CardZoneTable table = new CardZoneTable(sa.getLastStateBattlefield(), sa.getLastStateGraveyard()); - AbilityKey.addCardZoneTableParams(moveParams, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(moveParams, sa); game.getAction().exile(new CardCollection(game.getStackZone().getCards()), sa, moveParams); - table.triggerChangesZoneAll(game, sa); + zoneMovements.triggerChangesZoneAll(game, sa); game.getStack().clear(); game.getStack().clearSimultaneousStack(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/HauntEffect.java b/forge-game/src/main/java/forge/game/ability/effects/HauntEffect.java index 73417386492..74e1d631ea8 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/HauntEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/HauntEffect.java @@ -25,11 +25,10 @@ public class HauntEffect extends SpellAbilityEffect { } else if (sa.usesTargeting() && !card.isToken() && host.equalsWithTimestamp(card)) { // haunt target but only if card is no token and still in grave Map moveParams = AbilityKey.newMap(); - CardZoneTable table = new CardZoneTable(sa.getLastStateBattlefield(), sa.getLastStateGraveyard()); - AbilityKey.addCardZoneTableParams(moveParams, table); - final Card copy = game.getAction().exile(card, sa, moveParams); - sa.getTargetCard().addHauntedBy(copy); - table.triggerChangesZoneAll(game, sa); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(moveParams, sa); + final Card moved = game.getAction().exile(card, sa, moveParams); + sa.getTargetCard().addHauntedBy(moved); + zoneMovements.triggerChangesZoneAll(game, sa); } else if (!sa.usesTargeting() && card.getHaunting() != null) { // unhaunt card.getHaunting().removeHauntedBy(card); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ManifestBaseEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ManifestBaseEffect.java index a9a4a641a00..3c158733713 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ManifestBaseEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ManifestBaseEffect.java @@ -65,20 +65,15 @@ public abstract class ManifestBaseEffect extends SpellAbilityEffect { if (fromLibrary) { for (Card c : tgtCards) { // CR 701.34d If an effect instructs a player to manifest multiple cards from their library, those cards are manifested one at a time. - CardZoneTable triggerList = new CardZoneTable(game.copyLastStateBattlefield(), game.copyLastStateGraveyard()); - Map moveParams = AbilityKey.newMap(); - AbilityKey.addCardZoneTableParams(moveParams, triggerList); - + CardZoneTable triggerList = AbilityKey.addCardZoneTableParams(moveParams, sa); internalEffect(c, p, sa, moveParams); triggerList.triggerChangesZoneAll(game, sa); } } else { // manifest from other zones should be done at the same time - CardZoneTable triggerList = new CardZoneTable(game.copyLastStateBattlefield(), game.copyLastStateGraveyard()); - Map moveParams = AbilityKey.newMap(); - AbilityKey.addCardZoneTableParams(moveParams, triggerList); + CardZoneTable triggerList = AbilityKey.addCardZoneTableParams(moveParams, sa); for (Card c : tgtCards) { internalEffect(c, p, sa, moveParams); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/MeldEffect.java b/forge-game/src/main/java/forge/game/ability/effects/MeldEffect.java index 965c6d4dafd..7e9e9506359 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/MeldEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/MeldEffect.java @@ -42,11 +42,11 @@ public class MeldEffect extends SpellAbilityEffect { CardCollection exiled = CardLists.filter(Arrays.asList(hostCard, secondary), CardPredicates.canExiledBy(sa, true)); Map moveParams = AbilityKey.newMap(); - CardZoneTable table = new CardZoneTable(sa.getLastStateBattlefield(), sa.getLastStateGraveyard()); - AbilityKey.addCardZoneTableParams(moveParams, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(moveParams, sa); exiled = game.getAction().exile(exiled, sa, moveParams); - table.triggerChangesZoneAll(game, sa); + + zoneMovements.triggerChangesZoneAll(game, sa); if (exiled.size() < 2) { return; @@ -78,10 +78,16 @@ public class MeldEffect extends SpellAbilityEffect { primary.setMeldedWith(secondary); PlayerZoneBattlefield bf = (PlayerZoneBattlefield)controller.getZone(ZoneType.Battlefield); bf.addToMelded(secondary); - Card movedCard = game.getAction().changeZone(primary.getZone(), bf, primary, 0, sa); + + moveParams = AbilityKey.newMap(); + zoneMovements = AbilityKey.addCardZoneTableParams(moveParams, sa); + + Card movedCard = game.getAction().moveToPlay(primary, controller, sa, moveParams); if (addToCombat(movedCard, sa, "Attacking", "Blocking")) { game.updateCombatForView(); game.fireEvent(new GameEventCombatChanged()); } + + zoneMovements.triggerChangesZoneAll(game, sa); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java index ff372d9ec4d..95316edf2cc 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java @@ -3,8 +3,6 @@ package forge.game.ability.effects; import java.util.List; import java.util.Map; -import com.google.common.collect.Maps; - import forge.game.Game; import forge.game.GameActionUtil; import forge.game.ability.AbilityKey; @@ -14,7 +12,6 @@ import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; -import forge.game.card.CardUtil; import forge.game.card.CardZoneTable; import forge.game.player.Player; import forge.game.spellability.SpellAbility; @@ -45,13 +42,13 @@ public class SacrificeAllEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { - final Card card = sa.getHostCard(); + final Card host = sa.getHostCard(); final Player activator = sa.getActivatingPlayer(); final Game game = activator.getGame(); CardCollectionView list; if (sa.hasParam("Defined")) { - list = AbilityUtils.getDefinedCards(card, sa.getParam("Defined"), sa); + list = AbilityUtils.getDefinedCards(host, sa.getParam("Defined"), sa); } else { list = game.getCardsIn(ZoneType.Battlefield); if (sa.hasParam("ValidCards")) { @@ -61,7 +58,7 @@ public class SacrificeAllEffect extends SpellAbilityEffect { final boolean remSacrificed = sa.hasParam("RememberSacrificed"); if (remSacrificed) { - card.clearRemembered(); + host.clearRemembered(); } // update cards that where using LKI @@ -82,23 +79,22 @@ public class SacrificeAllEffect extends SpellAbilityEffect { list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard, sa); - Map cachedMap = Maps.newHashMap(); Map params = AbilityKey.newMap(); - CardZoneTable table = new CardZoneTable(game.copyLastStateBattlefield(), CardCollection.EMPTY); - AbilityKey.addCardZoneTableParams(params, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(params, sa); for (Card sac : list) { - final Card lKICopy = CardUtil.getLKICopy(sac, cachedMap); + final Card lKICopy = zoneMovements.getLastStateBattlefield().get(sac); if (game.getAction().sacrifice(sac, sa, true, params) != null) { if (remSacrificed) { - card.addRemembered(lKICopy); + host.addRemembered(lKICopy); } if (sa.hasParam("ImprintSacrificed")) { - card.addImprintedCard(lKICopy); + host.addImprintedCard(lKICopy); } } } - table.triggerChangesZoneAll(game, sa); + + zoneMovements.triggerChangesZoneAll(game, sa); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java index 2d1930bc621..3f6a377c641 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java @@ -10,8 +10,6 @@ import forge.card.CardType; import forge.util.Lang; import org.apache.commons.lang3.StringUtils; -import com.google.common.collect.Maps; - import forge.card.mana.ManaCost; import forge.game.Game; import forge.game.GameActionUtil; @@ -24,7 +22,6 @@ import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; import forge.game.card.CardPredicates; -import forge.game.card.CardUtil; import forge.game.card.CardZoneTable; import forge.game.card.CounterEnumType; import forge.game.cost.Cost; @@ -43,7 +40,7 @@ public class SacrificeEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final Player activator = sa.getActivatingPlayer(); final Game game = activator.getGame(); - final Card card = sa.getHostCard(); + final Card host = sa.getHostCard(); if (sa.hasParam("Echo")) { boolean isPaid; @@ -51,45 +48,45 @@ public class SacrificeEffect extends SpellAbilityEffect { && activator.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantPayEcho") + " {0}?", null)) { isPaid = true; } else { - isPaid = activator.getController().payManaOptional(card, new Cost(sa.getParam("Echo"), true), + isPaid = activator.getController().payManaOptional(host, new Cost(sa.getParam("Echo"), true), sa, Localizer.getInstance().getMessage("lblPayEcho"), ManaPaymentPurpose.Echo); } - final Map runParams = AbilityKey.mapFromCard(card); + final Map runParams = AbilityKey.mapFromCard(host); runParams.put(AbilityKey.EchoPaid, isPaid); game.getTriggerHandler().runTrigger(TriggerType.PayEcho, runParams, false); - if (isPaid || !card.getController().equals(activator)) { + if (isPaid || !host.getController().equals(activator)) { return; } } else if (sa.hasParam("CumulativeUpkeep")) { GameEntityCounterTable table = new GameEntityCounterTable(); - card.addCounter(CounterEnumType.AGE, 1, activator, table); + host.addCounter(CounterEnumType.AGE, 1, activator, table); table.replaceCounterEffect(game, sa, true); Cost payCost = new Cost(ManaCost.ZERO, true); - int n = card.getCounters(CounterEnumType.AGE); + int n = host.getCounters(CounterEnumType.AGE); if (n > 0) { Cost cumCost = new Cost(sa.getParam("CumulativeUpkeep"), true); payCost.mergeTo(cumCost, n, sa); } - game.updateLastStateForCard(card); + game.updateLastStateForCard(host); StringBuilder sb = new StringBuilder(); - sb.append("Cumulative upkeep for ").append(card); + sb.append("Cumulative upkeep for ").append(host); - boolean isPaid = activator.getController().payManaOptional(card, payCost, sa, sb.toString(), ManaPaymentPurpose.CumulativeUpkeep); - final Map runParams = AbilityKey.mapFromCard(card); + boolean isPaid = activator.getController().payManaOptional(host, payCost, sa, sb.toString(), ManaPaymentPurpose.CumulativeUpkeep); + final Map runParams = AbilityKey.mapFromCard(host); runParams.put(AbilityKey.CumulativeUpkeepPaid, isPaid); runParams.put(AbilityKey.PayingMana, StringUtils.join(sa.getPayingMana(), "")); game.getTriggerHandler().runTrigger(TriggerType.PayCumulativeUpkeep, runParams, false); - if (isPaid || !card.getController().equals(activator)) { + if (isPaid || !host.getController().equals(activator)) { return; } } // Expand Sacrifice keyword here depending on what we need out of it. - final int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Amount", "1"), sa); + final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Amount", "1"), sa); final boolean devour = sa.isKeyword(Keyword.DEVOUR); final boolean exploit = sa.isKeyword(Keyword.EXPLOIT); final boolean sacEachValid = sa.hasParam("SacEachValid"); @@ -102,17 +99,14 @@ public class SacrificeEffect extends SpellAbilityEffect { final boolean remSacrificed = sa.hasParam("RememberSacrificed"); final boolean optional = sa.hasParam("Optional"); Map params = AbilityKey.newMap(); - CardZoneTable table = new CardZoneTable(game.copyLastStateBattlefield(), CardCollection.EMPTY); - AbilityKey.addCardZoneTableParams(params, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(params, sa); - if (valid.equals("Self") && game.getZoneOf(card) != null) { - if (game.getZoneOf(card).is(ZoneType.Battlefield)) { + if (valid.equals("Self") && game.getZoneOf(host) != null) { + if (game.getZoneOf(host).is(ZoneType.Battlefield)) { if (!optional || activator.getController().confirmAction(sa, null, - Localizer.getInstance().getMessage("lblDoYouWantSacrificeThis", card.getName()), null)) { - if (game.getAction().sacrifice(card, sa, true, params) != null) { - if (remSacrificed) { - card.addRemembered(card); - } + Localizer.getInstance().getMessage("lblDoYouWantSacrificeThis", host.getName()), null)) { + if (game.getAction().sacrifice(host, sa, true, params) != null && remSacrificed) { + host.addRemembered(host); } } } @@ -165,35 +159,31 @@ public class SacrificeEffect extends SpellAbilityEffect { choosenToSacrifice = GameActionUtil.orderCardsByTheirOwners(game, choosenToSacrifice, ZoneType.Graveyard, sa); - Map cachedMap = Maps.newHashMap(); for (Card sac : choosenToSacrifice) { - Card lKICopy = null; - if (devour || exploit || remSacrificed) { - lKICopy = CardUtil.getLKICopy(sac, cachedMap); - } + Card lKICopy = zoneMovements.getLastStateBattlefield().get(sac); boolean wasSacrificed = !destroy && game.getAction().sacrifice(sac, sa, true, params) != null; boolean wasDestroyed = destroy && game.getAction().destroy(sac, sa, true, params); // Run Devour Trigger if (devour) { - card.addDevoured(lKICopy); + host.addDevoured(lKICopy); final Map runParams = AbilityKey.newMap(); runParams.put(AbilityKey.Devoured, lKICopy); game.getTriggerHandler().runTrigger(TriggerType.Devoured, runParams, false); } if (exploit) { - card.addExploited(lKICopy); - final Map runParams = AbilityKey.mapFromCard(card); + host.addExploited(lKICopy); + final Map runParams = AbilityKey.mapFromCard(host); runParams.put(AbilityKey.Exploited, lKICopy); game.getTriggerHandler().runTrigger(TriggerType.Exploited, runParams, false); } if ((wasDestroyed || wasSacrificed) && remSacrificed) { - card.addRemembered(lKICopy); + host.addRemembered(lKICopy); } } } } - table.triggerChangesZoneAll(game, sa); + zoneMovements.triggerChangesZoneAll(game, sa); } @Override diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 5742d348336..59441ca82eb 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -6155,11 +6155,6 @@ public class Card extends GameEntity implements Comparable, IHasSVars { damageType = DamageType.Deathtouch; } - // 704.8: if it looks like the creature might die from SBA make sure the LKI is refreshed - if (hasBeenDealtDeathtouchDamage() || (getDamage() > 0 && getLethal() <= getDamage())) { - game.updateLastStateForCard(this); - } - // Play the Damage sound game.fireEvent(new GameEventCardDamaged(this, source, damageIn, damageType)); } diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index f249c45da4c..1b8cb1d75d3 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -113,12 +113,11 @@ public class CardFactoryUtil { } final Game game = hostCard.getGame(); - CardZoneTable table = new CardZoneTable(game.copyLastStateBattlefield(), game.copyLastStateBattlefield()); Map params = AbilityKey.newMap(); - AbilityKey.addCardZoneTableParams(params, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(params, this); hostCard.getGame().getAction().moveToPlay(hostCard, this, params); - table.triggerChangesZoneAll(game, this); + zoneMovements.triggerChangesZoneAll(game, this); } @Override @@ -3036,11 +3035,10 @@ public class CardFactoryUtil { public void resolve() { final Game game = getHostCard().getGame(); Map moveParams = AbilityKey.newMap(); - CardZoneTable table = new CardZoneTable(this.getLastStateBattlefield(), this.getLastStateGraveyard()); - AbilityKey.addCardZoneTableParams(moveParams, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(moveParams, this); final Card c = game.getAction().exile(getHostCard(), this, moveParams); - table.triggerChangesZoneAll(game, this); + zoneMovements.triggerChangesZoneAll(game, this); c.setForetold(true); c.turnFaceDown(true); @@ -3500,11 +3498,10 @@ public class CardFactoryUtil { public void resolve() { final Game game = this.getHostCard().getGame(); Map moveParams = AbilityKey.newMap(); - CardZoneTable moveTable = new CardZoneTable(this.getLastStateBattlefield(), this.getLastStateGraveyard()); - AbilityKey.addCardZoneTableParams(moveParams, moveTable); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(moveParams, this); final Card c = game.getAction().exile(getHostCard(), this, moveParams); - moveTable.triggerChangesZoneAll(game, this); + zoneMovements.triggerChangesZoneAll(game, this); int counters = AbilityUtils.calculateAmount(c, k[1], this); GameEntityCounterTable table = new GameEntityCounterTable(); diff --git a/forge-game/src/main/java/forge/game/card/CardZoneTable.java b/forge-game/src/main/java/forge/game/card/CardZoneTable.java index fbbf873fae8..463b97cc803 100644 --- a/forge-game/src/main/java/forge/game/card/CardZoneTable.java +++ b/forge-game/src/main/java/forge/game/card/CardZoneTable.java @@ -11,8 +11,10 @@ import com.google.common.collect.*; import forge.game.CardTraitBase; import forge.game.Game; +import forge.game.GameAction; import forge.game.ability.AbilityKey; import forge.game.player.PlayerCollection; +import forge.game.replacement.ReplacementType; import forge.game.spellability.SpellAbility; import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; @@ -27,12 +29,6 @@ public class CardZoneTable extends ForwardingTable moveParams = AbilityKey.newMap(); - AbilityKey.addCardZoneTableParams(moveParams, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(moveParams, ability); CardCollection moved = game.getAction().exile(list, ability, moveParams); SpellAbilityEffect.handleExiledWith(moved, ability); + zoneMovements.triggerChangesZoneAll(game, ability); return true; } diff --git a/forge-game/src/main/java/forge/game/cost/CostMill.java b/forge-game/src/main/java/forge/game/cost/CostMill.java index 09cd36d64a0..de1a32875e9 100644 --- a/forge-game/src/main/java/forge/game/cost/CostMill.java +++ b/forge-game/src/main/java/forge/game/cost/CostMill.java @@ -19,7 +19,6 @@ package forge.game.cost; import java.util.Map; -import forge.game.Game; import forge.game.ability.AbilityKey; import forge.game.card.CardCollection; import forge.game.card.CardZoneTable; @@ -91,12 +90,10 @@ public class CostMill extends CostPart { @Override public final boolean payAsDecided(final Player ai, final PaymentDecision decision, SpellAbility ability, final boolean effect) { - final Game game = ai.getGame(); - CardZoneTable table = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateGraveyard()); Map moveParams = AbilityKey.newMap(); - AbilityKey.addCardZoneTableParams(moveParams, table); + CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(moveParams, ability); ability.getPaidHash().put("Milled", true, (CardCollection) ai.mill(decision.c, ZoneType.Graveyard, ability, moveParams)); - table.triggerChangesZoneAll(ai.getGame(), ability); + zoneMovements.triggerChangesZoneAll(ai.getGame(), ability); return true; }