From 8283720e4ae44c8bd2b7e0f54da54de327a2e344 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Thu, 24 Feb 2022 07:39:14 +0100 Subject: [PATCH 1/4] GameAction: register LTB for all cards on LastStateBattlefield --- .../src/main/java/forge/ai/GameState.java | 2 +- .../src/main/java/forge/game/GameAction.java | 197 ++++++++---------- .../main/java/forge/game/GameActionUtil.java | 2 +- .../src/main/java/forge/game/Match.java | 5 +- .../game/ability/SpellAbilityEffect.java | 8 +- .../game/ability/effects/AddTurnEffect.java | 3 +- .../game/ability/effects/BalanceEffect.java | 4 +- .../ability/effects/ChangeZoneEffect.java | 9 +- .../effects/DamagePreventEffectBase.java | 3 +- .../game/ability/effects/DiscardEffect.java | 7 +- .../game/ability/effects/DrawEffect.java | 7 +- .../game/ability/effects/EffectEffect.java | 8 +- .../game/ability/effects/EncodeEffect.java | 9 +- .../game/ability/effects/ExploreEffect.java | 8 +- .../forge/game/ability/effects/FogEffect.java | 3 +- .../game/ability/effects/LearnEffect.java | 8 +- .../game/ability/effects/MakeCardEffect.java | 10 +- .../game/ability/effects/MillEffect.java | 8 +- .../ability/effects/PlaneswalkEffect.java | 4 +- .../game/ability/effects/PlayEffect.java | 18 +- .../ability/effects/RegenerateBaseEffect.java | 3 +- .../ability/effects/SetInMotionEffect.java | 2 +- .../game/ability/effects/SkipPhaseEffect.java | 3 +- .../game/ability/effects/SkipTurnEffect.java | 3 +- .../game/ability/effects/SubgameEffect.java | 5 +- .../game/ability/effects/SurveilEffect.java | 8 +- .../game/ability/effects/VentureEffect.java | 14 +- .../ability/effects/ZoneExchangeEffect.java | 10 +- .../main/java/forge/game/cost/CostDraw.java | 8 +- .../main/java/forge/game/cost/CostMill.java | 8 +- .../java/forge/game/cost/CostSacrifice.java | 8 +- .../java/forge/game/phase/PhaseHandler.java | 6 +- .../main/java/forge/game/player/Player.java | 75 +++++-- .../forge/game/trigger/TriggerHandler.java | 16 +- .../forge/player/PlayerControllerHuman.java | 8 +- 35 files changed, 305 insertions(+), 195 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/GameState.java b/forge-ai/src/main/java/forge/ai/GameState.java index d441ab10721..f7defad4a36 100644 --- a/forge-ai/src/main/java/forge/ai/GameState.java +++ b/forge-ai/src/main/java/forge/ai/GameState.java @@ -1250,7 +1250,7 @@ public abstract class GameState { } if (cardsWithoutETBTrigs.contains(c)) { - p.getGame().getAction().moveTo(ZoneType.Battlefield, c, null); + p.getGame().getAction().moveTo(ZoneType.Battlefield, c, null, null); } else { p.getZone(ZoneType.Hand).add(c); p.getGame().getAction().moveToPlay(c, null, null); diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index f9cd5adae81..4d93d16a262 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Set; import forge.util.*; + import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -202,6 +203,16 @@ public class GameAction { lastKnownInfo = (Card) cause.getReplacingObject(AbilityKey.CardLKI); } } + CardCollectionView lastBattlefield = null; + if (params != null) { + lastBattlefield = (CardCollectionView) params.get(AbilityKey.LastStateBattlefield); + } + if (lastBattlefield == null && cause != null) { + lastBattlefield = cause.getLastStateBattlefield(); + } + if (lastBattlefield == null) { + lastBattlefield = game.getLastStateBattlefield(); + } if (c.isSplitCard()) { boolean resetToOriginal = false; @@ -254,7 +265,6 @@ public class GameAction { // if from Battlefield to Graveyard and Card does exist in LastStateBattlefield // use that instead if (fromBattlefield) { - CardCollectionView lastBattlefield = game.getLastStateBattlefield(); int idx = lastBattlefield.indexOf(c); if (idx != -1) { lastKnownInfo = lastBattlefield.get(idx); @@ -577,7 +587,10 @@ public class GameAction { } game.getTriggerHandler().clearActiveTriggers(copied, null); - game.getTriggerHandler().registerActiveLTBTrigger(lastKnownInfo); + // register all LTB trigger from last state battlefield + for (Card lki : lastBattlefield) { + game.getTriggerHandler().registerActiveLTBTrigger(lki); + } game.getTriggerHandler().registerActiveTrigger(copied, false); table.replaceCounterEffect(game, null, true); @@ -705,7 +718,7 @@ public class GameAction { } public final Card moveTo(final Zone zoneTo, Card c, SpellAbility cause) { - return moveTo(zoneTo, c, cause, null); + return moveTo(zoneTo, c, cause, AbilityKey.newMap()); } public final Card moveTo(final Zone zoneTo, Card c, SpellAbility cause, Map params) { // FThreads.assertExecutedByEdt(false); // This code must never be executed from EDT, @@ -713,14 +726,14 @@ public class GameAction { return moveTo(zoneTo, c, null, cause, params); } public final Card moveTo(final Zone zoneTo, Card c, Integer position, SpellAbility cause) { - return moveTo(zoneTo, c, position, cause, null); + return moveTo(zoneTo, c, position, cause, AbilityKey.newMap()); } - public final Card moveTo(final ZoneType name, final Card c, SpellAbility cause) { - return moveTo(name, c, 0, cause); + public final Card moveTo(final ZoneType name, final Card c, SpellAbility cause, Map params) { + return moveTo(name, c, 0, cause, params); } public final Card moveTo(final ZoneType name, final Card c, final int libPosition, SpellAbility cause) { - return moveTo(name, c, libPosition, cause, null); + return moveTo(name, c, libPosition, cause, AbilityKey.newMap()); } public final Card moveTo(final ZoneType name, final Card c, final int libPosition, SpellAbility cause, Map params) { // Call specific functions to set PlayerZone, then move onto moveTo @@ -786,7 +799,7 @@ public class GameAction { if (maingameCard.getZone().is(ZoneType.Stack)) { game.getMaingame().getStack().remove(maingameCard); } - game.getMaingame().getAction().moveTo(ZoneType.Subgame, maingameCard, null); + game.getMaingame().getAction().moveTo(ZoneType.Subgame, maingameCard, null, params); } } @@ -816,7 +829,10 @@ public class GameAction { } public final Card moveToStack(final Card c, SpellAbility cause) { - return moveToStack(c, cause, null); + Map params = AbilityKey.newMap(); + params.put(AbilityKey.LastStateBattlefield, game.getLastStateBattlefield()); + params.put(AbilityKey.LastStateGraveyard, game.getLastStateGraveyard()); + return moveToStack(c, cause, params); } public final Card moveToStack(final Card c, SpellAbility cause, Map params) { Card result = moveTo(game.getStackZone(), c, cause, params); @@ -833,7 +849,7 @@ public class GameAction { } public final Card moveToGraveyard(final Card c, SpellAbility cause) { - return moveToGraveyard(c, cause, null); + return moveToGraveyard(c, cause, AbilityKey.newMap()); } public final Card moveToGraveyard(final Card c, SpellAbility cause, Map params) { final PlayerZone grave = c.getOwner().getZone(ZoneType.Graveyard); @@ -842,7 +858,7 @@ public class GameAction { } public final Card moveToHand(final Card c, SpellAbility cause) { - return moveToHand(c, cause, null); + return moveToHand(c, cause, AbilityKey.newMap()); } public final Card moveToHand(final Card c, SpellAbility cause, Map params) { final PlayerZone hand = c.getOwner().getZone(ZoneType.Hand); @@ -859,14 +875,14 @@ public class GameAction { } public final Card moveToBottomOfLibrary(final Card c, SpellAbility cause) { - return moveToBottomOfLibrary(c, cause, null); + return moveToBottomOfLibrary(c, cause, AbilityKey.newMap()); } public final Card moveToBottomOfLibrary(final Card c, SpellAbility cause, Map params) { return moveToLibrary(c, -1, cause, params); } public final Card moveToLibrary(final Card c, SpellAbility cause) { - return moveToLibrary(c, cause, null); + return moveToLibrary(c, cause, AbilityKey.newMap()); } public final Card moveToLibrary(final Card c, SpellAbility cause, Map params) { return moveToLibrary(c, 0, cause, params); @@ -1229,7 +1245,12 @@ public class GameAction { // do this multiple times, sometimes creatures/permanents will survive when they shouldn't boolean orderedDesCreats = false; boolean orderedNoRegCreats = false; + boolean orderedSacrificeList = false; CardCollection cardsToUpdateLKI = new CardCollection(); + + Map mapParams = AbilityKey.newMap(); + mapParams.put(AbilityKey.LastStateBattlefield, game.getLastStateBattlefield()); + mapParams.put(AbilityKey.LastStateGraveyard, game.getLastStateGraveyard()); for (int q = 0; q < 9; q++) { checkStaticAbilities(false, affectedCards, CardCollection.EMPTY); boolean checkAgain = false; @@ -1253,16 +1274,14 @@ public class GameAction { } } } - CardCollection noRegCreats = null; + CardCollection noRegCreats = new CardCollection(); CardCollection desCreats = null; CardCollection unAttachList = new CardCollection(); + CardCollection sacrificeList = new CardCollection(); for (final Card c : game.getCardsIn(ZoneType.Battlefield)) { if (c.isCreature()) { // Rule 704.5f - Put into grave (no regeneration) for toughness <= 0 if (c.getNetToughness() <= 0) { - if (noRegCreats == null) { - noRegCreats = new CardCollection(); - } noRegCreats.add(c); checkAgain = true; } else if (c.hasKeyword("CARDNAME can't be destroyed by lethal damage unless lethal damage dealt by a single source is marked on it.")) { @@ -1306,7 +1325,7 @@ public class GameAction { } } - checkAgain |= stateBasedAction_Saga(c, table); + checkAgain |= stateBasedAction_Saga(c, sacrificeList); checkAgain |= stateBasedAction704_attach(c, unAttachList); // Attachment checkAgain |= stateBasedAction704_5r(c); // annihilate +1/+1 counters with -1/-1 ones @@ -1336,9 +1355,6 @@ public class GameAction { // cleanup aura if (c.isAura() && c.isInPlay() && !c.isEnchanting()) { - if (noRegCreats == null) { - noRegCreats = new CardCollection(); - } noRegCreats.add(c); checkAgain = true; } @@ -1351,28 +1367,46 @@ public class GameAction { // cleanup aura if (u.isAura() && u.isInPlay() && !u.isEnchanting()) { - if (noRegCreats == null) { - noRegCreats = new CardCollection(); - } noRegCreats.add(u); checkAgain = true; } } + for (Player p : game.getPlayers()) { + if (handleLegendRule(p, noRegCreats)) { + checkAgain = true; + } + + if ((game.getRules().hasAppliedVariant(GameType.Commander) + || game.getRules().hasAppliedVariant(GameType.Brawl) + || game.getRules().hasAppliedVariant(GameType.Planeswalker)) && !checkAgain) { + for (final Card c : p.getCardsIn(ZoneType.Graveyard).threadSafeIterable()) { + checkAgain |= stateBasedAction903_9a(c); + } + for (final Card c : p.getCardsIn(ZoneType.Exile).threadSafeIterable()) { + checkAgain |= stateBasedAction903_9a(c); + } + } + + if (handlePlaneswalkerRule(p, noRegCreats)) { + checkAgain = true; + } + } + // 704.5m World rule + checkAgain |= handleWorldRule(noRegCreats); // only check static abilities once after destroying all the creatures // (e.g. helpful for Erebos's Titan and another creature dealing lethal damage to each other simultaneously) setHoldCheckingStaticAbilities(true); - if (noRegCreats != null) { - if (noRegCreats.size() > 1 && !orderedNoRegCreats) { - noRegCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, noRegCreats, ZoneType.Graveyard, null); - orderedNoRegCreats = true; - } - for (Card c : noRegCreats) { - c.updateWasDestroyed(true); - sacrificeDestroy(c, null, table, null); - } + if (noRegCreats.size() > 1 && !orderedNoRegCreats) { + noRegCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, noRegCreats, ZoneType.Graveyard, null); + orderedNoRegCreats = true; } + for (Card c : noRegCreats) { + c.updateWasDestroyed(true); + sacrificeDestroy(c, null, table, mapParams); + } + if (desCreats != null) { if (desCreats.size() > 1 && !orderedDesCreats) { desCreats = CardLists.filter(desCreats, CardPredicates.Presets.CAN_BE_DESTROYED); @@ -1382,39 +1416,24 @@ public class GameAction { orderedDesCreats = true; } for (Card c : desCreats) { - destroy(c, null, true, table, null); + destroy(c, null, true, table, mapParams); } } + + if (sacrificeList.size() > 1 && !orderedSacrificeList) { + sacrificeList = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, sacrificeList, ZoneType.Graveyard, null); + orderedSacrificeList = true; + } + for (Card c : sacrificeList) { + c.updateWasDestroyed(true); + sacrifice(c, null, true, table, mapParams); + } setHoldCheckingStaticAbilities(false); if (game.getTriggerHandler().runWaitingTriggers()) { checkAgain = true; } - for (Player p : game.getPlayers()) { - if (handleLegendRule(p, table)) { - checkAgain = true; - } - - if ((game.getRules().hasAppliedVariant(GameType.Commander) - || game.getRules().hasAppliedVariant(GameType.Brawl) - || game.getRules().hasAppliedVariant(GameType.Planeswalker)) && !checkAgain) { - Iterable cards = p.getCardsIn(ZoneType.Graveyard).threadSafeIterable(); - for (final Card c : cards) { - checkAgain |= stateBasedAction903_9a(c); - } - cards = p.getCardsIn(ZoneType.Exile).threadSafeIterable(); - for (final Card c : cards) { - checkAgain |= stateBasedAction903_9a(c); - } - } - - if (handlePlaneswalkerRule(p, table)) { - checkAgain = true; - } - } - // 704.5m World rule - checkAgain |= handleWorldRule(table); if (game.getCombat() != null) { game.getCombat().removeAbsentCombatants(); @@ -1459,7 +1478,7 @@ public class GameAction { game.runSBACheckedCommands(); } - private boolean stateBasedAction_Saga(Card c, CardZoneTable table) { + private boolean stateBasedAction_Saga(Card c, CardCollection sacrificeList) { boolean checkAgain = false; if (!c.getType().hasSubtype("Saga")) { return false; @@ -1472,7 +1491,7 @@ public class GameAction { } if (!game.getStack().hasSourceOnStack(c, SpellAbilityPredicates.isChapter())) { // needs to be effect, because otherwise it might be a cost? - sacrifice(c, null, true, table, null); + sacrificeList.add(c); checkAgain = true; } return checkAgain; @@ -1653,57 +1672,28 @@ public class GameAction { game.getStack().clearSimultaneousStack(); } - private boolean handlePlaneswalkerRule(Player p, CardZoneTable table) { + private boolean handlePlaneswalkerRule(Player p, CardCollection noRegCreats) { // get all Planeswalkers final List list = p.getPlaneswalkersInPlay(); boolean recheck = false; - //final Multimap uniqueWalkers = ArrayListMultimap.create(); // Not used as of Ixalan - for (Card c : list) { if (c.getCounters(CounterEnumType.LOYALTY) <= 0) { - //for animation - c.updateWasDestroyed(true); - sacrificeDestroy(c, null, table, null); - // Play the Destroy sound - game.fireEvent(new GameEventCardDestroyed()); + noRegCreats.add(c); recheck = true; } - - /* -- Not used as of Ixalan -- - for (final String type : c.getType()) { - if (CardType.isAPlaneswalkerType(type)) { - uniqueWalkers.put(type, c); - } - }*/ } - /* -- Not used as of Ixalan -- - for (String key : uniqueWalkers.keySet()) { - Collection duplicates = uniqueWalkers.get(key); - if (duplicates.size() < 2) { - continue; - } - - recheck = true; - - Card toKeep = p.getController().chooseSingleEntityForEffect(new CardCollection(duplicates), new AbilitySub(ApiType.InternalLegendaryRule, null, null, null), "You have multiple planeswalkers of type \""+key+"\"in play.\n\nChoose one to stay on battlefield (the rest will be moved to graveyard)"); - for (Card c: duplicates) { - if (c != toKeep) { - moveToGraveyard(c, null); - } - } - } - */ return recheck; } - private boolean handleLegendRule(Player p, CardZoneTable table) { + private boolean handleLegendRule(Player p, CardCollection noRegCreats) { final List a = CardLists.getType(p.getCardsIn(ZoneType.Battlefield), "Legendary"); if (a.isEmpty() || game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule)) { return false; } boolean recheck = false; + // TODO legend rule exception into static ability List yamazaki = CardLists.getKeyword(a, "Legend rule doesn't apply to CARDNAME."); a.removeAll(yamazaki); @@ -1715,6 +1705,8 @@ public class GameAction { } } + // TODO handle Spy Kit + for (String name : uniqueLegends.keySet()) { Collection cc = uniqueLegends.get(name); if (cc.size() < 2) { @@ -1725,20 +1717,14 @@ public class GameAction { Card toKeep = p.getController().chooseSingleEntityForEffect(new CardCollection(cc), new SpellAbility.EmptySa(ApiType.InternalLegendaryRule, new Card(-1, game), p), "You have multiple legendary permanents named \""+name+"\" in play.\n\nChoose the one to stay on battlefield (the rest will be moved to graveyard)", null); - for (Card c: cc) { - if (c != toKeep) { - //for animation - c.updateWasDestroyed(true); - sacrificeDestroy(c, null, table, null); - } - } - game.fireEvent(new GameEventCardDestroyed()); + cc.remove(toKeep); + noRegCreats.addAll(cc); } return recheck; } - private boolean handleWorldRule(CardZoneTable table) { + private boolean handleWorldRule(CardCollection noRegCreats) { final List worlds = CardLists.getType(game.getCardsIn(ZoneType.Battlefield), "World"); if (worlds.size() <= 1) { return false; @@ -1762,12 +1748,7 @@ public class GameAction { worlds.removeAll(toKeep); } - for (Card c : worlds) { - //for animation - c.updateWasDestroyed(true); - sacrificeDestroy(c, null, table, null); - game.fireEvent(new GameEventCardDestroyed()); - } + noRegCreats.addAll(worlds); return true; } diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java index 81fbbc77dfd..0370d3fcfac 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -691,7 +691,7 @@ public final class GameActionUtil { // TODO: Add targeting to the effect so it knows who it's dealing with game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, null); + game.getAction().moveTo(ZoneType.Command, eff, null, null); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); return eff; diff --git a/forge-game/src/main/java/forge/game/Match.java b/forge-game/src/main/java/forge/game/Match.java index b7468054fd4..32329b57858 100644 --- a/forge-game/src/main/java/forge/game/Match.java +++ b/forge-game/src/main/java/forge/game/Match.java @@ -7,6 +7,7 @@ import forge.deck.CardPool; import forge.deck.Deck; import forge.deck.DeckFormat; import forge.deck.DeckSection; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CardCollectionView; import forge.game.event.Event; @@ -80,7 +81,7 @@ public class Match { Multimap list = game.chooseCardsForAnte(rules.getMatchAnteRarity()); for (Entry kv : list.entries()) { Player p = kv.getKey(); - game.getAction().moveTo(ZoneType.Ante, kv.getValue(), null); + game.getAction().moveTo(ZoneType.Ante, kv.getValue(), null, AbilityKey.newMap()); game.getGameLog().add(GameLogEntryType.ANTE, p + " anted " + kv.getValue()); } game.fireEvent(new GameEventAnteCardsSelected(list)); @@ -303,7 +304,7 @@ public class Match { // Create an effect that lets you cast your companion from your sideboard if (companion != null) { PlayerZone commandZone = player.getZone(ZoneType.Command); - companion = game.getAction().moveTo(ZoneType.Command, companion, null); + companion = game.getAction().moveTo(ZoneType.Command, companion, null, AbilityKey.newMap()); commandZone.add(Player.createCompanionEffect(game, companion)); player.updateZoneForView(commandZone); 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 9dbed5e6b24..27d34292b56 100644 --- a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java +++ b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java @@ -435,7 +435,7 @@ public abstract class SpellAbilityEffect { // TODO: Add targeting to the effect so it knows who it's dealing with game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, sa); + game.getAction().moveTo(ZoneType.Command, eff, sa, null); eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); } @@ -553,7 +553,7 @@ public abstract class SpellAbilityEffect { // TODO: Add targeting to the effect so it knows who it's dealing with game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, sa); + game.getAction().moveTo(ZoneType.Command, eff, sa, null); eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); } @@ -685,13 +685,13 @@ public abstract class SpellAbilityEffect { }; } - protected static void discard(SpellAbility sa, CardZoneTable table, final boolean effect, Map discardedMap) { + protected static void discard(SpellAbility sa, CardZoneTable table, final boolean effect, Map discardedMap, Map params) { Set discarders = discardedMap.keySet(); for (Player p : discarders) { final CardCollection discardedByPlayer = new CardCollection(); for (Card card : Lists.newArrayList(discardedMap.get(p))) { // without copying will get concurrent modification exception if (card == null) { continue; } - if (p.discard(card, sa, effect, table) != null) { + if (p.discard(card, sa, effect, table, params) != null) { discardedByPlayer.add(card); if (sa.hasParam("RememberDiscarded")) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/AddTurnEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AddTurnEffect.java index 71cd3c5b321..34861a8e750 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AddTurnEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AddTurnEffect.java @@ -4,6 +4,7 @@ import java.util.List; import forge.game.Game; import forge.game.ability.AbilityFactory; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -84,7 +85,7 @@ public class AddTurnEffect extends SpellAbilityEffect { eff.addStaticAbility(stEffect); game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, sa); + game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap()); eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java index 0622cbd6f8a..a726d0a47ee 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java @@ -49,6 +49,8 @@ public class BalanceEffect extends SpellAbilityEffect { } Map params = AbilityKey.newMap(); + params.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + params.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); CardZoneTable table = new CardZoneTable(); for (int i = 0; i < players.size(); i++) { Player p = players.get(i); @@ -67,7 +69,7 @@ public class BalanceEffect extends SpellAbilityEffect { } if (zone.equals(ZoneType.Hand)) { - discard(sa, table, true, discardedMap); + discard(sa, table, true, discardedMap, params); } table.triggerChangesZoneAll(game, sa); 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 c76f0ae1c7a..351367581a6 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 @@ -620,7 +620,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } } - Map moveParams = Maps.newEnumMap(AbilityKey.class); + Map moveParams = AbilityKey.newMap(); moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); if (sa.isReplacementAbility()) { @@ -699,7 +699,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect { gameCard.setExiledWith(host); gameCard.setExiledBy(host.getController()); } - movedCard = game.getAction().moveTo(destination, gameCard, sa); + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); + moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); + movedCard = game.getAction().moveTo(destination, gameCard, sa, moveParams); if (ZoneType.Hand.equals(destination) && ZoneType.Command.equals(originZone.getZoneType())) { StringBuilder sb = new StringBuilder(); sb.append(movedCard.getName()).append(" has moved from Command Zone to ").append(player).append("'s hand."); @@ -1210,7 +1213,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { for (final Card c : chosenCards) { Card movedCard = null; final Zone originZone = game.getZoneOf(c); - Map moveParams = Maps.newEnumMap(AbilityKey.class); + Map moveParams = AbilityKey.newMap(); moveParams.put(AbilityKey.FoundSearchingLibrary, searchedLibrary); moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffectBase.java index a0499a41be6..cdecd9ce083 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffectBase.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffectBase.java @@ -6,6 +6,7 @@ import forge.GameCommand; import forge.game.Game; import forge.game.GameObject; import forge.game.ability.AbilityFactory; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -65,7 +66,7 @@ public abstract class DamagePreventEffectBase extends SpellAbilityEffect { } game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, sa); + game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap()); eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java index f66fe752f83..fce8c6cf64c 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java @@ -9,6 +9,7 @@ import com.google.common.collect.Maps; import forge.game.Game; import forge.game.GameActionUtil; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -287,7 +288,11 @@ public class DiscardEffect extends SpellAbilityEffect { discardedMap.put(p, toBeDiscarded); } - discard(sa, table, true, discardedMap); + Map params = AbilityKey.newMap(); + params.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + params.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); + + discard(sa, table, true, discardedMap, params); // run trigger if something got milled table.triggerChangesZoneAll(game, sa); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java index 051b433e367..ab54029cd58 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java @@ -1,7 +1,9 @@ package forge.game.ability.effects; import java.util.List; +import java.util.Map; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -42,6 +44,9 @@ public class DrawEffect extends SpellAbilityEffect { final boolean upto = sa.hasParam("Upto"); final boolean optional = sa.hasParam("OptionalDecider") || upto; + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); for (final Player p : getDefinedPlayersOrTargeted(sa)) { // TODO can this be removed? @@ -70,7 +75,7 @@ public class DrawEffect extends SpellAbilityEffect { actualNum = p.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblHowManyCardDoYouWantDraw"), 0, actualNum); } - final CardCollectionView drawn = p.drawCards(actualNum, sa); + final CardCollectionView drawn = p.drawCards(actualNum, sa, moveParams); if (sa.hasParam("Reveal")) { if (sa.getParam("Reveal").equals("All")) { p.getGame().getAction().reveal(drawn, p, false); diff --git a/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java b/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java index 66d595cab19..58af067e77e 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java @@ -2,6 +2,7 @@ package forge.game.ability.effects; import java.util.EnumSet; import java.util.List; +import java.util.Map; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -12,6 +13,7 @@ import forge.card.CardRarity; import forge.game.Game; import forge.game.GameObject; import forge.game.ability.AbilityFactory; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -136,6 +138,10 @@ public class EffectEffect extends SpellAbilityEffect { image = hostCard.getImageKey(); } + Map params = AbilityKey.newMap(); + params.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + params.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); + for (Player controller : effectOwner) { final Card eff = createEffect(sa, controller, name, image); eff.setSetCode(sa.getHostCard().getSetCode()); @@ -322,7 +328,7 @@ public class EffectEffect extends SpellAbilityEffect { // TODO: Add targeting to the effect so it knows who it's dealing with game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, sa); + game.getAction().moveTo(ZoneType.Command, eff, sa, params); eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); //if (effectTriggers != null) { 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 314468cad29..05beb40e92d 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 @@ -1,7 +1,10 @@ package forge.game.ability.effects; +import java.util.Map; + import forge.game.Game; import forge.game.GameLogEntryType; +import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CardCollectionView; @@ -49,8 +52,12 @@ public class EncodeEffect extends SpellAbilityEffect { return; } + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); + // move host card to exile - Card movedCard = game.getAction().moveTo(ZoneType.Exile, host, sa); + Card movedCard = game.getAction().moveTo(ZoneType.Exile, host, sa, moveParams); // choose a creature Card choice = player.getController().chooseSingleEntityForEffect(choices, sa, Localizer.getInstance().getMessage("lblChooseACreatureYouControlToEncode") + " ", true, null); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ExploreEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ExploreEffect.java index 3299cef13a1..36170ceab0d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ExploreEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ExploreEffect.java @@ -1,6 +1,7 @@ package forge.game.ability.effects; import java.util.List; +import java.util.Map; import com.google.common.collect.Lists; @@ -48,6 +49,9 @@ public class ExploreEffect extends SpellAbilityEffect { GameEntityCounterTable table = new GameEntityCounterTable(); final CardZoneTable triggerList = new CardZoneTable(); + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); for (final Card c : getTargetCards(sa)) { // revealed land card boolean revealedLand = false; @@ -59,7 +63,7 @@ public class ExploreEffect extends SpellAbilityEffect { final Card r = top.getFirst(); final Zone originZone = game.getZoneOf(r); if (r.isLand()) { - movedCard = game.getAction().moveTo(ZoneType.Hand, r, sa); + movedCard = game.getAction().moveTo(ZoneType.Hand, r, sa, moveParams); revealedLand = true; } else { // TODO find better way to choose optional send away @@ -67,7 +71,7 @@ public class ExploreEffect extends SpellAbilityEffect { ZoneType.Graveyard, Lists.newArrayList(ZoneType.Library), sa, top, null, Localizer.getInstance().getMessage("lblPutThisCardToYourGraveyard"), true, pl); if (choosen != null) { - movedCard = game.getAction().moveTo(ZoneType.Graveyard, choosen, sa); + movedCard = game.getAction().moveTo(ZoneType.Graveyard, choosen, sa, moveParams); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/FogEffect.java b/forge-game/src/main/java/forge/game/ability/effects/FogEffect.java index 7db93850abe..335e8eeb3b7 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/FogEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/FogEffect.java @@ -2,6 +2,7 @@ package forge.game.ability.effects; import forge.GameCommand; import forge.game.Game; +import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.replacement.ReplacementEffect; @@ -32,7 +33,7 @@ public class FogEffect extends SpellAbilityEffect { eff.addReplacementEffect(re); game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, sa); + game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap()); eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); diff --git a/forge-game/src/main/java/forge/game/ability/effects/LearnEffect.java b/forge-game/src/main/java/forge/game/ability/effects/LearnEffect.java index 207b8606f54..68d89b805d2 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/LearnEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/LearnEffect.java @@ -1,6 +1,9 @@ package forge.game.ability.effects; +import java.util.Map; + import forge.game.Game; +import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CardZoneTable; @@ -18,8 +21,11 @@ public class LearnEffect extends SpellAbilityEffect { final Card source = sa.getHostCard(); final Game game = source.getGame(); CardZoneTable table = new CardZoneTable(); + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); for (Player p : getTargetPlayers(sa)) { - p.learnLesson(sa, table); + p.learnLesson(sa, table, moveParams); } table.triggerChangesZoneAll(game, sa); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java index a36c38d4507..5d32044542b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java @@ -1,7 +1,10 @@ package forge.game.ability.effects; +import java.util.Map; + import forge.StaticData; import forge.game.Game; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -13,6 +16,9 @@ import forge.game.zone.ZoneType; public class MakeCardEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); for (final Player player : getTargetPlayers(sa)) { final Card source = sa.getHostCard(); final Game game = player.getGame(); @@ -43,13 +49,13 @@ public class MakeCardEffect extends SpellAbilityEffect { if (!sa.hasParam("NotToken")) { card.setTokenCard(true); } - game.getAction().moveTo(ZoneType.None, card, sa); + game.getAction().moveTo(ZoneType.None, card, sa, moveParams); cards.add(card); amount--; } for (final Card c : cards) { - game.getAction().moveTo(zone, c, sa); + game.getAction().moveTo(zone, c, sa, moveParams); if (sa.hasParam("RememberMade")) { sa.getHostCard().addRemembered(c); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/MillEffect.java b/forge-game/src/main/java/forge/game/ability/effects/MillEffect.java index d9c2ff553fa..21bb6d86db3 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/MillEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/MillEffect.java @@ -1,7 +1,10 @@ package forge.game.ability.effects; +import java.util.Map; + import forge.game.Game; import forge.game.GameLogEntryType; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -35,6 +38,9 @@ public class MillEffect extends SpellAbilityEffect { } final CardZoneTable table = new CardZoneTable(); + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); for (final Player p : getTargetPlayers(sa)) { if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { @@ -45,7 +51,7 @@ public class MillEffect extends SpellAbilityEffect { continue; } } - final CardCollectionView milled = p.mill(numCards, destination, bottom, sa, table); + final CardCollectionView milled = p.mill(numCards, destination, bottom, sa, table, moveParams); // Reveal the milled cards, so players don't have to manually inspect the // graveyard to figure out which ones were milled. if (!facedown && reveal) { // do not reveal when exiling face down diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlaneswalkEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlaneswalkEffect.java index dc3bc6970ed..caac7f2b2c3 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PlaneswalkEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PlaneswalkEffect.java @@ -18,9 +18,9 @@ public class PlaneswalkEffect extends SpellAbilityEffect { } if (sa.hasParam("Defined")) { CardCollectionView destinations = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa); - sa.getActivatingPlayer().planeswalkTo(destinations); + sa.getActivatingPlayer().planeswalkTo(sa, destinations); } else { - sa.getActivatingPlayer().planeswalk(); + sa.getActivatingPlayer().planeswalk(sa); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java index 3b20b103075..dc6f8f64b63 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java @@ -19,6 +19,7 @@ import forge.StaticData; import forge.card.CardRulesPredicates; import forge.game.Game; import forge.game.ability.AbilityFactory; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -216,6 +217,11 @@ public class PlayEffect extends SpellAbilityEffect { boolean singleOption = tgtCards.size() == 1 && amount == 1 && optional; Map params = hasTotalCMCLimit ? new HashMap<>() : null; + + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); + while (!tgtCards.isEmpty() && amount > 0 && totalCMCLimit >= 0) { if (hasTotalCMCLimit) { // filter out cards with mana value greater than limit @@ -376,12 +382,12 @@ public class PlayEffect extends SpellAbilityEffect { // can't be done later if (sa.hasParam("ReplaceGraveyard")) { - addReplaceGraveyardEffect(tgtCard, sa, sa.getParam("ReplaceGraveyard")); + addReplaceGraveyardEffect(tgtCard, sa, sa.getParam("ReplaceGraveyard"), moveParams); } // For Illusionary Mask effect if (sa.hasParam("ReplaceIlluMask")) { - addIllusionaryMaskReplace(tgtCard, sa); + addIllusionaryMaskReplace(tgtCard, sa, moveParams); } tgtSA.setSVar("IsCastFromPlayEffect", "True"); @@ -420,7 +426,7 @@ public class PlayEffect extends SpellAbilityEffect { } // end resolve - protected void addReplaceGraveyardEffect(Card c, SpellAbility sa, String zone) { + protected void addReplaceGraveyardEffect(Card c, SpellAbility sa, String zone, Map moveParams) { final Card hostCard = sa.getHostCard(); final Game game = hostCard.getGame(); final Player controller = sa.getActivatingPlayer(); @@ -461,12 +467,12 @@ public class PlayEffect extends SpellAbilityEffect { // TODO: Add targeting to the effect so it knows who it's dealing with game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, sa); + game.getAction().moveTo(ZoneType.Command, eff, sa, moveParams); eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); } - protected void addIllusionaryMaskReplace(Card c, SpellAbility sa) { + protected void addIllusionaryMaskReplace(Card c, SpellAbility sa, Map moveParams) { final Card hostCard = sa.getHostCard(); final Game game = hostCard.getGame(); final Player controller = sa.getActivatingPlayer(); @@ -497,7 +503,7 @@ public class PlayEffect extends SpellAbilityEffect { addExileOnCounteredTrigger(eff); game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, sa); + game.getAction().moveTo(ZoneType.Command, eff, sa, moveParams); eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java index 82bbb917667..2ed822bb1d4 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java @@ -3,6 +3,7 @@ package forge.game.ability.effects; import forge.GameCommand; import forge.game.Game; import forge.game.ability.AbilityFactory; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -71,7 +72,7 @@ public abstract class RegenerateBaseEffect extends SpellAbilityEffect { c.addShield(eff); } game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, sa); + game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap()); eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); diff --git a/forge-game/src/main/java/forge/game/ability/effects/SetInMotionEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SetInMotionEffect.java index 2943b46b509..f471abd7c01 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SetInMotionEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SetInMotionEffect.java @@ -41,7 +41,7 @@ public class SetInMotionEffect extends SpellAbilityEffect { } game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, controller.getActiveScheme(), null); + game.getAction().moveTo(ZoneType.Command, controller.getActiveScheme(), null, AbilityKey.newMap()); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); // Run triggers diff --git a/forge-game/src/main/java/forge/game/ability/effects/SkipPhaseEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SkipPhaseEffect.java index 43d6c2b5631..a589a52d2c4 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SkipPhaseEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SkipPhaseEffect.java @@ -5,6 +5,7 @@ import java.util.List; import forge.GameCommand; import forge.game.Game; import forge.game.ability.AbilityFactory; +import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.player.Player; @@ -115,7 +116,7 @@ public class SkipPhaseEffect extends SpellAbilityEffect { eff.addReplacementEffect(re); game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, sa); + game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap()); eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/SkipTurnEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SkipTurnEffect.java index 4f64e1d89d2..0d81ed142ca 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SkipTurnEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SkipTurnEffect.java @@ -4,6 +4,7 @@ import java.util.List; import forge.game.Game; import forge.game.ability.AbilityFactory; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -61,7 +62,7 @@ public class SkipTurnEffect extends SpellAbilityEffect { eff.addReplacementEffect(re); game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, eff, sa); + game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap()); eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/SubgameEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SubgameEffect.java index 7ec64259baf..51bcf22dba2 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SubgameEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SubgameEffect.java @@ -9,6 +9,7 @@ import com.google.common.collect.Lists; import forge.card.MagicColor; import forge.game.Game; import forge.game.GameOutcome; +import forge.game.ability.AbilityKey; import forge.game.ability.ApiType; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -127,7 +128,7 @@ public class SubgameEffect extends SpellAbilityEffect { // Create an effect that lets you cast your companion from your sideboard if (companion != null) { PlayerZone commandZone = player.getZone(ZoneType.Command); - companion = subgame.getAction().moveTo(ZoneType.Command, companion, null); + companion = subgame.getAction().moveTo(ZoneType.Command, companion, null, AbilityKey.newMap()); commandZone.add(Player.createCompanionEffect(subgame, companion)); player.updateZoneForView(commandZone); @@ -242,7 +243,7 @@ public class SubgameEffect extends SpellAbilityEffect { } } for (final Card card : movedCommanders) { - maingame.getAction().moveTo(ZoneType.Library, card, null); + maingame.getAction().moveTo(ZoneType.Library, card, null, AbilityKey.newMap()); } player.shuffle(sa); diff --git a/forge-game/src/main/java/forge/game/ability/effects/SurveilEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SurveilEffect.java index 1ddc7776ea3..b148a44af13 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SurveilEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SurveilEffect.java @@ -1,5 +1,8 @@ package forge.game.ability.effects; +import java.util.Map; + +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.CardZoneTable; @@ -34,6 +37,9 @@ public class SurveilEffect extends SpellAbilityEffect { boolean isOptional = sa.hasParam("Optional"); CardZoneTable table = new CardZoneTable(); + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); for (final Player p : getTargetPlayers(sa)) { if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { @@ -41,7 +47,7 @@ public class SurveilEffect extends SpellAbilityEffect { continue; } - p.surveil(num, sa, table); + p.surveil(num, sa, table, moveParams); } } table.triggerChangesZoneAll(sa.getHostCard().getGame(), sa); diff --git a/forge-game/src/main/java/forge/game/ability/effects/VentureEffect.java b/forge-game/src/main/java/forge/game/ability/effects/VentureEffect.java index c13a27706ff..01009a820de 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/VentureEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/VentureEffect.java @@ -27,7 +27,7 @@ import forge.util.Localizer; public class VentureEffect extends SpellAbilityEffect { - private Card getDungeonCard(SpellAbility sa, Player player) { + private Card getDungeonCard(SpellAbility sa, Player player, Map moveParams) { final Game game = player.getGame(); CardCollectionView commandCards = player.getCardsIn(ZoneType.Command); @@ -50,7 +50,7 @@ public class VentureEffect extends SpellAbilityEffect { Card dungeon = player.getController().chooseDungeon(player, dungeonCards, message); game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); - game.getAction().moveTo(ZoneType.Command, dungeon, sa); + game.getAction().moveTo(ZoneType.Command, dungeon, sa, moveParams); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); return dungeon; @@ -85,13 +85,13 @@ public class VentureEffect extends SpellAbilityEffect { } } - private void ventureIntoDungeon(SpellAbility sa, Player player) { + private void ventureIntoDungeon(SpellAbility sa, Player player, Map moveParams) { if (StaticAbilityCantVenture.cantVenture(player)) { return; } final Game game = player.getGame(); - Card dungeon = getDungeonCard(sa, player); + Card dungeon = getDungeonCard(sa, player, moveParams); String room = dungeon.getCurrentRoom(); String nextRoom = null; @@ -117,9 +117,13 @@ public class VentureEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); + for (final Player p : getTargetPlayers(sa)) { if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) { - ventureIntoDungeon(sa, p); + ventureIntoDungeon(sa, p, moveParams); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java index 694fa05e8aa..280d5360963 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java @@ -1,6 +1,9 @@ package forge.game.ability.effects; +import java.util.Map; + import forge.game.Game; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -87,8 +90,11 @@ public class ZoneExchangeEffect extends SpellAbilityEffect { object1.unattachFromEntity(c); object2.attachToEntity(c); } + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); // Exchange Zone - game.getAction().moveTo(zone2, object1, sa); - game.getAction().moveTo(zone1, object2, sa); + game.getAction().moveTo(zone2, object1, sa, moveParams); + game.getAction().moveTo(zone1, object2, sa, moveParams); } } diff --git a/forge-game/src/main/java/forge/game/cost/CostDraw.java b/forge-game/src/main/java/forge/game/cost/CostDraw.java index 6885be83ebe..8a5c77f0287 100644 --- a/forge-game/src/main/java/forge/game/cost/CostDraw.java +++ b/forge-game/src/main/java/forge/game/cost/CostDraw.java @@ -17,6 +17,9 @@ */ package forge.game.cost; +import java.util.Map; + +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.player.Player; import forge.game.player.PlayerCollection; @@ -94,8 +97,11 @@ public class CostDraw extends CostPart { */ @Override public final boolean payAsDecided(final Player ai, final PaymentDecision decision, SpellAbility ability, final boolean effect) { + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, ability.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, ability.getLastStateGraveyard()); for (final Player p : decision.players) { - p.drawCards(decision.c, ability); + p.drawCards(decision.c, ability, moveParams); } 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 eb184a618d1..69091a6f337 100644 --- a/forge-game/src/main/java/forge/game/cost/CostMill.java +++ b/forge-game/src/main/java/forge/game/cost/CostMill.java @@ -17,6 +17,9 @@ */ package forge.game.cost; +import java.util.Map; + +import forge.game.ability.AbilityKey; import forge.game.card.CardCollection; import forge.game.card.CardZoneTable; import forge.game.player.Player; @@ -88,7 +91,10 @@ public class CostMill extends CostPart { @Override public final boolean payAsDecided(final Player ai, final PaymentDecision decision, SpellAbility ability, final boolean effect) { CardZoneTable table = new CardZoneTable(); - ability.getPaidHash().put("Milled", (CardCollection) ai.mill(decision.c, ZoneType.Graveyard, false, ability, table)); + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, ai.getGame().getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, ai.getGame().getLastStateGraveyard()); + ability.getPaidHash().put("Milled", (CardCollection) ai.mill(decision.c, ZoneType.Graveyard, false, ability, table, moveParams)); table.triggerChangesZoneAll(ai.getGame(), ability); return true; } diff --git a/forge-game/src/main/java/forge/game/cost/CostSacrifice.java b/forge-game/src/main/java/forge/game/cost/CostSacrifice.java index 2577ecb0957..ec48bb0d976 100644 --- a/forge-game/src/main/java/forge/game/cost/CostSacrifice.java +++ b/forge-game/src/main/java/forge/game/cost/CostSacrifice.java @@ -19,8 +19,11 @@ package forge.game.cost; import forge.card.CardType; +import java.util.Map; + import com.google.common.collect.Iterables; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; @@ -133,7 +136,10 @@ public class CostSacrifice extends CostPartWithList { @Override protected Card doPayment(SpellAbility ability, Card targetCard, final boolean effect) { // no table there, it is already handled by CostPartWithList - return targetCard.getGame().getAction().sacrifice(targetCard, ability, effect, null, null); + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, ability.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, ability.getLastStateGraveyard()); + return targetCard.getGame().getAction().sacrifice(targetCard, ability, effect, null, moveParams); } /* (non-Javadoc) diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java index 17cfd4e139e..3f4022e6590 100644 --- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java +++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java @@ -393,11 +393,15 @@ public class PhaseHandler implements java.io.Serializable { int numDiscard = playerTurn.isUnlimitedHandSize() || handSize <= max || handSize == 0 ? 0 : handSize - max; if (numDiscard > 0) { + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, game.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, game.getLastStateGraveyard()); + final CardZoneTable table = new CardZoneTable(); final CardCollection discarded = new CardCollection(); boolean firstDiscarded = playerTurn.getNumDiscardedThisTurn() == 0; for (Card c : playerTurn.getController().chooseCardsToDiscardToMaximumHandSize(numDiscard)) { - if (playerTurn.discard(c, null, false, table) != null) { + if (playerTurn.discard(c, null, false, table, moveParams) != null) { discarded.add(c); } } diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 2c63761879c..49dcbf8959d 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -326,10 +326,14 @@ public class Player extends GameEntity implements Comparable { return; } + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, game.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, game.getLastStateGraveyard()); + game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); activeScheme = getZone(ZoneType.SchemeDeck).get(0); // gameAction moveTo ? - game.getAction().moveTo(ZoneType.Command, activeScheme, null); + game.getAction().moveTo(ZoneType.Command, activeScheme, null, moveParams); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); // Run triggers @@ -1101,10 +1105,13 @@ public class Player extends GameEntity implements Comparable { return true; } - public void surveil(int num, SpellAbility cause, CardZoneTable table) { + public void surveil(int num, SpellAbility cause, CardZoneTable table, Map params) { final Map repParams = AbilityKey.mapFromAffected(this); repParams.put(AbilityKey.Source, cause); repParams.put(AbilityKey.SurveilNum, num); + if (params != null) { + repParams.putAll(params); + } switch (getGame().getReplacementHandler().run(ReplacementType.Surveil, repParams)) { case NotReplaced: @@ -1133,7 +1140,7 @@ public class Player extends GameEntity implements Comparable { if (toGrave != null) { for (Card c : toGrave) { ZoneType oZone = c.getZone().getZoneType(); - Card moved = getGame().getAction().moveToGraveyard(c, cause); + Card moved = getGame().getAction().moveToGraveyard(c, cause, params); table.put(oZone, moved.getZone().getZoneType(), moved); numToGrave++; } @@ -1142,7 +1149,7 @@ public class Player extends GameEntity implements Comparable { if (toTop != null) { Collections.reverse(toTop); // the last card in list will become topmost in library, have to revert thus. for (Card c : toTop) { - getGame().getAction().moveToLibrary(c, cause); + getGame().getAction().moveToLibrary(c, cause, params); numToTop++; } } @@ -1152,6 +1159,9 @@ public class Player extends GameEntity implements Comparable { surveilThisTurn++; final Map runParams = AbilityKey.mapFromPlayer(this); runParams.put(AbilityKey.NumThisTurn, surveilThisTurn); + if (params != null) { + runParams.putAll(params); + } getGame().getTriggerHandler().runTrigger(TriggerType.Surveil, runParams, false); } @@ -1176,13 +1186,13 @@ public class Player extends GameEntity implements Comparable { } public final CardCollectionView drawCard() { - return drawCards(1, null); + return drawCards(1, null, AbilityKey.newMap()); } public final CardCollectionView drawCards(final int n) { - return drawCards(n, null); + return drawCards(n, null, AbilityKey.newMap()); } - public final CardCollectionView drawCards(final int n, SpellAbility cause) { + public final CardCollectionView drawCards(final int n, SpellAbility cause, Map params) { final CardCollection drawn = new CardCollection(); if (n <= 0) { return drawn; @@ -1191,6 +1201,9 @@ public class Player extends GameEntity implements Comparable { // Replacement effects final Map repRunParams = AbilityKey.mapFromAffected(this); repRunParams.put(AbilityKey.Number, n); + if (params != null) { + repRunParams.putAll(params); + } if (game.getReplacementHandler().run(ReplacementType.DrawCards, repRunParams) != ReplacementResult.NotReplaced) { return drawn; @@ -1204,7 +1217,7 @@ public class Player extends GameEntity implements Comparable { if (gameStarted && !canDraw()) { return drawn; } - drawn.addAll(doDraw(toReveal, cause)); + drawn.addAll(doDraw(toReveal, cause, params)); } // reveal multiple drawn cards when playing with the top of the library revealed @@ -1219,13 +1232,16 @@ public class Player extends GameEntity implements Comparable { /** * @return a CardCollectionView of cards actually drawn */ - private CardCollectionView doDraw(Map revealed, SpellAbility cause) { + private CardCollectionView doDraw(Map revealed, SpellAbility cause, Map params) { final CardCollection drawn = new CardCollection(); final PlayerZone library = getZone(ZoneType.Library); // Replacement effects Map repParams = AbilityKey.mapFromAffected(this); repParams.put(AbilityKey.Cause, cause); + if (params != null) { + repParams.putAll(params); + } if (game.getReplacementHandler().run(ReplacementType.Draw, repParams) != ReplacementResult.NotReplaced) { return drawn; } @@ -1246,7 +1262,7 @@ public class Player extends GameEntity implements Comparable { } } - c = game.getAction().moveToHand(c, cause); + c = game.getAction().moveToHand(c, cause, params); drawn.add(c); for (Player p : pList) { @@ -1267,6 +1283,9 @@ public class Player extends GameEntity implements Comparable { view.updateNumDrawnThisTurn(this); final Map runParams = AbilityKey.mapFromPlayer(this); + if (params != null) { + runParams.putAll(params); + } // CR 121.8 card was drawn as part of another sa (e.g. paying with Chromantic Sphere), hide it temporarily if (game.getTopLibForPlayer(this) != null && getPaidForSA() != null && cause != null && getPaidForSA() != cause.getRootAbility()) { @@ -1414,9 +1433,6 @@ public class Player extends GameEntity implements Comparable { numRollsThisTurn++; } - public final Card discard(final Card c, final SpellAbility sa, final boolean effect, CardZoneTable table) { - return discard(c, sa, effect, table, null); - } public final Card discard(final Card c, final SpellAbility sa, final boolean effect, CardZoneTable table, Map params) { if (!c.canBeDiscardedBy(sa, effect)) { return null; @@ -1575,13 +1591,16 @@ public class Player extends GameEntity implements Comparable { } public final CardCollectionView mill(int n, final ZoneType destination, - final boolean bottom, SpellAbility sa, CardZoneTable table) { + final boolean bottom, SpellAbility sa, CardZoneTable table, Map params) { final CardCollectionView lib = getCardsIn(ZoneType.Library); final CardCollection milled = new CardCollection(); // Replacement effects final Map repRunParams = AbilityKey.mapFromAffected(this); repRunParams.put(AbilityKey.Number, n); + if (params != null) { + repRunParams.putAll(params); + } if (destination == ZoneType.Graveyard && !bottom) { switch (getGame().getReplacementHandler().run(ReplacementType.Mill, repRunParams)) { @@ -1618,7 +1637,7 @@ public class Player extends GameEntity implements Comparable { for (Card m : milledView) { final ZoneType origin = m.getZone().getZoneType(); - final Card d = game.getAction().moveTo(destination, m, sa); + final Card d = game.getAction().moveTo(destination, m, sa, params); if (d.getZone().is(destination)) { table.put(origin, d.getZone().getZoneType(), d); } @@ -2580,21 +2599,25 @@ public class Player extends GameEntity implements Comparable { * Takes the top plane of the planar deck and put it face up in the command zone. * Then runs triggers. */ - public void planeswalk() { - planeswalkTo(new CardCollection(getZone(ZoneType.PlanarDeck).get(0))); + public void planeswalk(SpellAbility sa) { + planeswalkTo(sa, new CardCollection(getZone(ZoneType.PlanarDeck).get(0))); } /** * Puts the planes in the argument and puts them face up in the command zone. * Then runs triggers. */ - public void planeswalkTo(final CardCollectionView destinations) { + public void planeswalkTo(SpellAbility sa, final CardCollectionView destinations) { System.out.println(getName() + ": planeswalk to " + destinations.toString()); currentPlanes.addAll(destinations); game.getView().updatePlanarPlayer(getView()); + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); + for (Card c : currentPlanes) { - game.getAction().moveTo(ZoneType.Command,c, null); + game.getAction().moveTo(ZoneType.Command, c, sa, moveParams); //getZone(ZoneType.PlanarDeck).remove(c); //getZone(ZoneType.Command).add(c); } @@ -3414,10 +3437,13 @@ public class Player extends GameEntity implements Comparable { } } - public void learnLesson(SpellAbility sa, CardZoneTable table) { + public void learnLesson(SpellAbility sa, CardZoneTable table, Map params) { // Replacement effects Map repParams = AbilityKey.mapFromAffected(this); repParams.put(AbilityKey.Cause, sa); + if (params != null) { + repParams.putAll(params); + } if (game.getReplacementHandler().run(ReplacementType.Learn, repParams) != ReplacementResult.NotReplaced) { return; } @@ -3438,11 +3464,11 @@ public class Player extends GameEntity implements Comparable { } if (c.isInZone(ZoneType.Sideboard)) { // Sideboard Lesson to Hand game.getAction().reveal(new CardCollection(c), c.getOwner(), true); - Card moved = game.getAction().moveTo(ZoneType.Hand, c, sa); + Card moved = game.getAction().moveTo(ZoneType.Hand, c, sa, params); table.put(ZoneType.Sideboard, ZoneType.Hand, moved); } else if (c.isInZone(ZoneType.Hand)) { // Discard and Draw boolean firstDiscard = getNumDiscardedThisTurn() == 0; - if (discard(c, sa, true, table) != null) { + if (discard(c, sa, true, table, params) != null) { // Change this if something would make multiple player learn at the same time // Discard Trigger outside Effect @@ -3450,9 +3476,12 @@ public class Player extends GameEntity implements Comparable { runParams.put(AbilityKey.Cards, new CardCollection(c)); runParams.put(AbilityKey.Cause, sa); runParams.put(AbilityKey.FirstTime, firstDiscard); + if (params != null) { + runParams.putAll(params); + } getGame().getTriggerHandler().runTrigger(TriggerType.DiscardedAll, runParams, false); - for (Card d : drawCards(1, sa)) { + for (Card d : drawCards(1, sa, params)) { table.put(ZoneType.Library, ZoneType.Hand, d); // does a ChangesZoneAll care about moving from Library to Hand } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java index 69b1be0d2b7..3187ab21a96 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java @@ -44,7 +44,8 @@ import io.sentry.Sentry; import io.sentry.event.BreadcrumbBuilder; public class TriggerHandler { - private final List suppressedModes = Collections.synchronizedList(new ArrayList<>()); + private final Set suppressedModes = Collections.synchronizedSet(EnumSet.noneOf(TriggerType.class)); + private boolean allSuppressed = false; private final List activeTriggers = Collections.synchronizedList(new ArrayList<>()); private final List delayedTriggers = Collections.synchronizedList(new ArrayList<>()); @@ -106,18 +107,15 @@ public class TriggerHandler { } public final void setSuppressAllTriggers(final boolean suppress) { - for (TriggerType t : TriggerType.values()) { - if (suppress) { - suppressMode(t); - } else { - clearSuppression(t); - } - } + allSuppressed = suppress; } public final void clearSuppression(final TriggerType mode) { suppressedModes.remove(mode); } + public boolean isTriggerSuppressed(final TriggerType mode) { + return allSuppressed || suppressedModes.contains(mode); + } public static Trigger parseTrigger(final String trigParse, final Card host, final boolean intrinsic) { return parseTrigger(trigParse, host, intrinsic, host.getCurrentState()); @@ -252,7 +250,7 @@ public class TriggerHandler { } public final void runTrigger(final TriggerType mode, final Map runParams, boolean holdTrigger) { - if (suppressedModes.contains(mode)) { + if (isTriggerSuppressed(mode)) { return; } diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 1b652bb756c..979949f9546 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -2803,7 +2803,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont } } } - getGame().getAction().moveTo(targetZone, forgeCard, null); + getGame().getAction().moveTo(targetZone, forgeCard, null, AbilityKey.newMap()); if (forgeCard.isCreature()) { forgeCard.setSickness(lastSummoningSickness); } @@ -2858,7 +2858,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont getGame().getAction().moveToBottomOfLibrary(forgeCard, null); } } else { - getGame().getAction().moveTo(targetZone, forgeCard, null); + getGame().getAction().moveTo(targetZone, forgeCard, null, AbilityKey.newMap()); } lastAdded = f; @@ -2898,7 +2898,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont if (c == null) { continue; } - if (getGame().getAction().moveTo(ZoneType.Exile, c, null) != null) { + if (getGame().getAction().moveTo(ZoneType.Exile, c, null, AbilityKey.newMap()) != null) { StringBuilder sb = new StringBuilder(); sb.append(p).append(" exiles ").append(c).append(" due to Dev Cheats."); getGame().getGameLog().add(GameLogEntryType.DISCARD, sb.toString()); @@ -2937,7 +2937,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont if (c == null) { continue; } - if (getGame().getAction().moveTo(ZoneType.Exile, c, null) != null) { + if (getGame().getAction().moveTo(ZoneType.Exile, c, null, AbilityKey.newMap()) != null) { StringBuilder sb = new StringBuilder(); sb.append(p).append(" exiles ").append(c).append(" due to Dev Cheats."); getGame().getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString()); From c2dbf1075c5541b60f27d9d20fc9eb28383ba1a4 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Fri, 25 Feb 2022 10:17:05 +0000 Subject: [PATCH 2/4] update RewardScene --- .../forge/adventure/scene/RewardScene.java | 248 ++++++++---------- .../adventure/Shandalar/ui/items_mobile.json | 29 ++ 2 files changed, 137 insertions(+), 140 deletions(-) create mode 100644 forge-gui/res/adventure/Shandalar/ui/items_mobile.json diff --git a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java index 21cd76c8220..ede92f2119e 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java @@ -18,87 +18,78 @@ import forge.adventure.util.Reward; import forge.adventure.util.RewardActor; import forge.adventure.world.WorldSave; import forge.assets.ImageCache; +import forge.gui.GuiBase; /** * Displays the rewards of a fight or a treasure */ -public class RewardScene extends UIScene { +public class RewardScene extends UIScene { private TextButton doneButton; - public enum Type - { + public enum Type { Shop, Loot - } + Type type; - Array generated =new Array<>(); - static public final float CARD_WIDTH =550f; - static public final float CARD_HEIGHT =400f; - static public final float CARD_WIDTH_TO_HEIGHT =CARD_WIDTH/CARD_HEIGHT; - public RewardScene() - { - super("ui/items.json"); + Array generated = new Array<>(); + static public final float CARD_WIDTH = 550f; + static public final float CARD_HEIGHT = 400f; + static public final float CARD_WIDTH_TO_HEIGHT = CARD_WIDTH / CARD_HEIGHT; + + public RewardScene() { + super(GuiBase.isAndroid() ? "ui/items_mobile.json" : "ui/items.json"); } - boolean doneClicked=false; - float flipCountDown=1.0f; - public boolean done() - { + boolean doneClicked = false; + float flipCountDown = 1.0f; + + public boolean done() { GameHUD.getInstance().getTouchpad().setVisible(false); - if(doneClicked) + if (doneClicked) return true; - if(type==Type.Loot) - { + if (type == Type.Loot) { - boolean wait=false; - for(Actor actor: new Array.ArrayIterator<>(generated)) - { - if(!(actor instanceof RewardActor)) - { + boolean wait = false; + for (Actor actor : new Array.ArrayIterator<>(generated)) { + if (!(actor instanceof RewardActor)) { continue; } - RewardActor reward=(RewardActor) actor; + RewardActor reward = (RewardActor) actor; AdventurePlayer.current().addReward(reward.getReward()); - if(!reward.isFlipped()) - { + if (!reward.isFlipped()) { wait = true; reward.flip(); } } - if(wait) - { - flipCountDown=3.0f; - doneClicked=true; - } - else - { + if (wait) { + flipCountDown = 3.0f; + doneClicked = true; + } else { Forge.switchToLast(); } - } - else - { + } else { Forge.switchToLast(); } return true; } + @Override public void act(float delta) { stage.act(delta); ImageCache.allowSingleLoad(); - if(doneClicked) - { - if(type==Type.Loot) - flipCountDown-=Gdx.graphics.getDeltaTime(); - if(flipCountDown<=0) - { + if (doneClicked) { + if (type == Type.Loot) + flipCountDown -= Gdx.graphics.getDeltaTime(); + if (flipCountDown <= 0) { Forge.switchToLast(); } } } + @Override public void resLoaded() { super.resLoaded(); @@ -108,56 +99,49 @@ public class RewardScene extends UIScene { RewardScene.this.done(); } }); - doneButton=ui.findActor("done"); + doneButton = ui.findActor("done"); } @Override - public boolean keyPressed(int keycode) - { - if (keycode == Input.Keys.ESCAPE) - { + public boolean keyPressed(int keycode) { + if (keycode == Input.Keys.ESCAPE) { done(); } return true; } - public void loadRewards(Array newRewards, Type type, ShopActor shopActor) - { - this.type=type; - doneClicked=false; + public void loadRewards(Array newRewards, Type type, ShopActor shopActor) { + this.type = type; + doneClicked = false; - - - for(Actor actor: new Array.ArrayIterator<>(generated)) - { + for (Actor actor : new Array.ArrayIterator<>(generated)) { actor.remove(); - if(actor instanceof RewardActor) - { - ((RewardActor)actor).dispose(); + if (actor instanceof RewardActor) { + ((RewardActor) actor).dispose(); } } generated.clear(); - Actor card=ui.findActor("cards"); + Actor card = ui.findActor("cards"); - // card.setDrawable(new TextureRegionDrawable(new Texture(Res.CurrentRes.GetFile("ui/transition.png")))); + // card.setDrawable(new TextureRegionDrawable(new Texture(Res.CurrentRes.GetFile("ui/transition.png")))); - float targetWidth = card.getWidth(); + float targetWidth = card.getWidth(); float targetHeight = card.getHeight(); - float xOff = card.getX(); + float xOff = card.getX(); float yOff = card.getY(); - int numberOfRows=0; - float cardWidth=0; - float cardHeight=0; - float bestCardHeight=0; - int numberOfColumns=0; - float targetArea=targetHeight*targetWidth; - float oldCardArea=0; - float newArea=0; + int numberOfRows = 0; + float cardWidth = 0; + float cardHeight = 0; + float bestCardHeight = 0; + int numberOfColumns = 0; + float targetArea = targetHeight * targetWidth; + float oldCardArea = 0; + float newArea = 0; switch (type) { case Shop: @@ -167,89 +151,74 @@ public class RewardScene extends UIScene { doneButton.setText("Take all"); break; } - for(int h=1;holdCardArea&&newArea<=targetArea&&rows*cardHeight oldCardArea && newArea <= targetArea && rows * cardHeight < targetHeight && cols * cardWidth < targetWidth) { + oldCardArea = newArea; + numberOfRows = rows; + numberOfColumns = cols; + bestCardHeight = h; } } - cardHeight=bestCardHeight; - cardWidth=bestCardHeight/ CARD_WIDTH_TO_HEIGHT; + cardHeight = bestCardHeight; + cardWidth = bestCardHeight / CARD_WIDTH_TO_HEIGHT; - yOff+=(targetHeight-(cardHeight*numberOfRows))/2f; - xOff+=(targetWidth-(cardWidth*numberOfColumns))/2f; - float spacing=2; - int i=0; - for(Reward reward:new Array.ArrayIterator<>(newRewards)) - { - boolean skipCard=false; - if(type==Type.Shop) - { - if(shopActor.getMapStage().getChanges().wasCardBought(shopActor.getObjectID(),i)) - { - skipCard=true; + yOff += (targetHeight - (cardHeight * numberOfRows)) / 2f; + xOff += (targetWidth - (cardWidth * numberOfColumns)) / 2f; + float spacing = 2; + int i = 0; + for (Reward reward : new Array.ArrayIterator<>(newRewards)) { + boolean skipCard = false; + if (type == Type.Shop) { + if (shopActor.getMapStage().getChanges().wasCardBought(shopActor.getObjectID(), i)) { + skipCard = true; } } - - int currentRow=(i/numberOfColumns); - float lastRowXAdjust=0; - if(currentRow==numberOfRows-1) - { - int lastRowCount=newRewards.size%numberOfColumns; - if(lastRowCount!=0) - lastRowXAdjust=((numberOfColumns*cardWidth)-(lastRowCount*cardWidth))/2; + int currentRow = (i / numberOfColumns); + float lastRowXAdjust = 0; + if (currentRow == numberOfRows - 1) { + int lastRowCount = newRewards.size % numberOfColumns; + if (lastRowCount != 0) + lastRowXAdjust = ((numberOfColumns * cardWidth) - (lastRowCount * cardWidth)) / 2; } - RewardActor actor=new RewardActor(reward,type==Type.Loot); - actor.setBounds(lastRowXAdjust+xOff+cardWidth*(i%numberOfColumns)+spacing,yOff+cardHeight*currentRow+spacing,cardWidth-spacing*2,cardHeight-spacing*2); + RewardActor actor = new RewardActor(reward, type == Type.Loot); + actor.setBounds(lastRowXAdjust + xOff + cardWidth * (i % numberOfColumns) + spacing, yOff + cardHeight * currentRow + spacing, cardWidth - spacing * 2, cardHeight - spacing * 2); - if(type==Type.Shop) - { - if(currentRow!=((i+1)/numberOfColumns)) - yOff+=doneButton.getHeight(); + if (type == Type.Shop) { + if (currentRow != ((i + 1) / numberOfColumns)) + yOff += doneButton.getHeight(); - TextButton buyCardButton=new BuyButton(shopActor.getObjectID(),i,shopActor.getMapStage().getChanges(),actor,doneButton); + TextButton buyCardButton = new BuyButton(shopActor.getObjectID(), i, shopActor.getMapStage().getChanges(), actor, doneButton); generated.add(buyCardButton); - if(!skipCard) - { + if (!skipCard) { stage.addActor(buyCardButton); } } generated.add(actor); - if(!skipCard) - { + if (!skipCard) { stage.addActor(actor); } i++; } updateBuyButtons(); - } private void updateBuyButtons() { - - for(Actor actor: new Array.ArrayIterator<>(generated)) - { - if(actor instanceof BuyButton) - { - ((BuyButton)actor).update(); + for (Actor actor : new Array.ArrayIterator<>(generated)) { + if (actor instanceof BuyButton) { + ((BuyButton) actor).update(); } } } @@ -260,28 +229,28 @@ public class RewardScene extends UIScene { private final PointOfInterestChanges changes; RewardActor reward; int price; - void update(){ - setDisabled(WorldSave.getCurrentSave().getPlayer().getGold()< price); + + void update() { + setDisabled(WorldSave.getCurrentSave().getPlayer().getGold() < price); } + public BuyButton(int id, int i, PointOfInterestChanges ch, RewardActor actor, TextButton style) { - super("",style.getStyle()); + super("", style.getStyle()); this.objectID = id; this.index = i; this.changes = ch; - reward=actor; + reward = actor; setHeight(style.getHeight()); setWidth(actor.getWidth()); setX(actor.getX()); - setY(actor.getY()-getHeight()); - price= CardUtil.getCardPrice(actor.getReward().getCard()); - setText("Buy for "+price); - addListener(new ClickListener(){ - + setY(actor.getY() - getHeight()); + price = CardUtil.getCardPrice(actor.getReward().getCard()); + setText("Buy for " + price); + addListener(new ClickListener() { @Override - public void clicked (InputEvent event, float x, float y) { - if(Current.player().getGold()>= price) - { - changes.buyCard(objectID,index); + public void clicked(InputEvent event, float x, float y) { + if (Current.player().getGold() >= price) { + changes.buyCard(objectID, index); Current.player().takeGold(price); Current.player().addReward(reward.getReward()); setDisabled(true); @@ -289,7 +258,6 @@ public class RewardScene extends UIScene { remove(); updateBuyButtons(); } - } }); } diff --git a/forge-gui/res/adventure/Shandalar/ui/items_mobile.json b/forge-gui/res/adventure/Shandalar/ui/items_mobile.json new file mode 100644 index 00000000000..75bd6ed37d6 --- /dev/null +++ b/forge-gui/res/adventure/Shandalar/ui/items_mobile.json @@ -0,0 +1,29 @@ +{ + "width": 480, + "height": 270, + "yDown": true, + "elements": [ + { + "type": "Image", + "name": "lastScreen", + "width": 480, + "height": 270 + }, + { + "name": "cards", + "x": 5, + "y": 5, + "width": 405, + "height": 265 + }, + { + "type": "TextButton", + "name": "done", + "text": "Take all", + "width": 48, + "height": 30, + "x": 420, + "y": 120 + } + ] +} \ No newline at end of file From e9f697da1bcd9c3cc9aad7a8bc573139bf2dd6b7 Mon Sep 17 00:00:00 2001 From: John Williams Date: Fri, 25 Feb 2022 10:53:05 +0000 Subject: [PATCH 3/4] Update Secret Lair Drop Series.txt --- forge-gui/res/editions/Secret Lair Drop Series.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/forge-gui/res/editions/Secret Lair Drop Series.txt b/forge-gui/res/editions/Secret Lair Drop Series.txt index 9ac5878e7af..92a71fdc2dd 100644 --- a/forge-gui/res/editions/Secret Lair Drop Series.txt +++ b/forge-gui/res/editions/Secret Lair Drop Series.txt @@ -363,6 +363,7 @@ ScryfallCode=SLD 383★ R Krark's Thumb @Wooden Cyclops 384 R Swamp @Jeanne D'Angelo 385 R Island @Jeanne D'Angelo +386 R Island @Jeanne D'Angelo 396 M Tamiyo, the Moon Sage @Uta Natsume 397 M Ajani, Mentor of Heroes @Uta Natsume 398 M Angrath, the Flame-Chained @Uta Natsume From 652bcbd41553a61e4ad37accfcbf2397dfd73a80 Mon Sep 17 00:00:00 2001 From: Bug Hunter Date: Fri, 25 Feb 2022 20:38:44 +0000 Subject: [PATCH 4/4] Update forge-gui/res/cardsfolder/t/tomb_tyrant.txt --- forge-gui/res/cardsfolder/t/tomb_tyrant.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/t/tomb_tyrant.txt b/forge-gui/res/cardsfolder/t/tomb_tyrant.txt index dcaa579b57d..999ec22aca1 100644 --- a/forge-gui/res/cardsfolder/t/tomb_tyrant.txt +++ b/forge-gui/res/cardsfolder/t/tomb_tyrant.txt @@ -3,7 +3,7 @@ ManaCost:3 B Types:Creature Zombie Noble PT:3/3 S:Mode$ Continuous | Affected$ Zombie.Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other Zombies you control get +1/+1. -A:AB$ ChangeZone | Cost$ 2 B T Sac<1/Creature/creature> | ChangeType$ Zombie.Creature.YouOwn | Origin$ Graveyard | Destination$ Battlefield | AtRandom$ True | CheckSVar$ X | SVarCompare$ GE3 | PlayerTurn$ True | Hidden$ True | StackDescription$ Return a Zombie creature card at random from your graveyard to the battlefield. | SpellDescription$ Return a Zombie creature card at random from your graveyard to the battlefield. Activate only during your turn and only if there are at least three Zombie creature cards in your graveyard. +A:AB$ ChangeZone | Cost$ 2 B T Sac<1/Creature/creature> | ChangeType$ Zombie.YouOwn | Origin$ Graveyard | Destination$ Battlefield | AtRandom$ True | CheckSVar$ X | SVarCompare$ GE3 | PlayerTurn$ True | Hidden$ True | StackDescription$ Return a Zombie creature card at random from your graveyard to the battlefield. | SpellDescription$ Return a Zombie creature card at random from your graveyard to the battlefield. Activate only during your turn and only if there are at least three Zombie creature cards in your graveyard. SVar:X:Count$ValidGraveyard Creature.Zombie+YouCtrl DeckNeeds:Type$Zombie DeckHas:Ability$Graveyard