diff --git a/forge-game/src/main/java/forge/game/CardTraitBase.java b/forge-game/src/main/java/forge/game/CardTraitBase.java index d1f82854e03..146c4d872e5 100644 --- a/forge-game/src/main/java/forge/game/CardTraitBase.java +++ b/forge-game/src/main/java/forge/game/CardTraitBase.java @@ -531,31 +531,6 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView, return true; } - public void changeText() { - // copy changed text words into card trait there - this.changedTextColors = getHostCard().getChangedTextColorWords(); - this.changedTextTypes = getHostCard().getChangedTextTypeWords(); - - for (final String key : this.mapParams.keySet()) { - final String value = this.originalMapParams.get(key), newValue; - if (noChangeKeys.contains(key)) { - continue; - } else if (descriptiveKeys.contains(key)) { - // change descriptions differently - newValue = AbilityUtils.applyDescriptionTextChangeEffects(value, this); - } else if (this.getHostCard().hasSVar(value)) { - // don't change literal SVar names! - newValue = null; - } else { - newValue = AbilityUtils.applyAbilityTextChangeEffects(value, this); - } - - if (newValue != null) { - this.mapParams.put(key, newValue); - } - } - } - @Override public CardView getCardView() { return CardView.get(hostCard); @@ -694,9 +669,37 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView, this.originalMapParams = Maps.newHashMap(this.mapParams); } + public void changeText() { + // copy changed text words into card trait there + this.changedTextColors = getHostCard().getChangedTextColorWords(); + this.changedTextTypes = getHostCard().getChangedTextTypeWords(); + + for (final String key : this.mapParams.keySet()) { + final String value = this.originalMapParams.get(key), newValue; + if (noChangeKeys.contains(key)) { + continue; + } else if (descriptiveKeys.contains(key)) { + // change descriptions differently + newValue = AbilityUtils.applyDescriptionTextChangeEffects(value, this); + } else if (this.getHostCard().hasSVar(value)) { + // don't change literal SVar names! + newValue = null; + } else { + newValue = AbilityUtils.applyAbilityTextChangeEffects(value, this); + } + + if (newValue != null) { + this.mapParams.put(key, newValue); + } + } + } + protected void copyHelper(CardTraitBase copy, Card host) { + copyHelper(copy, host, false); + } + protected void copyHelper(CardTraitBase copy, Card host, boolean keepTextChanges) { copy.originalMapParams = Maps.newHashMap(originalMapParams); - copy.mapParams = Maps.newHashMap(originalMapParams); + copy.mapParams = Maps.newHashMap(keepTextChanges ? mapParams : originalMapParams); copy.setSVars(sVars); copy.setCardState(cardState); // dont use setHostCard to not trigger the not copied parts yet diff --git a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java index 43a3aad45e3..7bdffdf86ba 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java @@ -25,7 +25,6 @@ import forge.game.card.token.TokenInfo; import forge.game.event.GameEventCombatChanged; import forge.game.event.GameEventTokenCreated; import forge.game.player.Player; -import forge.game.player.PlayerController; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; import forge.util.Lang; @@ -52,13 +51,10 @@ public class AmassEffect extends TokenEffectBase { @Override public void resolve(SpellAbility sa) { - final Card card = sa.getHostCard(); - final Game game = card.getGame(); + final Card source = sa.getHostCard(); + final Game game = source.getGame(); final Player activator = sa.getActivatingPlayer(); - final PlayerController pc = activator.getController(); - - final int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Num", "1"), sa); - final boolean remember = sa.hasParam("RememberAmass"); + final int amount = AbilityUtils.calculateAmount(source, sa.getParamOrDefault("Num", "1"), sa); final String type = sa.getParam("Type"); // create army token if needed @@ -84,29 +80,25 @@ public class AmassEffect extends TokenEffectBase { } } - Map params = Maps.newHashMap(); - params.put("CounterType", CounterType.get(CounterEnumType.P1P1)); - params.put("Amount", 1); - CardCollectionView tgtCards = CardLists.getType(activator.getCardsIn(ZoneType.Battlefield), "Army"); - tgtCards = pc.chooseCardsForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblChooseAnArmy"), 1, 1, false, params); - if (tgtCards.isEmpty()) { return; } - GameEntityCounterTable table = new GameEntityCounterTable(); - for (final Card tgtCard : tgtCards) { - tgtCard.addCounter(CounterEnumType.P1P1, amount, activator, table); - if (remember) { - card.addRemembered(tgtCard); - } + + Map params = Maps.newHashMap(); + params.put("CounterType", CounterType.get(CounterEnumType.P1P1)); + params.put("Amount", 1); + Card tgt = activator.getController().chooseSingleEntityForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblChooseAnArmy"), false, params); + + if (sa.hasParam("RememberAmass")) { + source.addRemembered(tgt); } + + GameEntityCounterTable table = new GameEntityCounterTable(); + tgt.addCounter(CounterEnumType.P1P1, amount, activator, table); table.replaceCounterEffect(game, sa, true); // change type after counters - long ts = game.getNextTimestamp(); - for (final Card tgtCard : tgtCards) { - tgtCard.addChangedCardTypes(CardType.parse(type, true), null, false, EnumSet.noneOf(RemoveType.class), ts, 0, true, false); - } + tgt.addChangedCardTypes(CardType.parse(type, true), null, false, EnumSet.noneOf(RemoveType.class), game.getNextTimestamp(), 0, true, false); } } 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 1c1116acdbd..88967f01014 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -4658,8 +4658,10 @@ public class Card extends GameEntity implements Comparable, IHasSVars { public final SpellAbility getSpellAbilityForStaticAbility(final String str, final StaticAbility stAb) { SpellAbility result = storedSpellAbility.get(stAb, str); - if (result == null) { + if (!canUseCachedTrait(result, stAb)) { result = AbilityFactory.getAbility(str, this, stAb); + // apply text changes from the statics host + result.changeTextIntrinsic(stAb.getChangedTextColors(), stAb.getChangedTextTypes()); result.setIntrinsic(false); result.setGrantorStatic(stAb); storedSpellAbility.put(stAb, str, result); @@ -4669,8 +4671,10 @@ public class Card extends GameEntity implements Comparable, IHasSVars { public final Trigger getTriggerForStaticAbility(final String str, final StaticAbility stAb) { Trigger result = storedTrigger.get(stAb, str); - if (result == null) { + if (!canUseCachedTrait(result, stAb)) { result = TriggerHandler.parseTrigger(str, this, false, stAb); + // apply text changes from the statics host + result.changeTextIntrinsic(stAb.getChangedTextColors(), stAb.getChangedTextTypes()); storedTrigger.put(stAb, str, result); } return result; @@ -4699,8 +4703,10 @@ public class Card extends GameEntity implements Comparable, IHasSVars { public final ReplacementEffect getReplacementEffectForStaticAbility(final String str, final StaticAbility stAb) { ReplacementEffect result = storedReplacementEffect.get(stAb, str); - if (result == null) { + if (!canUseCachedTrait(result, stAb)) { result = ReplacementHandler.parseReplacement(str, this, false, stAb); + // apply text changes from the statics host + result.changeTextIntrinsic(stAb.getChangedTextColors(), stAb.getChangedTextTypes()); storedReplacementEffect.put(stAb, str, result); } return result; @@ -4708,8 +4714,10 @@ public class Card extends GameEntity implements Comparable, IHasSVars { public final StaticAbility getStaticAbilityForStaticAbility(final String str, final StaticAbility stAb) { StaticAbility result = storedStaticAbility.get(stAb, str); - if (result == null) { + if (!canUseCachedTrait(result, stAb)) { result = StaticAbility.create(str, this, stAb.getCardState(), false); + // apply text changes from the statics host + result.changeTextIntrinsic(stAb.getChangedTextColors(), stAb.getChangedTextTypes()); storedStaticAbility.put(stAb, str, result); } return result; @@ -4781,6 +4789,13 @@ public class Card extends GameEntity implements Comparable, IHasSVars { return result; } + private boolean canUseCachedTrait(CardTraitBase cached, CardTraitBase stAb) { + if (cached == null) { + return false; + } + return cached.getChangedTextColors().equals(stAb.getChangedTextColors()) && cached.getChangedTextTypes().equals(stAb.getChangedTextTypes()); + } + 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/card/CardFactory.java b/forge-game/src/main/java/forge/game/card/CardFactory.java index ac5921536dd..5d15013cdd2 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactory.java +++ b/forge-game/src/main/java/forge/game/card/CardFactory.java @@ -574,6 +574,9 @@ public class CardFactory { } public static void copySpellAbility(SpellAbility from, SpellAbility to, final Card host, final Player p, final boolean lki) { + copySpellAbility(from, to, host, p, lki, false); + } + public static void copySpellAbility(SpellAbility from, SpellAbility to, final Card host, final Player p, final boolean lki, final boolean keepTextChanges) { if (from.usesTargeting()) { to.setTargetRestrictions(from.getTargetRestrictions()); } @@ -581,16 +584,16 @@ public class CardFactory { to.setStackDescription(from.getOriginalStackDescription()); if (from.getSubAbility() != null) { - to.setSubAbility((AbilitySub) from.getSubAbility().copy(host, p, lki)); + to.setSubAbility((AbilitySub) from.getSubAbility().copy(host, p, lki, keepTextChanges)); } for (Map.Entry e : from.getAdditionalAbilities().entrySet()) { - to.setAdditionalAbility(e.getKey(), e.getValue().copy(host, p, lki)); + to.setAdditionalAbility(e.getKey(), e.getValue().copy(host, p, lki, keepTextChanges)); } for (Map.Entry> e : from.getAdditionalAbilityLists().entrySet()) { to.setAdditionalAbilityList(e.getKey(), Lists.transform(e.getValue(), new Function() { @Override public AbilitySub apply(AbilitySub input) { - return (AbilitySub) input.copy(host, p, lki); + return (AbilitySub) input.copy(host, p, lki, keepTextChanges); } })); } diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index 18451713bea..070971aa1f0 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1473,7 +1473,7 @@ public class CardFactoryUtil { sbTrig.append("Living Weapon (").append(inst.getReminderText()).append(")"); final StringBuilder sbGerm = new StringBuilder(); - sbGerm.append("DB$ Token | TokenAmount$ 1 | TokenScript$ b_0_0_phyrexian_germ |TokenOwner$ You | RememberTokens$ True"); + sbGerm.append("DB$ Token | TokenAmount$ 1 | TokenScript$ b_0_0_phyrexian_germ | TokenOwner$ You | RememberTokens$ True"); final SpellAbility saGerm = AbilityFactory.getAbility(sbGerm.toString(), card); 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 c17c631be07..fa0fccfad60 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -1158,6 +1158,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit return copy(host, this.getActivatingPlayer(), lki); } public SpellAbility copy(Card host, Player activ, final boolean lki) { + return copy(host, activ, lki, false); + } + public SpellAbility copy(Card host, Player activ, final boolean lki, final boolean keepTextChanges) { SpellAbility clone = null; try { clone = (SpellAbility) clone(); @@ -1166,7 +1169,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit // don't use setHostCard to not trigger the not copied parts yet - copyHelper(clone, host); + copyHelper(clone, host, lki || keepTextChanges); // always set this to false, it is only set in CopyEffect clone.mayChooseNewTargets = false; @@ -1205,7 +1208,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit clone.additionalAbilities = Maps.newHashMap(); clone.additionalAbilityLists = Maps.newHashMap(); // run special copy Ability to make a deep copy - CardFactory.copySpellAbility(this, clone, host, activ, lki); + CardFactory.copySpellAbility(this, clone, host, activ, lki, keepTextChanges); } catch (final CloneNotSupportedException e) { System.err.println(e); } 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 b28774b16e1..cbaeeb3521a 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -830,7 +830,7 @@ public final class StaticAbilityContinuous { if (!stAb.matchesValidParam("GainsValidAbilities", sa)) { continue; } - SpellAbility newSA = sa.copy(affectedCard, false); + SpellAbility newSA = sa.copy(affectedCard, sa.getActivatingPlayer(), false, true); if (params.containsKey("GainsAbilitiesLimitPerTurn")) { newSA.setRestrictions(sa.getRestrictions()); newSA.getRestrictions().setLimitToCheck(params.get("GainsAbilitiesLimitPerTurn")); diff --git a/forge-game/src/main/java/forge/game/trigger/Trigger.java b/forge-game/src/main/java/forge/game/trigger/Trigger.java index ecb5dcd8a68..dc6f7e023b2 100644 --- a/forge-game/src/main/java/forge/game/trigger/Trigger.java +++ b/forge-game/src/main/java/forge/game/trigger/Trigger.java @@ -583,7 +583,6 @@ public abstract class Trigger extends TriggerReplacementBase { } } - /* (non-Javadoc) * @see forge.game.CardTraitBase#changeText() */ @@ -606,9 +605,6 @@ public abstract class Trigger extends TriggerReplacementBase { */ @Override public void changeTextIntrinsic(Map colorMap, Map typeMap) { - if (!isIntrinsic()) { - return; - } super.changeTextIntrinsic(colorMap, typeMap); SpellAbility sa = ensureAbility(); diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java index 375f2fb3a3a..2048ad4fb00 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java @@ -521,7 +521,7 @@ public class TriggerHandler { controller = regtrig.getSpawningAbility().getActivatingPlayer(); } // need to copy the SA because of TriggeringObjects - sa = sa.copy(host, controller, false); + sa = sa.copy(host, controller, false, true); } sa.setTrigger(regtrig); diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java index b5460630831..96f2795b198 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -302,9 +302,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable