From 64e08b49b15c4be7cb192d3f47a54847dfee3c24 Mon Sep 17 00:00:00 2001 From: Susucre <34709007+Susucre@users.noreply.github.com> Date: Sat, 22 Jun 2024 14:47:47 +0200 Subject: [PATCH] fix cost reduction not controller specific for [MH3] It That Heralds the End and [MH3] Ral, Leyline Prodify fix #12503 --- .../src/mage/cards/i/ItThatHeraldsTheEnd.java | 4 +- .../src/mage/cards/m/MutatedCultist.java | 29 ++++-------- .../src/mage/cards/r/RalLeylineProdigy.java | 4 +- .../single/mh3/ItThatHeraldsTheEndTest.java | 46 +++++++++++++++++++ .../serverside/base/MageTestPlayerBase.java | 26 +++++++---- .../cost/SpellsCostReductionAllEffect.java | 17 +++++-- .../SpellsCostReductionControllerEffect.java | 7 ++- 7 files changed, 93 insertions(+), 40 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/ItThatHeraldsTheEndTest.java diff --git a/Mage.Sets/src/mage/cards/i/ItThatHeraldsTheEnd.java b/Mage.Sets/src/mage/cards/i/ItThatHeraldsTheEnd.java index 5e1d40dfa1a..d41f0be8571 100644 --- a/Mage.Sets/src/mage/cards/i/ItThatHeraldsTheEnd.java +++ b/Mage.Sets/src/mage/cards/i/ItThatHeraldsTheEnd.java @@ -3,7 +3,7 @@ package mage.cards.i; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.cost.SpellsCostReductionAllEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -40,7 +40,7 @@ public final class ItThatHeraldsTheEnd extends CardImpl { this.toughness = new MageInt(2); // Colorless spells you cast with mana value 7 or greater cost {1} less to cast. - this.addAbility(new SimpleStaticAbility(new SpellsCostReductionAllEffect(filter, 1))); + this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); // Other colorless creatures you control get +1/+1. this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( diff --git a/Mage.Sets/src/mage/cards/m/MutatedCultist.java b/Mage.Sets/src/mage/cards/m/MutatedCultist.java index 0783103124c..5e58768aac6 100644 --- a/Mage.Sets/src/mage/cards/m/MutatedCultist.java +++ b/Mage.Sets/src/mage/cards/m/MutatedCultist.java @@ -1,33 +1,19 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.SpellAbility; -import mage.abilities.costs.Cost; -import mage.abilities.costs.common.RemoveAllCountersSourceCost; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.cost.CostModificationEffectImpl; -import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; -import mage.abilities.effects.common.cost.SpellsCostReductionAllEffect; -import mage.constants.*; -import mage.abilities.keyword.DevoidAbility; import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.DevoidAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.counters.CounterType; +import mage.constants.*; import mage.filter.FilterOpponent; import mage.filter.FilterPermanent; -import mage.filter.FilterPlayer; -import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterPermanentOrPlayer; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.filter.predicate.permanent.CounterAnyPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -35,8 +21,9 @@ import mage.target.common.TargetPermanentOrPlayer; import mage.util.CardUtil; import mage.watchers.common.CastSpellLastTurnWatcher; +import java.util.UUID; + /** - * * @author grimreap124 */ public final class MutatedCultist extends CardImpl { @@ -49,7 +36,7 @@ public final class MutatedCultist extends CardImpl { public MutatedCultist(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); - + this.subtype.add(SubType.ELDRAZI); this.subtype.add(SubType.HORROR); this.power = new MageInt(1); @@ -119,7 +106,7 @@ class MutatedCultistSpellsCostReductionEffect extends CostModificationEffectImpl int spellsCast; int reductionAmount; - + public MutatedCultistSpellsCostReductionEffect(int reductionAmount) { super(Duration.EndOfTurn, Outcome.Benefit, CostModificationType.REDUCE_COST); this.reductionAmount = reductionAmount; @@ -136,7 +123,7 @@ class MutatedCultistSpellsCostReductionEffect extends CostModificationEffectImpl super.init(source, game); CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { - spellsCast = watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()); + spellsCast = watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()); } } @@ -154,7 +141,7 @@ class MutatedCultistSpellsCostReductionEffect extends CostModificationEffectImpl discard(); // only one use return false; } - } + } if (abilityToModify instanceof SpellAbility) { return abilityToModify.isControlledBy(source.getControllerId()); } diff --git a/Mage.Sets/src/mage/cards/r/RalLeylineProdigy.java b/Mage.Sets/src/mage/cards/r/RalLeylineProdigy.java index 07d95045b10..d0d24fb8de8 100644 --- a/Mage.Sets/src/mage/cards/r/RalLeylineProdigy.java +++ b/Mage.Sets/src/mage/cards/r/RalLeylineProdigy.java @@ -16,7 +16,7 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageMultiEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.cost.SpellsCostReductionAllEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; @@ -119,7 +119,7 @@ class RalLeylineProdigyCostReductionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - SpellsCostReductionAllEffect effect = new SpellsCostReductionAllEffect(filter, 1); + SpellsCostReductionControllerEffect effect = new SpellsCostReductionControllerEffect(filter, 1); effect.setDuration(Duration.UntilYourNextTurn); game.addEffect(effect, source); return true; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/ItThatHeraldsTheEndTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/ItThatHeraldsTheEndTest.java new file mode 100644 index 00000000000..f5b381ddd39 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/ItThatHeraldsTheEndTest.java @@ -0,0 +1,46 @@ +package org.mage.test.cards.single.mh3; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author Susucr + */ +public class ItThatHeraldsTheEndTest extends CardTestPlayerBase { + + /** + * {@link mage.cards.i.ItThatHeraldsTheEnd It That Heralds the End} {1}{C} + * Creature — Eldrazi Drone + * Colorless spells you cast with mana value 7 or greater cost {1} less to cast. + * Other colorless creatures you control get +1/+1. + * 2/2 + */ + private static final String it = "It That Heralds the End"; + + @Test + public void test_Simple() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, it); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); + addCard(Zone.BATTLEFIELD, playerB, "Forest", 7); + addCard(Zone.HAND, playerA, "Ebony Rhino"); + addCard(Zone.HAND, playerB, "Ebony Rhino"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ebony Rhino"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Ebony Rhino"); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertTappedCount("Swamp", true, 6); + assertTappedCount("Forest", true, 7); + assertPermanentCount(playerA, "Ebony Rhino", 1); + assertPowerToughness(playerA, "Ebony Rhino", 5, 6); + assertPermanentCount(playerB, "Ebony Rhino", 1); + assertPowerToughness(playerB, "Ebony Rhino", 4, 5); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java index 5ae7956d2da..ca7e6c859e8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java @@ -11,7 +11,7 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.*; import mage.abilities.effects.common.cost.SpellsCostIncreasingAllEffect; -import mage.abilities.effects.common.cost.SpellsCostReductionAllEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.Card; import mage.cards.CardImpl; @@ -31,7 +31,6 @@ import mage.server.managers.ConfigSettings; import mage.server.util.ConfigFactory; import mage.server.util.ConfigWrapper; import mage.server.util.PluginClassLoader; -import mage.utils.SystemUtil; import mage.server.util.config.GamePlugin; import mage.server.util.config.Plugin; import mage.target.TargetPermanent; @@ -40,6 +39,7 @@ import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCardInLibrary; import mage.util.Copier; +import mage.utils.SystemUtil; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.junit.Assert; @@ -241,10 +241,18 @@ public abstract class MageTestPlayerBase { * @param enable */ protected void setStrictChooseMode(boolean enable) { - if (playerA != null) playerA.setChooseStrictMode(enable); - if (playerB != null) playerB.setChooseStrictMode(enable); - if (playerC != null) playerC.setChooseStrictMode(enable); - if (playerD != null) playerD.setChooseStrictMode(enable); + if (playerA != null) { + playerA.setChooseStrictMode(enable); + } + if (playerB != null) { + playerB.setChooseStrictMode(enable); + } + if (playerC != null) { + playerC.setChooseStrictMode(enable); + } + if (playerD != null) { + playerD.setChooseStrictMode(enable); + } } protected void addCustomCardWithSpell(TestPlayer controllerPlayer, SpellAbility spellAbility, Ability extraAbility, CardType cardType) { @@ -319,7 +327,7 @@ public abstract class MageTestPlayerBase { if (modificationAmount >= 0) { effect = new SpellsCostIncreasingAllEffect(modificationAmount, StaticFilters.FILTER_CARD, TargetController.YOU); } else { - effect = new SpellsCostReductionAllEffect(StaticFilters.FILTER_CARD, -1 * modificationAmount, false, true); + effect = new SpellsCostReductionControllerEffect(StaticFilters.FILTER_CARD, -1 * modificationAmount, false); } addCustomCardWithAbility( @@ -439,7 +447,9 @@ class CustomTestCard extends CardImpl { abilitiesList.put(cardName, new AbilitiesImpl<>()); } Abilities oldAbilities = abilitiesList.get(cardName); - if (ability != null) oldAbilities.add(ability); + if (ability != null) { + oldAbilities.add(ability); + } spellAbilitiesList.put(cardName, spellAbility); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionAllEffect.java index 4786eb69af3..7a4acdf218f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionAllEffect.java @@ -1,8 +1,5 @@ package mage.abilities.effects.common.cost; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -16,11 +13,18 @@ import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + /** + * Reduce cost of spells from any controller. + * * @author LevelX2 */ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl { + private static final FilterCard defaultFilter = new FilterCard("Spells"); private final FilterCard filter; private final int amount; private final boolean upTo; @@ -28,7 +32,7 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl { private UUID controllerId; public SpellsCostReductionAllEffect(int amount) { - this(new FilterCard("Spells"), amount); + this(defaultFilter, amount); } public SpellsCostReductionAllEffect(FilterCard filter, int amount) { @@ -39,7 +43,10 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl { this(filter, amount, upTo, false); } - public SpellsCostReductionAllEffect(FilterCard filter, int amount, boolean upTo, boolean onlyControlled) { + /** + * Note to devs: If you need onlyControlled at true, use SpellsCostReductionControllerEffect instead. + */ + protected SpellsCostReductionAllEffect(FilterCard filter, int amount, boolean upTo, boolean onlyControlled) { super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); this.filter = filter; this.amount = amount; diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java index 25b84b57b56..317d61f6f89 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java @@ -1,7 +1,5 @@ package mage.abilities.effects.common.cost; -import java.util.LinkedHashSet; -import java.util.Set; import mage.MageObject; import mage.Mana; import mage.abilities.Ability; @@ -20,7 +18,12 @@ import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; +import java.util.LinkedHashSet; +import java.util.Set; + /** + * Reduces cost of spell for the controller of the effect. + * * @author North */ public class SpellsCostReductionControllerEffect extends CostModificationEffectImpl {