> implements K
}
}
+ /* (non-Javadoc)
+ * @see forge.game.keyword.KeywordInterface#createTraits(forge.game.player.Player)
+ */
+ @Override
+ public void createTraits(Player player) {
+ createTraits(player, false);
+ }
+ /* (non-Javadoc)
+ * @see forge.game.keyword.KeywordInterface#createTraits(forge.game.player.Player, boolean)
+ */
+ @Override
+ public void createTraits(Player player, boolean clear) {
+ if (clear) {
+ triggers.clear();
+ replacements.clear();
+ abilities.clear();
+ staticAbilities.clear();
+ }
+ try {
+ String msg = "KeywordInstance:createTraits: make Traits for Keyword";
+ Sentry.getContext().recordBreadcrumb(
+ new BreadcrumbBuilder().setMessage(msg)
+ .withData("Player", player.getName()).withData("Keyword", this.original).build()
+ );
+
+ // add Extra for debugging
+ Sentry.getContext().addExtra("Player", player);
+ Sentry.getContext().addExtra("Keyword", this.original);
+
+ PlayerFactoryUtil.addTriggerAbility(this, player);
+ PlayerFactoryUtil.addReplacementEffect(this, player);
+ PlayerFactoryUtil.addSpellAbility(this, player);
+ PlayerFactoryUtil.addStaticAbility(this, player);
+ } catch (Exception e) {
+ String msg = "KeywordInstance:createTraits: failed Traits for Keyword";
+ Sentry.getContext().recordBreadcrumb(
+ new BreadcrumbBuilder().setMessage(msg)
+ .withData("Player", player.getName()).withData("Keyword", this.original).build()
+ );
+ //rethrow
+ throw new RuntimeException("Error in Keyword " + this.original + " for player " + player.getName(), e);
+ } finally {
+ // remove added extra
+ Sentry.getContext().removeExtra("Player");
+ Sentry.getContext().removeExtra("Keyword");
+ }
+ }
/*
* (non-Javadoc)
* @see forge.game.keyword.KeywordInterface#addTrigger(forge.game.trigger.Trigger)
diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java b/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java
index d8b5f152605..2832cdd2ee4 100644
--- a/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java
+++ b/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java
@@ -3,6 +3,7 @@ package forge.game.keyword;
import java.util.Collection;
import forge.game.card.Card;
+import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility;
@@ -24,6 +25,9 @@ public interface KeywordInterface extends Cloneable {
void createTraits(final Card host, final boolean intrinsic);
void createTraits(final Card host, final boolean intrinsic, final boolean clear);
+ void createTraits(final Player player);
+ void createTraits(final Player player, final boolean clear);
+
void addTrigger(final Trigger trg);
void addReplacement(final ReplacementEffect trg);
diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java b/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java
index 1f87bc4762f..73e1c1aa272 100644
--- a/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java
+++ b/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java
@@ -23,6 +23,11 @@ import java.util.List;
import com.google.common.collect.Lists;
import forge.game.card.Card;
+import forge.game.player.Player;
+import forge.game.replacement.ReplacementEffect;
+import forge.game.spellability.SpellAbility;
+import forge.game.staticability.StaticAbility;
+import forge.game.trigger.Trigger;
/**
*
@@ -131,7 +136,13 @@ public class KeywordsChange implements Cloneable {
inst.createTraits(host, false, true);
}
}
-
+
+ public final void addKeywordsToPlayer(final Player player) {
+ for (KeywordInterface inst : keywords.getValues()) {
+ inst.createTraits(player, true);
+ }
+ }
+
public final boolean removeKeywordfromAdd(final String keyword) {
return keywords.remove(keyword);
}
@@ -201,6 +212,47 @@ public class KeywordsChange implements Cloneable {
}
}
+ /**
+ * @return the triggers
+ */
+ public Collection getTriggers() {
+ List result = Lists.newArrayList();
+ for (KeywordInterface k : this.keywords.getValues()) {
+ result.addAll(k.getTriggers());
+ }
+ return result;
+ }
+ /**
+ * @return the replacements
+ */
+ public Collection getReplacements() {
+ List result = Lists.newArrayList();
+ for (KeywordInterface k : this.keywords.getValues()) {
+ result.addAll(k.getReplacements());
+ }
+ return result;
+ }
+ /**
+ * @return the abilities
+ */
+ public Collection getAbilities() {
+ List result = Lists.newArrayList();
+ for (KeywordInterface k : this.keywords.getValues()) {
+ result.addAll(k.getAbilities());
+ }
+ return result;
+ }
+ /**
+ * @return the staticAbilities
+ */
+ public Collection getStaticAbilities() {
+ List result = Lists.newArrayList();
+ for (KeywordInterface k : this.keywords.getValues()) {
+ result.addAll(k.getStaticAbilities());
+ }
+ return result;
+ }
+
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
diff --git a/forge-game/src/main/java/forge/game/mana/ManaPool.java b/forge-game/src/main/java/forge/game/mana/ManaPool.java
index 9fb66880820..e90e6eb9b50 100644
--- a/forge-game/src/main/java/forge/game/mana/ManaPool.java
+++ b/forge-game/src/main/java/forge/game/mana/ManaPool.java
@@ -234,7 +234,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable {
final Card host = sa.getHostCard();
if (mana.addsKeywords(sa) && mana.addsKeywordsType()
&& host.getType().hasStringType(mana.getManaAbility().getAddsKeywordsType())) {
- final long timestamp = sa.getHostCard().getGame().getNextTimestamp();
+ final long timestamp = host.getGame().getNextTimestamp();
final List kws = Arrays.asList(mana.getAddedKeywords().split(" & "));
host.addChangedCardKeywords(kws, null, false, false, timestamp);
if (mana.addsKeywordsUntil()) {
@@ -243,14 +243,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable {
@Override
public void run() {
- if (!kws.isEmpty()) {
- for (String kw : kws) {
- if (kw.startsWith("HIDDEN")) {
- sa.getHostCard().removeHiddenExtrinsicKeyword(kw);
- }
- }
- host.removeChangedCardKeywords(timestamp);
- }
+ host.removeChangedCardKeywords(timestamp);
host.getGame().fireEvent(new GameEventCardStatsChanged(host));
}
};
@@ -261,10 +254,10 @@ public class ManaPool extends ManaConversionMatrix implements Iterable {
}
}
if (mana.addsCounters(sa)) {
- mana.getManaAbility().createETBCounters(sa.getHostCard());
+ mana.getManaAbility().createETBCounters(host);
}
if (mana.triggersWhenSpent()) {
- mana.getManaAbility().addTriggersWhenSpent(sa, sa.getHostCard());
+ mana.getManaAbility().addTriggersWhenSpent(sa, host);
}
}
return true;
diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
index 48e86dbfa72..85e7a784d90 100644
--- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
+++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
@@ -283,6 +283,7 @@ public class PhaseHandler implements java.io.Serializable {
case COMBAT_DECLARE_ATTACKERS:
if (!playerTurn.hasLost()) {
+ combat.initConstraints();
game.getStack().freezeStack();
declareAttackersTurnBasedAction();
game.getStack().unfreezeStack();
diff --git a/forge-game/src/main/java/forge/game/phase/PhaseType.java b/forge-game/src/main/java/forge/game/phase/PhaseType.java
index 15fda8e63d1..565f772f156 100644
--- a/forge-game/src/main/java/forge/game/phase/PhaseType.java
+++ b/forge-game/src/main/java/forge/game/phase/PhaseType.java
@@ -44,7 +44,16 @@ public enum PhaseType {
nameForScripts = name_for_scripts;
}
-
+
+ public final boolean phaseforUpdateField() {
+ boolean result =
+ ((ALL_PHASES.indexOf(this) >= ALL_PHASES.indexOf(UNTAP)
+ && ALL_PHASES.indexOf(this) < ALL_PHASES.indexOf(COMBAT_FIRST_STRIKE_DAMAGE))
+ || (ALL_PHASES.indexOf(this) >= ALL_PHASES.indexOf(MAIN2)
+ && ALL_PHASES.indexOf(this) < ALL_PHASES.indexOf(CLEANUP)));
+ return result;
+ }
+
public final boolean isAfter(final PhaseType phase) {
return ALL_PHASES.indexOf(this) > ALL_PHASES.indexOf(phase);
}
diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java
index a187d2a101e..510041f2043 100644
--- a/forge-game/src/main/java/forge/game/player/Player.java
+++ b/forge-game/src/main/java/forge/game/player/Player.java
@@ -20,6 +20,8 @@ package forge.game.player;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.*;
+
+import forge.ImageKeys;
import forge.LobbyPlayer;
import forge.card.MagicColor;
import forge.game.*;
@@ -41,7 +43,6 @@ import forge.game.phase.PhaseType;
import forge.game.replacement.ReplacementHandler;
import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
-import forge.game.spellability.AbilityActivated;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger;
@@ -155,6 +156,7 @@ public class Player extends GameEntity implements Comparable {
private Card monarchEffect = null;
private Card blessingEffect = null;
+ private Card keywordEffect = null;
private final AchievementTracker achievementTracker = new AchievementTracker();
private final PlayerView view;
@@ -235,10 +237,7 @@ public class Player extends GameEntity implements Comparable {
}
// Replacement effects
- final Map repRunParams = Maps.newHashMap();
- repRunParams.put("Affected", this);
-
- if (game.getReplacementHandler().run(ReplacementType.SetInMotion, repRunParams) != ReplacementResult.NotReplaced) {
+ if (game.getReplacementHandler().run(ReplacementType.SetInMotion, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) {
return;
}
@@ -403,10 +402,9 @@ public class Player extends GameEntity implements Comparable {
public final boolean gainLife(int lifeGain, final Card source, final SpellAbility sa) {
// Run any applicable replacement effects.
- final Map repParams = Maps.newHashMap();
- repParams.put("Affected", this);
- repParams.put("LifeGained", lifeGain);
- repParams.put("Source", source);
+ final Map repParams = AbilityKey.mapFromAffected(this);
+ repParams.put(AbilityKey.LifeGained, lifeGain);
+ repParams.put(AbilityKey.Source, source);
if (!canGainLife()) {
return false;
@@ -417,8 +415,8 @@ public class Player extends GameEntity implements Comparable {
break;
case Updated:
// check if this is still the affected player
- if (this.equals(repParams.get("Affected"))) {
- lifeGain = (int) repParams.get("LifeGained");
+ if (this.equals(repParams.get(AbilityKey.Affected))) {
+ lifeGain = (int) repParams.get(AbilityKey.LifeGained);
// negative update means life loss
if (lifeGain < 0) {
this.loseLife(-lifeGain);
@@ -914,18 +912,17 @@ public class Player extends GameEntity implements Comparable {
return 0;
}
- final Map repParams = Maps.newHashMap();
- repParams.put("Affected", this);
- repParams.put("Source", source);
- repParams.put("CounterType", counterType);
- repParams.put("CounterNum", addAmount);
- repParams.put("EffectOnly", applyMultiplier);
+ final Map repParams = AbilityKey.mapFromAffected(this);
+ repParams.put(AbilityKey.Source, source);
+ repParams.put(AbilityKey.CounterType, counterType);
+ repParams.put(AbilityKey.CounterNum, addAmount);
+ repParams.put(AbilityKey.EffectOnly, applyMultiplier);
switch (getGame().getReplacementHandler().run(ReplacementType.AddCounter, repParams)) {
case NotReplaced:
break;
case Updated: {
- addAmount = (int) repParams.get("CounterNum");
+ addAmount = (int) repParams.get(AbilityKey.CounterNum);
break;
}
default:
@@ -1030,23 +1027,25 @@ public class Player extends GameEntity implements Comparable {
public final void addChangedKeywords(final List addKeywords, final List removeKeywords, final Long timestamp) {
// if the key already exists - merge entries
+ KeywordsChange cks = null;
if (changedKeywords.containsKey(timestamp)) {
- final KeywordsChange cks = changedKeywords.get(timestamp);
+ getKeywordCard().removeChangedCardTraits(timestamp);
- changedKeywords.put(timestamp, cks.merge(addKeywords, removeKeywords,
- cks.isRemoveAllKeywords(), cks.isRemoveIntrinsicKeywords()));
- updateKeywords();
- return;
+ cks = changedKeywords.get(timestamp).merge(addKeywords, removeKeywords, false, false);
+ } else {
+ cks = new KeywordsChange(addKeywords, removeKeywords, false, false);
}
-
- changedKeywords.put(timestamp, new KeywordsChange(addKeywords, removeKeywords, false, false));
+ cks.addKeywordsToPlayer(this);
+ getKeywordCard().addChangedCardTraits(cks.getAbilities(), null, cks.getTriggers(), cks.getReplacements(), cks.getStaticAbilities(), false, false, false, timestamp);
+ changedKeywords.put(timestamp, cks);
updateKeywords();
game.fireEvent(new GameEventPlayerStatsChanged(this));
}
public final KeywordsChange removeChangedKeywords(final Long timestamp) {
- KeywordsChange change = changedKeywords.remove(Long.valueOf(timestamp));
+ KeywordsChange change = changedKeywords.remove(timestamp);
if (change != null) {
+ getKeywordCard().removeChangedCardTraits(timestamp);
updateKeywords();
game.fireEvent(new GameEventPlayerStatsChanged(this));
}
@@ -1105,6 +1104,7 @@ public class Player extends GameEntity implements Comparable {
for (final Entry ck : ImmutableList.copyOf(changedKeywords.entrySet())) {
if (ck.getValue().isEmpty() && changedKeywords.remove(ck.getKey()) != null) {
keywordRemoved = true;
+ getKeywordCard().removeChangedCardTraits(ck.getKey());
}
}
@@ -1183,33 +1183,17 @@ public class Player extends GameEntity implements Comparable {
@Override
public final boolean canBeTargetedBy(final SpellAbility sa) {
- if (hasKeyword("Shroud")) {
- return false;
- }
- if (hasKeyword("Hexproof")) {
- final Player a = sa.getActivatingPlayer();
- if (isOpponentOf(a)) {
- boolean cancelHexproof = false;
- for (String k : a.getKeywords()) {
- if (k.startsWith("IgnoreHexproof")) {
- String[] m = k.split(":");
- if (isValid(m[1].split(","), a, sa.getHostCard(), sa)) {
- cancelHexproof = true;
- break;
- }
- }
- }
- if (!cancelHexproof) {
+
+ // CantTarget static abilities
+ for (final Card ca : getGame().getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) {
+ for (final StaticAbility stAb : ca.getStaticAbilities()) {
+ if (stAb.applyAbility("CantTarget", this, sa)) {
return false;
}
}
}
- if (hasProtectionFrom(sa.getHostCard())) {
- return false;
- }
-
- return (!hasKeyword("You can't be the targets of spells or activated abilities") || (!sa.isSpell() && (!(sa instanceof AbilityActivated))));
+ return !hasProtectionFrom(sa.getHostCard());
}
@@ -1276,16 +1260,15 @@ public class Player extends GameEntity implements Comparable {
public void surveil(int num, SpellAbility cause) {
- final Map repParams = Maps.newHashMap();
- repParams.put("Affected", this);
- repParams.put("Source", cause);
- repParams.put("SurveilNum", num);
+ final Map repParams = AbilityKey.mapFromAffected(this);
+ repParams.put(AbilityKey.Source, cause);
+ repParams.put(AbilityKey.SurveilNum, num);
switch (getGame().getReplacementHandler().run(ReplacementType.Surveil, repParams)) {
case NotReplaced:
break;
case Updated: {
- num = (int) repParams.get("SurveilNum");
+ num = (int) repParams.get(AbilityKey.SurveilNum);
break;
}
default:
@@ -1346,9 +1329,8 @@ public class Player extends GameEntity implements Comparable {
final CardCollection toReveal = new CardCollection();
// Replacement effects
- final Map repRunParams = Maps.newHashMap();
- repRunParams.put("Affected", this);
- repRunParams.put("Number", n);
+ final Map repRunParams = AbilityKey.mapFromAffected(this);
+ repRunParams.put(AbilityKey.Number, n);
if (game.getReplacementHandler().run(ReplacementType.DrawCards, repRunParams) != ReplacementResult.NotReplaced) {
return drawn;
@@ -1378,10 +1360,7 @@ public class Player extends GameEntity implements Comparable {
final PlayerZone library = getZone(ZoneType.Library);
// Replacement effects
- final Map repRunParams = Maps.newHashMap();
- repRunParams.put("Affected", this);
-
- if (game.getReplacementHandler().run(ReplacementType.Draw, repRunParams) != ReplacementResult.NotReplaced) {
+ if (game.getReplacementHandler().run(ReplacementType.Draw, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) {
return drawn;
}
@@ -1556,10 +1535,9 @@ public class Player extends GameEntity implements Comparable {
// that should not trigger other Replacement again
if (!discardToTopOfLibrary && !discardMadness) {
// Replacement effects
- final Map repRunParams = Maps.newHashMap();
- repRunParams.put("Card", c);
- repRunParams.put("Source", source);
- repRunParams.put("Affected", this);
+ final Map repRunParams = AbilityKey.mapFromCard(c);
+ repRunParams.put(AbilityKey.Source, source);
+ repRunParams.put(AbilityKey.Affected, this);
if (game.getReplacementHandler().run(ReplacementType.Discard, repRunParams) != ReplacementResult.NotReplaced) {
return null;
@@ -1861,10 +1839,7 @@ public class Player extends GameEntity implements Comparable {
}
// Replacement effects
- final Map runParams = Maps.newHashMap();
- runParams.put("Affected", this);
-
- if (game.getReplacementHandler().run(ReplacementType.GameLoss, runParams) != ReplacementResult.NotReplaced) {
+ if (game.getReplacementHandler().run(ReplacementType.GameLoss, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) {
return false;
}
}
@@ -2455,6 +2430,7 @@ public class Player extends GameEntity implements Comparable {
controllerCreator = ctrlr;
controller = ctrlr;
updateAvatar();
+ updateSleeve();
view.updateIsAI(this);
view.updateLobbyPlayerName(this);
}
@@ -2464,6 +2440,10 @@ public class Player extends GameEntity implements Comparable {
view.updateAvatarCardImageKey(this);
}
+ public void updateSleeve() {
+ view.updateSleeveIndex(this);
+ }
+
/**
* Run a procedure using a different controller
*/
@@ -2985,4 +2965,26 @@ public class Player extends GameEntity implements Comparable {
|| !hasKeyword("Spells and abilities you control can't cause you to search your library.");
}
+
+ public Card getKeywordCard() {
+ if (keywordEffect != null) {
+ return keywordEffect;
+ }
+
+ final PlayerZone com = getZone(ZoneType.Command);
+
+ keywordEffect = new Card(game.nextCardId(), null, false, game);
+ keywordEffect.setImmutable(true);
+ keywordEffect.setOwner(this);
+ keywordEffect.setName("Keyword Effects");
+ keywordEffect.setImageKey(ImageKeys.HIDDEN_CARD);
+ keywordEffect.addType("Effect");
+
+ keywordEffect.updateStateForView();
+
+ com.add(keywordEffect);
+
+ this.updateZoneForView(com);
+ return keywordEffect;
+ }
}
diff --git a/forge-game/src/main/java/forge/game/player/PlayerController.java b/forge-game/src/main/java/forge/game/player/PlayerController.java
index ecea26174d9..d5cef95818b 100644
--- a/forge-game/src/main/java/forge/game/player/PlayerController.java
+++ b/forge-game/src/main/java/forge/game/player/PlayerController.java
@@ -211,7 +211,7 @@ public abstract class PlayerController {
Map params);
public abstract boolean confirmPayment(CostPart costPart, String string, SpellAbility sa);
- public abstract ReplacementEffect chooseSingleReplacementEffect(String prompt, List possibleReplacers, Map runParams);
+ public abstract ReplacementEffect chooseSingleReplacementEffect(String prompt, List possibleReplacers);
public abstract String chooseProtectionType(String string, SpellAbility sa, List choices);
// these 4 need some refining.
diff --git a/forge-game/src/main/java/forge/game/player/PlayerFactoryUtil.java b/forge-game/src/main/java/forge/game/player/PlayerFactoryUtil.java
new file mode 100644
index 00000000000..0eff22b1711
--- /dev/null
+++ b/forge-game/src/main/java/forge/game/player/PlayerFactoryUtil.java
@@ -0,0 +1,46 @@
+package forge.game.player;
+
+import forge.game.card.Card;
+import forge.game.keyword.KeywordInterface;
+import forge.game.staticability.StaticAbility;
+
+public class PlayerFactoryUtil {
+
+ public static void addStaticAbility(final KeywordInterface inst, final Player player) {
+ final Card card = player.getKeywordCard();
+ String keyword = inst.getOriginal();
+ String effect = null;
+ if (keyword.startsWith("Hexproof")) {
+ final StringBuilder sbDesc = new StringBuilder("Hexproof");
+ final StringBuilder sbValid = new StringBuilder();
+
+ if (!keyword.equals("Hexproof")) {
+ final String[] k = keyword.split(":");
+
+ sbDesc.append(" from ").append(k[2]);
+ sbValid.append("| ValidSource$ ").append(k[1]);
+ }
+
+ effect = "Mode$ CantTarget | Hexproof$ True | ValidPlayer$ Player.You | Secondary$ True "
+ + sbValid.toString() + " | Activator$ Opponent | EffectZone$ Command | Description$ "
+ + sbDesc.toString() + " (" + inst.getReminderText() + ")";
+ } else if (keyword.equals("Shroud")) {
+ effect = "Mode$ CantTarget | Shroud$ True | ValidPlayer$ Player.You | Secondary$ True "
+ + "| EffectZone$ Command | Description$ Shroud (" + inst.getReminderText() + ")";
+ }
+ if (effect != null) {
+ StaticAbility st = new StaticAbility(effect, card);
+ st.setIntrinsic(false);
+ inst.addStaticAbility(st);
+ }
+ }
+
+ public static void addTriggerAbility(final KeywordInterface inst, Player player) {
+ }
+
+ public static void addReplacementEffect(final KeywordInterface inst, Player player) {
+ }
+
+ public static void addSpellAbility(final KeywordInterface inst, Player player) {
+ }
+}
diff --git a/forge-game/src/main/java/forge/game/player/PlayerView.java b/forge-game/src/main/java/forge/game/player/PlayerView.java
index 28dfb54c0e3..735c0709f1b 100644
--- a/forge-game/src/main/java/forge/game/player/PlayerView.java
+++ b/forge-game/src/main/java/forge/game/player/PlayerView.java
@@ -85,6 +85,13 @@ public class PlayerView extends GameEntityView {
set(TrackableProperty.AvatarCardImageKey, p.getLobbyPlayer().getAvatarCardImageKey());
}
+ public int getSleeveIndex() {
+ return get(TrackableProperty.SleeveIndex);
+ }
+ void updateSleeveIndex(Player p) {
+ set(TrackableProperty.SleeveIndex, p.getLobbyPlayer().getSleeveIndex());
+ }
+
public String getCurrentPlaneName() { return get(TrackableProperty.CurrentPlane); }
void updateCurrentPlaneName( String plane ) {
set(TrackableProperty.CurrentPlane, plane);
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceAddCounter.java b/forge-game/src/main/java/forge/game/replacement/ReplaceAddCounter.java
index 882daefed56..27a388c2160 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceAddCounter.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceAddCounter.java
@@ -1,5 +1,6 @@
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CounterType;
import forge.game.player.Player;
@@ -27,20 +28,20 @@ public class ReplaceAddCounter extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
- if (((int) runParams.get("CounterNum")) <= 0) {
+ public boolean canReplace(Map runParams) {
+ if (((int) runParams.get(AbilityKey.CounterNum)) <= 0) {
return false;
}
if (hasParam("EffectOnly")) {
- final Boolean effectOnly = (Boolean) runParams.get("EffectOnly");
+ final Boolean effectOnly = (Boolean) runParams.get(AbilityKey.EffectOnly);
if (!effectOnly) {
return false;
}
}
if (hasParam("ValidCard")) {
- Object o = runParams.get("Affected");
+ Object o = runParams.get(AbilityKey.Affected);
if (!(o instanceof Card)) {
return false;
}
@@ -48,7 +49,7 @@ public class ReplaceAddCounter extends ReplacementEffect {
return false;
}
} else if (hasParam("ValidPlayer")) {
- Object o = runParams.get("Affected");
+ Object o = runParams.get(AbilityKey.Affected);
if (!(o instanceof Player)) {
return false;
}
@@ -59,7 +60,7 @@ public class ReplaceAddCounter extends ReplacementEffect {
if (hasParam("ValidCounterType")) {
String type = getParam("ValidCounterType");
- if (CounterType.getType(type) != runParams.get("CounterType")) {
+ if (CounterType.getType(type) != runParams.get(AbilityKey.CounterType)) {
return false;
}
}
@@ -71,14 +72,14 @@ public class ReplaceAddCounter extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("CounterNum", runParams.get("CounterNum"));
- sa.setReplacingObject("CounterType", ((CounterType) runParams.get("CounterType")).getName());
- Object o = runParams.get("Affected");
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.CounterNum, runParams.get(AbilityKey.CounterNum));
+ sa.setReplacingObject(AbilityKey.CounterType, ((CounterType) runParams.get(AbilityKey.CounterType)).getName());
+ Object o = runParams.get(AbilityKey.Affected);
if (o instanceof Card) {
- sa.setReplacingObject("Card", o);
+ sa.setReplacingObject(AbilityKey.Card, o);
} else if (o instanceof Player) {
- sa.setReplacingObject("Player", o);
+ sa.setReplacingObject(AbilityKey.Player, o);
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceCounter.java b/forge-game/src/main/java/forge/game/replacement/ReplaceCounter.java
index b3d27814b95..c5968fd1d16 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceCounter.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceCounter.java
@@ -17,6 +17,7 @@
*/
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
@@ -42,15 +43,15 @@ public class ReplaceCounter extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
- final SpellAbility spellAbility = (SpellAbility) runParams.get("TgtSA");
+ public boolean canReplace(Map runParams) {
+ final SpellAbility spellAbility = (SpellAbility) runParams.get(AbilityKey.TgtSA);
if (hasParam("ValidCard")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) {
return false;
}
}
if (hasParam("ValidCause")) {
- if (!matchesValid(runParams.get("Cause"), getParam("ValidCause").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Cause), getParam("ValidCause").split(","), this.getHostCard())) {
return false;
}
}
@@ -67,8 +68,8 @@ public class ReplaceCounter extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("Card", runParams.get("Affected"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java b/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java
index 4063ec610bb..2d8681ef508 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java
@@ -17,6 +17,7 @@
*/
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardFactoryUtil;
@@ -46,49 +47,49 @@ public class ReplaceDamage extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
- if (!(runParams.containsKey("Prevention") == (hasParam("PreventionEffect") || hasParam("Prevent")))) {
+ public boolean canReplace(Map runParams) {
+ if (!(runParams.containsKey(AbilityKey.Prevention) == (hasParam("PreventionEffect") || hasParam("Prevent")))) {
return false;
}
- if (((Integer) runParams.get("DamageAmount")) == 0) {
+ if (((Integer) runParams.get(AbilityKey.DamageAmount)) == 0) {
// If no actual damage is dealt, there is nothing to replace
return false;
}
if (hasParam("ValidSource")) {
String validSource = getParam("ValidSource");
validSource = AbilityUtils.applyAbilityTextChangeEffects(validSource, this);
- if (!matchesValid(runParams.get("DamageSource"), validSource.split(","), getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.DamageSource), validSource.split(","), getHostCard())) {
return false;
}
}
if (hasParam("ValidTarget")) {
String validTarget = getParam("ValidTarget");
validTarget = AbilityUtils.applyAbilityTextChangeEffects(validTarget, this);
- if (!matchesValid(runParams.get("Affected"), validTarget.split(","), getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), validTarget.split(","), getHostCard())) {
return false;
}
}
if (hasParam("ValidCause")) {
- if (!runParams.containsKey("Cause")) {
+ if (!runParams.containsKey(AbilityKey.Cause)) {
return false;
}
- SpellAbility cause = (SpellAbility) runParams.get("Cause");
+ SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause);
String validCause = getParam("ValidCause");
validCause = AbilityUtils.applyAbilityTextChangeEffects(validCause, this);
if (!matchesValid(cause, validCause.split(","), getHostCard())) {
return false;
}
if (hasParam("CauseIsSource")) {
- if (!cause.getHostCard().equals(runParams.get("DamageSource"))) {
+ if (!cause.getHostCard().equals(runParams.get(AbilityKey.DamageSource))) {
return false;
}
}
}
if (hasParam("RelativeToSource")) {
- Card source = (Card) runParams.get("DamageSource");
+ Card source = (Card) runParams.get(AbilityKey.DamageSource);
String validRelative = getParam("RelativeToSource");
validRelative = AbilityUtils.applyAbilityTextChangeEffects(validRelative, this);
- if (!matchesValid(runParams.get("DamageTarget"), validRelative.split(","), source)) {
+ if (!matchesValid(runParams.get(AbilityKey.DamageTarget), validRelative.split(","), source)) {
return false;
}
}
@@ -103,17 +104,17 @@ public class ReplaceDamage extends ReplacementEffect {
intoperand = CardFactoryUtil.xCount(getHostCard(), getHostCard().getSVar(operand));
}
- if (!Expressions.compare((Integer) runParams.get("DamageAmount"), operator, intoperand)) {
+ if (!Expressions.compare((Integer) runParams.get(AbilityKey.DamageAmount), operator, intoperand)) {
return false;
}
}
if (hasParam("IsCombat")) {
if (getParam("IsCombat").equals("True")) {
- if (!((Boolean) runParams.get("IsCombat"))) {
+ if (!((Boolean) runParams.get(AbilityKey.IsCombat))) {
return false;
}
} else {
- if ((Boolean) runParams.get("IsCombat")) {
+ if ((Boolean) runParams.get(AbilityKey.IsCombat)) {
return false;
}
}
@@ -149,10 +150,10 @@ public class ReplaceDamage extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("DamageAmount", runParams.get("DamageAmount"));
- sa.setReplacingObject("Target", runParams.get("Affected"));
- sa.setReplacingObject("Source", runParams.get("DamageSource"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.DamageAmount, runParams.get(AbilityKey.DamageAmount));
+ sa.setReplacingObject(AbilityKey.Target, runParams.get(AbilityKey.Affected));
+ sa.setReplacingObject(AbilityKey.Source, runParams.get(AbilityKey.DamageSource));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceDestroy.java b/forge-game/src/main/java/forge/game/replacement/ReplaceDestroy.java
index d5fe606ab2b..e9c22681fb7 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceDestroy.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceDestroy.java
@@ -17,6 +17,7 @@
*/
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
@@ -42,23 +43,23 @@ public class ReplaceDestroy extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
+ public boolean canReplace(Map runParams) {
if (hasParam("ValidPlayer")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), getHostCard())) {
return false;
}
}
if (hasParam("ValidCard")) {
- Card card = (Card)runParams.get("Card");
+ Card card = (Card)runParams.get(AbilityKey.Card);
if (!matchesValid(card, getParam("ValidCard").split(","), getHostCard())) {
return false;
}
// extra check for Regeneration
if (hasParam("Regeneration")) {
- if (!runParams.containsKey("Regeneration")) {
+ if (!runParams.containsKey(AbilityKey.Regeneration)) {
return false;
}
- if (!(Boolean)runParams.get("Regeneration")) {
+ if (!(Boolean)runParams.get(AbilityKey.Regeneration)) {
return false;
}
if (!card.canBeShielded()) {
@@ -71,7 +72,7 @@ public class ReplaceDestroy extends ReplacementEffect {
}
}
if (hasParam("ValidSource")) {
- if (!matchesValid(runParams.get("Source"), getParam("ValidSource").split(","), getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Source), getParam("ValidSource").split(","), getHostCard())) {
return false;
}
}
@@ -83,8 +84,8 @@ public class ReplaceDestroy extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("Card", runParams.get("Card"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Card));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceDiscard.java b/forge-game/src/main/java/forge/game/replacement/ReplaceDiscard.java
index e761d06540e..25bde9c0c6e 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceDiscard.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceDiscard.java
@@ -17,6 +17,7 @@
*/
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
@@ -42,24 +43,24 @@ public class ReplaceDiscard extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
+ public boolean canReplace(Map runParams) {
if (hasParam("ValidPlayer")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
return false;
}
}
if (hasParam("ValidCard")) {
- if (!matchesValid(runParams.get("Card"), getParam("ValidCard").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Card), getParam("ValidCard").split(","), this.getHostCard())) {
return false;
}
}
if (hasParam("ValidSource")) {
- if (!matchesValid(runParams.get("Source"), getParam("ValidSource").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Source), getParam("ValidSource").split(","), this.getHostCard())) {
return false;
}
}
if (hasParam("DiscardFromEffect")) {
- if (null == runParams.get("Source")) {
+ if (null == runParams.get(AbilityKey.Source)) {
return false;
}
}
@@ -71,10 +72,10 @@ public class ReplaceDiscard extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("Card", runParams.get("Card"));
- sa.setReplacingObject("Player", runParams.get("Affected"));
- sa.setReplacingObject("Source", runParams.get("Source"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Card));
+ sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
+ sa.setReplacingObject(AbilityKey.Source, runParams.get(AbilityKey.Source));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceDraw.java b/forge-game/src/main/java/forge/game/replacement/ReplaceDraw.java
index 7a32b0b30d0..9dbaf529cad 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceDraw.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceDraw.java
@@ -17,6 +17,7 @@
*/
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
@@ -44,14 +45,14 @@ public class ReplaceDraw extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
+ public boolean canReplace(Map runParams) {
if (hasParam("ValidPlayer")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
return false;
}
}
if (hasParam("NotFirstCardInDrawStep")) {
- final Player p = (Player)runParams.get("Affected");
+ final Player p = (Player)runParams.get(AbilityKey.Affected);
if (p.numDrawnThisDrawStep() == 0
&& this.getHostCard().getGame().getPhaseHandler().is(PhaseType.DRAW)
&& this.getHostCard().getGame().getPhaseHandler().isPlayerTurn(p)) {
@@ -68,7 +69,7 @@ public class ReplaceDraw extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("Player", runParams.get("Affected"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceDrawCards.java b/forge-game/src/main/java/forge/game/replacement/ReplaceDrawCards.java
index ca486aa3e64..fecf53a8bf2 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceDrawCards.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceDrawCards.java
@@ -17,6 +17,7 @@
*/
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
import forge.util.Expressions;
@@ -43,14 +44,14 @@ public class ReplaceDrawCards extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
+ public boolean canReplace(Map runParams) {
if (hasParam("ValidPlayer")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
return false;
}
}
if (hasParam("Number")) {
- final int n = (Integer)runParams.get("Number");
+ final int n = (Integer)runParams.get(AbilityKey.Number);
String comparator = getParam("Number");
final String operator = comparator.substring(0, 2);
final int operandValue = Integer.parseInt(comparator.substring(2));
@@ -68,7 +69,7 @@ public class ReplaceDrawCards extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("Player", runParams.get("Affected"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceGainLife.java b/forge-game/src/main/java/forge/game/replacement/ReplaceGainLife.java
index c026bd4ff38..083ad7b23d2 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceGainLife.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceGainLife.java
@@ -17,6 +17,7 @@
*/
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
@@ -42,22 +43,22 @@ public class ReplaceGainLife extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
- if (((int)runParams.get("LifeGained")) <= 0) {
+ public boolean canReplace(Map runParams) {
+ if (((int)runParams.get(AbilityKey.LifeGained)) <= 0) {
return false;
}
if (hasParam("ValidPlayer")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
return false;
}
}
if (hasParam("ValidSource")) {
- if (!matchesValid(runParams.get("Source"), getParam("ValidSource").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Source), getParam("ValidSource").split(","), this.getHostCard())) {
return false;
}
}
if ("True".equals(getParam("SourceController"))) {
- if (runParams.get("Source") == null || !runParams.get("Affected").equals(((Card)runParams.get("Source")).getController())) {
+ if (runParams.get(AbilityKey.Source) == null || !runParams.get(AbilityKey.Affected).equals(((Card)runParams.get(AbilityKey.Source)).getController())) {
return false;
}
}
@@ -69,9 +70,9 @@ public class ReplaceGainLife extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("LifeGained", runParams.get("LifeGained"));
- sa.setReplacingObject("Player", runParams.get("Affected"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.LifeGained, runParams.get(AbilityKey.LifeGained));
+ sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceGameLoss.java b/forge-game/src/main/java/forge/game/replacement/ReplaceGameLoss.java
index 0cb784588e5..3860af6c119 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceGameLoss.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceGameLoss.java
@@ -1,5 +1,6 @@
package forge.game.replacement;
+ import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import java.util.Map;
@@ -24,9 +25,9 @@ public class ReplaceGameLoss extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
+ public boolean canReplace(Map runParams) {
if (hasParam("ValidPlayer")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
return false;
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceMoved.java b/forge-game/src/main/java/forge/game/replacement/ReplaceMoved.java
index 650b0e82085..ee295efe59d 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceMoved.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceMoved.java
@@ -1,5 +1,6 @@
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.player.Player;
@@ -28,9 +29,9 @@ public class ReplaceMoved extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
+ public boolean canReplace(Map runParams) {
final Player controller = getHostCard().getController();
- final Card affected = (Card) runParams.get("Affected");
+ final Card affected = (Card) runParams.get(AbilityKey.Affected);
if (hasParam("ValidCard")) {
if (!matchesValid(affected, getParam("ValidCard").split(","), getHostCard())) {
@@ -39,27 +40,27 @@ public class ReplaceMoved extends ReplacementEffect {
}
if (hasParam("ValidLKI")) {
- if (!matchesValid(runParams.get("CardLKI"), getParam("ValidLKI").split(","), getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.CardLKI), getParam("ValidLKI").split(","), getHostCard())) {
return false;
}
}
if (hasParam("Origin")) {
- ZoneType zt = (ZoneType) runParams.get("Origin");
+ ZoneType zt = (ZoneType) runParams.get(AbilityKey.Origin);
if (!ZoneType.listValueOf(getParam("Origin")).contains(zt)) {
return false;
}
}
if (hasParam("Destination")) {
- ZoneType zt = (ZoneType) runParams.get("Destination");
+ ZoneType zt = (ZoneType) runParams.get(AbilityKey.Destination);
if (!ZoneType.listValueOf(getParam("Destination")).contains(zt)) {
return false;
}
}
if (hasParam("ExcludeDestination")) {
- ZoneType zt = (ZoneType) runParams.get("Destination");
+ ZoneType zt = (ZoneType) runParams.get(AbilityKey.Destination);
if (ZoneType.listValueOf(getParam("ExcludeDestination")).contains(zt)) {
return false;
}
@@ -67,29 +68,29 @@ public class ReplaceMoved extends ReplacementEffect {
if (hasParam("Fizzle")) {
// if Replacement look for Fizzle
- if (!runParams.containsKey("Fizzle")) {
+ if (!runParams.containsKey(AbilityKey.Fizzle)) {
return false;
}
- Boolean val = (Boolean) runParams.get("Fizzle");
+ Boolean val = (Boolean) runParams.get(AbilityKey.Fizzle);
if ("True".equals(getParam("Fizzle")) != val) {
return false;
}
}
if (hasParam("ValidStackSa")) {
- if (!runParams.containsKey("StackSa")) {
+ if (!runParams.containsKey(AbilityKey.StackSa)) {
return false;
}
- if (!((SpellAbility)runParams.get("StackSa")).isValid(getParam("ValidStackSa").split(","), getHostCard().getController(), getHostCard(), null)) {
+ if (!((SpellAbility)runParams.get(AbilityKey.StackSa)).isValid(getParam("ValidStackSa").split(","), getHostCard().getController(), getHostCard(), null)) {
return false;
}
}
if (hasParam("Cause")) {
- if (!runParams.containsKey("Cause")) {
+ if (!runParams.containsKey(AbilityKey.Cause)) {
return false;
}
- SpellAbility cause = (SpellAbility) runParams.get("Cause");
+ SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause);
if (cause == null) {
return false;
}
@@ -99,8 +100,8 @@ public class ReplaceMoved extends ReplacementEffect {
}
if (hasParam("NotCause")) {
- if (runParams.containsKey("Cause")) {
- SpellAbility cause = (SpellAbility) runParams.get("Cause");
+ if (runParams.containsKey(AbilityKey.Cause)) {
+ SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause);
if (cause != null) {
if (cause.isValid(getParam("NotCause").split(","), controller, getHostCard(), null)) {
return false;
@@ -116,10 +117,10 @@ public class ReplaceMoved extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("Card", runParams.get("Affected"));
- sa.setReplacingObject("CardLKI", runParams.get("CardLKI"));
- sa.setReplacingObject("Cause", runParams.get("Cause"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected));
+ sa.setReplacingObject(AbilityKey.CardLKI, runParams.get(AbilityKey.CardLKI));
+ sa.setReplacingObject(AbilityKey.Cause, runParams.get(AbilityKey.Cause));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceProduceMana.java b/forge-game/src/main/java/forge/game/replacement/ReplaceProduceMana.java
index 3cfc1f92d81..13e8b68f782 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceProduceMana.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceProduceMana.java
@@ -1,5 +1,6 @@
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardFactoryUtil;
import forge.game.spellability.SpellAbility;
@@ -29,10 +30,10 @@ public class ReplaceProduceMana extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
+ public boolean canReplace(Map runParams) {
//Check for tapping
if (!hasParam("NoTapCheck")) {
- final SpellAbility manaAbility = (SpellAbility) runParams.get("AbilityMana");
+ final SpellAbility manaAbility = (SpellAbility) runParams.get(AbilityKey.AbilityMana);
if (manaAbility == null || manaAbility.getRootAbility().getPayCosts() == null || !manaAbility.getRootAbility().getPayCosts().hasTapCost()) {
return false;
}
@@ -48,14 +49,14 @@ public class ReplaceProduceMana extends ReplacementEffect {
} catch (NumberFormatException e) {
intoperand = CardFactoryUtil.xCount(getHostCard(), getHostCard().getSVar(operand));
}
- int manaAmount = StringUtils.countMatches((String) runParams.get("Mana"), " ") + 1;
+ int manaAmount = StringUtils.countMatches((String) runParams.get(AbilityKey.Mana), " ") + 1;
if (!Expressions.compare(manaAmount, operator, intoperand)) {
return false;
}
}
if (hasParam("ValidCard")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) {
return false;
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceSetInMotion.java b/forge-game/src/main/java/forge/game/replacement/ReplaceSetInMotion.java
index d74b1171dad..1b2b39f382b 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceSetInMotion.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceSetInMotion.java
@@ -17,6 +17,7 @@
*/
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import java.util.Map;
@@ -41,9 +42,9 @@ public class ReplaceSetInMotion extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
+ public boolean canReplace(Map runParams) {
if (hasParam("ValidPlayer")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), getHostCard())) {
return false;
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceSurveil.java b/forge-game/src/main/java/forge/game/replacement/ReplaceSurveil.java
index 3ee74291981..e7b8440e0b5 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceSurveil.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceSurveil.java
@@ -1,5 +1,6 @@
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
@@ -25,13 +26,13 @@ public class ReplaceSurveil extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.Map)
*/
@Override
- public boolean canReplace(Map runParams) {
- if (((int) runParams.get("SurveilNum")) <= 0) {
+ public boolean canReplace(Map runParams) {
+ if (((int) runParams.get(AbilityKey.SurveilNum)) <= 0) {
return false;
}
if (hasParam("ValidPlayer")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
return false;
}
}
@@ -43,9 +44,9 @@ public class ReplaceSurveil extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("Player", runParams.get("Affected"));
- sa.setReplacingObject("SurveilNum", runParams.get("SurveilNum"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
+ sa.setReplacingObject(AbilityKey.SurveilNum, runParams.get(AbilityKey.SurveilNum));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java b/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java
index fc6bb5ef15c..7204edfdcbe 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java
@@ -1,5 +1,6 @@
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
@@ -25,27 +26,27 @@ public class ReplaceToken extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.Map)
*/
@Override
- public boolean canReplace(Map runParams) {
- if (((int) runParams.get("TokenNum")) <= 0) {
+ public boolean canReplace(Map runParams) {
+ if (((int) runParams.get(AbilityKey.TokenNum)) <= 0) {
return false;
}
if (hasParam("EffectOnly")) {
- final Boolean effectOnly = (Boolean) runParams.get("EffectOnly");
+ final Boolean effectOnly = (Boolean) runParams.get(AbilityKey.EffectOnly);
if (!effectOnly) {
return false;
}
}
if (hasParam("ValidPlayer")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), getHostCard())) {
return false;
}
}
if (hasParam("ValidToken")) {
- if (runParams.containsKey("Token")) {
- if (!matchesValid(runParams.get("Token"), getParam("ValidToken").split(","), getHostCard())) {
+ if (runParams.containsKey(AbilityKey.Token)) {
+ if (!matchesValid(runParams.get(AbilityKey.Token), getParam("ValidToken").split(","), getHostCard())) {
return false;
}
} else {
@@ -61,9 +62,9 @@ public class ReplaceToken extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("TokenNum", runParams.get("TokenNum"));
- sa.setReplacingObject("Player", runParams.get("Affected"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.TokenNum, runParams.get(AbilityKey.TokenNum));
+ sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceTurnFaceUp.java b/forge-game/src/main/java/forge/game/replacement/ReplaceTurnFaceUp.java
index a2c78959de3..3f433f38916 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceTurnFaceUp.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceTurnFaceUp.java
@@ -1,5 +1,6 @@
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
@@ -25,9 +26,9 @@ public class ReplaceTurnFaceUp extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
+ public boolean canReplace(Map runParams) {
if (hasParam("ValidCard")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) {
return false;
}
}
@@ -38,8 +39,8 @@ public class ReplaceTurnFaceUp extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("Card", runParams.get("Affected"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceUntap.java b/forge-game/src/main/java/forge/game/replacement/ReplaceUntap.java
index 7e4168f1281..d52c65e75b8 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplaceUntap.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceUntap.java
@@ -17,6 +17,7 @@
*/
package forge.game.replacement;
+import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.phase.PhaseType;
@@ -44,14 +45,14 @@ public class ReplaceUntap extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
- public boolean canReplace(Map runParams) {
+ public boolean canReplace(Map runParams) {
if (hasParam("ValidCard")) {
- if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) {
return false;
}
}
if (hasParam("UntapStep")) {
- final Object o = runParams.get("Affected");
+ final Object o = runParams.get(AbilityKey.Affected);
//normally should not happen, but protect from possible crash.
if (!(o instanceof Card)) {
return false;
@@ -72,8 +73,8 @@ public class ReplaceUntap extends ReplacementEffect {
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
- public void setReplacingObjects(Map runParams, SpellAbility sa) {
- sa.setReplacingObject("Card", runParams.get("Affected"));
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected));
}
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java b/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java
index 0c23c297da5..a3989336f0a 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java
@@ -19,6 +19,7 @@ package forge.game.replacement;
import forge.game.Game;
import forge.game.TriggerReplacementBase;
+import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.phase.PhaseType;
@@ -121,7 +122,7 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
* the run params
* @return true, if successful
*/
- public abstract boolean canReplace(final Map runParams);
+ public abstract boolean canReplace (final Map runParams);
/**
*
@@ -198,13 +199,11 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
/**
* Sets the replacing objects.
- *
- * @param runParams
+ * @param runParams
* the run params
* @param spellAbility
- * the SpellAbility
*/
- public void setReplacingObjects(final Map runParams, final SpellAbility spellAbility) {
+ public void setReplacingObjects(final Map runParams, final SpellAbility spellAbility) {
// Should be overridden by replacers that need it.
}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java
index 04f1e61cbda..cba94673457 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java
@@ -21,10 +21,14 @@ import forge.card.MagicColor;
import forge.game.Game;
import forge.game.GameLogEntryType;
import forge.game.ability.AbilityFactory;
+import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
+import forge.game.card.CardTraitChanges;
import forge.game.card.CardUtil;
+import forge.game.keyword.KeywordInterface;
+import forge.game.keyword.KeywordsChange;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.Zone;
@@ -42,6 +46,8 @@ import java.util.*;
public class ReplacementHandler {
private final Game game;
+
+ private Set hasRun = Sets.newHashSet();
/**
* ReplacementHandler.
* @param gameState
@@ -52,57 +58,82 @@ public class ReplacementHandler {
//private final List tmpEffects = new ArrayList();
- public ReplacementResult run(ReplacementType event, final Map runParams) {
- final Object affected = runParams.get("Affected");
- Player decider = null;
-
- // Figure out who decides which of multiple replacements to apply
- // as well as whether or not to apply optional replacements.
- if (affected instanceof Player) {
- decider = (Player) affected;
- } else {
- decider = ((Card) affected).getController();
- }
-
- // try out all layer
- for (ReplacementLayer layer : ReplacementLayer.values()) {
- ReplacementResult res = run(event, runParams, layer, decider);
- if (res != ReplacementResult.NotReplaced) {
- return res;
- }
- }
-
- return ReplacementResult.NotReplaced;
-
- }
-
- public List getReplacementList(final ReplacementType event, final Map runParams, final ReplacementLayer layer) {
+ public List getReplacementList(final ReplacementType event, final Map runParams, final ReplacementLayer layer) {
final CardCollection preList = new CardCollection();
boolean checkAgain = false;
Card affectedLKI = null;
Card affectedCard = null;
- if (ReplacementType.Moved.equals(event) && ZoneType.Battlefield.equals(runParams.get("Destination"))) {
+ if (ReplacementType.Moved.equals(event) && ZoneType.Battlefield.equals(runParams.get(AbilityKey.Destination))) {
// if it was caused by an replacement effect, use the already calculated RE list
// otherwise the RIOT card would cause a StackError
- SpellAbility cause = (SpellAbility) runParams.get("Cause");
+ SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause);
if (cause != null && cause.isReplacementAbility()) {
final ReplacementEffect re = cause.getReplacementEffect();
// only return for same layer
if (ReplacementType.Moved.equals(re.getMode()) && layer.equals(re.getLayer())) {
- return re.getOtherChoices();
+ if (!re.getOtherChoices().isEmpty())
+ return re.getOtherChoices();
}
}
// Rule 614.12 Enter the Battlefield Replacement Effects look at what the card would be on the battlefield
- affectedCard = (Card) runParams.get("Affected");
+ affectedCard = (Card) runParams.get(AbilityKey.Affected);
affectedLKI = CardUtil.getLKICopy(affectedCard);
affectedLKI.setLastKnownZone(affectedCard.getController().getZone(ZoneType.Battlefield));
preList.add(affectedLKI);
game.getAction().checkStaticAbilities(false, Sets.newHashSet(affectedLKI), preList);
checkAgain = true;
- runParams.put("Affected", affectedLKI);
+
+ // need to check if Intrinsic has run
+ for (ReplacementEffect re : affectedLKI.getReplacementEffects()) {
+ if (re.isIntrinsic() && this.hasRun.contains(re)) {
+ re.setHasRun(true);
+ }
+ }
+
+ // need to check non Intrinsic
+ for (Map.Entry e : affectedLKI.getChangedCardTraits().entrySet()) {
+ boolean hasRunRE = false;
+ String skey = String.valueOf(e.getKey());
+
+ for (ReplacementEffect re : this.hasRun) {
+ if (!re.isIntrinsic() && skey.equals(re.getSVar("_ReplacedTimestamp"))) {
+ hasRunRE = true;
+ break;
+ }
+ }
+
+ for (ReplacementEffect re : e.getValue().getReplacements()) {
+ re.setSVar("_ReplacedTimestamp", skey);
+ if (hasRunRE) {
+ re.setHasRun(true);
+ }
+ }
+ }
+ for (Map.Entry e : affectedLKI.getChangedCardKeywords().entrySet()) {
+ boolean hasRunRE = false;
+ String skey = String.valueOf(e.getKey());
+
+ for (ReplacementEffect re : this.hasRun) {
+ if (!re.isIntrinsic() && skey.equals(re.getSVar("_ReplacedTimestamp"))) {
+ hasRunRE = true;
+ break;
+ }
+ }
+
+ for (KeywordInterface k : e.getValue().getKeywords()) {
+ for (ReplacementEffect re : k.getReplacements()) {
+ re.setSVar("_ReplacedTimestamp", skey);
+ if (hasRunRE) {
+ re.setHasRun(true);
+ }
+ }
+ }
+ }
+
+ runParams.put(AbilityKey.Affected, affectedLKI);
}
final List possibleReplacers = Lists.newArrayList();
@@ -157,7 +188,7 @@ public class ReplacementHandler {
for (final ReplacementEffect re : affectedLKI.getReplacementEffects()) {
re.setHostCard(affectedCard);
}
- runParams.put("Affected", affectedCard);
+ runParams.put(AbilityKey.Affected, affectedCard);
}
game.getAction().checkStaticAbilities(false);
}
@@ -171,20 +202,45 @@ public class ReplacementHandler {
*
* @param runParams
* the run params,same as for triggers.
- * @return true if the event was replaced.
+ * @return ReplacementResult, an enum that represents what happened to the replacement effect.
*/
- public ReplacementResult run(final ReplacementType event, final Map runParams, final ReplacementLayer layer, final Player decider) {
+ public ReplacementResult run(ReplacementType event, final Map runParams) {
+ final Object affected = runParams.get(AbilityKey.Affected);
+ Player decider = null;
+
+ // Figure out who decides which of multiple replacements to apply
+ // as well as whether or not to apply optional replacements.
+ if (affected instanceof Player) {
+ decider = (Player) affected;
+ } else {
+ decider = ((Card) affected).getController();
+ }
+
+ // try out all layer
+ for (ReplacementLayer layer : ReplacementLayer.values()) {
+ ReplacementResult res = run(event, runParams, layer, decider);
+ if (res != ReplacementResult.NotReplaced) {
+ return res;
+ }
+ }
+
+ return ReplacementResult.NotReplaced;
+
+ }
+
+ private ReplacementResult run(final ReplacementType event, final Map