builder()
- .add("TokenScript", "LegacyImage", "TokenImage", "NewName", "ChooseFromList").build();
+ .add("TokenScript", "LegacyImage", "TokenImage", "NewName", "ChooseFromList")
+ .add("AddAbility").build();
/**
*
@@ -259,6 +257,18 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
}
if (params.containsKey("Revolt")) {
if ("True".equalsIgnoreCase(params.get("Revolt")) != hostController.hasRevolt()) return false;
+ else if ("None".equalsIgnoreCase(params.get("Revolt"))) {
+ boolean none = true;
+ for (Player p : game.getRegisteredPlayers()) {
+ if (p.hasRevolt()) {
+ none = false;
+ break;
+ }
+ }
+ if (!none) {
+ return false;
+ }
+ }
}
if (params.containsKey("Desert")) {
if ("True".equalsIgnoreCase(params.get("Desert")) != hostController.hasDesert()) return false;
@@ -422,6 +432,16 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
if (!Expressions.compare(sVar, svarOperator, operandValue)) {
return false;
}
+ if (hasParam("CheckSecondSVar")) {
+ final int sVar2 = AbilityUtils.calculateAmount(this.hostCard, getParam("CheckSecondSVar"), this);
+ final String comparator2 = getParamOrDefault("SecondSVarCompare", "GE1");
+ final String svarOperator2 = comparator2.substring(0, 2);
+ final String svarOperand2 = comparator2.substring(2);
+ final int operandValue2 = AbilityUtils.calculateAmount(this.hostCard, svarOperand2, this);
+ if (!Expressions.compare(sVar2, svarOperator2, operandValue2)) {
+ return false;
+ }
+ }
}
if (params.containsKey("ManaSpent")) {
@@ -489,11 +509,6 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
} else if (descriptiveKeys.contains(key)) {
// change descriptions differently
newValue = AbilityUtils.applyDescriptionTextChangeEffects(value, this);
- } else if (mutableKeys.contains(key)) {
- // follow SVar and change it
- final String originalSVarValue = hostCard.getSVar(value);
- hostCard.changeSVar(value, AbilityUtils.applyAbilityTextChangeEffects(originalSVarValue, this));
- newValue = null;
} else if (this.getHostCard().hasSVar(value)) {
// don't change literal SVar names!
newValue = null;
diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java
index 919e35d914f..8e650d1ae22 100644
--- a/forge-game/src/main/java/forge/game/GameAction.java
+++ b/forge-game/src/main/java/forge/game/GameAction.java
@@ -233,13 +233,6 @@ public class GameAction {
}
}
- // Clean up the temporary Dash/Blitz SVar when the card leaves the battlefield
- // Clean up the temporary AtEOT SVar
- String endofTurn = c.getSVar("EndOfTurnLeavePlay");
- if (fromBattlefield && (endofTurn.equals("Dash") || endofTurn.equals("Blitz") || endofTurn.equals("AtEOT"))) {
- c.removeSVar("EndOfTurnLeavePlay");
- }
-
if (fromBattlefield && !toBattlefield) {
c.getController().setRevolt(true);
}
@@ -337,7 +330,7 @@ public class GameAction {
CardCollectionView comCards = c.getOwner().getCardsIn(ZoneType.Command);
for (final Card effCard : comCards) {
for (final ReplacementEffect re : effCard.getReplacementEffects()) {
- if (re.hasSVar("CommanderMoveReplacement") && effCard.getEffectSource().getName().equals(c.getRealCommander().getName())) {
+ if (re.hasParam("CommanderMoveReplacement") && effCard.getEffectSource().getName().equals(c.getRealCommander().getName())) {
commanderEffect = effCard;
break;
}
@@ -365,7 +358,7 @@ public class GameAction {
}
ReplacementResult repres = game.getReplacementHandler().run(ReplacementType.Moved, repParams);
- if (repres != ReplacementResult.NotReplaced) {
+ if (repres != ReplacementResult.NotReplaced && repres != ReplacementResult.Updated) {
// reset failed manifested Cards back to original
if (c.isManifested() && !c.isInPlay()) {
c.forceTurnFaceUp();
diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java
index 3f563ff302a..addc8e311c9 100644
--- a/forge-game/src/main/java/forge/game/GameActionUtil.java
+++ b/forge-game/src/main/java/forge/game/GameActionUtil.java
@@ -677,13 +677,12 @@ public final class GameActionUtil {
if (!StringUtils.isNumeric(amount)) {
sa.setSVar(amount, sourceCard.getSVar(amount));
}
- CardFactoryUtil.setupETBReplacementAbility(sa);
String desc = "It enters the battlefield with ";
desc += Lang.nounWithNumeral(amount, CounterType.getType(counter).getName() + " counter");
desc += " on it.";
- String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
+ String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | ReplacementResult$ Updated | Description$ " + desc;
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
re.setLayer(ReplacementLayer.Other);
diff --git a/forge-game/src/main/java/forge/game/StaticEffect.java b/forge-game/src/main/java/forge/game/StaticEffect.java
index 05bed4adb7a..639f13588cd 100644
--- a/forge-game/src/main/java/forge/game/StaticEffect.java
+++ b/forge-game/src/main/java/forge/game/StaticEffect.java
@@ -288,6 +288,8 @@ public class StaticEffect {
affectedCard.removeCanBlockAdditional(getTimestamp());
}
+ affectedCard.removeChangedSVars(getTimestamp(), ability.getId());
+
affectedCard.updateAbilityTextForView(); // only update keywords and text for view to avoid flickering
}
return affectedCards;
diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java
index 1f748ff53b2..5461441ab2d 100644
--- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java
+++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java
@@ -55,6 +55,7 @@ import forge.game.phase.PhaseHandler;
import forge.game.player.Player;
import forge.game.player.PlayerCollection;
import forge.game.player.PlayerPredicates;
+import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.LandAbility;
import forge.game.spellability.OptionalCost;
@@ -217,10 +218,15 @@ public class AbilityUtils {
else if (defined.startsWith("Replaced") && sa instanceof SpellAbility) {
final SpellAbility root = ((SpellAbility)sa).getRootAbility();
AbilityKey type = AbilityKey.fromString(defined.substring(8));
+ // for Moved Effects, if it wants to know the affected Card, it might need to return the LKI
+ // or otherwise the timestamp does match
+ if (type == AbilityKey.Card && root.isReplacementAbility() && root.getReplacementEffect().getMode() == ReplacementType.Moved) {
+ type = AbilityKey.CardLKI;
+ }
final Object crd = root.getReplacingObject(type);
if (crd instanceof Card) {
- c = game.getCardState((Card) crd);
+ c = (Card) crd;
} else if (crd instanceof Iterable>) {
cards.addAll(Iterables.filter((Iterable>) crd, Card.class));
}
@@ -1415,11 +1421,7 @@ public class AbilityUtils {
// Needed - Equip an untapped creature with Sword of the Paruns then cast Deadshot on it. Should deal 2 more damage.
game.getAction().checkStaticAbilities(); // this will refresh continuous abilities for players and permanents.
- if (sa.isReplacementAbility() && abSub.getApi() == ApiType.InternalEtbReplacement) {
- game.getTriggerHandler().resetActiveTriggers(false);
- } else {
- game.getTriggerHandler().resetActiveTriggers();
- }
+ game.getTriggerHandler().resetActiveTriggers(!sa.isReplacementAbility());
AbilityUtils.resolveApiAbility(abSub, game);
}
diff --git a/forge-game/src/main/java/forge/game/ability/ApiType.java b/forge-game/src/main/java/forge/game/ability/ApiType.java
index f09b5b5fffa..9016ad5f03b 100644
--- a/forge-game/src/main/java/forge/game/ability/ApiType.java
+++ b/forge-game/src/main/java/forge/game/ability/ApiType.java
@@ -189,7 +189,6 @@ public enum ApiType {
DamageResolve (DamageResolveEffect.class),
ChangeZoneResolve (ChangeZoneResolveEffect.class),
- InternalEtbReplacement (ETBReplacementEffect.class),
InternalLegendaryRule (CharmEffect.class),
InternalIgnoreEffect (CharmEffect.class),
UpdateRemember (UpdateRememberEffect.class);
diff --git a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java
index da91b969bef..9cd9c20eade 100644
--- a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java
@@ -300,13 +300,12 @@ public abstract class SpellAbilityEffect {
delTrig.append("| TriggerDescription$ ").append(desc);
final Trigger trig = TriggerHandler.parseTrigger(delTrig.toString(), CardUtil.getLKICopy(sa.getHostCard()), intrinsic);
+ long ts = sa.getHostCard().getGame().getNextTimestamp();
for (final Card c : crds) {
trig.addRemembered(c);
// Svar for AI
- if (!c.hasSVar("EndOfTurnLeavePlay")) {
- c.setSVar("EndOfTurnLeavePlay", "AtEOT");
- }
+ c.addChangedSVars(Collections.singletonMap("EndOfTurnLeavePlay", "AtEOT"), ts, 0);
}
String trigSA = "";
if (location.equals("Hand")) {
@@ -346,9 +345,7 @@ public abstract class SpellAbilityEffect {
card.addTrigger(trig);
// Svar for AI
- if (!card.hasSVar("EndOfTurnLeavePlay")) {
- card.setSVar("EndOfTurnLeavePlay", "AtEOT");
- }
+ card.addChangedSVars(Collections.singletonMap("EndOfTurnLeavePlay", "AtEOT"), card.getGame().getNextTimestamp(), 0);
}
protected static SpellAbility getForgetSpellAbility(final Card card) {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/AnimateAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AnimateAllEffect.java
index efd631c5773..d79bb6d4502 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/AnimateAllEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/AnimateAllEffect.java
@@ -1,10 +1,12 @@
package forge.game.ability.effects;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import forge.GameCommand;
import forge.card.CardType;
@@ -64,17 +66,17 @@ public class AnimateAllEffect extends AnimateEffectBase {
types.add(host.getChosenType2());
}
- final List keywords = new ArrayList<>();
+ final List keywords = Lists.newArrayList();
if (sa.hasParam("Keywords")) {
keywords.addAll(Arrays.asList(sa.getParam("Keywords").split(" & ")));
}
- final List removeKeywords = new ArrayList<>();
+ final List removeKeywords = Lists.newArrayList();
if (sa.hasParam("RemoveKeywords")) {
removeKeywords.addAll(Arrays.asList(sa.getParam("RemoveKeywords").split(" & ")));
}
- final List hiddenKeywords = new ArrayList<>();
+ final List hiddenKeywords = Lists.newArrayList();
if (sa.hasParam("HiddenKeywords")) {
hiddenKeywords.addAll(Arrays.asList(sa.getParam("HiddenKeywords").split(" & ")));
}
@@ -99,27 +101,32 @@ public class AnimateAllEffect extends AnimateEffectBase {
}
// abilities to add to the animated being
- final List abilities = new ArrayList<>();
+ final List abilities = Lists.newArrayList();
if (sa.hasParam("Abilities")) {
abilities.addAll(Arrays.asList(sa.getParam("Abilities").split(",")));
}
// replacement effects to add to the animated being
- final List replacements = new ArrayList<>();
+ final List replacements = Lists.newArrayList();
if (sa.hasParam("Replacements")) {
replacements.addAll(Arrays.asList(sa.getParam("Replacements").split(",")));
}
// triggers to add to the animated being
- final List triggers = new ArrayList<>();
+ final List triggers = Lists.newArrayList();
if (sa.hasParam("Triggers")) {
triggers.addAll(Arrays.asList(sa.getParam("Triggers").split(",")));
}
// sVars to add to the animated being
- final List sVars = new ArrayList<>();
+ final List sVars = Lists.newArrayList();
if (sa.hasParam("sVars")) {
sVars.addAll(Arrays.asList(sa.getParam("sVars").split(",")));
}
+ Map sVarsMap = Maps.newHashMap();
+ for (final String s : sVars) {
+ sVarsMap.put(s, AbilityUtils.getSVar(sa, s));
+ }
+
final String valid = sa.getParamOrDefault("ValidCards", "");
CardCollectionView list;
@@ -139,9 +146,10 @@ public class AnimateAllEffect extends AnimateEffectBase {
timestamp);
// give sVars
- for (final String s : sVars) {
- c.setSVar(s, AbilityUtils.getSVar(sa, s));
+ if (!sVarsMap.isEmpty() ) {
+ c.addChangedSVars(sVarsMap, timestamp, 0);
}
+
game.fireEvent(new GameEventCardStatsChanged(c));
final GameCommand unanimate = new GameCommand() {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java
index f2c37658ead..bc166d03de7 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java
@@ -2,7 +2,9 @@ package forge.game.ability.effects;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
+import com.google.common.collect.Maps;
import com.google.common.collect.Lists;
import forge.card.CardType;
@@ -138,11 +140,22 @@ public class AnimateEffect extends AnimateEffectBase {
}
// sVars to add to the animated being
- final List sVars = Lists.newArrayList();
+ Map sVarsMap = Maps.newHashMap();
if (sa.hasParam("sVars")) {
- sVars.addAll(Arrays.asList(sa.getParam("sVars").split(",")));
+ for (final String s : sa.getParam("sVars").split(",")) {
+ String actualsVar = AbilityUtils.getSVar(sa, s);
+ String name = s;
+ if (actualsVar.startsWith("SVar:")) {
+ actualsVar = actualsVar.split("SVar:")[1];
+ name = actualsVar.split(":")[0];
+ actualsVar = actualsVar.split(":")[1];
+ }
+ sVarsMap.put(name, actualsVar);
+ }
}
+
+
List tgts = getCardsfromTargets(sa);
if (sa.hasParam("Optional")) {
@@ -166,15 +179,8 @@ public class AnimateEffect extends AnimateEffectBase {
}
// give sVars
- for (final String s : sVars) {
- String actualsVar = AbilityUtils.getSVar(sa, s);
- String name = s;
- if (actualsVar.startsWith("SVar:")) {
- actualsVar = actualsVar.split("SVar:")[1];
- name = actualsVar.split(":")[0];
- actualsVar = actualsVar.split(":")[1];
- }
- c.setSVar(name, actualsVar);
+ if (!sVarsMap.isEmpty()) {
+ c.addChangedSVars(sVarsMap, timestamp, 0);
}
// give Remembered
diff --git a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java
index 70ac1823195..6df27fae809 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java
@@ -137,6 +137,7 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
public void run() {
doUnanimate(c, timestamp);
+ c.removeChangedSVars(timestamp, 0);
c.removeChangedName(timestamp, 0);
c.updateStateForView();
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java
index a62b98dc667..c3d65a43026 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java
@@ -21,7 +21,7 @@ import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetRestrictions;
import forge.util.CardTranslation;
import forge.util.Localizer;
-import forge.util.collect.FCollectionView;
+import forge.util.collect.FCollection;
public class ChangeCombatantsEffect extends SpellAbilityEffect {
@@ -47,7 +47,8 @@ public class ChangeCombatantsEffect extends SpellAbilityEffect {
if ((tgt == null) || c.canBeTargetedBy(sa)) {
final Combat combat = game.getCombat();
final GameEntity originalDefender = combat.getDefenderByAttacker(c);
- final FCollectionView defs = combat.getDefenders();
+ final FCollection defs = new FCollection<>();
+ defs.addAll(sa.hasParam("PlayerOnly") ? combat.getDefendingPlayers() : combat.getDefenders());
String title = Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName()));
Map params = Maps.newHashMap();
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java
index 28881ebb355..a7133e10f6a 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java
@@ -1,5 +1,9 @@
package forge.game.ability.effects;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
import com.google.common.collect.Lists;
import forge.GameCommand;
@@ -16,9 +20,6 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Localizer;
-import java.util.Arrays;
-import java.util.List;
-
public class ControlGainEffect extends SpellAbilityEffect {
@Override
@@ -210,11 +211,11 @@ public class ControlGainEffect extends SpellAbilityEffect {
}
if (lose.contains("EOT")) {
game.getEndOfTurn().addUntil(loseControl);
- tgtC.setSVar("SacMe", "6");
+ tgtC.addChangedSVars(Collections.singletonMap("SacMe", "6"), tStamp, 0);
}
if (lose.contains("EndOfCombat")) {
game.getEndOfCombat().addUntil(loseControl);
- tgtC.setSVar("SacMe", "6");
+ tgtC.addChangedSVars(Collections.singletonMap("SacMe", "6"), tStamp, 0);
}
if (lose.contains("StaticCommandCheck")) {
String leftVar = sa.getSVar(sa.getParam("StaticCommandCheckSVar"));
@@ -276,7 +277,7 @@ public class ControlGainEffect extends SpellAbilityEffect {
@Override
public void run() {
doLoseControl(c, hostCard, bTapOnLose, tStamp);
- c.removeSVar("SacMe");
+ c.removeChangedSVars(tStamp, 0);
}
};
diff --git a/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java
index 6591ceaeb6e..bb1d424d7f6 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java
@@ -299,7 +299,7 @@ public class DamageDealEffect extends DamageBaseEffect {
} else {
damageMap.put(sourceLKI, c, dmg);
if (sa.hasParam("ExcessSVar")) {
- hostCard.setSVar(sa.getParam("ExcessSVar"), Integer.toString(excess));
+ sa.setSVar(sa.getParam("ExcessSVar"), Integer.toString(excess));
}
}
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ETBReplacementEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ETBReplacementEffect.java
deleted file mode 100644
index 77241fecdac..00000000000
--- a/forge-game/src/main/java/forge/game/ability/effects/ETBReplacementEffect.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package forge.game.ability.effects;
-
-import java.util.Map;
-
-import forge.game.Game;
-import forge.game.ability.AbilityKey;
-import forge.game.ability.SpellAbilityEffect;
-import forge.game.card.Card;
-import forge.game.spellability.SpellAbility;
-
-/**
- * TODO: Write javadoc for this type.
- *
- */
-public class ETBReplacementEffect extends SpellAbilityEffect {
- @Override
- public void resolve(SpellAbility sa) {
- final Game game = sa.getActivatingPlayer().getGame();
- final Card card = (Card) sa.getReplacingObject(AbilityKey.Card);
-
- Map params = AbilityKey.newMap();
- params.put(AbilityKey.CardLKI, sa.getReplacingObject(AbilityKey.CardLKI));
- params.put(AbilityKey.ReplacementEffect, sa.getReplacementEffect());
- params.put(AbilityKey.LastStateBattlefield, sa.getReplacingObject(AbilityKey.LastStateBattlefield));
- params.put(AbilityKey.LastStateGraveyard, sa.getReplacingObject(AbilityKey.LastStateGraveyard));
-
- final SpellAbility root = sa.getRootAbility();
- SpellAbility cause = (SpellAbility) root.getReplacingObject(AbilityKey.Cause);
-
- game.getAction().moveToPlay(card, card.getController(), cause, params);
- }
-}
\ No newline at end of file
diff --git a/forge-game/src/main/java/forge/game/ability/effects/LifeLoseEffect.java b/forge-game/src/main/java/forge/game/ability/effects/LifeLoseEffect.java
index fa1334fffa6..136a70e7c3f 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/LifeLoseEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/LifeLoseEffect.java
@@ -2,7 +2,6 @@ package forge.game.ability.effects;
import forge.game.ability.AbilityUtils;
-import forge.game.ability.ApiType;
import forge.game.ability.SpellAbilityEffect;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -41,14 +40,7 @@ public class LifeLoseEffect extends SpellAbilityEffect {
lifeLost += p.loseLife(lifeAmount, false, false);
}
}
- sa.getHostCard().setSVar("AFLifeLost", "Number$" + lifeLost);
-
- // Exceptional case for Extort: must propagate the amount of life lost to subability,
- // otherwise the first Extort trigger per game won't work
- if (sa.getSubAbility() != null && ApiType.GainLife.equals(sa.getSubAbility().getApi())) {
- sa.getSubAbility().setSVar("AFLifeLost", "Number$" + lifeLost);
- }
-
+ sa.setSVar("AFLifeLost", "Number$" + lifeLost);
}
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/PermanentEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PermanentEffect.java
index ddb356c4da1..e985b309554 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/PermanentEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/PermanentEffect.java
@@ -1,5 +1,6 @@
package forge.game.ability.effects;
+import java.util.Collections;
import java.util.Map;
import com.google.common.collect.Lists;
@@ -42,12 +43,12 @@ public class PermanentEffect extends SpellAbilityEffect {
// some extra for Dashing
if (sa.isDash() && c.isInPlay()) {
- c.setSVar("EndOfTurnLeavePlay", "Dash");
+ c.addChangedSVars(Collections.singletonMap("EndOfTurnLeavePlay", "Dash"), c.getGame().getNextTimestamp(), 0);
registerDelayedTrigger(sa, "Hand", Lists.newArrayList(c));
}
// similar for Blitz keyword
if (sa.isBlitz() && c.isInPlay()) {
- c.setSVar("EndOfTurnLeavePlay", "Blitz");
+ c.addChangedSVars(Collections.singletonMap("EndOfTurnLeavePlay", "Blitz"), c.getGame().getNextTimestamp(), 0);
registerDelayedTrigger(sa, "Sacrifice", Lists.newArrayList(c));
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java
index 2931da09e9f..fb0a99ace99 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java
@@ -126,13 +126,13 @@ public class RollDiceEffect extends SpellAbilityEffect {
total += modifier;
if (sa.hasParam("ResultSVar")) {
- host.setSVar(sa.getParam("ResultSVar"), Integer.toString(total));
+ sa.setSVar(sa.getParam("ResultSVar"), Integer.toString(total));
}
if (sa.hasParam("ChosenSVar")) {
int chosen = player.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblChooseAResult"), rolls, player);
String message = Localizer.getInstance().getMessage("lblPlayerChooseValue", player, chosen);
player.getGame().getAction().notifyOfValue(sa, player, message, player);
- host.setSVar(sa.getParam("ChosenSVar"), Integer.toString(chosen));
+ sa.setSVar(sa.getParam("ChosenSVar"), Integer.toString(chosen));
if (sa.hasParam("OtherSVar")) {
int other = rolls.get(0);
for (int i = 1; i < rolls.size(); ++i) {
@@ -141,7 +141,7 @@ public class RollDiceEffect extends SpellAbilityEffect {
break;
}
}
- host.setSVar(sa.getParam("OtherSVar"), Integer.toString(other));
+ sa.setSVar(sa.getParam("OtherSVar"), Integer.toString(other));
}
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/VoteEffect.java b/forge-game/src/main/java/forge/game/ability/effects/VoteEffect.java
index 5ef63f3ba3b..2305418b22a 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/VoteEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/VoteEffect.java
@@ -126,7 +126,7 @@ public class VoteEffect extends SpellAbilityEffect {
}
if (sa.hasParam("StoreVoteNum")) {
for (final Object type : voteType) {
- host.setSVar("VoteNum" + type, "Number$" + votes.get(type).size());
+ sa.setSVar("VoteNum" + type, "Number$" + votes.get(type).size());
}
} else {
for (final String subAb : subAbs) {
diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java
index 4dd21525c89..927454d398e 100644
--- a/forge-game/src/main/java/forge/game/card/Card.java
+++ b/forge-game/src/main/java/forge/game/card/Card.java
@@ -159,6 +159,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars {
private final NavigableMap clonedStates = Maps.newTreeMap(); // Layer 1
+ private final Table> changedSVars = TreeBasedTable.create();
+
private final Map mayLook = Maps.newHashMap();
private final PlayerCollection mayLookFaceDownExile = new PlayerCollection();
private final PlayerCollection mayLookTemp = new PlayerCollection();
@@ -175,9 +177,6 @@ public class Card extends GameEntity implements Comparable, IHasSVars {
private final CardChangedWords changedTextColors = new CardChangedWords();
private final CardChangedWords changedTextTypes = new CardChangedWords();
- /** Original values of SVars changed by text changes. */
- private Map originalSVars = Maps.newHashMap();
-
private final Set