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 216f1ef7cf4..37f22b26c09 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -152,6 +152,14 @@ public class Card extends GameEntity implements Comparable, IHasSVars { private final Table storedReplacementEffect = TreeBasedTable.create(); private final Table storedStaticAbility = TreeBasedTable.create(); + private final Table storedSpellAbililityByText = HashBasedTable.create(); + private final Table storedSpellAbililityGainedByText = TreeBasedTable.create(); + private final Table storedTriggerByText = HashBasedTable.create(); + private final Table storedReplacementEffectByText = HashBasedTable.create(); + private final Table storedStaticAbilityByText = HashBasedTable.create(); + + private final Map, KeywordInterface> storedKeywordByText = Maps.newHashMap(); + // x=timestamp y=StaticAbility id private final Table changedCardColorsByText = TreeBasedTable.create(); // Layer 3 by Text Change private final Table changedCardColorsCharacterDefining = TreeBasedTable.create(); // Layer 5 CDA @@ -4525,6 +4533,71 @@ public class Card extends GameEntity implements Comparable, IHasSVars { return result; } + public final SpellAbility getSpellAbilityForStaticAbilityByText(final SpellAbility sa, final StaticAbility stAb) { + SpellAbility result = storedSpellAbililityByText.get(stAb, sa); + if (result == null) { + result = sa.copy(this, false); + result.setOriginalAbility(sa); // need to be set to get the Once Per turn Clause correct + result.setGrantorStatic(stAb); + result.setIntrinsic(true); // needs to be changed by CardTextChanges + storedSpellAbililityByText.put(stAb, sa, result); + } + return result; + } + + public final SpellAbility getSpellAbilityForStaticAbilityGainedByText(final String str, final StaticAbility stAb) { + SpellAbility result = storedSpellAbililityGainedByText.get(stAb, str); + if (result == null) { + result = AbilityFactory.getAbility(str, this, stAb); + result.setIntrinsic(true); // needs to be affected by Text + result.setGrantorStatic(stAb); + storedSpellAbililityGainedByText.put(stAb, str, result); + } + return result; + } + + public final Trigger getTriggerForStaticAbilityByText(final Trigger tr, final StaticAbility stAb) { + Trigger result = storedTriggerByText.get(stAb, tr); + if (result == null) { + result = tr.copy(this, false); + result.setIntrinsic(false); // needs to be changed by CardTextChanges + storedTriggerByText.put(stAb, tr, result); + } + return result; + } + + public final ReplacementEffect getReplacementEffectForStaticAbilityByText(final ReplacementEffect re, final StaticAbility stAb) { + ReplacementEffect result = storedReplacementEffectByText.get(stAb, re); + if (result == null) { + result = re.copy(this, false); + result.setIntrinsic(false); // needs to be changed by CardTextChanges + storedReplacementEffectByText.put(stAb, re, result); + } + return result; + } + + public final StaticAbility getStaticAbilityForStaticAbilityByText(final StaticAbility st, final StaticAbility stAb) { + StaticAbility result = storedStaticAbilityByText.get(stAb, st); + if (result == null) { + result = st.copy(this, false); + result.setIntrinsic(false); // needs to be changed by CardTextChanges + storedStaticAbilityByText.put(stAb, st, result); + } + return result; + } + + public final KeywordInterface getKeywordForStaticAbilityByText(final KeywordInterface ki, final StaticAbility stAb, long idx) { + Triple triple = Triple.of(ki.getOriginal(), (long)stAb.getId(), idx); + KeywordInterface result = storedKeywordByText.get(triple); + if (result == null) { + result = ki.copy(this, false); + result.setStaticId(stAb.getId()); + result.setIdx(idx); + storedKeywordByText.put(triple, result); + } + return result; + } + public final void addChangedCardTraits(Collection spells, Collection removedAbilities, Collection trigger, Collection replacements, Collection statics, boolean removeAll, boolean removeNonMana, long timestamp, long staticId) { diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java index 451e8f2295a..ef91858b55c 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -43,7 +43,6 @@ import forge.game.Game; import forge.game.GlobalRuleChange; import forge.game.StaticEffect; import forge.game.StaticEffects; -import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.card.Card; @@ -630,40 +629,26 @@ public final class StaticAbilityContinuous { List keywords = Lists.newArrayList(); for (SpellAbility sa : state.getSpellAbilities()) { - SpellAbility newSA = sa.copy(affectedCard, false); - newSA.setOriginalAbility(sa); // need to be set to get the Once Per turn Clause correct - newSA.setGrantorStatic(stAb); - //newSA.setIntrinsic(false); needs to be changed by CardTextChanges - - spellAbilities.add(newSA); + spellAbilities.add(affectedCard.getSpellAbilityForStaticAbilityByText(sa, stAb)); } if (params.containsKey("GainTextAbilities")) { for (String ability : params.get("GainTextAbilities").split(" & ")) { - final SpellAbility sa = AbilityFactory.getAbility(AbilityUtils.getSVar(stAb, ability), affectedCard, stAb); - sa.setIntrinsic(true); // needs to be affected by Text - sa.setGrantorStatic(stAb); - spellAbilities.add(sa); + spellAbilities.add(affectedCard.getSpellAbilityForStaticAbilityGainedByText(AbilityUtils.getSVar(stAb, ability), stAb)); } } for (Trigger tr : state.getTriggers()) { - Trigger newTr = tr.copy(affectedCard, false); - //newTr.setIntrinsic(false); needs to be changed by CardTextChanges - trigger.add(newTr); + trigger.add(affectedCard.getTriggerForStaticAbilityByText(tr, stAb)); } for (ReplacementEffect re : state.getReplacementEffects()) { - ReplacementEffect newRE = re.copy(affectedCard, false); - //newRE.setIntrinsic(false); needs to be changed by CardTextChanges - replacementEffects.add(newRE); + replacementEffects.add(affectedCard.getReplacementEffectForStaticAbilityByText(re, stAb)); } - for (StaticAbility sa : state.getStaticAbilities()) { - StaticAbility newST = sa.copy(affectedCard, false); - //newST.setIntrinsic(false); needs to be changed by CardTextChanges - staticAbilities.add(newST); + for (StaticAbility st : state.getStaticAbilities()) { + staticAbilities.add(affectedCard.getStaticAbilityForStaticAbilityByText(st, stAb)); } + long kwIdx = 1; for (KeywordInterface ki : state.getIntrinsicKeywords()) { - KeywordInterface newKi = ki.copy(affectedCard, false); - //newKi.setIntrinsic(false); needs to be changed by CardTextChanges - keywords.add(newKi); + keywords.add(affectedCard.getKeywordForStaticAbilityByText(ki, stAb, kwIdx)); + kwIdx++; } // Volrath’s Shapeshifter has that card’s name, mana cost, color, types, abilities, power, and toughness.