From 4dd7e963bc985d8f945eb2ec7bf946be9a1c042d Mon Sep 17 00:00:00 2001 From: Jmlundeen <98545818+Jmlundeen@users.noreply.github.com> Date: Sun, 7 Sep 2025 16:50:46 -0500 Subject: [PATCH] update RemoveCountersSourceCost, Gwen Stacy, and Price of Betrayal (#13941) * update RemoveCountersSourceCost, Gwen Stacy, and Price of Betrayal * added support for choosing multiple counters to RemoveCountersSourceCost * changed Price of Betrayal to use player.getMultiAmount method * added REMOVE_COUNTERS to MultiAmountType * create common RemoveUpToAmountCountersEffect and update cards * update default target wording on RemoveUpToAmountCountersEffect --- .../src/mage/cards/g/GlissaSunslayer.java | 59 +----------- Mage.Sets/src/mage/cards/g/GwenStacy.java | 2 +- Mage.Sets/src/mage/cards/h/HeartlessAct.java | 62 +------------ .../src/mage/cards/p/PriceOfBetrayal.java | 90 +------------------ Mage.Sets/src/mage/cards/r/RenderInert.java | 58 +----------- .../test/cards/single/spm/GwenStacyTest.java | 61 +++++++++++++ .../cards/single/war/PriceOfBetrayalTest.java | 86 ++++++++++++++++++ .../common/RemoveCountersSourceCost.java | 62 ++++++------- .../RemoveUpToAmountCountersEffect.java | 86 ++++++++++++++++++ .../java/mage/constants/MultiAmountType.java | 1 + 10 files changed, 270 insertions(+), 297 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/war/PriceOfBetrayalTest.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/RemoveUpToAmountCountersEffect.java diff --git a/Mage.Sets/src/mage/cards/g/GlissaSunslayer.java b/Mage.Sets/src/mage/cards/g/GlissaSunslayer.java index 13b5de6d9c4..91ee16b5ae6 100644 --- a/Mage.Sets/src/mage/cards/g/GlissaSunslayer.java +++ b/Mage.Sets/src/mage/cards/g/GlissaSunslayer.java @@ -4,19 +4,15 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; -import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.RemoveUpToAmountCountersEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetEnchantmentPermanent; @@ -54,7 +50,7 @@ public final class GlissaSunslayer extends CardImpl { ability.addMode(mode); // • Remove up to three counters from target permanent. - mode = new Mode(new GlissaSunslayerEffect()); + mode = new Mode(new RemoveUpToAmountCountersEffect(3)); mode.addTarget(new TargetPermanent()); ability.addMode(mode); @@ -69,55 +65,4 @@ public final class GlissaSunslayer extends CardImpl { public GlissaSunslayer copy() { return new GlissaSunslayer(this); } -} - -class GlissaSunslayerEffect extends OneShotEffect { - - GlissaSunslayerEffect() { - super(Outcome.AIDontUseIt); - staticText = "Remove up to three counters from target permanent"; - } - - private GlissaSunslayerEffect(final GlissaSunslayerEffect effect) { - super(effect); - } - - @Override - public GlissaSunslayerEffect copy() { - return new GlissaSunslayerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - int toRemove = 3; - int removed = 0; - String[] counterNames = permanent.getCounters(game).keySet().toArray(new String[0]); - for (String counterName : counterNames) { - if (controller.chooseUse(Outcome.Neutral, "Remove " + counterName + " counters?", source, game)) { - if (permanent.getCounters(game).get(counterName).getCount() == 1 || (toRemove - removed == 1)) { - permanent.removeCounters(counterName, 1, source, game); - removed++; - } else { - int amount = controller.getAmount(1, Math.min(permanent.getCounters(game).get(counterName).getCount(), toRemove - removed), "How many?", source, game); - if (amount > 0) { - removed += amount; - permanent.removeCounters(counterName, amount, source, game); - } - } - } - if (removed >= toRemove) { - break; - } - } - game.addEffect(new BoostSourceEffect(removed, 0, Duration.EndOfTurn), source); - return true; - } - return true; - } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GwenStacy.java b/Mage.Sets/src/mage/cards/g/GwenStacy.java index d5076e6e817..cfb9cbbfc5e 100644 --- a/Mage.Sets/src/mage/cards/g/GwenStacy.java +++ b/Mage.Sets/src/mage/cards/g/GwenStacy.java @@ -53,7 +53,7 @@ public final class GwenStacy extends ModalDoubleFacedCard { // Remove two counters from Ghost-Spider: Exile the top card of your library. You may play that card this turn. this.getRightHalfCard().addAbility(new SimpleActivatedAbility( new ExileTopXMayPlayUntilEffect(1, Duration.EndOfTurn), - new RemoveCountersSourceCost(CounterType.P1P1.createInstance(2)))); + new RemoveCountersSourceCost(2))); } private GwenStacy(final GwenStacy card) { diff --git a/Mage.Sets/src/mage/cards/h/HeartlessAct.java b/Mage.Sets/src/mage/cards/h/HeartlessAct.java index 7451941044b..3a2e701c8ac 100644 --- a/Mage.Sets/src/mage/cards/h/HeartlessAct.java +++ b/Mage.Sets/src/mage/cards/h/HeartlessAct.java @@ -1,21 +1,14 @@ package mage.cards.h; -import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.RemoveUpToAmountCountersEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.CounterAnyPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -42,7 +35,7 @@ public final class HeartlessAct extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filterWithoutCounters)); // • Remove up to three counters from target creature. - Mode mode = new Mode(new HeartlessActEffect()); + Mode mode = new Mode(new RemoveUpToAmountCountersEffect(3)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } @@ -55,55 +48,4 @@ public final class HeartlessAct extends CardImpl { public HeartlessAct copy() { return new HeartlessAct(this); } -} - -class HeartlessActEffect extends OneShotEffect { - - HeartlessActEffect() { - super(Outcome.AIDontUseIt); - staticText = "Remove up to three counters from target creature"; - } - - private HeartlessActEffect(final HeartlessActEffect effect) { - super(effect); - } - - @Override - public HeartlessActEffect copy() { - return new HeartlessActEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - int toRemove = 3; - int removed = 0; - String[] counterNames = permanent.getCounters(game).keySet().toArray(new String[0]); - for (String counterName : counterNames) { - if (controller.chooseUse(Outcome.Neutral, "Remove " + counterName + " counters?", source, game)) { - if (permanent.getCounters(game).get(counterName).getCount() == 1 || (toRemove - removed == 1)) { - permanent.removeCounters(counterName, 1, source, game); - removed++; - } else { - int amount = controller.getAmount(1, Math.min(permanent.getCounters(game).get(counterName).getCount(), toRemove - removed), "How many?", source, game); - if (amount > 0) { - removed += amount; - permanent.removeCounters(counterName, amount, source, game); - } - } - } - if (removed >= toRemove) { - break; - } - } - game.addEffect(new BoostSourceEffect(removed, 0, Duration.EndOfTurn), source); - return true; - } - return true; - } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/PriceOfBetrayal.java b/Mage.Sets/src/mage/cards/p/PriceOfBetrayal.java index 8de18f96784..1ced9838a30 100644 --- a/Mage.Sets/src/mage/cards/p/PriceOfBetrayal.java +++ b/Mage.Sets/src/mage/cards/p/PriceOfBetrayal.java @@ -1,19 +1,13 @@ package mage.cards.p; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.RemoveUpToAmountCountersEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.counters.Counter; import mage.filter.FilterOpponent; import mage.filter.FilterPermanent; import mage.filter.common.FilterPermanentOrPlayer; import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetPermanentOrPlayer; import java.util.UUID; @@ -39,7 +33,7 @@ public final class PriceOfBetrayal extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); // Remove up to five counters from target artifact, creature, planeswalker or opponent. - this.getSpellAbility().addEffect(new PriceOfBetrayalEffect()); + this.getSpellAbility().addEffect(new RemoveUpToAmountCountersEffect(5)); this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(1, 1, filter2, false)); } @@ -51,82 +45,4 @@ public final class PriceOfBetrayal extends CardImpl { public PriceOfBetrayal copy() { return new PriceOfBetrayal(this); } -} - -class PriceOfBetrayalEffect extends OneShotEffect { - - PriceOfBetrayalEffect() { - super(Outcome.AIDontUseIt); - staticText = "Remove up to five counters from target artifact, creature, planeswalker, or opponent."; - } - - private PriceOfBetrayalEffect(final PriceOfBetrayalEffect effect) { - super(effect); - } - - @Override - public PriceOfBetrayalEffect copy() { - return new PriceOfBetrayalEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - - // from permanent - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - int toRemove = 5; - int removed = 0; - String[] counterNames = permanent.getCounters(game).keySet().toArray(new String[0]); - for (String counterName : counterNames) { - if (controller.chooseUse(Outcome.Neutral, "Remove " + counterName + " counters?", source, game)) { - if (permanent.getCounters(game).get(counterName).getCount() == 1 || (toRemove - removed == 1)) { - permanent.removeCounters(counterName, 1, source, game); - removed++; - } else { - int amount = controller.getAmount(1, Math.min(permanent.getCounters(game).get(counterName).getCount(), toRemove - removed), "How many?", source, game); - if (amount > 0) { - removed += amount; - permanent.removeCounters(counterName, amount, source, game); - } - } - } - if (removed >= toRemove) { - break; - } - } - return true; - } - - // from player - Player player = game.getPlayer(source.getFirstTarget()); - if (player != null) { - int toRemove = 5; - int removed = 0; - for (Counter counter : player.getCountersAsCopy().values()) { - String counterName = counter.getName(); - if (controller.chooseUse(Outcome.Neutral, "Remove " + counterName + " counters?", source, game)) { - if (player.getCountersCount(counterName) == 1 || (toRemove - removed == 1)) { - player.loseCounters(counterName, 1, source, game); - removed++; - } else { - int amount = controller.getAmount(1, Math.min(player.getCountersCount(counterName), toRemove - removed), "How many?", source, game); - if (amount > 0) { - removed += amount; - player.loseCounters(counterName, amount, source, game); - } - } - } - if (removed >= toRemove) { - break; - } - } - return true; - } - return false; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RenderInert.java b/Mage.Sets/src/mage/cards/r/RenderInert.java index eca89427255..b119d3ff9a1 100644 --- a/Mage.Sets/src/mage/cards/r/RenderInert.java +++ b/Mage.Sets/src/mage/cards/r/RenderInert.java @@ -1,15 +1,10 @@ package mage.cards.r; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.RemoveUpToAmountCountersEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; import java.util.UUID; @@ -23,7 +18,7 @@ public final class RenderInert extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); // Remove up to five counters from target permanent. - this.getSpellAbility().addEffect(new RenderInertEffect()); + this.getSpellAbility().addEffect(new RemoveUpToAmountCountersEffect(5)); this.getSpellAbility().addTarget(new TargetPermanent()); // Draw a card. @@ -38,51 +33,4 @@ public final class RenderInert extends CardImpl { public RenderInert copy() { return new RenderInert(this); } -} - -class RenderInertEffect extends OneShotEffect { - - RenderInertEffect() { - super(Outcome.Benefit); - staticText = "remove up to five counters from target permanent"; - } - - private RenderInertEffect(final RenderInertEffect effect) { - super(effect); - } - - @Override - public RenderInertEffect copy() { - return new RenderInertEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (controller == null || permanent == null) { - return false; - } - int toRemove = 5; - int removed = 0; - String[] counterNames = permanent.getCounters(game).keySet().toArray(new String[0]); - for (String counterName : counterNames) { - if (controller.chooseUse(Outcome.Neutral, "Remove " + counterName + " counters?", source, game)) { - if (permanent.getCounters(game).get(counterName).getCount() == 1 || (toRemove - removed == 1)) { - permanent.removeCounters(counterName, 1, source, game); - removed++; - } else { - int amount = controller.getAmount(1, Math.min(permanent.getCounters(game).get(counterName).getCount(), toRemove - removed), "How many?", source, game); - if (amount > 0) { - removed += amount; - permanent.removeCounters(counterName, amount, source, game); - } - } - } - if (removed >= toRemove) { - break; - } - } - return true; - } -} +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java new file mode 100644 index 00000000000..223f35b68c7 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java @@ -0,0 +1,61 @@ +package org.mage.test.cards.single.spm; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author Jmlundeen + */ +public class GwenStacyTest extends CardTestPlayerBase { + + /* + Gwen Stacy + {1}{R} + Legendary Creature - Human Performer Hero + When Gwen Stacy enters, exile the top card of your library. You may play that card for as long as you control this creature. + {2}{U}{R}{W}: Transform Gwen Stacy. Activate only as a sorcery. + 2/1 + Ghost-Spider + {2}{U}{R}{W} + Legendary Creature - Spider Human Hero + Flying, vigilance, haste + Whenever you play a land from exile or cast a spell from exile, put a +1/+1 counter on Ghost-Spider. + Remove two counters from Ghost-Spider: Exile the top card of your library. You may play that card this turn. + 4/4 + + */ + private static final String gwenStacy = "Gwen Stacy"; + private static final String ghostSpider = "Ghost-Spider"; + + @Test + @Ignore("Enable after transform mdfc rework") + public void testGhostSpider() { + setStrictChooseMode(true); + + addCard(Zone.HAND, playerA, gwenStacy); + addCard(Zone.BATTLEFIELD, playerA, "Plateau", 4); + addCard(Zone.BATTLEFIELD, playerA, "Island"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ghostSpider, true); + addCounters(1, PhaseStep.PRECOMBAT_MAIN, playerA, ghostSpider, CounterType.P1P1, 1); + addCounters(1, PhaseStep.PRECOMBAT_MAIN, playerA, ghostSpider, CounterType.CHARGE, 1); + addCounters(1, PhaseStep.PRECOMBAT_MAIN, playerA, ghostSpider, CounterType.P0P1, 1); + + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Remove two counters"); + setChoiceAmount(playerA, 1); // Charge + setChoiceAmount(playerA, 1); // P0P1 + setChoiceAmount(playerA, 0); // P1P1 + waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN); + playLand(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Mountain"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPowerToughness(playerA, ghostSpider, 4 + 1 + 1, 4 + 1 + 1); + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/war/PriceOfBetrayalTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/war/PriceOfBetrayalTest.java new file mode 100644 index 00000000000..f800e0f1c8c --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/war/PriceOfBetrayalTest.java @@ -0,0 +1,86 @@ +package org.mage.test.cards.single.war; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.TargetPlayer; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import static org.junit.Assert.assertEquals; + +/** + * + * @author Jmlundeen + */ +public class PriceOfBetrayalTest extends CardTestPlayerBase { + + /* + Price of Betrayal + {B} + Sorcery + Remove up to five counters from target artifact, creature, planeswalker, or opponent. + */ + private static final String priceOfBetrayal = "Price of Betrayal"; + + /* + Bear Cub + {1}{G} + Creature - Bear + + 2/2 + */ + private static final String bearCub = "Bear Cub"; + + @Test + public void testPriceOfBetrayalPermanent() { + setStrictChooseMode(true); + + addCard(Zone.HAND, playerA, priceOfBetrayal); + addCard(Zone.BATTLEFIELD, playerA, bearCub); + addCard(Zone.BATTLEFIELD, playerA, "Swamp"); + + addCounters(1, PhaseStep.PRECOMBAT_MAIN, playerA, bearCub, CounterType.P1P1, 3); + addCounters(1, PhaseStep.PRECOMBAT_MAIN, playerA, bearCub, CounterType.CHARGE, 1); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, priceOfBetrayal, bearCub); + setChoiceAmount(playerA, 1); // charge counter + setChoiceAmount(playerA, 3); // P1P1 counter + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPowerToughness(playerA, bearCub, 2, 2); + } + + @Test + public void testPriceOfBetrayalPlayer() { + setStrictChooseMode(true); + + Ability ability = new SimpleActivatedAbility( + new AddCountersTargetEffect(CounterType.ENERGY.createInstance(5)), + new ManaCostsImpl<>("") + ); + ability.addTarget(new TargetPlayer(1)); + addCustomCardWithAbility("add counter", playerA, ability); + + addCard(Zone.BATTLEFIELD, playerA, "Swamp"); + addCard(Zone.HAND, playerA, priceOfBetrayal); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target player gets", playerB); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, priceOfBetrayal, playerB); + setChoiceAmount(playerA, 5); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertEquals("Player should have no counters", 0, playerA.getCountersCount(CounterType.ENERGY)); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java index 5fc6f56077c..2c5b8ac5552 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java @@ -3,19 +3,15 @@ package mage.abilities.costs.common; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; +import mage.constants.MultiAmountType; import mage.constants.Outcome; import mage.counters.Counter; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.util.RandomUtil; +import mage.util.CardUtil; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.UUID; +import java.util.*; /** * @author BetaSteward_at_googlemail.com @@ -31,6 +27,12 @@ public class RemoveCountersSourceCost extends CostImpl { this.text = "remove a counter from {this}"; } + public RemoveCountersSourceCost(int amount) { + this.amount = amount; + this.name = ""; + this.text = "remove " + CardUtil.numberToText(amount) + " counters from {this}"; + } + public RemoveCountersSourceCost(Counter counter) { this.amount = counter.getCount(); this.name = counter.getName(); @@ -56,8 +58,8 @@ public class RemoveCountersSourceCost extends CostImpl { .getCounters(game) .values() .stream() - .map(Counter::getCount) - .anyMatch(i -> i >= amount); + .mapToInt(Counter::getCount) + .sum() >= amount; } else { // specific counter return permanent.getCounters(game).getCount(name) >= amount; @@ -71,36 +73,22 @@ public class RemoveCountersSourceCost extends CostImpl { if (player == null || permanent == null) { return paid; } - String toRemove; if (name.isEmpty()) { - Set toChoose = new LinkedHashSet<>(permanent.getCounters(game).keySet()); - switch (toChoose.size()) { - case 0: - return paid; - case 1: - toRemove = RandomUtil.randomFromCollection(toChoose); - break; - case 2: - Iterator iterator = toChoose.iterator(); - String choice1 = iterator.next(); - String choice2 = iterator.next(); - toRemove = player.chooseUse( - Outcome.UnboostCreature, "Choose a type of counter to remove", - null, choice1, choice2, source, game - ) ? choice1 : choice2; - break; - default: - Choice choice = new ChoiceImpl(true); - choice.setChoices(toChoose); - choice.setMessage("Choose a type of counter to remove"); - player.choose(Outcome.UnboostCreature, choice, game); - toRemove = choice.getChoice(); + List toChoose = new ArrayList<>(permanent.getCounters(game).keySet()); + if (toChoose.isEmpty()) { + return paid; + } else { + List counterList = player.getMultiAmount(Outcome.UnboostCreature, toChoose, 0, amount, amount, MultiAmountType.REMOVE_COUNTERS, game); + for (int i = 0; i < toChoose.size(); i++) { + int amountToRemove = counterList.get(i); + if (amountToRemove > 0) { + permanent.removeCounters(toChoose.get(i), amountToRemove, source, game); + } + } + paid = true; } - } else { - toRemove = name; - } - if (permanent.getCounters(game).getCount(toRemove) >= amount) { - permanent.removeCounters(toRemove, amount, source, game); + } else if (permanent.getCounters(game).getCount(name) >= amount){ + permanent.removeCounters(name, amount, source, game); this.paid = true; } return paid; diff --git a/Mage/src/main/java/mage/abilities/effects/common/RemoveUpToAmountCountersEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RemoveUpToAmountCountersEffect.java new file mode 100644 index 00000000000..e69d9cce542 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/RemoveUpToAmountCountersEffect.java @@ -0,0 +1,86 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.constants.MultiAmountType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.ArrayList; +import java.util.List; + +public class RemoveUpToAmountCountersEffect extends OneShotEffect { + + final DynamicValue amount; + + public RemoveUpToAmountCountersEffect(int amount) { + super(Outcome.Neutral); + this.amount = StaticValue.get(amount); + } + + public RemoveUpToAmountCountersEffect(DynamicValue amount) { + super(Outcome.Neutral); + this.amount = amount; + } + + private RemoveUpToAmountCountersEffect(final RemoveUpToAmountCountersEffect effect) { + super(effect); + this.amount = effect.amount; + } + + @Override + public RemoveUpToAmountCountersEffect copy() { + return new RemoveUpToAmountCountersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + int max = this.amount.calculate(game, source, this); + // from permanent + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + List toChoose = new ArrayList<>(permanent.getCounters(game).keySet()); + List counterList = controller.getMultiAmount(Outcome.UnboostCreature, toChoose, 0, 0, max, MultiAmountType.REMOVE_COUNTERS, game); + for (int i = 0; i < toChoose.size(); i++) { + int amountToRemove = counterList.get(i); + if (amountToRemove > 0) { + permanent.removeCounters(toChoose.get(i), amountToRemove, source, game); + } + } + return true; + } + + // from player + Player player = game.getPlayer(source.getFirstTarget()); + if (player != null) { + List toChoose = new ArrayList<>(player.getCountersAsCopy().keySet()); + List counterList = controller.getMultiAmount(Outcome.Neutral, toChoose, 0, 0, max, MultiAmountType.REMOVE_COUNTERS, game); + for (int i = 0; i < toChoose.size(); i++) { + int amountToRemove = counterList.get(i); + if (amountToRemove > 0) { + player.loseCounters(toChoose.get(i), amountToRemove, source, game); + } + } + return true; + } + return false; + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + return "remove up to " + CardUtil.numberToText(this.amount.toString()) + " counters from " + getTargetPointer().describeTargets(mode.getTargets(), "that permanent"); + } +} diff --git a/Mage/src/main/java/mage/constants/MultiAmountType.java b/Mage/src/main/java/mage/constants/MultiAmountType.java index 398ca7a0fd8..1755424a611 100644 --- a/Mage/src/main/java/mage/constants/MultiAmountType.java +++ b/Mage/src/main/java/mage/constants/MultiAmountType.java @@ -15,6 +15,7 @@ public class MultiAmountType { public static final MultiAmountType P1P1 = new MultiAmountType("Add +1/+1 counters", "Distribute +1/+1 counters among creatures"); public static final MultiAmountType COUNTERS = new MultiAmountType("Choose counters", "Move counters"); + public static final MultiAmountType REMOVE_COUNTERS = new MultiAmountType("Choose counters", "Remove counters"); public static final MultiAmountType CHEAT_LANDS = new MultiAmountType("Choose lands", "Add lands to your battlefield", true); private final String title;