From c91d7263d828567e1a0485216550b8833a3cc7a6 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Fri, 11 Apr 2025 07:13:12 +0200 Subject: [PATCH] Card: add CounterKeywordStatic --- .../src/main/java/forge/game/card/Card.java | 106 +++++++----------- .../java/forge/game/card/CardCopyService.java | 3 +- .../StaticAbilityContinuous.java | 4 + 3 files changed, 44 insertions(+), 69 deletions(-) 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 cbfb20f2365..738220fd4e0 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -172,7 +172,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr // don't use Enum Set Values or it causes a slow down private final Multimap cantHaveKeywords = MultimapBuilder.hashKeys().hashSetValues().build(); - private final Map counterTypeTimestamps = Maps.newHashMap(); + private final Map counterTypeKeywordStatic = Maps.newHashMap(); private final Map canBlockAdditional = Maps.newTreeMap(); private final Set canBlockAny = Sets.newHashSet(); @@ -1817,9 +1817,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr getGame().addCounterAddedThisTurn(source, counterType, this, addAmount); view.updateCounters(this); } - if (newValue <= 0) { - removeCounterTimestamp(counterType); - } else if (addCounterTimestamp(counterType, false)) { + if (createCounterStatic(counterType)) { updateKeywords(); } if (table != null) { @@ -1827,57 +1825,31 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr } } - public boolean addCounterTimestamp(CounterType counterType) { - return addCounterTimestamp(counterType, true); - } - public boolean addCounterTimestamp(CounterType counterType, boolean updateView) { + public boolean createCounterStatic(CounterType counterType) { + StaticAbility result; if (counterType.is(CounterEnumType.MANABOND)) { - removeCounterTimestamp(counterType); + result = counterTypeKeywordStatic.computeIfAbsent(counterType, ct -> { + String s = "Mode$ Continuous | AffectedDefined$ Self | AddType$ Land | RemoveCardTypes$ True | RemoveSubTypes$ True | RemoveAllAbilities$ True | AddAbility$ ManaReflected"; + StaticAbility stAb = StaticAbility.create(s, this, currentState, true); + String abStr = "AB$ ManaReflected | Cost$ T | Valid$ Defined.Self | ColorOrType$ Color | ReflectProperty$ Is | SpellDescription$ Add one mana of any of this card's colors."; + stAb.setSVar("ManaReflected", abStr); + return stAb; + }); + } else if (counterType.isKeywordCounter()) { + result = counterTypeKeywordStatic.computeIfAbsent(counterType, ct -> { + return StaticAbility.create("Mode$ Continuous | AffectedDefined$ Self | AddKeyword$ " + ct.toString(), this, currentState, true); + }); - long timestamp = game.getNextTimestamp(); - counterTypeTimestamps.put(counterType, timestamp); - // becomes land in instead of other card types - addChangedCardTypes(new CardType(ImmutableList.of("Land"), false), null, false, - EnumSet.of(RemoveType.CardTypes, RemoveType.SubTypes), - timestamp, 0, updateView, false); - - String abStr = "AB$ ManaReflected | Cost$ T | Valid$ Defined.Self | ColorOrType$ Color | ReflectProperty$ Is | SpellDescription$ Add one mana of any of this card's colors."; - - SpellAbility sa = AbilityFactory.getAbility(abStr, this); - sa.setIntrinsic(false); - - addChangedCardTraits(ImmutableList.of(sa), null, null, null, null, true, false, timestamp, 0); - return true; - } - if (!counterType.isKeywordCounter()) { + if (!Keyword.smartValueOf(counterType.toString().split(":")[0]).isMultipleRedundant()) { + result.putParam("KeywordMultiplier", String.valueOf(getCounters(counterType))); + } + } else { return false; } - removeCounterTimestamp(counterType); - - long timestamp = game.getNextTimestamp(); - counterTypeTimestamps.put(counterType, timestamp); - - int num = 1; - if (!Keyword.smartValueOf(counterType.toString().split(":")[0]).isMultipleRedundant()) { - num = getCounters(counterType); - } - addChangedCardKeywords(Collections.nCopies(num, counterType.toString()), null, false, timestamp, null, updateView); + result.putParam("Timestamp", String.valueOf(game.getNextTimestamp())); return true; } - public boolean removeCounterTimestamp(CounterType counterType) { - return removeCounterTimestamp(counterType, true); - } - public boolean removeCounterTimestamp(CounterType counterType, boolean updateView) { - Long old = counterTypeTimestamps.remove(counterType); - if (old != null) { - removeChangedCardTypes(old, 0, updateView); - removeChangedCardTraits(old, 0); - removeChangedCardKeywords(old, 0, updateView); - } - return old != null; - } - @Override public final int subtractCounter(final CounterType counterName, final int n, final Player remover) { return subtractCounter(counterName, n, remover, false); @@ -1917,10 +1889,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr setCounters(counterName, newValue); view.updateCounters(this); - if (newValue <= 0) { - if (removeCounterTimestamp(counterName, false)) { - updateKeywords(); - } + if (newValue <= 0 && (counterName.is(CounterEnumType.MANABOND) || counterName.isKeywordCounter())) { + updateKeywords(); } //fire card stats changed event if p/t bonuses or loyalty changed from subtracted counters @@ -1951,18 +1921,15 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr @Override public final void setCounters(final Map allCounters) { - boolean changed = false; - for (CounterType ct : counters.keySet()) { - if (removeCounterTimestamp(ct, false)) { - changed = true; - } - } + boolean changed = counters.containsKey(CounterEnumType.MANABOND) || counters.keySet().stream().allMatch(CounterType::isKeywordCounter); counters = allCounters; view.updateCounters(this); - for (CounterType ct : counters.keySet()) { - if (addCounterTimestamp(ct, false)) { - changed = true; + if (!isLKI()) { + for (CounterType ct : counters.keySet()) { + if (createCounterStatic(ct)) { + changed = true; + } } } if (changed) { @@ -1973,15 +1940,11 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr @Override public final void clearCounters() { if (counters.isEmpty()) { return; } + boolean changed = counters.containsKey(CounterEnumType.MANABOND) || counters.keySet().stream().allMatch(CounterType::isKeywordCounter); + counters.clear(); view.updateCounters(this); - boolean changed = false; - for (CounterType ct : Lists.newArrayList(counterTypeTimestamps.keySet())) { - if (removeCounterTimestamp(ct, false)) { - changed = true; - } - } if (changed) { updateKeywords(); } @@ -7291,6 +7254,11 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr if (this.isInPlay() && this.isSuspected()) { result.add(suspectedStatic); } + for (Map.Entry e : this.counterTypeKeywordStatic.entrySet()) { + if (this.getCounters(e.getKey()) > 0) { + result.add(e.getValue()); + } + } return result; } @@ -8384,5 +8352,9 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr setChangedCardTraitsByText(in.getChangedCardTraitsByText()); setChangedCardKeywordsByText(in.getChangedCardKeywordsByText()); + + for (Map.Entry e : in.counterTypeKeywordStatic.entrySet()) { + this.counterTypeKeywordStatic.put(e.getKey(), e.getValue().copy(this, true)); + } } } diff --git a/forge-game/src/main/java/forge/game/card/CardCopyService.java b/forge-game/src/main/java/forge/game/card/CardCopyService.java index 9ed4e07b362..3f682bcd3ab 100644 --- a/forge-game/src/main/java/forge/game/card/CardCopyService.java +++ b/forge-game/src/main/java/forge/game/card/CardCopyService.java @@ -301,6 +301,7 @@ public class CardCopyService { // extra copy PT boost newCopy.setPTBoost(copyFrom.getPTBoostTable()); + newCopy.copyFrom(copyFrom); newCopy.setCounters(Maps.newHashMap(copyFrom.getCounters())); newCopy.setColor(copyFrom.getColor()); @@ -352,8 +353,6 @@ public class CardCopyService { } newCopy.setChosenEvenOdd(copyFrom.getChosenEvenOdd()); - newCopy.copyFrom(copyFrom); - // for getReplacementList (run after setChangedCardKeywords for caching) newCopy.setStoredKeywords(copyFrom.getStoredKeywords(), true); newCopy.setStoredReplacements(copyFrom.getStoredReplacements()); 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 74dc337f353..9e81657301e 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -725,6 +725,10 @@ public final class StaticAbilityContinuous { }).collect(Collectors.toList()); } + if (newKeywords != null && !newKeywords.isEmpty() && params.containsKey("KeywordMultiplier")) { + newKeywords = newKeywords.stream().flatMap(s -> Collections.nCopies(Integer.valueOf(params.get("KeywordMultiplier")), s).stream()).collect(Collectors.toList()); + } + affectedCard.addChangedCardKeywords(newKeywords, removeKeywords, removeAllAbilities, se.getTimestamp(), stAb, false); affectedCard.updateKeywordsCache(affectedCard.getCurrentState());