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