From 47d3a743870607efc9caecf84e83838ff609da43 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sat, 14 Sep 2019 16:33:56 +0000 Subject: [PATCH] Resolve "multiple StaticAbility Pump on same creature does conflict" --- .../main/java/forge/ai/ComputerUtilCard.java | 8 +-- .../java/forge/ai/simulation/GameCopier.java | 4 +- .../main/java/forge/game/StaticEffect.java | 2 +- .../game/ability/effects/PumpAllEffect.java | 4 +- .../game/ability/effects/PumpEffect.java | 4 +- .../src/main/java/forge/game/card/Card.java | 30 ++++---- .../main/java/forge/game/card/CardState.java | 2 +- .../forge/game/keyword/KeywordInstance.java | 2 +- .../game/replacement/ReplacementEffect.java | 3 +- .../forge/game/spellability/SpellAbility.java | 2 +- .../game/staticability/StaticAbility.java | 68 ++++++++++++++----- .../StaticAbilityContinuous.java | 2 +- .../main/java/forge/game/trigger/Trigger.java | 2 +- .../ai/simulation/GameSimulatorTest.java | 19 ++++++ 14 files changed, 102 insertions(+), 50 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index bb8bc575f55..a56e032dc87 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -1601,8 +1601,8 @@ public class ComputerUtilCard { } pumped.addNewPT(c.getCurrentPower(), c.getCurrentToughness(), timestamp); - pumped.setPTBoost(c.getPTBoostMap()); - pumped.addPTBoost(power + berserkPower, toughness, timestamp); + pumped.setPTBoost(c.getPTBoostTable()); + pumped.addPTBoost(power + berserkPower, toughness, timestamp, null); pumped.addChangedCardKeywords(kws, null, false, false, timestamp); Set types = c.getCounters().keySet(); for(CounterType ct : types) { @@ -1649,8 +1649,8 @@ public class ComputerUtilCard { list.add(vCard); // account for the static abilities that may be present on the card itself for (final Card c : list) { // remove old boost that might be copied - vCard.removePTBoost(c.getTimestamp()); for (final StaticAbility stAb : c.getStaticAbilities()) { + vCard.removePTBoost(c.getTimestamp(), stAb.getId()); final Map params = stAb.getMapParams(); if (!params.get("Mode").equals("Continuous")) { continue; @@ -1683,7 +1683,7 @@ public class ComputerUtilCard { def = AbilityUtils.calculateAmount(c, addT, stAb); } } - vCard.addPTBoost(att, def, c.getTimestamp()); + vCard.addPTBoost(att, def, c.getTimestamp(), stAb.getId()); } } } diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java index 8cd20c54a26..d2ae1de2379 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java +++ b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java @@ -246,7 +246,7 @@ public class GameCopier { newCard.addType(type); } for (StaticAbility stAb : c.getStaticAbilities()) { - newCard.addStaticAbility(stAb); + newCard.addStaticAbility(stAb.copy(newCard, true)); } for (SpellAbility sa : c.getSpellAbilities()) { SpellAbility saCopy = sa.copy(newCard, true); @@ -277,7 +277,7 @@ public class GameCopier { // TODO: Copy the full list with timestamps. newCard.addNewPT(setPower, setToughness, newGame.getNextTimestamp()); } - newCard.setPTBoost(c.getPTBoostMap()); + newCard.setPTBoost(c.getPTBoostTable()); newCard.setDamage(c.getDamage()); newCard.setChangedCardTypes(c.getChangedCardTypesMap()); diff --git a/forge-game/src/main/java/forge/game/StaticEffect.java b/forge-game/src/main/java/forge/game/StaticEffect.java index b27ed2f3d20..8261b4d8143 100644 --- a/forge-game/src/main/java/forge/game/StaticEffect.java +++ b/forge-game/src/main/java/forge/game/StaticEffect.java @@ -798,7 +798,7 @@ public class StaticEffect { } // remove P/T bonus - affectedCard.removePTBoost(getTimestamp()); + affectedCard.removePTBoost(getTimestamp(), ability.getId()); // the view is updated in GameAction#checkStaticAbilities to avoid flickering diff --git a/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java index 010914c6775..790eed68849 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java @@ -52,7 +52,7 @@ public class PumpAllEffect extends SpellAbilityEffect { boolean redrawPT = false; if (a != 0 || d != 0) { - tgtC.addPTBoost(a, d, timestamp); + tgtC.addPTBoost(a, d, timestamp, 0); redrawPT = true; } @@ -76,7 +76,7 @@ public class PumpAllEffect extends SpellAbilityEffect { @Override public void run() { - tgtC.removePTBoost(timestamp); + tgtC.removePTBoost(timestamp, 0); tgtC.removeChangedCardKeywords(timestamp); for (String kw : hiddenkws) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java index 1c89e3a66ff..e43f7876b5d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java @@ -56,7 +56,7 @@ public class PumpEffect extends SpellAbilityEffect { } if (a != 0 || d != 0) { - gameCard.addPTBoost(a, d, timestamp); + gameCard.addPTBoost(a, d, timestamp, 0); redrawPT = true; } @@ -84,7 +84,7 @@ public class PumpEffect extends SpellAbilityEffect { @Override public void run() { - gameCard.removePTBoost(timestamp); + gameCard.removePTBoost(timestamp, 0); boolean updateText = false; updateText = gameCard.removeCanBlockAny(timestamp) || updateText; updateText = gameCard.removeCanBlockAdditional(timestamp) || updateText; 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 5dbedb0c59a..cef51f069ee 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -198,7 +198,9 @@ public class Card extends GameEntity implements Comparable { // stack of set power/toughness private Map> newPT = Maps.newTreeMap(); private Map> newPTCharacterDefining = Maps.newTreeMap(); - private Map> boostPT = Maps.newTreeMap(); + + // x=Static Avility id or 0, y=timestamp + private Table> boostPT = TreeBasedTable.create(); private String basePowerString = null; private String baseToughnessString = null; @@ -3474,23 +3476,21 @@ public class Card extends GameEntity implements Comparable { return result; } - public void addPTBoost(final Integer power, final Integer toughness, final long timestamp) { - boostPT.put(timestamp, Pair.of(power, toughness)); + public void addPTBoost(final Integer power, final Integer toughness, final long timestamp, final Integer staticId) { + boostPT.put(staticId == null ? 0 : staticId, timestamp, Pair.of(power, toughness)); } - public void removePTBoost(final long timestamp) { - boostPT.remove(timestamp); + public void removePTBoost(final long timestamp, final Integer staticId) { + boostPT.remove(staticId, timestamp); } - public Map> getPTBoostMap() { - return ImmutableMap.copyOf(boostPT); + public Table> getPTBoostTable() { + return ImmutableTable.copyOf(boostPT); } - public void setPTBoost(Map> map) { + public void setPTBoost(Table> table) { this.boostPT.clear(); - for (Map.Entry> e : map.entrySet()) { - this.boostPT.put(e.getKey(), Pair.of(e.getValue().getLeft(), e.getValue().getRight())); - } + boostPT.putAll(table); } public final boolean isUntapped() { @@ -3965,12 +3965,8 @@ public class Card extends GameEntity implements Comparable { return null; } public final StaticAbility addStaticAbility(final StaticAbility stAb) { - return addStaticAbility(stAb, false); - } - public final StaticAbility addStaticAbility(final StaticAbility stAb, boolean intrinsic) { - final StaticAbility stAbCopy = new StaticAbility(stAb, this); - currentState.addStaticAbility(stAbCopy); - return stAbCopy; + currentState.addStaticAbility(stAb); + return stAb; } public final void removeStaticAbility(StaticAbility stAb) { currentState.removeStaticAbility(stAb); diff --git a/forge-game/src/main/java/forge/game/card/CardState.java b/forge-game/src/main/java/forge/game/card/CardState.java index eb9cb92e1bf..84ece1c6bdf 100644 --- a/forge-game/src/main/java/forge/game/card/CardState.java +++ b/forge-game/src/main/java/forge/game/card/CardState.java @@ -529,7 +529,7 @@ public class CardState extends GameObject { staticAbilities.clear(); for (StaticAbility sa : source.staticAbilities) { if (sa.isIntrinsic()) { - staticAbilities.add(new StaticAbility(sa, this.card)); + staticAbilities.add(sa.copy(card, lki)); } } } diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java b/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java index 50b99b5e66a..6e7adb840fb 100644 --- a/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java +++ b/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java @@ -228,7 +228,7 @@ public abstract class KeywordInstance> implements K result.staticAbilities = Lists.newArrayList(); for (StaticAbility sa : this.staticAbilities) { - result.staticAbilities.add(new StaticAbility(sa, host)); + result.staticAbilities.add(sa.copy(host, lki)); } return result; 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 34d1f58538e..fd7796a1bf3 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java @@ -27,6 +27,7 @@ import forge.util.TextUtil; import java.util.List; import java.util.Map; +import java.util.Objects; /** * TODO: Write javadoc for this type. @@ -261,6 +262,6 @@ public abstract class ReplacementEffect extends TriggerReplacementBase { /** {@inheritDoc} */ @Override public int hashCode() { - return 42 * (42 + this.getId()); + return Objects.hash(ReplacementEffect.class, getId()); } } diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index cfa028365c6..88fe88e9833 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -205,7 +205,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit } @Override public int hashCode() { - return getId(); + return Objects.hash(SpellAbility.class, getId()); } @Override public boolean equals(final Object obj) { diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java index 21d4edff7d5..3906fe03688 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -17,6 +17,7 @@ */ package forge.game.staticability; +import com.google.common.collect.ComparisonChain; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import forge.card.MagicColor; @@ -24,6 +25,7 @@ import forge.game.CardTraitBase; import forge.game.Game; import forge.game.GameEntity; import forge.game.GameStage; +import forge.game.IIdentifiable; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardCollection; @@ -43,18 +45,38 @@ import forge.util.TextUtil; import java.util.EnumSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; /** * The Class StaticAbility. */ -public class StaticAbility extends CardTraitBase implements Comparable { +public class StaticAbility extends CardTraitBase implements IIdentifiable, Cloneable, Comparable { + private static int maxId = 0; + private static int nextId() { return ++maxId; } - private final Set layers; + private int id; + + private Set layers; private CardCollectionView ignoreEffectCards = new CardCollection(); private final List ignoreEffectPlayers = Lists.newArrayList(); private int mayPlayTurn = 0; + @Override + public final int getId() { + return id; + } + + @Override + public int hashCode() { + return Objects.hash(StaticAbility.class, getId()); + } + + @Override + public boolean equals(final Object obj) { + return obj instanceof StaticAbility && this.id == ((StaticAbility) obj).id; + } + /** *

* Getter for the field mapParams. @@ -228,6 +250,7 @@ public class StaticAbility extends CardTraitBase implements Comparable params, final Card host) { + this.id = nextId(); this.originalMapParams.putAll(params); this.mapParams.putAll(params); this.layers = this.generateLayer(); @@ -235,19 +258,6 @@ public class StaticAbility extends CardTraitBase implements Comparable