Compare commits

...

4 Commits

Author SHA1 Message Date
Hans Mackowiak
ca1247fc10 ~ fix lki for now 2025-04-12 20:22:51 +02:00
Hans Mackowiak
23c29261b9 Update Card.java 2025-04-11 09:29:52 +02:00
Hans Mackowiak
d149ff8020 Update Card.java 2025-04-11 09:22:42 +02:00
Hans Mackowiak
fba791d685 Card: add CounterKeywordEffects 2025-04-11 07:13:12 +02:00
9 changed files with 77 additions and 34 deletions

View File

@@ -1743,7 +1743,7 @@ public class ComputerUtilCard {
if (!hiddenKws.isEmpty()) {
pumped.addHiddenExtrinsicKeywords(timestamp, 0, hiddenKws);
}
pumped.setCounters(c.getCounters());
pumped.setCounters(c.getCounters(), true);
//Copies tap-state and extra keywords (auras, equipment, etc.)
if (c.isTapped()) {
pumped.setTapped(true);

View File

@@ -1121,7 +1121,7 @@ public abstract class GameState {
}
private void applyCountersToGameEntity(GameEntity entity, String counterString) {
entity.setCounters(Maps.newHashMap());
entity.setCounters(Maps.newHashMap(), false);
String[] allCounterStrings = counterString.split(",");
for (final String counterPair : allCounterStrings) {
String[] pair = counterPair.split("=", 2);
@@ -1173,7 +1173,7 @@ public abstract class GameState {
boolean sickness = c.hasSickness();
Map<CounterType, Integer> counters = c.getCounters();
// Note: Not clearCounters() since we want to keep the counters var as-is.
c.setCounters(Maps.newHashMap());
c.setCounters(Maps.newHashMap(), false);
if (c.isAura()) {
// dummy "enchanting" to indicate that the card will be force-attached elsewhere
// (will be overridden later, so the actual value shouldn't matter)
@@ -1191,7 +1191,7 @@ public abstract class GameState {
c.setTapped(tapped);
c.setSickness(sickness);
c.setCounters(counters);
c.setCounters(counters, false);
}
} else {
zone.setCards(kv.getValue());

View File

@@ -94,7 +94,7 @@ public class GameCopier {
newPlayer.setLifeStartedThisTurnWith(origPlayer.getLifeStartedThisTurnWith());
newPlayer.setDamageReceivedThisTurn(origPlayer.getDamageReceivedThisTurn());
newPlayer.setLandsPlayedThisTurn(origPlayer.getLandsPlayedThisTurn());
newPlayer.setCounters(Maps.newHashMap(origPlayer.getCounters()));
newPlayer.setCounters(Maps.newHashMap(origPlayer.getCounters()), false);
newPlayer.setSpeed(origPlayer.getSpeed());
newPlayer.setBlessing(origPlayer.hasBlessing());
newPlayer.setRevolt(origPlayer.hasRevolt());
@@ -415,7 +415,7 @@ public class GameCopier {
Map<CounterType, Integer> counters = c.getCounters();
if (!counters.isEmpty()) {
newCard.setCounters(Maps.newHashMap(counters));
newCard.setCounters(Maps.newHashMap(counters), true);
}
if (c.hasChosenPlayer()) {
newCard.setChosenPlayer(playerMap.get(c.getChosenPlayer()));

View File

@@ -249,7 +249,7 @@ public class GameAction {
// need to copy counters when card enters another zone than hand or library
if (lastKnownInfo.hasKeyword("Counters remain on CARDNAME as it moves to any zone other than a player's hand or library.") &&
!(zoneTo.is(ZoneType.Hand) || zoneTo.is(ZoneType.Library))) {
copied.setCounters(Maps.newHashMap(lastKnownInfo.getCounters()));
copied.setCounters(Maps.newHashMap(lastKnownInfo.getCounters()), false);
}
// perpetual stuff

View File

@@ -306,7 +306,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
setCounters(CounterType.get(counterType), num);
}
abstract public void setCounters(final Map<CounterType, Integer> allCounters);
abstract public void setCounters(final Map<CounterType, Integer> allCounters, boolean lki);
abstract public boolean canRemoveCounters(final CounterType type);

View File

@@ -169,7 +169,7 @@ public class GameSnapshot {
newPlayer.setLifeStartedThisTurnWith(origPlayer.getLifeStartedThisTurnWith());
newPlayer.setDamageReceivedThisTurn(origPlayer.getDamageReceivedThisTurn());
newPlayer.setLandsPlayedThisTurn(origPlayer.getLandsPlayedThisTurn());
newPlayer.setCounters(Maps.newHashMap(origPlayer.getCounters()));
newPlayer.setCounters(Maps.newHashMap(origPlayer.getCounters()), false);
newPlayer.setBlessing(origPlayer.hasBlessing());
newPlayer.setRevolt(origPlayer.hasRevolt());
newPlayer.setLibrarySearched(origPlayer.getLibrarySearched());

View File

@@ -64,6 +64,7 @@ import org.apache.commons.lang3.tuple.Triple;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import static java.lang.Math.max;
@@ -169,6 +170,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
private final Multimap<Long, Keyword> cantHaveKeywords = MultimapBuilder.hashKeys().hashSetValues().build();
private final Map<CounterType, Long> counterTypeTimestamps = Maps.newHashMap();
private final Map<CounterType, Card> counterTypeKeywordEffects = Maps.newHashMap();
private final Map<Long, Integer> canBlockAdditional = Maps.newTreeMap();
private final Set<Long> canBlockAny = Sets.newHashSet();
@@ -1793,7 +1795,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
view.updateCounters(this);
}
if (newValue <= 0) {
removeCounterTimestamp(counterType);
removeCounterTimestamp(counterType, false);
} else if (addCounterTimestamp(counterType, false)) {
updateKeywords();
}
@@ -1802,12 +1804,52 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
}
}
public boolean addCounterTimestamp(CounterType counterType) {
return addCounterTimestamp(counterType, true);
public Card getCounterEffect(CounterType counterType, long timestamp) {
Card result = counterTypeKeywordEffects.get(counterType);
int num = 1;
if (!Keyword.smartValueOf(counterType.toString().split(":")[0]).isMultipleRedundant()) {
num = getCounters(counterType);
}
String keywords = Collections.nCopies(num, counterType.toString()).stream().collect(Collectors.joining(" & "));
if (result == null) {
result = SpellAbilityEffect.createEffect(castSA, this, this.getController(), counterType.toString(), this.getImageKey(), timestamp);
result.setRenderForUI(false);
result.addRemembered(this);
String s = "Mode$ Continuous | AffectedDefined$ Remembered | AddKeyword$ " + keywords;
StaticAbility stAb = result.addStaticAbility(s);
stAb.setActiveZone(EnumSet.of(ZoneType.Command));
// TODO add for zone changes, not just Battlefield?
if (isInPlay()) {
GameCommand until = SpellAbilityEffect.exileEffectCommand(getGame(), result);
addLeavesPlayCommand(until);
} else {
SpellAbilityEffect.addForgetOnMovedTrigger(result, getZone().getZoneType().toString());
}
getGame().getAction().moveToCommand(result, null);
counterTypeKeywordEffects.put(counterType, result);
}
// update timestamp
result.setGameTimestamp(timestamp);
// update amount
for (StaticAbility stAb : result.getStaticAbilities()) {
stAb.getMapParams().put("AddKeyword", keywords);
}
return result;
}
public boolean addCounterTimestamp(CounterType counterType, boolean updateView) {
if (counterType.is(CounterEnumType.MANABOND)) {
removeCounterTimestamp(counterType);
removeCounterTimestamp(counterType, updateView);
long timestamp = game.getNextTimestamp();
counterTypeTimestamps.put(counterType, timestamp);
@@ -1827,28 +1869,25 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
if (!counterType.isKeywordCounter()) {
return false;
}
removeCounterTimestamp(counterType);
long timestamp = game.getNextTimestamp();
getCounterEffect(counterType, timestamp);
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;
}
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);
}
if (counterType.isKeywordCounter()) {
Card effect = counterTypeKeywordEffects.remove(counterType);
if (effect != null) {
getGame().getAction().exileEffect(effect);
}
}
return old != null;
}
@@ -1925,19 +1964,23 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
}
@Override
public final void setCounters(final Map<CounterType, Integer> allCounters) {
public final void setCounters(final Map<CounterType, Integer> allCounters, boolean lki) {
boolean changed = false;
for (CounterType ct : counters.keySet()) {
if (removeCounterTimestamp(ct, false)) {
changed = true;
if (!lki) {
for (CounterType ct : counters.keySet()) {
if (removeCounterTimestamp(ct, false)) {
changed = true;
}
}
}
counters = allCounters;
view.updateCounters(this);
for (CounterType ct : counters.keySet()) {
if (addCounterTimestamp(ct, false)) {
changed = true;
if (!lki) {
for (CounterType ct : counters.keySet()) {
if (addCounterTimestamp(ct, false)) {
changed = true;
}
}
}
if (changed) {
@@ -3782,7 +3825,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
public final void addLeavesPlayCommand(final GameCommand c) {
leavePlayCommandList.add(c);
}
public void addStaticCommandList(Object[] objects) {
staticCommandList.add(objects);
}
@@ -4795,7 +4838,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
public void addDraftAction(String s) {
draftActions.add(s);
}
private int intensity = 0;
public final void addIntensity(final int n) {
intensity += n;

View File

@@ -302,7 +302,7 @@ public class CardCopyService {
// extra copy PT boost
newCopy.setPTBoost(copyFrom.getPTBoostTable());
newCopy.setCounters(Maps.newHashMap(copyFrom.getCounters()));
newCopy.setCounters(Maps.newHashMap(copyFrom.getCounters()), true);
newCopy.setColor(copyFrom.getColor().getColor());
newCopy.setPhasedOut(copyFrom.getPhasedOut());

View File

@@ -955,7 +955,7 @@ public class Player extends GameEntity implements Comparable<Player> {
}
@Override
public void setCounters(Map<CounterType, Integer> allCounters) {
public void setCounters(Map<CounterType, Integer> allCounters, boolean lki) {
counters = allCounters;
view.updateCounters(this);
getGame().fireEvent(new GameEventPlayerCounters(this, null, 0, 0));