diff --git a/forge-ai/src/main/java/forge/ai/AiAttackController.java b/forge-ai/src/main/java/forge/ai/AiAttackController.java index b4c522c6dac..e879226c098 100644 --- a/forge-ai/src/main/java/forge/ai/AiAttackController.java +++ b/forge-ai/src/main/java/forge/ai/AiAttackController.java @@ -932,7 +932,7 @@ public class AiAttackController { // check defenders in order of maximum requirements List> reqs = combat.getAttackConstraints().getRequirements().get(attacker).getSortedRequirements(); final GameEntity def = defender; - Collections.sort(reqs, new Comparator>() { + reqs.sort(new Comparator>() { @Override public int compare(Pair r1, Pair r2) { if (r1.getValue() == r2.getValue()) { diff --git a/forge-ai/src/main/java/forge/ai/AiBlockController.java b/forge-ai/src/main/java/forge/ai/AiBlockController.java index 04fb2c2bf43..c12adbab18e 100644 --- a/forge-ai/src/main/java/forge/ai/AiBlockController.java +++ b/forge-ai/src/main/java/forge/ai/AiBlockController.java @@ -140,7 +140,7 @@ public class AiBlockController { ComputerUtilCard.sortByEvaluateCreature(attackers); CardLists.sortByPowerDesc(attackers); //move cards like Phage the Untouchable to the front - Collections.sort(attackers, new Comparator() { + attackers.sort(new Comparator() { @Override public int compare(final Card o1, final Card o2) { if (o1.hasSVar("MustBeBlocked") && !o2.hasSVar("MustBeBlocked")) { diff --git a/forge-ai/src/main/java/forge/ai/AiCostDecision.java b/forge-ai/src/main/java/forge/ai/AiCostDecision.java index 417c04bcbc2..0fa59234f8c 100644 --- a/forge-ai/src/main/java/forge/ai/AiCostDecision.java +++ b/forge-ai/src/main/java/forge/ai/AiCostDecision.java @@ -505,7 +505,7 @@ public class AiCostDecision extends CostDecisionMakerBase { protected int removeCounter(GameEntityCounterTable table, List prefs, CounterEnumType cType, int stillToRemove) { int removed = 0; if (!prefs.isEmpty() && stillToRemove > 0) { - Collections.sort(prefs, CardPredicates.compareByCounterType(cType)); + prefs.sort(CardPredicates.compareByCounterType(cType)); for (Card prefCard : prefs) { // already enough removed @@ -667,7 +667,7 @@ public class AiCostDecision extends CostDecisionMakerBase { return crd.getCounters(CounterEnumType.QUEST) > e; } }); - Collections.sort(prefs, Collections.reverseOrder(CardPredicates.compareByCounterType(CounterEnumType.QUEST))); + prefs.sort(Collections.reverseOrder(CardPredicates.compareByCounterType(CounterEnumType.QUEST))); for (final Card crd : prefs) { int e = 0; diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index 04340d65bac..f0f16854db5 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -2451,7 +2451,7 @@ public class ComputerUtil { return goodChoices; } - Collections.sort(goodChoices, CardLists.TextLenComparator); + goodChoices.sort(CardLists.TextLenComparator); CardLists.sortByCmcDesc(goodChoices); diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilAbility.java b/forge-ai/src/main/java/forge/ai/ComputerUtilAbility.java index a76df0a12e6..d8750ad2e02 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilAbility.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilAbility.java @@ -1,6 +1,5 @@ package forge.ai; -import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; @@ -402,7 +401,7 @@ public class ComputerUtilAbility { return all; } // TODO this doesn't account for nearly identical creatures where one is a newer but more cost efficient variant - Collections.sort(creatures, ComputerUtilCard.EvaluateCreatureSpellComparator); + creatures.sort(ComputerUtilCard.EvaluateCreatureSpellComparator); int idx = 0; for (int i = 0; i < all.size(); i++) { if (all.get(i).getApi() == ApiType.PermanentCreature) { diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index 1588a113f85..a747aae9b88 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -84,7 +84,7 @@ public class ComputerUtilCard { * @param list */ public static void sortByEvaluateCreature(final CardCollection list) { - Collections.sort(list, ComputerUtilCard.EvaluateCreatureComparator); + list.sort(ComputerUtilCard.EvaluateCreatureComparator); } // The AI doesn't really pick the best artifact, just the most expensive. @@ -552,12 +552,13 @@ public class ComputerUtilCard { if (!Iterables.isEmpty(list)) { CardCollection cc = CardLists.filter(list, Predicates.or(CardPredicates.isType("Instant"), CardPredicates.isType("Sorcery"))); - Collections.sort(cc, CardLists.CmcComparatorInv); if (cc.isEmpty()) { return null; } + cc.sort(CardLists.CmcComparatorInv); + Card cheapest = cc.getLast(); if (cheapest.hasSVar("DoNotDiscardIfAble")) { for (int i = cc.size() - 1; i >= 0; i--) { diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index f1f467a8902..45089d914d5 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -126,7 +126,7 @@ public class ComputerUtilMana { } } } - Collections.sort(orderedCards, new Comparator() { + orderedCards.sort(new Comparator() { @Override public int compare(final Card card1, final Card card2) { return Integer.compare(manaCardMap.get(card1), manaCardMap.get(card2)); @@ -149,7 +149,7 @@ public class ComputerUtilMana { System.out.println("Unsorted Abilities: " + newAbilities); } - Collections.sort(newAbilities, new Comparator() { + newAbilities.sort(new Comparator() { @Override public int compare(final SpellAbility ability1, final SpellAbility ability2) { int preOrder = orderedCards.indexOf(ability1.getHostCard()) - orderedCards.indexOf(ability2.getHostCard()); @@ -195,7 +195,7 @@ public class ComputerUtilMana { final List prefSortedAbilities = new ArrayList<>(newAbilities); final List otherSortedAbilities = new ArrayList<>(newAbilities); - Collections.sort(prefSortedAbilities, new Comparator() { + prefSortedAbilities.sort(new Comparator() { @Override public int compare(final SpellAbility ability1, final SpellAbility ability2) { if (ability1.getManaPart().mana(ability1).contains(preferredShard)) @@ -206,7 +206,7 @@ public class ComputerUtilMana { return 0; } }); - Collections.sort(otherSortedAbilities, new Comparator() { + otherSortedAbilities.sort(new Comparator() { @Override public int compare(final SpellAbility ability1, final SpellAbility ability2) { if (ability1.getManaPart().mana(ability1).contains(preferredShard)) @@ -1094,7 +1094,7 @@ public class ComputerUtilMana { private static ManaCostShard getNextShardToPay(ManaCostBeingPaid cost, Multimap sourcesForShards) { List shardsToPay = Lists.newArrayList(cost.getDistinctShards()); // optimize order so that the shards with less available sources are considered first - Collections.sort(shardsToPay, new Comparator() { + shardsToPay.sort(new Comparator() { @Override public int compare(final ManaCostShard shard1, final ManaCostShard shard2) { return sourcesForShards.get(shard1).size() - sourcesForShards.get(shard2).size(); diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java index 28dbaf0fc17..c1075bc5f8b 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java @@ -1398,7 +1398,7 @@ public class ChangeZoneAi extends SpellAbilityAi { chance = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_CHANCE); } if (MyRandom.percentTrue(chance)) { - Collections.sort(aiPlaneswalkers, CardPredicates.compareByCounterType(CounterEnumType.LOYALTY)); + aiPlaneswalkers.sort(CardPredicates.compareByCounterType(CounterEnumType.LOYALTY)); for (Card pw : aiPlaneswalkers) { int curLoyalty = pw.getCounters(CounterEnumType.LOYALTY); int freshLoyalty = Integer.valueOf(pw.getCurrentState().getBaseLoyalty()); diff --git a/forge-core/src/main/java/forge/deck/CardPool.java b/forge-core/src/main/java/forge/deck/CardPool.java index 05d7d6398d0..e1029521e9f 100644 --- a/forge-core/src/main/java/forge/deck/CardPool.java +++ b/forge-core/src/main/java/forge/deck/CardPool.java @@ -440,7 +440,7 @@ public class CardPool extends ItemPool { public String toCardList(String separator) { List> main2sort = Lists.newArrayList(this); - Collections.sort(main2sort, ItemPoolSorter.BY_NAME_THEN_SET); + main2sort.sort(ItemPoolSorter.BY_NAME_THEN_SET); final CardDb commonDb = StaticData.instance().getCommonCards(); StringBuilder sb = new StringBuilder(); diff --git a/forge-game/src/main/java/forge/game/Game.java b/forge-game/src/main/java/forge/game/Game.java index 107240cc3d4..4d4fa74870e 100644 --- a/forge-game/src/main/java/forge/game/Game.java +++ b/forge-game/src/main/java/forge/game/Game.java @@ -794,7 +794,7 @@ public class Game { boolean planarControllerLost = false; boolean planarOwnerLost = false; boolean isMultiplayer = getPlayers().size() > 2; - CardZoneTable triggerList = new CardZoneTable(); + CardZoneTable triggerList = new CardZoneTable(getLastStateBattlefield(), getLastStateGraveyard()); // 702.142f & 707.9 // If a player leaves the game, all face-down cards that player owns must be revealed to all players. diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 2318ee5b2a7..f5497b9f36d 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -184,24 +184,8 @@ public class GameAction { lastKnownInfo = (Card) cause.getReplacingObject(AbilityKey.CardLKI); } } - CardCollectionView lastBattlefield = null; - CardCollectionView lastGraveyard = null; - if (params != null) { - lastBattlefield = (CardCollectionView) params.get(AbilityKey.LastStateBattlefield); - lastGraveyard = (CardCollectionView) params.get(AbilityKey.LastStateGraveyard); - } - if (lastBattlefield == null && cause != null) { - lastBattlefield = cause.getLastStateBattlefield(); - } - if (lastGraveyard == null && cause != null) { - lastGraveyard = cause.getLastStateGraveyard(); - } - if (lastBattlefield == null) { - lastBattlefield = game.getLastStateBattlefield(); - } - if (lastGraveyard == null) { - lastGraveyard = game.getLastStateGraveyard(); - } + CardCollectionView lastBattlefield = getLastState(AbilityKey.LastStateBattlefield, cause, params); + CardCollectionView lastGraveyard = getLastState(AbilityKey.LastStateGraveyard, cause, params); if (c.isSplitCard()) { boolean resetToOriginal = false; @@ -211,11 +195,9 @@ public class GameAction { // Make sure the card returns from the battlefield as the original card with two halves resetToOriginal = true; } - } else { - if (!zoneTo.is(ZoneType.Stack)) { - // For regular splits, recreate the original state unless the card is going to stack as one half - resetToOriginal = true; - } + } else if (!zoneTo.is(ZoneType.Stack)) { + // For regular splits, recreate the original state unless the card is going to stack as one half + resetToOriginal = true; } if (resetToOriginal) { @@ -917,7 +899,7 @@ public class GameAction { } public final CardCollection exile(final CardCollection cards, SpellAbility cause, Map params) { - CardZoneTable table = new CardZoneTable(); + CardZoneTable table = new CardZoneTable(getLastState(AbilityKey.LastStateBattlefield, cause, params), getLastState(AbilityKey.LastStateGraveyard, cause, params)); CardCollection result = new CardCollection(); for (Card card : cards) { if (cause != null) { @@ -964,7 +946,6 @@ public class GameAction { if (z.is(ZoneType.Battlefield)) { c.runLeavesPlayCommands(); } - } // CR 603.6c other players LTB triggers should work @@ -1042,7 +1023,6 @@ public class GameAction { game.getTriggerHandler().runTrigger(TriggerType.ChangesController, runParams, false); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); - } // Temporarily disable (if mode = true) actively checking static abilities. @@ -1264,7 +1244,7 @@ public class GameAction { checkStaticAbilities(false, affectedCards, CardCollection.EMPTY); boolean checkAgain = false; - CardZoneTable table = new CardZoneTable(); + CardZoneTable table = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateGraveyard()); for (final Player p : game.getPlayers()) { for (final ZoneType zt : ZoneType.values()) { @@ -2593,4 +2573,28 @@ public class GameAction { } } } + + private CardCollectionView getLastState(final AbilityKey key, final SpellAbility cause, final Map params) { + CardCollectionView lastState = null; + if (params != null) { + lastState = (CardCollectionView) params.get(key); + } + if (lastState == null && cause != null) { + if (key == AbilityKey.LastStateBattlefield) { + lastState = cause.getLastStateBattlefield(); + } + if (key == AbilityKey.LastStateGraveyard) { + lastState = cause.getLastStateGraveyard(); + } + } + if (lastState == null) { + if (key == AbilityKey.LastStateBattlefield) { + lastState = game.getLastStateBattlefield(); + } + if (key == AbilityKey.LastStateGraveyard) { + lastState = game.getLastStateGraveyard(); + } + } + return lastState; + } } diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 56171d63d64..060814f3d5c 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -2141,9 +2141,11 @@ public class AbilityUtils { if (sq[0].contains("CardManaCost")) { int cmc = c.getCMC(); - if (sq[0].contains("LKI") && ctb instanceof SpellAbility && !c.isInZone(ZoneType.Stack) && c.getManaCost() != null) { - if (((SpellAbility) ctb).getXManaCostPaid() != null) { + if (sq[0].contains("LKI") && !c.isInZone(ZoneType.Stack) && c.getManaCost() != null) { + if (ctb instanceof SpellAbility && ((SpellAbility) ctb).getXManaCostPaid() != null) { cmc += ((SpellAbility) ctb).getXManaCostPaid() * c.getManaCost().countX(); + } else { + cmc += c.getXManaCostPaid() * c.getManaCost().countX(); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java index e3fd922065e..43a3aad45e3 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java @@ -75,7 +75,6 @@ public class AmassEffect extends TokenEffectBase { makeTokenTable(makeTokenTableInternal(activator, result, 1), false, triggerList, combatChanged, sa); triggerList.triggerChangesZoneAll(game, sa); - triggerList.clear(); game.fireEvent(new GameEventTokenCreated()); diff --git a/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java index 6d2167610d1..8a9dcc5627c 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java @@ -151,12 +151,9 @@ public class AttachEffect extends SpellAbilityEffect { ZoneType previousZone = source.getZone().getZoneType(); - CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield(); - CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard(); - - Map moveParams = Maps.newEnumMap(AbilityKey.class); - moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); - moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, game.copyLastStateGraveyard()); // The Spell_Permanent (Auras) version of this AF needs to // move the card into play before Attaching 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 11cb88b32d2..61b7dcd0826 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,9 +49,10 @@ 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(); + params.put(AbilityKey.LastStateBattlefield, game.getLastStateBattlefield()); + params.put(AbilityKey.LastStateGraveyard, game.getLastStateBattlefield()); + CardZoneTable table = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateBattlefield()); + for (int i = 0; i < players.size(); i++) { Player p = players.get(i); int numToBalance = validCards.get(i).size() - min; 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 6be096854f7..1fbd452520c 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 @@ -155,7 +155,7 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect { CardLists.shuffle(cards); } - final CardZoneTable triggerList = new CardZoneTable(); + final CardZoneTable triggerList = new CardZoneTable(lastStateBattlefield, lastStateGraveyard); 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 51ebf34d227..f98109e9db2 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 @@ -468,7 +468,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect { libraryPosition = pair.getValue(); } - final CardZoneTable triggerList = new CardZoneTable(); + CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield(); + CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard(); + + final CardZoneTable triggerList = new CardZoneTable(lastStateBattlefield, lastStateGraveyard); GameEntityCounterTable counterTable = new GameEntityCounterTable(); // changing zones for spells on the stack for (final SpellAbility tgtSA : getTargetSpells(sa)) { @@ -505,9 +508,6 @@ public class ChangeZoneEffect extends SpellAbilityEffect { chooser = AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("Chooser"), sa).get(0); } - CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield(); - CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard(); - // CR 401.4 if (destination.equals(ZoneType.Library) && !shuffle && tgtCards.size() > 1) { if (sa.hasParam("RandomOrder")) { @@ -1262,10 +1262,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect { final boolean imprint = sa.hasParam("Imprint"); boolean combatChanged = false; - final CardZoneTable triggerList = new CardZoneTable(); CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield(); CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard(); + final CardZoneTable triggerList = new CardZoneTable(lastStateBattlefield, lastStateGraveyard); for (Player player : HiddenOriginChoicesMap.keySet()) { boolean searchedLibrary = HiddenOriginChoicesMap.get(player).searchedLibrary; diff --git a/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java index 10884e3408a..6fc489e3c64 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java @@ -1,6 +1,5 @@ package forge.game.ability.effects; -import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -246,7 +245,7 @@ public class CharmEffect extends SpellAbilityEffect { } // Sort Chosen by SA order - Collections.sort(chosen, new Comparator() { + chosen.sort(new Comparator() { @Override public int compare(AbilitySub o1, AbilitySub o2) { return Integer.compare(o1.getSVarInt("CharmOrder"), o2.getSVarInt("CharmOrder")); 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 469a7765ac8..e9c51966707 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 @@ -89,10 +89,11 @@ public class DestroyAllEffect extends SpellAbilityEffect { list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard, sa); - CardZoneTable table = new CardZoneTable(); Map params = AbilityKey.newMap(); params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield()); + CardZoneTable table = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateGraveyard()); + Map cachedMap = Maps.newHashMap(); for (Card c : list) { if (game.getAction().destroy(c, sa, !noRegen, table, params) && remDestroyed) { 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 2f7978ae969..454bcd69719 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 @@ -10,6 +10,7 @@ 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; @@ -61,7 +62,7 @@ public class DestroyEffect extends SpellAbilityEffect { Map params = AbilityKey.newMap(); params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield()); - CardZoneTable table = new CardZoneTable(); + CardZoneTable table = new CardZoneTable(game.getLastStateBattlefield(), CardCollection.EMPTY); Map cachedMap = Maps.newHashMap(); for (final Card tgtC : tgtCards) { if (!tgtC.isInPlay()) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java index 54a0a89797e..909e7c42e39 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.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.ability.AbilityKey; import forge.game.ability.AbilityUtils; @@ -30,12 +28,9 @@ public class ManifestEffect extends SpellAbilityEffect { // Most commonly "defined" is Top of Library final String defined = sa.getParamOrDefault("Defined", "TopOfLibrary"); - CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield(); - CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard(); - - Map moveParams = Maps.newEnumMap(AbilityKey.class); - moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); - moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield()); + moveParams.put(AbilityKey.LastStateGraveyard, game.copyLastStateGraveyard()); for (final Player p : getTargetPlayers(sa, "DefinedPlayer")) { CardCollection tgtCards; @@ -73,8 +68,7 @@ public class ManifestEffect extends SpellAbilityEffect { if (sa.hasParam("RememberManifested") && rem.isManifested()) { source.addRemembered(rem); } - // 701.34d. If an effect instructs a player to manifest multiple cards from their library, - // those cards are manifested one at a time. + // CR 701.34d multiple cards are manifested one at a time triggerList.put(origin, ZoneType.Battlefield, rem); triggerList.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 90f611c1d3f..24fb3de2be1 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 @@ -82,10 +82,10 @@ public class SacrificeAllEffect extends SpellAbilityEffect { list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard, sa); - CardZoneTable table = new CardZoneTable(); Map cachedMap = Maps.newHashMap(); Map params = AbilityKey.newMap(); params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield()); + CardZoneTable table = new CardZoneTable(game.getLastStateBattlefield(), CardCollection.EMPTY); for (Card sac : list) { final Card lKICopy = CardUtil.getLKICopy(sac, cachedMap); 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 2c81516936d..04d3ff299a1 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 @@ -100,9 +100,9 @@ public class SacrificeEffect extends SpellAbilityEffect { final boolean destroy = sa.hasParam("Destroy"); final boolean remSacrificed = sa.hasParam("RememberSacrificed"); final boolean optional = sa.hasParam("Optional"); - CardZoneTable table = new CardZoneTable(); Map params = AbilityKey.newMap(); params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield()); + CardZoneTable table = new CardZoneTable(game.getLastStateBattlefield(), CardCollection.EMPTY); if (valid.equals("Self") && game.getZoneOf(card) != null) { if (game.getZoneOf(card).is(ZoneType.Battlefield)) { 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 11d508fd08d..ffa86fa21a1 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -4055,7 +4055,6 @@ public class Card extends GameEntity implements Comparable, IHasSVars { public final int getCurrentLoyalty() { return getCounters(CounterEnumType.LOYALTY); } - public final void setBaseLoyalty(final int n) { currentState.setBaseLoyalty(Integer.toString(n)); } @@ -4066,13 +4065,13 @@ public class Card extends GameEntity implements Comparable, IHasSVars { public final void setBaseDefense(final int n) { currentState.setBaseDefense(Integer.toString(n)); } + public final int getBasePower() { return currentState.getBasePower(); } public final int getBaseToughness() { return currentState.getBaseToughness(); } - public final void setBasePower(final int n) { currentState.setBasePower(n); } diff --git a/forge-game/src/main/java/forge/game/card/CardProperty.java b/forge-game/src/main/java/forge/game/card/CardProperty.java index e229c35ceab..6eddea05c85 100644 --- a/forge-game/src/main/java/forge/game/card/CardProperty.java +++ b/forge-game/src/main/java/forge/game/card/CardProperty.java @@ -403,6 +403,7 @@ public class CardProperty { } } else if (property.startsWith("ExiledWithSourceLKI")) { List exiled = card.getZone().getCardsAddedThisTurn(null); + exiled.sort(CardPredicates.compareByTimestamp()); int idx = exiled.lastIndexOf(card); if (idx == -1) { return false; 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 bf5bf60785e..2321adcb7f7 100644 --- a/forge-game/src/main/java/forge/game/card/CardZoneTable.java +++ b/forge-game/src/main/java/forge/game/card/CardZoneTable.java @@ -22,11 +22,35 @@ public class CardZoneTable extends ForwardingTable cardZoneTable) { + private CardCollectionView lastStateBattlefield; + private CardCollectionView lastStateGraveyard; + + public CardZoneTable(CardZoneTable cardZoneTable) { this.putAll(cardZoneTable); + lastStateBattlefield = cardZoneTable.getLastStateBattlefield(); + lastStateGraveyard = cardZoneTable.getLastStateGraveyard(); } public CardZoneTable() { + this(CardCollection.EMPTY, CardCollection.EMPTY); + } + + public CardZoneTable(CardCollectionView lastStateBattlefield, CardCollectionView lastStateGraveyard) { + this.lastStateBattlefield = lastStateBattlefield; + this.lastStateGraveyard = lastStateGraveyard; + } + + public CardCollectionView getLastStateBattlefield() { + return lastStateBattlefield; + } + public CardCollectionView getLastStateGraveyard() { + return lastStateGraveyard; + } + public void setLastStateBattlefield(CardCollectionView lastState) { + this.lastStateBattlefield = lastState; + } + public void setLastStateGraveyard(CardCollectionView lastState) { + this.lastStateGraveyard = lastState; } /** @@ -88,12 +112,20 @@ public class CardZoneTable extends ForwardingTable etbLKI = moved.getController().getZone(ZoneType.Battlefield).getCardsAddedThisTurn(null); - Collections.sort(etbLKI, CardPredicates.compareByTimestamp()); + etbLKI.sort(CardPredicates.compareByTimestamp()); moved = etbLKI.get(etbLKI.lastIndexOf(moved)); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerChangesZoneAll.java b/forge-game/src/main/java/forge/game/trigger/TriggerChangesZoneAll.java index b77f8cf9a07..e69058c8f2f 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerChangesZoneAll.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerChangesZoneAll.java @@ -3,6 +3,8 @@ package forge.game.trigger; import java.util.List; import java.util.Map; +import com.google.common.collect.Iterables; + import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.card.Card; @@ -23,13 +25,21 @@ public class TriggerChangesZoneAll extends Trigger { public boolean performTest(Map runParams) { final CardZoneTable table = (CardZoneTable) runParams.get(AbilityKey.Cards); + // leaves the GY trigger look back in time + if (Iterables.contains(getActiveZone(), ZoneType.Battlefield) && "Graveyard".equals(getParam("Origin")) + && !table.getLastStateBattlefield().contains(getHostCard())) { + return false; + } + if (!matchesValidParam("ValidCause", runParams.get(AbilityKey.Cause))) { return false; } if (hasParam("ValidAmount")) { int right = AbilityUtils.calculateAmount(hostCard, getParam("ValidAmount").substring(2), this); - if (!Expressions.compare(this.filterCards(table).size(), getParam("ValidAmount").substring(0, 2), right)) { return false; } + if (!Expressions.compare(this.filterCards(table).size(), getParam("ValidAmount").substring(0, 2), right)) { + return false; + } } return !filterCards(table).isEmpty(); diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java index 11f16129484..0cac96efda1 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -739,10 +739,8 @@ public class MagicStack /* extends MyObservable */ implements Iterable sortAndCreateList(List> cardScores) { // even if some cards might be assigned the same rank we don't need randomization here // as the limited variant is responsible for that during generation - Collections.sort(cardScores, Collections.reverseOrder(new CardRankingComparator())); + cardScores.sort(Collections.reverseOrder(new CardRankingComparator())); List rankedCards = new ArrayList<>(cardScores.size()); for (Pair pair : cardScores) {