mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Merge branch '2053-ltb-trigger-might-be-stopped-by-own-die-replacementeffect' into 'master'
Resolve "LTB Trigger might be stopped by own Die ReplacementEffect" Closes #2053 See merge request core-developers/forge!6298
This commit is contained in:
@@ -1250,7 +1250,7 @@ public abstract class GameState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cardsWithoutETBTrigs.contains(c)) {
|
if (cardsWithoutETBTrigs.contains(c)) {
|
||||||
p.getGame().getAction().moveTo(ZoneType.Battlefield, c, null);
|
p.getGame().getAction().moveTo(ZoneType.Battlefield, c, null, null);
|
||||||
} else {
|
} else {
|
||||||
p.getZone(ZoneType.Hand).add(c);
|
p.getZone(ZoneType.Hand).add(c);
|
||||||
p.getGame().getAction().moveToPlay(c, null, null);
|
p.getGame().getAction().moveToPlay(c, null, null);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import forge.util.*;
|
import forge.util.*;
|
||||||
|
|
||||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
@@ -202,6 +203,16 @@ public class GameAction {
|
|||||||
lastKnownInfo = (Card) cause.getReplacingObject(AbilityKey.CardLKI);
|
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()) {
|
if (c.isSplitCard()) {
|
||||||
boolean resetToOriginal = false;
|
boolean resetToOriginal = false;
|
||||||
@@ -254,7 +265,6 @@ public class GameAction {
|
|||||||
// if from Battlefield to Graveyard and Card does exist in LastStateBattlefield
|
// if from Battlefield to Graveyard and Card does exist in LastStateBattlefield
|
||||||
// use that instead
|
// use that instead
|
||||||
if (fromBattlefield) {
|
if (fromBattlefield) {
|
||||||
CardCollectionView lastBattlefield = game.getLastStateBattlefield();
|
|
||||||
int idx = lastBattlefield.indexOf(c);
|
int idx = lastBattlefield.indexOf(c);
|
||||||
if (idx != -1) {
|
if (idx != -1) {
|
||||||
lastKnownInfo = lastBattlefield.get(idx);
|
lastKnownInfo = lastBattlefield.get(idx);
|
||||||
@@ -577,7 +587,10 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
game.getTriggerHandler().clearActiveTriggers(copied, null);
|
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);
|
game.getTriggerHandler().registerActiveTrigger(copied, false);
|
||||||
|
|
||||||
table.replaceCounterEffect(game, null, true);
|
table.replaceCounterEffect(game, null, true);
|
||||||
@@ -705,7 +718,7 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final Card moveTo(final Zone zoneTo, Card c, SpellAbility cause) {
|
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<AbilityKey, Object> params) {
|
public final Card moveTo(final Zone zoneTo, Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
|
||||||
// FThreads.assertExecutedByEdt(false); // This code must never be executed from EDT,
|
// 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);
|
return moveTo(zoneTo, c, null, cause, params);
|
||||||
}
|
}
|
||||||
public final Card moveTo(final Zone zoneTo, Card c, Integer position, SpellAbility cause) {
|
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) {
|
public final Card moveTo(final ZoneType name, final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
|
||||||
return moveTo(name, c, 0, cause);
|
return moveTo(name, c, 0, cause, params);
|
||||||
}
|
}
|
||||||
public final Card moveTo(final ZoneType name, final Card c, final int libPosition, SpellAbility cause) {
|
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<AbilityKey, Object> params) {
|
public final Card moveTo(final ZoneType name, final Card c, final int libPosition, SpellAbility cause, Map<AbilityKey, Object> params) {
|
||||||
// Call specific functions to set PlayerZone, then move onto moveTo
|
// Call specific functions to set PlayerZone, then move onto moveTo
|
||||||
@@ -786,7 +799,7 @@ public class GameAction {
|
|||||||
if (maingameCard.getZone().is(ZoneType.Stack)) {
|
if (maingameCard.getZone().is(ZoneType.Stack)) {
|
||||||
game.getMaingame().getStack().remove(maingameCard);
|
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) {
|
public final Card moveToStack(final Card c, SpellAbility cause) {
|
||||||
return moveToStack(c, cause, null);
|
Map<AbilityKey, Object> 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<AbilityKey, Object> params) {
|
public final Card moveToStack(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
|
||||||
Card result = moveTo(game.getStackZone(), c, cause, 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) {
|
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<AbilityKey, Object> params) {
|
public final Card moveToGraveyard(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
|
||||||
final PlayerZone grave = c.getOwner().getZone(ZoneType.Graveyard);
|
final PlayerZone grave = c.getOwner().getZone(ZoneType.Graveyard);
|
||||||
@@ -842,7 +858,7 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final Card moveToHand(final Card c, SpellAbility cause) {
|
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<AbilityKey, Object> params) {
|
public final Card moveToHand(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
|
||||||
final PlayerZone hand = c.getOwner().getZone(ZoneType.Hand);
|
final PlayerZone hand = c.getOwner().getZone(ZoneType.Hand);
|
||||||
@@ -859,14 +875,14 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final Card moveToBottomOfLibrary(final Card c, SpellAbility cause) {
|
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<AbilityKey, Object> params) {
|
public final Card moveToBottomOfLibrary(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
|
||||||
return moveToLibrary(c, -1, cause, params);
|
return moveToLibrary(c, -1, cause, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Card moveToLibrary(final Card c, SpellAbility cause) {
|
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<AbilityKey, Object> params) {
|
public final Card moveToLibrary(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
|
||||||
return moveToLibrary(c, 0, cause, 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
|
// do this multiple times, sometimes creatures/permanents will survive when they shouldn't
|
||||||
boolean orderedDesCreats = false;
|
boolean orderedDesCreats = false;
|
||||||
boolean orderedNoRegCreats = false;
|
boolean orderedNoRegCreats = false;
|
||||||
|
boolean orderedSacrificeList = false;
|
||||||
CardCollection cardsToUpdateLKI = new CardCollection();
|
CardCollection cardsToUpdateLKI = new CardCollection();
|
||||||
|
|
||||||
|
Map<AbilityKey, Object> mapParams = AbilityKey.newMap();
|
||||||
|
mapParams.put(AbilityKey.LastStateBattlefield, game.getLastStateBattlefield());
|
||||||
|
mapParams.put(AbilityKey.LastStateGraveyard, game.getLastStateGraveyard());
|
||||||
for (int q = 0; q < 9; q++) {
|
for (int q = 0; q < 9; q++) {
|
||||||
checkStaticAbilities(false, affectedCards, CardCollection.EMPTY);
|
checkStaticAbilities(false, affectedCards, CardCollection.EMPTY);
|
||||||
boolean checkAgain = false;
|
boolean checkAgain = false;
|
||||||
@@ -1253,16 +1274,14 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CardCollection noRegCreats = null;
|
CardCollection noRegCreats = new CardCollection();
|
||||||
CardCollection desCreats = null;
|
CardCollection desCreats = null;
|
||||||
CardCollection unAttachList = new CardCollection();
|
CardCollection unAttachList = new CardCollection();
|
||||||
|
CardCollection sacrificeList = new CardCollection();
|
||||||
for (final Card c : game.getCardsIn(ZoneType.Battlefield)) {
|
for (final Card c : game.getCardsIn(ZoneType.Battlefield)) {
|
||||||
if (c.isCreature()) {
|
if (c.isCreature()) {
|
||||||
// Rule 704.5f - Put into grave (no regeneration) for toughness <= 0
|
// Rule 704.5f - Put into grave (no regeneration) for toughness <= 0
|
||||||
if (c.getNetToughness() <= 0) {
|
if (c.getNetToughness() <= 0) {
|
||||||
if (noRegCreats == null) {
|
|
||||||
noRegCreats = new CardCollection();
|
|
||||||
}
|
|
||||||
noRegCreats.add(c);
|
noRegCreats.add(c);
|
||||||
checkAgain = true;
|
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.")) {
|
} 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_attach(c, unAttachList); // Attachment
|
||||||
|
|
||||||
checkAgain |= stateBasedAction704_5r(c); // annihilate +1/+1 counters with -1/-1 ones
|
checkAgain |= stateBasedAction704_5r(c); // annihilate +1/+1 counters with -1/-1 ones
|
||||||
@@ -1336,9 +1355,6 @@ public class GameAction {
|
|||||||
|
|
||||||
// cleanup aura
|
// cleanup aura
|
||||||
if (c.isAura() && c.isInPlay() && !c.isEnchanting()) {
|
if (c.isAura() && c.isInPlay() && !c.isEnchanting()) {
|
||||||
if (noRegCreats == null) {
|
|
||||||
noRegCreats = new CardCollection();
|
|
||||||
}
|
|
||||||
noRegCreats.add(c);
|
noRegCreats.add(c);
|
||||||
checkAgain = true;
|
checkAgain = true;
|
||||||
}
|
}
|
||||||
@@ -1351,28 +1367,46 @@ public class GameAction {
|
|||||||
|
|
||||||
// cleanup aura
|
// cleanup aura
|
||||||
if (u.isAura() && u.isInPlay() && !u.isEnchanting()) {
|
if (u.isAura() && u.isInPlay() && !u.isEnchanting()) {
|
||||||
if (noRegCreats == null) {
|
|
||||||
noRegCreats = new CardCollection();
|
|
||||||
}
|
|
||||||
noRegCreats.add(u);
|
noRegCreats.add(u);
|
||||||
checkAgain = true;
|
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
|
// 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)
|
// (e.g. helpful for Erebos's Titan and another creature dealing lethal damage to each other simultaneously)
|
||||||
setHoldCheckingStaticAbilities(true);
|
setHoldCheckingStaticAbilities(true);
|
||||||
|
|
||||||
if (noRegCreats != null) {
|
if (noRegCreats.size() > 1 && !orderedNoRegCreats) {
|
||||||
if (noRegCreats.size() > 1 && !orderedNoRegCreats) {
|
noRegCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, noRegCreats, ZoneType.Graveyard, null);
|
||||||
noRegCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, noRegCreats, ZoneType.Graveyard, null);
|
orderedNoRegCreats = true;
|
||||||
orderedNoRegCreats = true;
|
|
||||||
}
|
|
||||||
for (Card c : noRegCreats) {
|
|
||||||
c.updateWasDestroyed(true);
|
|
||||||
sacrificeDestroy(c, null, table, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
for (Card c : noRegCreats) {
|
||||||
|
c.updateWasDestroyed(true);
|
||||||
|
sacrificeDestroy(c, null, table, mapParams);
|
||||||
|
}
|
||||||
|
|
||||||
if (desCreats != null) {
|
if (desCreats != null) {
|
||||||
if (desCreats.size() > 1 && !orderedDesCreats) {
|
if (desCreats.size() > 1 && !orderedDesCreats) {
|
||||||
desCreats = CardLists.filter(desCreats, CardPredicates.Presets.CAN_BE_DESTROYED);
|
desCreats = CardLists.filter(desCreats, CardPredicates.Presets.CAN_BE_DESTROYED);
|
||||||
@@ -1382,39 +1416,24 @@ public class GameAction {
|
|||||||
orderedDesCreats = true;
|
orderedDesCreats = true;
|
||||||
}
|
}
|
||||||
for (Card c : desCreats) {
|
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);
|
setHoldCheckingStaticAbilities(false);
|
||||||
|
|
||||||
if (game.getTriggerHandler().runWaitingTriggers()) {
|
if (game.getTriggerHandler().runWaitingTriggers()) {
|
||||||
checkAgain = true;
|
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<Card> 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) {
|
if (game.getCombat() != null) {
|
||||||
game.getCombat().removeAbsentCombatants();
|
game.getCombat().removeAbsentCombatants();
|
||||||
@@ -1459,7 +1478,7 @@ public class GameAction {
|
|||||||
game.runSBACheckedCommands();
|
game.runSBACheckedCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean stateBasedAction_Saga(Card c, CardZoneTable table) {
|
private boolean stateBasedAction_Saga(Card c, CardCollection sacrificeList) {
|
||||||
boolean checkAgain = false;
|
boolean checkAgain = false;
|
||||||
if (!c.getType().hasSubtype("Saga")) {
|
if (!c.getType().hasSubtype("Saga")) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1472,7 +1491,7 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
if (!game.getStack().hasSourceOnStack(c, SpellAbilityPredicates.isChapter())) {
|
if (!game.getStack().hasSourceOnStack(c, SpellAbilityPredicates.isChapter())) {
|
||||||
// needs to be effect, because otherwise it might be a cost?
|
// needs to be effect, because otherwise it might be a cost?
|
||||||
sacrifice(c, null, true, table, null);
|
sacrificeList.add(c);
|
||||||
checkAgain = true;
|
checkAgain = true;
|
||||||
}
|
}
|
||||||
return checkAgain;
|
return checkAgain;
|
||||||
@@ -1653,57 +1672,28 @@ public class GameAction {
|
|||||||
game.getStack().clearSimultaneousStack();
|
game.getStack().clearSimultaneousStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handlePlaneswalkerRule(Player p, CardZoneTable table) {
|
private boolean handlePlaneswalkerRule(Player p, CardCollection noRegCreats) {
|
||||||
// get all Planeswalkers
|
// get all Planeswalkers
|
||||||
final List<Card> list = p.getPlaneswalkersInPlay();
|
final List<Card> list = p.getPlaneswalkersInPlay();
|
||||||
boolean recheck = false;
|
boolean recheck = false;
|
||||||
|
|
||||||
//final Multimap<String, Card> uniqueWalkers = ArrayListMultimap.create(); // Not used as of Ixalan
|
|
||||||
|
|
||||||
for (Card c : list) {
|
for (Card c : list) {
|
||||||
if (c.getCounters(CounterEnumType.LOYALTY) <= 0) {
|
if (c.getCounters(CounterEnumType.LOYALTY) <= 0) {
|
||||||
//for animation
|
noRegCreats.add(c);
|
||||||
c.updateWasDestroyed(true);
|
|
||||||
sacrificeDestroy(c, null, table, null);
|
|
||||||
// Play the Destroy sound
|
|
||||||
game.fireEvent(new GameEventCardDestroyed());
|
|
||||||
recheck = true;
|
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<Card> 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;
|
return recheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleLegendRule(Player p, CardZoneTable table) {
|
private boolean handleLegendRule(Player p, CardCollection noRegCreats) {
|
||||||
final List<Card> a = CardLists.getType(p.getCardsIn(ZoneType.Battlefield), "Legendary");
|
final List<Card> a = CardLists.getType(p.getCardsIn(ZoneType.Battlefield), "Legendary");
|
||||||
if (a.isEmpty() || game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule)) {
|
if (a.isEmpty() || game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean recheck = false;
|
boolean recheck = false;
|
||||||
|
// TODO legend rule exception into static ability
|
||||||
List<Card> yamazaki = CardLists.getKeyword(a, "Legend rule doesn't apply to CARDNAME.");
|
List<Card> yamazaki = CardLists.getKeyword(a, "Legend rule doesn't apply to CARDNAME.");
|
||||||
a.removeAll(yamazaki);
|
a.removeAll(yamazaki);
|
||||||
|
|
||||||
@@ -1715,6 +1705,8 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO handle Spy Kit
|
||||||
|
|
||||||
for (String name : uniqueLegends.keySet()) {
|
for (String name : uniqueLegends.keySet()) {
|
||||||
Collection<Card> cc = uniqueLegends.get(name);
|
Collection<Card> cc = uniqueLegends.get(name);
|
||||||
if (cc.size() < 2) {
|
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),
|
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);
|
"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) {
|
cc.remove(toKeep);
|
||||||
if (c != toKeep) {
|
noRegCreats.addAll(cc);
|
||||||
//for animation
|
|
||||||
c.updateWasDestroyed(true);
|
|
||||||
sacrificeDestroy(c, null, table, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
game.fireEvent(new GameEventCardDestroyed());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return recheck;
|
return recheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleWorldRule(CardZoneTable table) {
|
private boolean handleWorldRule(CardCollection noRegCreats) {
|
||||||
final List<Card> worlds = CardLists.getType(game.getCardsIn(ZoneType.Battlefield), "World");
|
final List<Card> worlds = CardLists.getType(game.getCardsIn(ZoneType.Battlefield), "World");
|
||||||
if (worlds.size() <= 1) {
|
if (worlds.size() <= 1) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1762,12 +1748,7 @@ public class GameAction {
|
|||||||
worlds.removeAll(toKeep);
|
worlds.removeAll(toKeep);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Card c : worlds) {
|
noRegCreats.addAll(worlds);
|
||||||
//for animation
|
|
||||||
c.updateWasDestroyed(true);
|
|
||||||
sacrificeDestroy(c, null, table, null);
|
|
||||||
game.fireEvent(new GameEventCardDestroyed());
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -691,7 +691,7 @@ public final class GameActionUtil {
|
|||||||
|
|
||||||
// TODO: Add targeting to the effect so it knows who it's dealing with
|
// TODO: Add targeting to the effect so it knows who it's dealing with
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
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);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
|
|
||||||
return eff;
|
return eff;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import forge.deck.CardPool;
|
|||||||
import forge.deck.Deck;
|
import forge.deck.Deck;
|
||||||
import forge.deck.DeckFormat;
|
import forge.deck.DeckFormat;
|
||||||
import forge.deck.DeckSection;
|
import forge.deck.DeckSection;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
import forge.game.event.Event;
|
import forge.game.event.Event;
|
||||||
@@ -80,7 +81,7 @@ public class Match {
|
|||||||
Multimap<Player, Card> list = game.chooseCardsForAnte(rules.getMatchAnteRarity());
|
Multimap<Player, Card> list = game.chooseCardsForAnte(rules.getMatchAnteRarity());
|
||||||
for (Entry<Player, Card> kv : list.entries()) {
|
for (Entry<Player, Card> kv : list.entries()) {
|
||||||
Player p = kv.getKey();
|
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.getGameLog().add(GameLogEntryType.ANTE, p + " anted " + kv.getValue());
|
||||||
}
|
}
|
||||||
game.fireEvent(new GameEventAnteCardsSelected(list));
|
game.fireEvent(new GameEventAnteCardsSelected(list));
|
||||||
@@ -303,7 +304,7 @@ public class Match {
|
|||||||
// Create an effect that lets you cast your companion from your sideboard
|
// Create an effect that lets you cast your companion from your sideboard
|
||||||
if (companion != null) {
|
if (companion != null) {
|
||||||
PlayerZone commandZone = player.getZone(ZoneType.Command);
|
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));
|
commandZone.add(Player.createCompanionEffect(game, companion));
|
||||||
|
|
||||||
player.updateZoneForView(commandZone);
|
player.updateZoneForView(commandZone);
|
||||||
|
|||||||
@@ -435,7 +435,7 @@ public abstract class SpellAbilityEffect {
|
|||||||
|
|
||||||
// TODO: Add targeting to the effect so it knows who it's dealing with
|
// TODO: Add targeting to the effect so it knows who it's dealing with
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
game.getAction().moveTo(ZoneType.Command, eff, sa, null);
|
||||||
eff.updateStateForView();
|
eff.updateStateForView();
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
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
|
// TODO: Add targeting to the effect so it knows who it's dealing with
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
game.getAction().moveTo(ZoneType.Command, eff, sa, null);
|
||||||
eff.updateStateForView();
|
eff.updateStateForView();
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
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<Player, CardCollectionView> discardedMap) {
|
protected static void discard(SpellAbility sa, CardZoneTable table, final boolean effect, Map<Player, CardCollectionView> discardedMap, Map<AbilityKey, Object> params) {
|
||||||
Set<Player> discarders = discardedMap.keySet();
|
Set<Player> discarders = discardedMap.keySet();
|
||||||
for (Player p : discarders) {
|
for (Player p : discarders) {
|
||||||
final CardCollection discardedByPlayer = new CardCollection();
|
final CardCollection discardedByPlayer = new CardCollection();
|
||||||
for (Card card : Lists.newArrayList(discardedMap.get(p))) { // without copying will get concurrent modification exception
|
for (Card card : Lists.newArrayList(discardedMap.get(p))) { // without copying will get concurrent modification exception
|
||||||
if (card == null) { continue; }
|
if (card == null) { continue; }
|
||||||
if (p.discard(card, sa, effect, table) != null) {
|
if (p.discard(card, sa, effect, table, params) != null) {
|
||||||
discardedByPlayer.add(card);
|
discardedByPlayer.add(card);
|
||||||
|
|
||||||
if (sa.hasParam("RememberDiscarded")) {
|
if (sa.hasParam("RememberDiscarded")) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -84,7 +85,7 @@ public class AddTurnEffect extends SpellAbilityEffect {
|
|||||||
eff.addStaticAbility(stEffect);
|
eff.addStaticAbility(stEffect);
|
||||||
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap());
|
||||||
eff.updateStateForView();
|
eff.updateStateForView();
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ public class BalanceEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<AbilityKey, Object> params = AbilityKey.newMap();
|
Map<AbilityKey, Object> params = AbilityKey.newMap();
|
||||||
|
params.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
params.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
CardZoneTable table = new CardZoneTable();
|
CardZoneTable table = new CardZoneTable();
|
||||||
for (int i = 0; i < players.size(); i++) {
|
for (int i = 0; i < players.size(); i++) {
|
||||||
Player p = players.get(i);
|
Player p = players.get(i);
|
||||||
@@ -67,7 +69,7 @@ public class BalanceEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (zone.equals(ZoneType.Hand)) {
|
if (zone.equals(ZoneType.Hand)) {
|
||||||
discard(sa, table, true, discardedMap);
|
discard(sa, table, true, discardedMap, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
table.triggerChangesZoneAll(game, sa);
|
table.triggerChangesZoneAll(game, sa);
|
||||||
|
|||||||
@@ -620,7 +620,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<AbilityKey, Object> moveParams = Maps.newEnumMap(AbilityKey.class);
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield);
|
moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield);
|
||||||
moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard);
|
moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard);
|
||||||
if (sa.isReplacementAbility()) {
|
if (sa.isReplacementAbility()) {
|
||||||
@@ -699,7 +699,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
gameCard.setExiledWith(host);
|
gameCard.setExiledWith(host);
|
||||||
gameCard.setExiledBy(host.getController());
|
gameCard.setExiledBy(host.getController());
|
||||||
}
|
}
|
||||||
movedCard = game.getAction().moveTo(destination, gameCard, sa);
|
Map<AbilityKey, Object> 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())) {
|
if (ZoneType.Hand.equals(destination) && ZoneType.Command.equals(originZone.getZoneType())) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(movedCard.getName()).append(" has moved from Command Zone to ").append(player).append("'s hand.");
|
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) {
|
for (final Card c : chosenCards) {
|
||||||
Card movedCard = null;
|
Card movedCard = null;
|
||||||
final Zone originZone = game.getZoneOf(c);
|
final Zone originZone = game.getZoneOf(c);
|
||||||
Map<AbilityKey, Object> moveParams = Maps.newEnumMap(AbilityKey.class);
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
moveParams.put(AbilityKey.FoundSearchingLibrary, searchedLibrary);
|
moveParams.put(AbilityKey.FoundSearchingLibrary, searchedLibrary);
|
||||||
moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield);
|
moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield);
|
||||||
moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard);
|
moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import forge.GameCommand;
|
|||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameObject;
|
import forge.game.GameObject;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -65,7 +66,7 @@ public abstract class DamagePreventEffectBase extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap());
|
||||||
eff.updateStateForView();
|
eff.updateStateForView();
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.google.common.collect.Maps;
|
|||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameActionUtil;
|
import forge.game.GameActionUtil;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -287,7 +288,11 @@ public class DiscardEffect extends SpellAbilityEffect {
|
|||||||
discardedMap.put(p, toBeDiscarded);
|
discardedMap.put(p, toBeDiscarded);
|
||||||
}
|
}
|
||||||
|
|
||||||
discard(sa, table, true, discardedMap);
|
Map<AbilityKey, Object> 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
|
// run trigger if something got milled
|
||||||
table.triggerChangesZoneAll(game, sa);
|
table.triggerChangesZoneAll(game, sa);
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -52,6 +54,9 @@ public class DrawEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
final boolean upto = sa.hasParam("Upto");
|
final boolean upto = sa.hasParam("Upto");
|
||||||
final boolean optional = sa.hasParam("OptionalDecider") || upto;
|
final boolean optional = sa.hasParam("OptionalDecider") || upto;
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
|
|
||||||
for (final Player p : getDefinedPlayersOrTargeted(sa)) {
|
for (final Player p : getDefinedPlayersOrTargeted(sa)) {
|
||||||
// TODO can this be removed?
|
// TODO can this be removed?
|
||||||
@@ -80,7 +85,7 @@ public class DrawEffect extends SpellAbilityEffect {
|
|||||||
actualNum = p.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblHowManyCardDoYouWantDraw"), 0, actualNum);
|
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.hasParam("Reveal")) {
|
||||||
if (sa.getParam("Reveal").equals("All")) {
|
if (sa.getParam("Reveal").equals("All")) {
|
||||||
p.getGame().getAction().reveal(drawn, p, false);
|
p.getGame().getAction().reveal(drawn, p, false);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package forge.game.ability.effects;
|
|||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
@@ -12,6 +13,7 @@ import forge.card.CardRarity;
|
|||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameObject;
|
import forge.game.GameObject;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -136,6 +138,10 @@ public class EffectEffect extends SpellAbilityEffect {
|
|||||||
image = hostCard.getImageKey();
|
image = hostCard.getImageKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<AbilityKey, Object> params = AbilityKey.newMap();
|
||||||
|
params.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
params.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
|
|
||||||
for (Player controller : effectOwner) {
|
for (Player controller : effectOwner) {
|
||||||
final Card eff = createEffect(sa, controller, name, image);
|
final Card eff = createEffect(sa, controller, name, image);
|
||||||
eff.setSetCode(sa.getHostCard().getSetCode());
|
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
|
// TODO: Add targeting to the effect so it knows who it's dealing with
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
game.getAction().moveTo(ZoneType.Command, eff, sa, params);
|
||||||
eff.updateStateForView();
|
eff.updateStateForView();
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
//if (effectTriggers != null) {
|
//if (effectTriggers != null) {
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameLogEntryType;
|
import forge.game.GameLogEntryType;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
@@ -49,8 +52,12 @@ public class EncodeEffect extends SpellAbilityEffect {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
|
|
||||||
// move host card to exile
|
// 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
|
// choose a creature
|
||||||
Card choice = player.getController().chooseSingleEntityForEffect(choices, sa, Localizer.getInstance().getMessage("lblChooseACreatureYouControlToEncode") + " ", true, null);
|
Card choice = player.getController().chooseSingleEntityForEffect(choices, sa, Localizer.getInstance().getMessage("lblChooseACreatureYouControlToEncode") + " ", true, null);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
@@ -48,6 +49,9 @@ public class ExploreEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
GameEntityCounterTable table = new GameEntityCounterTable();
|
GameEntityCounterTable table = new GameEntityCounterTable();
|
||||||
final CardZoneTable triggerList = new CardZoneTable();
|
final CardZoneTable triggerList = new CardZoneTable();
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
for (final Card c : getTargetCards(sa)) {
|
for (final Card c : getTargetCards(sa)) {
|
||||||
// revealed land card
|
// revealed land card
|
||||||
boolean revealedLand = false;
|
boolean revealedLand = false;
|
||||||
@@ -59,7 +63,7 @@ public class ExploreEffect extends SpellAbilityEffect {
|
|||||||
final Card r = top.getFirst();
|
final Card r = top.getFirst();
|
||||||
final Zone originZone = game.getZoneOf(r);
|
final Zone originZone = game.getZoneOf(r);
|
||||||
if (r.isLand()) {
|
if (r.isLand()) {
|
||||||
movedCard = game.getAction().moveTo(ZoneType.Hand, r, sa);
|
movedCard = game.getAction().moveTo(ZoneType.Hand, r, sa, moveParams);
|
||||||
revealedLand = true;
|
revealedLand = true;
|
||||||
} else {
|
} else {
|
||||||
// TODO find better way to choose optional send away
|
// 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,
|
ZoneType.Graveyard, Lists.newArrayList(ZoneType.Library), sa, top, null,
|
||||||
Localizer.getInstance().getMessage("lblPutThisCardToYourGraveyard"), true, pl);
|
Localizer.getInstance().getMessage("lblPutThisCardToYourGraveyard"), true, pl);
|
||||||
if (choosen != null) {
|
if (choosen != null) {
|
||||||
movedCard = game.getAction().moveTo(ZoneType.Graveyard, choosen, sa);
|
movedCard = game.getAction().moveTo(ZoneType.Graveyard, choosen, sa, moveParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package forge.game.ability.effects;
|
|||||||
|
|
||||||
import forge.GameCommand;
|
import forge.GameCommand;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.replacement.ReplacementEffect;
|
import forge.game.replacement.ReplacementEffect;
|
||||||
@@ -32,7 +33,7 @@ public class FogEffect extends SpellAbilityEffect {
|
|||||||
eff.addReplacementEffect(re);
|
eff.addReplacementEffect(re);
|
||||||
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap());
|
||||||
eff.updateStateForView();
|
eff.updateStateForView();
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardZoneTable;
|
import forge.game.card.CardZoneTable;
|
||||||
@@ -18,8 +21,11 @@ public class LearnEffect extends SpellAbilityEffect {
|
|||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
final Game game = source.getGame();
|
final Game game = source.getGame();
|
||||||
CardZoneTable table = new CardZoneTable();
|
CardZoneTable table = new CardZoneTable();
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
for (Player p : getTargetPlayers(sa)) {
|
for (Player p : getTargetPlayers(sa)) {
|
||||||
p.learnLesson(sa, table);
|
p.learnLesson(sa, table, moveParams);
|
||||||
}
|
}
|
||||||
table.triggerChangesZoneAll(game, sa);
|
table.triggerChangesZoneAll(game, sa);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import forge.StaticData;
|
import forge.StaticData;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -13,6 +16,9 @@ import forge.game.zone.ZoneType;
|
|||||||
public class MakeCardEffect extends SpellAbilityEffect {
|
public class MakeCardEffect extends SpellAbilityEffect {
|
||||||
@Override
|
@Override
|
||||||
public void resolve(SpellAbility sa) {
|
public void resolve(SpellAbility sa) {
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
for (final Player player : getTargetPlayers(sa)) {
|
for (final Player player : getTargetPlayers(sa)) {
|
||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
final Game game = player.getGame();
|
final Game game = player.getGame();
|
||||||
@@ -43,13 +49,13 @@ public class MakeCardEffect extends SpellAbilityEffect {
|
|||||||
if (!sa.hasParam("NotToken")) {
|
if (!sa.hasParam("NotToken")) {
|
||||||
card.setTokenCard(true);
|
card.setTokenCard(true);
|
||||||
}
|
}
|
||||||
game.getAction().moveTo(ZoneType.None, card, sa);
|
game.getAction().moveTo(ZoneType.None, card, sa, moveParams);
|
||||||
cards.add(card);
|
cards.add(card);
|
||||||
amount--;
|
amount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final Card c : cards) {
|
for (final Card c : cards) {
|
||||||
game.getAction().moveTo(zone, c, sa);
|
game.getAction().moveTo(zone, c, sa, moveParams);
|
||||||
if (sa.hasParam("RememberMade")) {
|
if (sa.hasParam("RememberMade")) {
|
||||||
sa.getHostCard().addRemembered(c);
|
sa.getHostCard().addRemembered(c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameLogEntryType;
|
import forge.game.GameLogEntryType;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -35,6 +38,9 @@ public class MillEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final CardZoneTable table = new CardZoneTable();
|
final CardZoneTable table = new CardZoneTable();
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
|
|
||||||
for (final Player p : getTargetPlayers(sa)) {
|
for (final Player p : getTargetPlayers(sa)) {
|
||||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||||
@@ -45,7 +51,7 @@ public class MillEffect extends SpellAbilityEffect {
|
|||||||
continue;
|
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
|
// Reveal the milled cards, so players don't have to manually inspect the
|
||||||
// graveyard to figure out which ones were milled.
|
// graveyard to figure out which ones were milled.
|
||||||
if (!facedown && reveal) { // do not reveal when exiling face down
|
if (!facedown && reveal) { // do not reveal when exiling face down
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ public class PlaneswalkEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
if (sa.hasParam("Defined")) {
|
if (sa.hasParam("Defined")) {
|
||||||
CardCollectionView destinations = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa);
|
CardCollectionView destinations = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa);
|
||||||
sa.getActivatingPlayer().planeswalkTo(destinations);
|
sa.getActivatingPlayer().planeswalkTo(sa, destinations);
|
||||||
} else {
|
} else {
|
||||||
sa.getActivatingPlayer().planeswalk();
|
sa.getActivatingPlayer().planeswalk(sa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import forge.StaticData;
|
|||||||
import forge.card.CardRulesPredicates;
|
import forge.card.CardRulesPredicates;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -216,6 +217,11 @@ public class PlayEffect extends SpellAbilityEffect {
|
|||||||
boolean singleOption = tgtCards.size() == 1 && amount == 1 && optional;
|
boolean singleOption = tgtCards.size() == 1 && amount == 1 && optional;
|
||||||
Map<String, Object> params = hasTotalCMCLimit ? new HashMap<>() : null;
|
Map<String, Object> params = hasTotalCMCLimit ? new HashMap<>() : null;
|
||||||
|
|
||||||
|
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
|
|
||||||
while (!tgtCards.isEmpty() && amount > 0 && totalCMCLimit >= 0) {
|
while (!tgtCards.isEmpty() && amount > 0 && totalCMCLimit >= 0) {
|
||||||
if (hasTotalCMCLimit) {
|
if (hasTotalCMCLimit) {
|
||||||
// filter out cards with mana value greater than limit
|
// filter out cards with mana value greater than limit
|
||||||
@@ -376,12 +382,12 @@ public class PlayEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
// can't be done later
|
// can't be done later
|
||||||
if (sa.hasParam("ReplaceGraveyard")) {
|
if (sa.hasParam("ReplaceGraveyard")) {
|
||||||
addReplaceGraveyardEffect(tgtCard, sa, sa.getParam("ReplaceGraveyard"));
|
addReplaceGraveyardEffect(tgtCard, sa, sa.getParam("ReplaceGraveyard"), moveParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Illusionary Mask effect
|
// For Illusionary Mask effect
|
||||||
if (sa.hasParam("ReplaceIlluMask")) {
|
if (sa.hasParam("ReplaceIlluMask")) {
|
||||||
addIllusionaryMaskReplace(tgtCard, sa);
|
addIllusionaryMaskReplace(tgtCard, sa, moveParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
tgtSA.setSVar("IsCastFromPlayEffect", "True");
|
tgtSA.setSVar("IsCastFromPlayEffect", "True");
|
||||||
@@ -420,7 +426,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
|||||||
} // end resolve
|
} // end resolve
|
||||||
|
|
||||||
|
|
||||||
protected void addReplaceGraveyardEffect(Card c, SpellAbility sa, String zone) {
|
protected void addReplaceGraveyardEffect(Card c, SpellAbility sa, String zone, Map<AbilityKey, Object> moveParams) {
|
||||||
final Card hostCard = sa.getHostCard();
|
final Card hostCard = sa.getHostCard();
|
||||||
final Game game = hostCard.getGame();
|
final Game game = hostCard.getGame();
|
||||||
final Player controller = sa.getActivatingPlayer();
|
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
|
// TODO: Add targeting to the effect so it knows who it's dealing with
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
game.getAction().moveTo(ZoneType.Command, eff, sa, moveParams);
|
||||||
eff.updateStateForView();
|
eff.updateStateForView();
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addIllusionaryMaskReplace(Card c, SpellAbility sa) {
|
protected void addIllusionaryMaskReplace(Card c, SpellAbility sa, Map<AbilityKey, Object> moveParams) {
|
||||||
final Card hostCard = sa.getHostCard();
|
final Card hostCard = sa.getHostCard();
|
||||||
final Game game = hostCard.getGame();
|
final Game game = hostCard.getGame();
|
||||||
final Player controller = sa.getActivatingPlayer();
|
final Player controller = sa.getActivatingPlayer();
|
||||||
@@ -497,7 +503,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
|||||||
addExileOnCounteredTrigger(eff);
|
addExileOnCounteredTrigger(eff);
|
||||||
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
game.getAction().moveTo(ZoneType.Command, eff, sa, moveParams);
|
||||||
eff.updateStateForView();
|
eff.updateStateForView();
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package forge.game.ability.effects;
|
|||||||
import forge.GameCommand;
|
import forge.GameCommand;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -71,7 +72,7 @@ public abstract class RegenerateBaseEffect extends SpellAbilityEffect {
|
|||||||
c.addShield(eff);
|
c.addShield(eff);
|
||||||
}
|
}
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap());
|
||||||
eff.updateStateForView();
|
eff.updateStateForView();
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public class SetInMotionEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
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);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
|
|
||||||
// Run triggers
|
// Run triggers
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import java.util.List;
|
|||||||
import forge.GameCommand;
|
import forge.GameCommand;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -115,7 +116,7 @@ public class SkipPhaseEffect extends SpellAbilityEffect {
|
|||||||
eff.addReplacementEffect(re);
|
eff.addReplacementEffect(re);
|
||||||
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap());
|
||||||
eff.updateStateForView();
|
eff.updateStateForView();
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -61,7 +62,7 @@ public class SkipTurnEffect extends SpellAbilityEffect {
|
|||||||
eff.addReplacementEffect(re);
|
eff.addReplacementEffect(re);
|
||||||
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap());
|
||||||
eff.updateStateForView();
|
eff.updateStateForView();
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.google.common.collect.Lists;
|
|||||||
import forge.card.MagicColor;
|
import forge.card.MagicColor;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameOutcome;
|
import forge.game.GameOutcome;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.ApiType;
|
import forge.game.ability.ApiType;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
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
|
// Create an effect that lets you cast your companion from your sideboard
|
||||||
if (companion != null) {
|
if (companion != null) {
|
||||||
PlayerZone commandZone = player.getZone(ZoneType.Command);
|
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));
|
commandZone.add(Player.createCompanionEffect(subgame, companion));
|
||||||
|
|
||||||
player.updateZoneForView(commandZone);
|
player.updateZoneForView(commandZone);
|
||||||
@@ -242,7 +243,7 @@ public class SubgameEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (final Card card : movedCommanders) {
|
for (final Card card : movedCommanders) {
|
||||||
maingame.getAction().moveTo(ZoneType.Library, card, null);
|
maingame.getAction().moveTo(ZoneType.Library, card, null, AbilityKey.newMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
player.shuffle(sa);
|
player.shuffle(sa);
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.CardZoneTable;
|
import forge.game.card.CardZoneTable;
|
||||||
@@ -34,6 +37,9 @@ public class SurveilEffect extends SpellAbilityEffect {
|
|||||||
boolean isOptional = sa.hasParam("Optional");
|
boolean isOptional = sa.hasParam("Optional");
|
||||||
|
|
||||||
CardZoneTable table = new CardZoneTable();
|
CardZoneTable table = new CardZoneTable();
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
|
|
||||||
for (final Player p : getTargetPlayers(sa)) {
|
for (final Player p : getTargetPlayers(sa)) {
|
||||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||||
@@ -41,7 +47,7 @@ public class SurveilEffect extends SpellAbilityEffect {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.surveil(num, sa, table);
|
p.surveil(num, sa, table, moveParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
table.triggerChangesZoneAll(sa.getHostCard().getGame(), sa);
|
table.triggerChangesZoneAll(sa.getHostCard().getGame(), sa);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import forge.util.Localizer;
|
|||||||
|
|
||||||
public class VentureEffect extends SpellAbilityEffect {
|
public class VentureEffect extends SpellAbilityEffect {
|
||||||
|
|
||||||
private Card getDungeonCard(SpellAbility sa, Player player) {
|
private Card getDungeonCard(SpellAbility sa, Player player, Map<AbilityKey, Object> moveParams) {
|
||||||
final Game game = player.getGame();
|
final Game game = player.getGame();
|
||||||
|
|
||||||
CardCollectionView commandCards = player.getCardsIn(ZoneType.Command);
|
CardCollectionView commandCards = player.getCardsIn(ZoneType.Command);
|
||||||
@@ -50,7 +50,7 @@ public class VentureEffect extends SpellAbilityEffect {
|
|||||||
Card dungeon = player.getController().chooseDungeon(player, dungeonCards, message);
|
Card dungeon = player.getController().chooseDungeon(player, dungeonCards, message);
|
||||||
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
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);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
|
|
||||||
return dungeon;
|
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<AbilityKey, Object> moveParams) {
|
||||||
if (StaticAbilityCantVenture.cantVenture(player)) {
|
if (StaticAbilityCantVenture.cantVenture(player)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Game game = player.getGame();
|
final Game game = player.getGame();
|
||||||
Card dungeon = getDungeonCard(sa, player);
|
Card dungeon = getDungeonCard(sa, player, moveParams);
|
||||||
String room = dungeon.getCurrentRoom();
|
String room = dungeon.getCurrentRoom();
|
||||||
String nextRoom = null;
|
String nextRoom = null;
|
||||||
|
|
||||||
@@ -117,9 +117,13 @@ public class VentureEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolve(SpellAbility sa) {
|
public void resolve(SpellAbility sa) {
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
|
|
||||||
for (final Player p : getTargetPlayers(sa)) {
|
for (final Player p : getTargetPlayers(sa)) {
|
||||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||||
ventureIntoDungeon(sa, p);
|
ventureIntoDungeon(sa, p, moveParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -87,8 +90,11 @@ public class ZoneExchangeEffect extends SpellAbilityEffect {
|
|||||||
object1.unattachFromEntity(c);
|
object1.unattachFromEntity(c);
|
||||||
object2.attachToEntity(c);
|
object2.attachToEntity(c);
|
||||||
}
|
}
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
// Exchange Zone
|
// Exchange Zone
|
||||||
game.getAction().moveTo(zone2, object1, sa);
|
game.getAction().moveTo(zone2, object1, sa, moveParams);
|
||||||
game.getAction().moveTo(zone1, object2, sa);
|
game.getAction().moveTo(zone1, object2, sa, moveParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
package forge.game.cost;
|
package forge.game.cost;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.player.PlayerCollection;
|
import forge.game.player.PlayerCollection;
|
||||||
@@ -94,8 +97,11 @@ public class CostDraw extends CostPart {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final boolean payAsDecided(final Player ai, final PaymentDecision decision, SpellAbility ability, final boolean effect) {
|
public final boolean payAsDecided(final Player ai, final PaymentDecision decision, SpellAbility ability, final boolean effect) {
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, ability.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, ability.getLastStateGraveyard());
|
||||||
for (final Player p : decision.players) {
|
for (final Player p : decision.players) {
|
||||||
p.drawCards(decision.c, ability);
|
p.drawCards(decision.c, ability, moveParams);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
package forge.game.cost;
|
package forge.game.cost;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardZoneTable;
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -88,7 +91,10 @@ public class CostMill extends CostPart {
|
|||||||
@Override
|
@Override
|
||||||
public final boolean payAsDecided(final Player ai, final PaymentDecision decision, SpellAbility ability, final boolean effect) {
|
public final boolean payAsDecided(final Player ai, final PaymentDecision decision, SpellAbility ability, final boolean effect) {
|
||||||
CardZoneTable table = new CardZoneTable();
|
CardZoneTable table = new CardZoneTable();
|
||||||
ability.getPaidHash().put("Milled", (CardCollection) ai.mill(decision.c, ZoneType.Graveyard, false, ability, table));
|
Map<AbilityKey, Object> 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);
|
table.triggerChangesZoneAll(ai.getGame(), ability);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,11 @@ package forge.game.cost;
|
|||||||
|
|
||||||
import forge.card.CardType;
|
import forge.card.CardType;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
@@ -133,7 +136,10 @@ public class CostSacrifice extends CostPartWithList {
|
|||||||
@Override
|
@Override
|
||||||
protected Card doPayment(SpellAbility ability, Card targetCard, final boolean effect) {
|
protected Card doPayment(SpellAbility ability, Card targetCard, final boolean effect) {
|
||||||
// no table there, it is already handled by CostPartWithList
|
// no table there, it is already handled by CostPartWithList
|
||||||
return targetCard.getGame().getAction().sacrifice(targetCard, ability, effect, null, null);
|
Map<AbilityKey, Object> 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)
|
/* (non-Javadoc)
|
||||||
|
|||||||
@@ -393,11 +393,15 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
int numDiscard = playerTurn.isUnlimitedHandSize() || handSize <= max || handSize == 0 ? 0 : handSize - max;
|
int numDiscard = playerTurn.isUnlimitedHandSize() || handSize <= max || handSize == 0 ? 0 : handSize - max;
|
||||||
|
|
||||||
if (numDiscard > 0) {
|
if (numDiscard > 0) {
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, game.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, game.getLastStateGraveyard());
|
||||||
|
|
||||||
final CardZoneTable table = new CardZoneTable();
|
final CardZoneTable table = new CardZoneTable();
|
||||||
final CardCollection discarded = new CardCollection();
|
final CardCollection discarded = new CardCollection();
|
||||||
boolean firstDiscarded = playerTurn.getNumDiscardedThisTurn() == 0;
|
boolean firstDiscarded = playerTurn.getNumDiscardedThisTurn() == 0;
|
||||||
for (Card c : playerTurn.getController().chooseCardsToDiscardToMaximumHandSize(numDiscard)) {
|
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);
|
discarded.add(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -326,10 +326,14 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, game.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, game.getLastStateGraveyard());
|
||||||
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
activeScheme = getZone(ZoneType.SchemeDeck).get(0);
|
activeScheme = getZone(ZoneType.SchemeDeck).get(0);
|
||||||
// gameAction moveTo ?
|
// gameAction moveTo ?
|
||||||
game.getAction().moveTo(ZoneType.Command, activeScheme, null);
|
game.getAction().moveTo(ZoneType.Command, activeScheme, null, moveParams);
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
|
|
||||||
// Run triggers
|
// Run triggers
|
||||||
@@ -1101,10 +1105,13 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void surveil(int num, SpellAbility cause, CardZoneTable table) {
|
public void surveil(int num, SpellAbility cause, CardZoneTable table, Map<AbilityKey, Object> params) {
|
||||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||||
repParams.put(AbilityKey.Source, cause);
|
repParams.put(AbilityKey.Source, cause);
|
||||||
repParams.put(AbilityKey.SurveilNum, num);
|
repParams.put(AbilityKey.SurveilNum, num);
|
||||||
|
if (params != null) {
|
||||||
|
repParams.putAll(params);
|
||||||
|
}
|
||||||
|
|
||||||
switch (getGame().getReplacementHandler().run(ReplacementType.Surveil, repParams)) {
|
switch (getGame().getReplacementHandler().run(ReplacementType.Surveil, repParams)) {
|
||||||
case NotReplaced:
|
case NotReplaced:
|
||||||
@@ -1133,7 +1140,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
if (toGrave != null) {
|
if (toGrave != null) {
|
||||||
for (Card c : toGrave) {
|
for (Card c : toGrave) {
|
||||||
ZoneType oZone = c.getZone().getZoneType();
|
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);
|
table.put(oZone, moved.getZone().getZoneType(), moved);
|
||||||
numToGrave++;
|
numToGrave++;
|
||||||
}
|
}
|
||||||
@@ -1142,7 +1149,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
if (toTop != null) {
|
if (toTop != null) {
|
||||||
Collections.reverse(toTop); // the last card in list will become topmost in library, have to revert thus.
|
Collections.reverse(toTop); // the last card in list will become topmost in library, have to revert thus.
|
||||||
for (Card c : toTop) {
|
for (Card c : toTop) {
|
||||||
getGame().getAction().moveToLibrary(c, cause);
|
getGame().getAction().moveToLibrary(c, cause, params);
|
||||||
numToTop++;
|
numToTop++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1152,6 +1159,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
surveilThisTurn++;
|
surveilThisTurn++;
|
||||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this);
|
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this);
|
||||||
runParams.put(AbilityKey.NumThisTurn, surveilThisTurn);
|
runParams.put(AbilityKey.NumThisTurn, surveilThisTurn);
|
||||||
|
if (params != null) {
|
||||||
|
runParams.putAll(params);
|
||||||
|
}
|
||||||
getGame().getTriggerHandler().runTrigger(TriggerType.Surveil, runParams, false);
|
getGame().getTriggerHandler().runTrigger(TriggerType.Surveil, runParams, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1176,13 +1186,13 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final CardCollectionView drawCard() {
|
public final CardCollectionView drawCard() {
|
||||||
return drawCards(1, null);
|
return drawCards(1, null, AbilityKey.newMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
public final CardCollectionView drawCards(final int n) {
|
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<AbilityKey, Object> params) {
|
||||||
final CardCollection drawn = new CardCollection();
|
final CardCollection drawn = new CardCollection();
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return drawn;
|
return drawn;
|
||||||
@@ -1191,6 +1201,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
// Replacement effects
|
// Replacement effects
|
||||||
final Map<AbilityKey, Object> repRunParams = AbilityKey.mapFromAffected(this);
|
final Map<AbilityKey, Object> repRunParams = AbilityKey.mapFromAffected(this);
|
||||||
repRunParams.put(AbilityKey.Number, n);
|
repRunParams.put(AbilityKey.Number, n);
|
||||||
|
if (params != null) {
|
||||||
|
repRunParams.putAll(params);
|
||||||
|
}
|
||||||
|
|
||||||
if (game.getReplacementHandler().run(ReplacementType.DrawCards, repRunParams) != ReplacementResult.NotReplaced) {
|
if (game.getReplacementHandler().run(ReplacementType.DrawCards, repRunParams) != ReplacementResult.NotReplaced) {
|
||||||
return drawn;
|
return drawn;
|
||||||
@@ -1204,7 +1217,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
if (gameStarted && !canDraw()) {
|
if (gameStarted && !canDraw()) {
|
||||||
return drawn;
|
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
|
// reveal multiple drawn cards when playing with the top of the library revealed
|
||||||
@@ -1219,13 +1232,16 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
/**
|
/**
|
||||||
* @return a CardCollectionView of cards actually drawn
|
* @return a CardCollectionView of cards actually drawn
|
||||||
*/
|
*/
|
||||||
private CardCollectionView doDraw(Map<Player, CardCollection> revealed, SpellAbility cause) {
|
private CardCollectionView doDraw(Map<Player, CardCollection> revealed, SpellAbility cause, Map<AbilityKey, Object> params) {
|
||||||
final CardCollection drawn = new CardCollection();
|
final CardCollection drawn = new CardCollection();
|
||||||
final PlayerZone library = getZone(ZoneType.Library);
|
final PlayerZone library = getZone(ZoneType.Library);
|
||||||
|
|
||||||
// Replacement effects
|
// Replacement effects
|
||||||
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||||
repParams.put(AbilityKey.Cause, cause);
|
repParams.put(AbilityKey.Cause, cause);
|
||||||
|
if (params != null) {
|
||||||
|
repParams.putAll(params);
|
||||||
|
}
|
||||||
if (game.getReplacementHandler().run(ReplacementType.Draw, repParams) != ReplacementResult.NotReplaced) {
|
if (game.getReplacementHandler().run(ReplacementType.Draw, repParams) != ReplacementResult.NotReplaced) {
|
||||||
return drawn;
|
return drawn;
|
||||||
}
|
}
|
||||||
@@ -1246,7 +1262,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c = game.getAction().moveToHand(c, cause);
|
c = game.getAction().moveToHand(c, cause, params);
|
||||||
drawn.add(c);
|
drawn.add(c);
|
||||||
|
|
||||||
for (Player p : pList) {
|
for (Player p : pList) {
|
||||||
@@ -1267,6 +1283,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
view.updateNumDrawnThisTurn(this);
|
view.updateNumDrawnThisTurn(this);
|
||||||
|
|
||||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this);
|
final Map<AbilityKey, Object> 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
|
// 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()) {
|
if (game.getTopLibForPlayer(this) != null && getPaidForSA() != null && cause != null && getPaidForSA() != cause.getRootAbility()) {
|
||||||
@@ -1414,9 +1433,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
numRollsThisTurn++;
|
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<AbilityKey, Object> params) {
|
public final Card discard(final Card c, final SpellAbility sa, final boolean effect, CardZoneTable table, Map<AbilityKey, Object> params) {
|
||||||
if (!c.canBeDiscardedBy(sa, effect)) {
|
if (!c.canBeDiscardedBy(sa, effect)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -1575,13 +1591,16 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final CardCollectionView mill(int n, final ZoneType destination,
|
public final CardCollectionView mill(int n, final ZoneType destination,
|
||||||
final boolean bottom, SpellAbility sa, CardZoneTable table) {
|
final boolean bottom, SpellAbility sa, CardZoneTable table, Map<AbilityKey, Object> params) {
|
||||||
final CardCollectionView lib = getCardsIn(ZoneType.Library);
|
final CardCollectionView lib = getCardsIn(ZoneType.Library);
|
||||||
final CardCollection milled = new CardCollection();
|
final CardCollection milled = new CardCollection();
|
||||||
|
|
||||||
// Replacement effects
|
// Replacement effects
|
||||||
final Map<AbilityKey, Object> repRunParams = AbilityKey.mapFromAffected(this);
|
final Map<AbilityKey, Object> repRunParams = AbilityKey.mapFromAffected(this);
|
||||||
repRunParams.put(AbilityKey.Number, n);
|
repRunParams.put(AbilityKey.Number, n);
|
||||||
|
if (params != null) {
|
||||||
|
repRunParams.putAll(params);
|
||||||
|
}
|
||||||
|
|
||||||
if (destination == ZoneType.Graveyard && !bottom) {
|
if (destination == ZoneType.Graveyard && !bottom) {
|
||||||
switch (getGame().getReplacementHandler().run(ReplacementType.Mill, repRunParams)) {
|
switch (getGame().getReplacementHandler().run(ReplacementType.Mill, repRunParams)) {
|
||||||
@@ -1618,7 +1637,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
|
|
||||||
for (Card m : milledView) {
|
for (Card m : milledView) {
|
||||||
final ZoneType origin = m.getZone().getZoneType();
|
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)) {
|
if (d.getZone().is(destination)) {
|
||||||
table.put(origin, d.getZone().getZoneType(), d);
|
table.put(origin, d.getZone().getZoneType(), d);
|
||||||
}
|
}
|
||||||
@@ -2580,21 +2599,25 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
* Takes the top plane of the planar deck and put it face up in the command zone.
|
* Takes the top plane of the planar deck and put it face up in the command zone.
|
||||||
* Then runs triggers.
|
* Then runs triggers.
|
||||||
*/
|
*/
|
||||||
public void planeswalk() {
|
public void planeswalk(SpellAbility sa) {
|
||||||
planeswalkTo(new CardCollection(getZone(ZoneType.PlanarDeck).get(0)));
|
planeswalkTo(sa, new CardCollection(getZone(ZoneType.PlanarDeck).get(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the planes in the argument and puts them face up in the command zone.
|
* Puts the planes in the argument and puts them face up in the command zone.
|
||||||
* Then runs triggers.
|
* 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());
|
System.out.println(getName() + ": planeswalk to " + destinations.toString());
|
||||||
currentPlanes.addAll(destinations);
|
currentPlanes.addAll(destinations);
|
||||||
game.getView().updatePlanarPlayer(getView());
|
game.getView().updatePlanarPlayer(getView());
|
||||||
|
|
||||||
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
|
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
|
||||||
|
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||||
|
|
||||||
for (Card c : currentPlanes) {
|
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.PlanarDeck).remove(c);
|
||||||
//getZone(ZoneType.Command).add(c);
|
//getZone(ZoneType.Command).add(c);
|
||||||
}
|
}
|
||||||
@@ -3414,10 +3437,13 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void learnLesson(SpellAbility sa, CardZoneTable table) {
|
public void learnLesson(SpellAbility sa, CardZoneTable table, Map<AbilityKey, Object> params) {
|
||||||
// Replacement effects
|
// Replacement effects
|
||||||
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||||
repParams.put(AbilityKey.Cause, sa);
|
repParams.put(AbilityKey.Cause, sa);
|
||||||
|
if (params != null) {
|
||||||
|
repParams.putAll(params);
|
||||||
|
}
|
||||||
if (game.getReplacementHandler().run(ReplacementType.Learn, repParams) != ReplacementResult.NotReplaced) {
|
if (game.getReplacementHandler().run(ReplacementType.Learn, repParams) != ReplacementResult.NotReplaced) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3438,11 +3464,11 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
if (c.isInZone(ZoneType.Sideboard)) { // Sideboard Lesson to Hand
|
if (c.isInZone(ZoneType.Sideboard)) { // Sideboard Lesson to Hand
|
||||||
game.getAction().reveal(new CardCollection(c), c.getOwner(), true);
|
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);
|
table.put(ZoneType.Sideboard, ZoneType.Hand, moved);
|
||||||
} else if (c.isInZone(ZoneType.Hand)) { // Discard and Draw
|
} else if (c.isInZone(ZoneType.Hand)) { // Discard and Draw
|
||||||
boolean firstDiscard = getNumDiscardedThisTurn() == 0;
|
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
|
// Change this if something would make multiple player learn at the same time
|
||||||
|
|
||||||
// Discard Trigger outside Effect
|
// Discard Trigger outside Effect
|
||||||
@@ -3450,9 +3476,12 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
runParams.put(AbilityKey.Cards, new CardCollection(c));
|
runParams.put(AbilityKey.Cards, new CardCollection(c));
|
||||||
runParams.put(AbilityKey.Cause, sa);
|
runParams.put(AbilityKey.Cause, sa);
|
||||||
runParams.put(AbilityKey.FirstTime, firstDiscard);
|
runParams.put(AbilityKey.FirstTime, firstDiscard);
|
||||||
|
if (params != null) {
|
||||||
|
runParams.putAll(params);
|
||||||
|
}
|
||||||
getGame().getTriggerHandler().runTrigger(TriggerType.DiscardedAll, runParams, false);
|
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
|
table.put(ZoneType.Library, ZoneType.Hand, d); // does a ChangesZoneAll care about moving from Library to Hand
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ import io.sentry.Sentry;
|
|||||||
import io.sentry.event.BreadcrumbBuilder;
|
import io.sentry.event.BreadcrumbBuilder;
|
||||||
|
|
||||||
public class TriggerHandler {
|
public class TriggerHandler {
|
||||||
private final List<TriggerType> suppressedModes = Collections.synchronizedList(new ArrayList<>());
|
private final Set<TriggerType> suppressedModes = Collections.synchronizedSet(EnumSet.noneOf(TriggerType.class));
|
||||||
|
private boolean allSuppressed = false;
|
||||||
private final List<Trigger> activeTriggers = Collections.synchronizedList(new ArrayList<>());
|
private final List<Trigger> activeTriggers = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
private final List<Trigger> delayedTriggers = Collections.synchronizedList(new ArrayList<>());
|
private final List<Trigger> delayedTriggers = Collections.synchronizedList(new ArrayList<>());
|
||||||
@@ -106,18 +107,15 @@ public class TriggerHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final void setSuppressAllTriggers(final boolean suppress) {
|
public final void setSuppressAllTriggers(final boolean suppress) {
|
||||||
for (TriggerType t : TriggerType.values()) {
|
allSuppressed = suppress;
|
||||||
if (suppress) {
|
|
||||||
suppressMode(t);
|
|
||||||
} else {
|
|
||||||
clearSuppression(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void clearSuppression(final TriggerType mode) {
|
public final void clearSuppression(final TriggerType mode) {
|
||||||
suppressedModes.remove(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) {
|
public static Trigger parseTrigger(final String trigParse, final Card host, final boolean intrinsic) {
|
||||||
return parseTrigger(trigParse, host, intrinsic, host.getCurrentState());
|
return parseTrigger(trigParse, host, intrinsic, host.getCurrentState());
|
||||||
@@ -252,7 +250,7 @@ public class TriggerHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final void runTrigger(final TriggerType mode, final Map<AbilityKey, Object> runParams, boolean holdTrigger) {
|
public final void runTrigger(final TriggerType mode, final Map<AbilityKey, Object> runParams, boolean holdTrigger) {
|
||||||
if (suppressedModes.contains(mode)) {
|
if (isTriggerSuppressed(mode)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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()) {
|
if (forgeCard.isCreature()) {
|
||||||
forgeCard.setSickness(lastSummoningSickness);
|
forgeCard.setSickness(lastSummoningSickness);
|
||||||
}
|
}
|
||||||
@@ -2858,7 +2858,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
|||||||
getGame().getAction().moveToBottomOfLibrary(forgeCard, null);
|
getGame().getAction().moveToBottomOfLibrary(forgeCard, null);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getGame().getAction().moveTo(targetZone, forgeCard, null);
|
getGame().getAction().moveTo(targetZone, forgeCard, null, AbilityKey.newMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
lastAdded = f;
|
lastAdded = f;
|
||||||
@@ -2898,7 +2898,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
|||||||
if (c == null) {
|
if (c == null) {
|
||||||
continue;
|
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();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(p).append(" exiles ").append(c).append(" due to Dev Cheats.");
|
sb.append(p).append(" exiles ").append(c).append(" due to Dev Cheats.");
|
||||||
getGame().getGameLog().add(GameLogEntryType.DISCARD, sb.toString());
|
getGame().getGameLog().add(GameLogEntryType.DISCARD, sb.toString());
|
||||||
@@ -2937,7 +2937,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
|||||||
if (c == null) {
|
if (c == null) {
|
||||||
continue;
|
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();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(p).append(" exiles ").append(c).append(" due to Dev Cheats.");
|
sb.append(p).append(" exiles ").append(c).append(" due to Dev Cheats.");
|
||||||
getGame().getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString());
|
getGame().getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString());
|
||||||
|
|||||||
Reference in New Issue
Block a user