From b6f118f89b96aaae3f5030091f001179c9372b35 Mon Sep 17 00:00:00 2001 From: tool4ever Date: Mon, 14 Oct 2024 12:55:00 +0200 Subject: [PATCH] Fear of Sleep Paralysis and support (#6287) --- .../main/java/forge/ai/AiCostDecision.java | 4 +-- .../src/main/java/forge/ai/ComputerUtil.java | 12 +++------ .../forge/ai/ability/CountersRemoveAi.java | 2 ++ .../src/main/java/forge/game/GameEntity.java | 8 +++--- .../ability/effects/CountersMoveEffect.java | 19 +++++++------ .../effects/CountersPutOrRemoveEffect.java | 13 ++++++++- .../effects/CountersRemoveAllEffect.java | 5 ++-- .../ability/effects/CountersRemoveEffect.java | 21 +++++++++------ .../src/main/java/forge/game/card/Card.java | 27 ++++++++++++++++--- .../forge/game/cost/CostRemoveAnyCounter.java | 10 +++++-- .../main/java/forge/game/cost/CostUntap.java | 5 +++- .../java/forge/game/cost/CostUntapType.java | 4 ++- .../main/java/forge/game/player/Player.java | 13 +++++++-- .../upcoming/fear_of_sleep_paralysis.txt | 11 ++++++++ .../java/forge/player/HumanCostDecision.java | 4 +-- 15 files changed, 110 insertions(+), 48 deletions(-) create mode 100644 forge-gui/res/cardsfolder/upcoming/fear_of_sleep_paralysis.txt diff --git a/forge-ai/src/main/java/forge/ai/AiCostDecision.java b/forge-ai/src/main/java/forge/ai/AiCostDecision.java index 0da8034e52f..fd176603ff0 100644 --- a/forge-ai/src/main/java/forge/ai/AiCostDecision.java +++ b/forge-ai/src/main/java/forge/ai/AiCostDecision.java @@ -651,7 +651,7 @@ public class AiCostDecision extends CostDecisionMakerBase { // TODO sort negatives to remove from best Cards first? for (final Card crd : negatives) { for (Map.Entry e : table.filterToRemove(crd).entrySet()) { - if (ComputerUtil.isNegativeCounter(e.getKey(), crd)) { + if (ComputerUtil.isNegativeCounter(e.getKey(), crd) && crd.canRemoveCounters(e.getKey())) { int over = Math.min(e.getValue(), c - toRemove); if (over > 0) { toRemove += over; @@ -762,7 +762,7 @@ public class AiCostDecision extends CostDecisionMakerBase { } } - // if table is empty, than no counter was removed + // if table is empty, then no counter was removed return table.isEmpty() ? null : PaymentDecision.counters(table); } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index af51c5afa0b..3af26c3358f 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -836,10 +836,9 @@ public class ComputerUtil { } public static CardCollection chooseUntapType(final Player ai, final String type, final Card activate, final boolean untap, final int amount, SpellAbility sa) { - CardCollection typeList = - CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa); + CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa); - typeList = CardLists.filter(typeList, Presets.TAPPED); + typeList = CardLists.filter(typeList, Presets.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterType.get(CounterEnumType.STUN))); if (untap) { typeList.remove(activate); @@ -851,12 +850,7 @@ public class ComputerUtil { CardLists.sortByPowerDesc(typeList); - final CardCollection untapList = new CardCollection(); - - for (int i = 0; i < amount; i++) { - untapList.add(typeList.get(i)); - } - return untapList; + return typeList.subList(0, amount); } public static CardCollection chooseReturnType(final Player ai, final String type, final Card activate, final Card target, final int amount, SpellAbility sa) { diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java index 6a307d80773..d386ad08d87 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java @@ -221,6 +221,8 @@ public class CountersRemoveAi extends SpellAbilityAi { sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(aiUndyingList)); return true; } + + // TODO stun counters with canRemoveCounters check // remove P1P1 counters from opposing creatures CardCollection oppP1P1List = CardLists.filter(list, diff --git a/forge-game/src/main/java/forge/game/GameEntity.java b/forge-game/src/main/java/forge/game/GameEntity.java index 285514b2189..a6c986b9d94 100644 --- a/forge-game/src/main/java/forge/game/GameEntity.java +++ b/forge-game/src/main/java/forge/game/GameEntity.java @@ -309,8 +309,10 @@ public abstract class GameEntity extends GameObject implements IIdentifiable { abstract public void setCounters(final Map allCounters); + abstract public boolean canRemoveCounters(final CounterType type); + abstract public boolean canReceiveCounters(final CounterType type); - abstract public void subtractCounter(final CounterType counterName, final int n, final Player remover); + abstract public int subtractCounter(final CounterType counterName, final int n, final Player remover); abstract public void clearCounters(); public boolean canReceiveCounters(final CounterEnumType type) { @@ -331,8 +333,8 @@ public abstract class GameEntity extends GameObject implements IIdentifiable { addCounter(CounterType.get(counterType), n, source, table); } - public void subtractCounter(final CounterEnumType counterName, final int n, final Player remover) { - subtractCounter(CounterType.get(counterName), n, remover); + public int subtractCounter(final CounterEnumType counterName, final int n, final Player remover) { + return subtractCounter(CounterType.get(counterName), n, remover); } abstract public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map params); diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersMoveEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersMoveEffect.java index 1f22a9db209..55f85d87356 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CountersMoveEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CountersMoveEffect.java @@ -101,8 +101,7 @@ public class CountersMoveEffect extends SpellAbilityEffect { // uses for multi sources -> one defined/target // this needs given counter type if (sa.hasParam("ValidSource")) { - CardCollectionView srcCards = game.getCardsIn(ZoneType.Battlefield); - srcCards = CardLists.getValidCards(srcCards, sa.getParam("ValidSource"), activator, host, sa); + CardCollectionView srcCards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("ValidSource"), activator, host, sa); List tgtCards = getDefinedCardsOrTargeted(sa); if (tgtCards.isEmpty()) { @@ -147,11 +146,6 @@ public class CountersMoveEffect extends SpellAbilityEffect { Map countersToAdd = Maps.newHashMap(); for (Card src : srcCards) { - // rule 121.5: If the first and second objects are the same object, nothing happens - if (src.equals(dest)) { - continue; - } - if ("All".equals(counterName)) { final Map tgtCounters = Maps.newHashMap(src.getCounters()); for (Map.Entry e : tgtCounters.entrySet()) { @@ -183,8 +177,7 @@ public class CountersMoveEffect extends SpellAbilityEffect { params.put("CounterType", cType); params.put("Source", source); - CardCollectionView tgtCards = game.getCardsIn(ZoneType.Battlefield); - tgtCards = CardLists.getValidCards(tgtCards, sa.getParam("ValidDefined"), activator, host, sa); + CardCollectionView tgtCards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("ValidDefined"), activator, host, sa); if (counterNum.equals("Any")) { tgtCards = activator.getController().chooseCardsForEffect( @@ -203,6 +196,9 @@ public class CountersMoveEffect extends SpellAbilityEffect { if (!dest.canReceiveCounters(cType)) { continue; } + if (!source.canRemoveCounters(cType)) { + continue; + } Card cur = game.getCardState(dest, null); if (cur == null || !cur.equalsWithGameTimestamp(dest)) { @@ -287,7 +283,7 @@ public class CountersMoveEffect extends SpellAbilityEffect { final List typeChoices = Lists.newArrayList(); // get types of counters for (CounterType ct : tgtCounters.keySet()) { - if (dest.canReceiveCounters(ct)) { + if (dest.canReceiveCounters(ct) && source.canRemoveCounters(cType)) { typeChoices.add(ct); } } @@ -337,6 +333,9 @@ public class CountersMoveEffect extends SpellAbilityEffect { if (!dest.canReceiveCounters(cType)) { return; } + if (!src.canRemoveCounters(cType)) { + return; + } int cmax = src.getCounters(cType); if (cmax <= 0) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java index 0b4f50aa69f..90c56c66c70 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java @@ -127,7 +127,18 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect { putCounter = !Expressions.compare(value, operator, operandValue); } else { - putCounter = pc.chooseBinary(sa, prompt, BinaryChoiceType.AddOrRemove, params); + boolean canReceive = tgtCard.canReceiveCounters(ctype); + boolean canRemove = tgtCard.canRemoveCounters(ctype); + if (!canReceive && !canRemove) { + return; + } + if (canReceive && !canRemove) { + putCounter = true; + } else if (!canReceive && canRemove) { + putCounter = false; + } else { + putCounter = pc.chooseBinary(sa, prompt, BinaryChoiceType.AddOrRemove, params); + } } if (putCounter) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveAllEffect.java index 459b6d7371f..4a9de811f88 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveAllEffect.java @@ -63,8 +63,7 @@ public class CountersRemoveAllEffect extends SpellAbilityEffect { for (final Card tgtCard : cards) { if (sa.hasParam("AllCounterTypes")) { for (Map.Entry e : Lists.newArrayList(tgtCard.getCounters().entrySet())) { - numberRemoved += e.getValue(); - tgtCard.subtractCounter(e.getKey(), e.getValue(), sa.getActivatingPlayer()); + numberRemoved += tgtCard.subtractCounter(e.getKey(), e.getValue(), sa.getActivatingPlayer()); } //tgtCard.getCounters().clear(); continue; @@ -74,7 +73,7 @@ public class CountersRemoveAllEffect extends SpellAbilityEffect { } if (counterAmount > 0) { - tgtCard.subtractCounter(CounterType.getType(type), counterAmount, sa.getActivatingPlayer()); + numberRemoved += tgtCard.subtractCounter(CounterType.getType(type), counterAmount, sa.getActivatingPlayer()); game.updateLastStateForCard(tgtCard); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java index d2baf42e9e3..524d430a95d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java @@ -110,8 +110,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect { // Removing energy if (type.equals("All")) { for (Map.Entry e : Lists.newArrayList(tgtPlayer.getCounters().entrySet())) { - tgtPlayer.subtractCounter(e.getKey(), e.getValue(), activator); - totalRemoved += e.getValue(); + totalRemoved += tgtPlayer.subtractCounter(e.getKey(), e.getValue(), activator); } } else { if (num.equals("All")) { @@ -120,8 +119,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect { if (type.equals("Any")) { totalRemoved += removeAnyType(tgtPlayer, cntToRemove, sa); } else { - tgtPlayer.subtractCounter(counterType, cntToRemove, activator); - totalRemoved += cntToRemove; + totalRemoved += tgtPlayer.subtractCounter(counterType, cntToRemove, activator); } } } @@ -165,11 +163,11 @@ public class CountersRemoveEffect extends SpellAbilityEffect { if (gameCard == null || !tgtCard.equalsWithGameTimestamp(gameCard)) { continue; } + final Zone zone = game.getZoneOf(gameCard); if (type.equals("All")) { for (Map.Entry e : Lists.newArrayList(gameCard.getCounters().entrySet())) { - gameCard.subtractCounter(e.getKey(), e.getValue(), activator); - totalRemoved += e.getValue(); + totalRemoved += gameCard.subtractCounter(e.getKey(), e.getValue(), activator); } game.updateLastStateForCard(gameCard); continue; @@ -180,6 +178,9 @@ public class CountersRemoveEffect extends SpellAbilityEffect { if (type.equals("Any")) { totalRemoved += removeAnyType(gameCard, cntToRemove, sa); } else { + if (!tgtCard.canRemoveCounters(counterType)) { + continue; + } cntToRemove = Math.min(cntToRemove, gameCard.getCounters(counterType)); if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) { @@ -221,14 +222,18 @@ public class CountersRemoveEffect extends SpellAbilityEffect { final Player activator = sa.getActivatingPlayer(); final PlayerController pc = activator.getController(); final Map tgtCounters = Maps.newHashMap(entity.getCounters()); + for (CounterType ct : ImmutableList.copyOf(tgtCounters.keySet())) { + if (!entity.canRemoveCounters(ct)) { + tgtCounters.remove(ct); + } + } while (cntToRemove > 0 && !tgtCounters.isEmpty()) { Map params = Maps.newHashMap(); params.put("Target", entity); String prompt = Localizer.getInstance().getMessage("lblSelectCountersTypeToRemove"); - CounterType chosenType = pc.chooseCounterType( - ImmutableList.copyOf(tgtCounters.keySet()), sa, prompt, params); + CounterType chosenType = pc.chooseCounterType(ImmutableList.copyOf(tgtCounters.keySet()), sa, prompt, params); int max = Math.min(cntToRemove, tgtCounters.get(chosenType)); // remove selection so player can't cheat additional trigger by choosing the same type multiple times 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 e7ffd5e6ff1..f413b32e8f3 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -1600,6 +1600,21 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr return true; } + @Override + public final boolean canRemoveCounters(final CounterType type) { + if (isPhasedOut()) { + return false; + } + final Map repParams = AbilityKey.mapFromAffected(this); + repParams.put(AbilityKey.CounterType, type); + repParams.put(AbilityKey.Result, 0); + repParams.put(AbilityKey.IsDamage, false); + if (game.getReplacementHandler().cantHappenCheck(ReplacementType.RemoveCounter, repParams)) { + return false; + } + return true; + } + @Override public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map params) { int addAmount = n; @@ -1736,11 +1751,11 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr } @Override - public final void subtractCounter(final CounterType counterName, final int n, final Player remover) { - subtractCounter(counterName, n, remover, false); + public final int subtractCounter(final CounterType counterName, final int n, final Player remover) { + return subtractCounter(counterName, n, remover, false); } - public final void subtractCounter(final CounterType counterName, final int n, final Player remover, final boolean isDamage) { + public final int subtractCounter(final CounterType counterName, final int n, final Player remover, final boolean isDamage) { int oldValue = getCounters(counterName); int newValue = Math.max(oldValue - n, 0); @@ -1758,12 +1773,14 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr newValue = 0; } break; + case Replaced: + return 0; default: break; } final int delta = oldValue - newValue; - if (delta == 0) { return; } + if (delta == 0) { return 0; } int powerBonusBefore = getPowerBonusFromCounters(); int toughnessBonusBefore = getToughnessBonusFromCounters(); @@ -1800,6 +1817,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr runParams.put(AbilityKey.CounterAmount, delta); runParams.put(AbilityKey.NewCounterAmount, newValue); getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemovedOnce, runParams, false); + + return delta; } @Override diff --git a/forge-game/src/main/java/forge/game/cost/CostRemoveAnyCounter.java b/forge-game/src/main/java/forge/game/cost/CostRemoveAnyCounter.java index 95818b6eff9..c68f97212ff 100644 --- a/forge-game/src/main/java/forge/game/cost/CostRemoveAnyCounter.java +++ b/forge-game/src/main/java/forge/game/cost/CostRemoveAnyCounter.java @@ -70,10 +70,16 @@ public class CostRemoveAnyCounter extends CostPart { int allCounters = 0; for (Card c : validCards) { if (this.counter != null) { + if (!c.canRemoveCounters(this.counter)) { + continue; + } allCounters += c.getCounters(this.counter); } else { - for (Integer value : c.getCounters().values()) { - allCounters += value; + for (Map.Entry entry : c.getCounters().entrySet()) { + if (!c.canRemoveCounters(entry.getKey())) { + continue; + } + allCounters += entry.getValue(); } } } diff --git a/forge-game/src/main/java/forge/game/cost/CostUntap.java b/forge-game/src/main/java/forge/game/cost/CostUntap.java index 0fbebd0bbed..2a4a800be0c 100644 --- a/forge-game/src/main/java/forge/game/cost/CostUntap.java +++ b/forge-game/src/main/java/forge/game/cost/CostUntap.java @@ -21,6 +21,8 @@ import com.google.common.collect.Maps; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CardCollection; +import forge.game.card.CounterEnumType; +import forge.game.card.CounterType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.trigger.TriggerType; @@ -78,7 +80,8 @@ public class CostUntap extends CostPart { @Override public final boolean canPay(final SpellAbility ability, final Player payer, final boolean effect) { final Card source = ability.getHostCard(); - return source.isTapped() && !source.isAbilitySick(); + return source.isTapped() && !source.isAbilitySick() && + (source.getCounters(CounterEnumType.STUN) == 0 || source.canRemoveCounters(CounterType.get(CounterEnumType.STUN))); } @Override diff --git a/forge-game/src/main/java/forge/game/cost/CostUntapType.java b/forge-game/src/main/java/forge/game/cost/CostUntapType.java index 4fc1cbd34bc..4cc9894e32d 100644 --- a/forge-game/src/main/java/forge/game/cost/CostUntapType.java +++ b/forge-game/src/main/java/forge/game/cost/CostUntapType.java @@ -23,6 +23,8 @@ import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; +import forge.game.card.CounterEnumType; +import forge.game.card.CounterType; import forge.game.card.CardPredicates.Presets; import forge.game.player.Player; import forge.game.spellability.SpellAbility; @@ -90,7 +92,7 @@ public class CostUntapType extends CostPartWithList { if (!canUntapSource) { typeList.remove(source); } - typeList = CardLists.filter(typeList, Presets.TAPPED); + typeList = CardLists.filter(typeList, Presets.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterType.get(CounterEnumType.STUN))); final int amount = this.getAbilityAmount(ability); return (typeList.size() != 0) && (typeList.size() >= amount); diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 02d9db748e2..df35d49a727 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -855,6 +855,14 @@ public class Player extends GameEntity implements Comparable { return true; } + public final boolean canRemoveCounters(final CounterType type) { + if (!isInGame()) { + return false; + } + // no RE affecting players currently, skip check for performance + return true; + } + @Override public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map params) { int addAmount = n; @@ -896,12 +904,12 @@ public class Player extends GameEntity implements Comparable { } @Override - public void subtractCounter(CounterType counterName, int num, final Player remover) { + public int subtractCounter(CounterType counterName, int num, final Player remover) { int oldValue = getCounters(counterName); int newValue = Math.max(oldValue - num, 0); final int delta = oldValue - newValue; - if (delta == 0) { return; } + if (delta == 0) { return 0; } setCounters(counterName, newValue, null, true); @@ -917,6 +925,7 @@ public class Player extends GameEntity implements Comparable { getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemoved, runParams, false); } */ + return delta; } public final void clearCounters() { diff --git a/forge-gui/res/cardsfolder/upcoming/fear_of_sleep_paralysis.txt b/forge-gui/res/cardsfolder/upcoming/fear_of_sleep_paralysis.txt new file mode 100644 index 00000000000..a750cc23ea3 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/fear_of_sleep_paralysis.txt @@ -0,0 +1,11 @@ +Name:Fear of Sleep Paralysis +ManaCost:5 U +Types:Enchantment Creature Nightmare +PT:6/6 +K:Flying +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigTap | TriggerDescription$ Eerie — Whenever CARDNAME or another enchantment you control enters and whenever you fully unlock a Room, tap up to one target creature and put a stun counter on it. +T:Mode$ FullyUnlock | ValidCard$ Card.Room | ValidPlayer$ You | Secondary$ True | Execute$ TrigTap | TriggerZones$ Battlefield | TriggerDescription$ Eerie — Whenever CARDNAME or another enchantment you control enters and whenever you fully unlock a Room, tap up to one target creature and put a stun counter on it. +SVar:TrigTap:DB$ Tap | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 1 | SubAbility$ DBStun +SVar:DBStun:DB$ PutCounter | Defined$ Targeted | CounterType$ Stun | CounterNum$ 1 +R:Event$ RemoveCounter | ActiveZones$ Battlefield | ValidCard$ Permanent.OppCtrl | ValidCounterType$ STUN | Layer$ CantHappen | Description$ Stun counters can't be removed from permanents your opponents control. +Oracle:Flying\nEerie — Whenever Fear of Sleep Paralysis or another enchantment you control enters and whenever you fully unlock a Room, tap up to one target creature and put a stun counter on it.\nStun counters can't be removed from permanents your opponents control. (They won't untap if they have stun counters.) diff --git a/forge-gui/src/main/java/forge/player/HumanCostDecision.java b/forge-gui/src/main/java/forge/player/HumanCostDecision.java index 6f8437163dc..4ffa07d42fc 100644 --- a/forge-gui/src/main/java/forge/player/HumanCostDecision.java +++ b/forge-gui/src/main/java/forge/player/HumanCostDecision.java @@ -992,7 +992,7 @@ public class HumanCostDecision extends CostDecisionMakerBase { cType = getController().chooseCounterType(Lists.newArrayList(cmap.keySet()), sa, prompt, null); } - if (cType == null) { + if (cType == null || !c.canRemoveCounters(cType)) { return false; } @@ -1308,7 +1308,7 @@ public class HumanCostDecision extends CostDecisionMakerBase { public PaymentDecision visit(final CostUntapType cost) { CardCollection typeList = CardLists.getValidCards(player.getGame().getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), player, source, ability); - typeList = CardLists.filter(typeList, Presets.TAPPED); + typeList = CardLists.filter(typeList, Presets.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterType.get(CounterEnumType.STUN))); if (!cost.canUntapSource) { typeList.remove(source); }