Card: add CounterKeywordStatic

This commit is contained in:
Hans Mackowiak
2025-04-11 07:13:12 +02:00
parent 41fc4e5041
commit c91d7263d8
3 changed files with 44 additions and 69 deletions

View File

@@ -172,7 +172,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
// don't use Enum Set Values or it causes a slow down // don't use Enum Set Values or it causes a slow down
private final Multimap<Long, Keyword> cantHaveKeywords = MultimapBuilder.hashKeys().hashSetValues().build(); private final Multimap<Long, Keyword> cantHaveKeywords = MultimapBuilder.hashKeys().hashSetValues().build();
private final Map<CounterType, Long> counterTypeTimestamps = Maps.newHashMap(); private final Map<CounterType, StaticAbility> counterTypeKeywordStatic = Maps.newHashMap();
private final Map<Long, Integer> canBlockAdditional = Maps.newTreeMap(); private final Map<Long, Integer> canBlockAdditional = Maps.newTreeMap();
private final Set<Long> canBlockAny = Sets.newHashSet(); private final Set<Long> canBlockAny = Sets.newHashSet();
@@ -1817,9 +1817,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
getGame().addCounterAddedThisTurn(source, counterType, this, addAmount); getGame().addCounterAddedThisTurn(source, counterType, this, addAmount);
view.updateCounters(this); view.updateCounters(this);
} }
if (newValue <= 0) { if (createCounterStatic(counterType)) {
removeCounterTimestamp(counterType);
} else if (addCounterTimestamp(counterType, false)) {
updateKeywords(); updateKeywords();
} }
if (table != null) { if (table != null) {
@@ -1827,57 +1825,31 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} }
} }
public boolean addCounterTimestamp(CounterType counterType) { public boolean createCounterStatic(CounterType counterType) {
return addCounterTimestamp(counterType, true); StaticAbility result;
}
public boolean addCounterTimestamp(CounterType counterType, boolean updateView) {
if (counterType.is(CounterEnumType.MANABOND)) { 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";
long timestamp = game.getNextTimestamp(); StaticAbility stAb = StaticAbility.create(s, this, currentState, true);
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."; 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);
});
SpellAbility sa = AbilityFactory.getAbility(abStr, this); if (!Keyword.smartValueOf(counterType.toString().split(":")[0]).isMultipleRedundant()) {
sa.setIntrinsic(false); result.putParam("KeywordMultiplier", String.valueOf(getCounters(counterType)));
addChangedCardTraits(ImmutableList.of(sa), null, null, null, null, true, false, timestamp, 0);
return true;
} }
if (!counterType.isKeywordCounter()) { } else {
return false; return false;
} }
removeCounterTimestamp(counterType); result.putParam("Timestamp", String.valueOf(game.getNextTimestamp()));
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);
return true; 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 @Override
public final int subtractCounter(final CounterType counterName, final int n, final Player remover) { public final int subtractCounter(final CounterType counterName, final int n, final Player remover) {
return subtractCounter(counterName, n, remover, false); return subtractCounter(counterName, n, remover, false);
@@ -1917,11 +1889,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
setCounters(counterName, newValue); setCounters(counterName, newValue);
view.updateCounters(this); view.updateCounters(this);
if (newValue <= 0) { if (newValue <= 0 && (counterName.is(CounterEnumType.MANABOND) || counterName.isKeywordCounter())) {
if (removeCounterTimestamp(counterName, false)) {
updateKeywords(); updateKeywords();
} }
}
//fire card stats changed event if p/t bonuses or loyalty changed from subtracted counters //fire card stats changed event if p/t bonuses or loyalty changed from subtracted counters
if (powerBonusBefore != getPowerBonusFromCounters() || toughnessBonusBefore != getToughnessBonusFromCounters() || loyaltyBefore != getCurrentLoyalty()) { if (powerBonusBefore != getPowerBonusFromCounters() || toughnessBonusBefore != getToughnessBonusFromCounters() || loyaltyBefore != getCurrentLoyalty()) {
@@ -1951,20 +1921,17 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
@Override @Override
public final void setCounters(final Map<CounterType, Integer> allCounters) { public final void setCounters(final Map<CounterType, Integer> allCounters) {
boolean changed = false; boolean changed = counters.containsKey(CounterEnumType.MANABOND) || counters.keySet().stream().allMatch(CounterType::isKeywordCounter);
for (CounterType ct : counters.keySet()) {
if (removeCounterTimestamp(ct, false)) {
changed = true;
}
}
counters = allCounters; counters = allCounters;
view.updateCounters(this); view.updateCounters(this);
if (!isLKI()) {
for (CounterType ct : counters.keySet()) { for (CounterType ct : counters.keySet()) {
if (addCounterTimestamp(ct, false)) { if (createCounterStatic(ct)) {
changed = true; changed = true;
} }
} }
}
if (changed) { if (changed) {
updateKeywords(); updateKeywords();
} }
@@ -1973,15 +1940,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
@Override @Override
public final void clearCounters() { public final void clearCounters() {
if (counters.isEmpty()) { return; } if (counters.isEmpty()) { return; }
boolean changed = counters.containsKey(CounterEnumType.MANABOND) || counters.keySet().stream().allMatch(CounterType::isKeywordCounter);
counters.clear(); counters.clear();
view.updateCounters(this); view.updateCounters(this);
boolean changed = false;
for (CounterType ct : Lists.newArrayList(counterTypeTimestamps.keySet())) {
if (removeCounterTimestamp(ct, false)) {
changed = true;
}
}
if (changed) { if (changed) {
updateKeywords(); updateKeywords();
} }
@@ -7291,6 +7254,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
if (this.isInPlay() && this.isSuspected()) { if (this.isInPlay() && this.isSuspected()) {
result.add(suspectedStatic); result.add(suspectedStatic);
} }
for (Map.Entry<CounterType, StaticAbility> e : this.counterTypeKeywordStatic.entrySet()) {
if (this.getCounters(e.getKey()) > 0) {
result.add(e.getValue());
}
}
return result; return result;
} }
@@ -8384,5 +8352,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
setChangedCardTraitsByText(in.getChangedCardTraitsByText()); setChangedCardTraitsByText(in.getChangedCardTraitsByText());
setChangedCardKeywordsByText(in.getChangedCardKeywordsByText()); setChangedCardKeywordsByText(in.getChangedCardKeywordsByText());
for (Map.Entry<CounterType, StaticAbility> e : in.counterTypeKeywordStatic.entrySet()) {
this.counterTypeKeywordStatic.put(e.getKey(), e.getValue().copy(this, true));
}
} }
} }

View File

@@ -301,6 +301,7 @@ public class CardCopyService {
// extra copy PT boost // extra copy PT boost
newCopy.setPTBoost(copyFrom.getPTBoostTable()); newCopy.setPTBoost(copyFrom.getPTBoostTable());
newCopy.copyFrom(copyFrom);
newCopy.setCounters(Maps.newHashMap(copyFrom.getCounters())); newCopy.setCounters(Maps.newHashMap(copyFrom.getCounters()));
newCopy.setColor(copyFrom.getColor()); newCopy.setColor(copyFrom.getColor());
@@ -352,8 +353,6 @@ public class CardCopyService {
} }
newCopy.setChosenEvenOdd(copyFrom.getChosenEvenOdd()); newCopy.setChosenEvenOdd(copyFrom.getChosenEvenOdd());
newCopy.copyFrom(copyFrom);
// for getReplacementList (run after setChangedCardKeywords for caching) // for getReplacementList (run after setChangedCardKeywords for caching)
newCopy.setStoredKeywords(copyFrom.getStoredKeywords(), true); newCopy.setStoredKeywords(copyFrom.getStoredKeywords(), true);
newCopy.setStoredReplacements(copyFrom.getStoredReplacements()); newCopy.setStoredReplacements(copyFrom.getStoredReplacements());

View File

@@ -725,6 +725,10 @@ public final class StaticAbilityContinuous {
}).collect(Collectors.toList()); }).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, affectedCard.addChangedCardKeywords(newKeywords, removeKeywords,
removeAllAbilities, se.getTimestamp(), stAb, false); removeAllAbilities, se.getTimestamp(), stAb, false);
affectedCard.updateKeywordsCache(affectedCard.getCurrentState()); affectedCard.updateKeywordsCache(affectedCard.getCurrentState());