diff --git a/Mage.Sets/src/mage/cards/t/TheGreatHenge.java b/Mage.Sets/src/mage/cards/t/TheGreatHenge.java index 54a11b8030a..a46ed29443c 100644 --- a/Mage.Sets/src/mage/cards/t/TheGreatHenge.java +++ b/Mage.Sets/src/mage/cards/t/TheGreatHenge.java @@ -1,24 +1,25 @@ package mage.cards.t; +import mage.MageInt; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.dynamicvalue.common.GreatestPowerAmongControlledCreaturesValue; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SetTargetPointer; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; import java.util.UUID; @@ -33,9 +34,7 @@ public final class TheGreatHenge extends CardImpl { this.supertype.add(SuperType.LEGENDARY); // This spell costs {X} less to cast, where X is the greatest power among creatures you control. - this.addAbility(new SimpleStaticAbility( - Zone.ALL, new SpellCostReductionSourceEffect(GreatestPowerAmongControlledCreaturesValue.instance) - ).setRuleAtTheTop(true).addHint(GreatestPowerAmongControlledCreaturesValue.getHint())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new TheGreatHengeCostReductionEffect())); // {T}: Add {G}{G}. You gain 2 life. Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GreenMana(2), new TapSourceCost()); @@ -60,4 +59,42 @@ public final class TheGreatHenge extends CardImpl { public TheGreatHenge copy() { return new TheGreatHenge(this); } -} \ No newline at end of file +} + +class TheGreatHengeCostReductionEffect extends CostModificationEffectImpl { + + TheGreatHengeCostReductionEffect() { + super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "This spell costs {X} less to cast, where X is the greatest power among creatures you control"; + } + + private TheGreatHengeCostReductionEffect(final TheGreatHengeCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + int reductionAmount = game.getBattlefield() + .getAllActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, abilityToModify.getControllerId(), game + ).stream() + .map(Permanent::getPower) + .mapToInt(MageInt::getValue) + .max() + .orElse(0); + CardUtil.reduceCost(abilityToModify, Math.max(0, reductionAmount)); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify instanceof SpellAbility + && abilityToModify.getSourceId().equals(source.getSourceId()) + && game.getCard(abilityToModify.getSourceId()) != null; + } + + @Override + public TheGreatHengeCostReductionEffect copy() { + return new TheGreatHengeCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheSkullsporeNexus.java b/Mage.Sets/src/mage/cards/t/TheSkullsporeNexus.java index 26ff5ef4cd9..530092dd1e5 100644 --- a/Mage.Sets/src/mage/cards/t/TheSkullsporeNexus.java +++ b/Mage.Sets/src/mage/cards/t/TheSkullsporeNexus.java @@ -1,23 +1,25 @@ package mage.cards.t; +import mage.MageInt; import mage.MageItem; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.dynamicvalue.common.GreatestPowerAmongControlledCreaturesValue; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeGroupEvent; @@ -25,6 +27,7 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.FungusDinosaurToken; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; import java.util.List; import java.util.Objects; @@ -42,9 +45,7 @@ public final class TheSkullsporeNexus extends CardImpl { this.supertype.add(SuperType.LEGENDARY); // This spell costs {X} less to cast, where X is the greatest power among creatures you control. - this.addAbility(new SimpleStaticAbility( - Zone.ALL, new SpellCostReductionSourceEffect(GreatestPowerAmongControlledCreaturesValue.instance) - ).setRuleAtTheTop(true).addHint(GreatestPowerAmongControlledCreaturesValue.getHint())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new TheSkullsporeNexusReductionEffect())); // Whenever one or more nontoken creatures you control die, create a green Fungus Dinosaur creature token with base power and toughness each equal to the total power of those creatures. this.addAbility(new TheSkullsporeNexusTrigger()); @@ -69,6 +70,44 @@ public final class TheSkullsporeNexus extends CardImpl { } } +class TheSkullsporeNexusReductionEffect extends CostModificationEffectImpl { + + TheSkullsporeNexusReductionEffect() { + super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "This spell costs {X} less to cast, where X is the greatest power among creatures you control"; + } + + private TheSkullsporeNexusReductionEffect(final TheSkullsporeNexusReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + int reductionAmount = game.getBattlefield() + .getAllActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, abilityToModify.getControllerId(), game + ).stream() + .map(Permanent::getPower) + .mapToInt(MageInt::getValue) + .max() + .orElse(0); + CardUtil.reduceCost(abilityToModify, Math.max(0, reductionAmount)); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify instanceof SpellAbility + && abilityToModify.getSourceId().equals(source.getSourceId()) + && game.getCard(abilityToModify.getSourceId()) != null; + } + + @Override + public TheSkullsporeNexusReductionEffect copy() { + return new TheSkullsporeNexusReductionEffect(this); + } +} + class TheSkullsporeNexusTrigger extends TriggeredAbilityImpl { TheSkullsporeNexusTrigger() { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/TheSkullsporeNexusTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/TheSkullsporeNexusTest.java index 19652fd7404..e1010e95e0f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/TheSkullsporeNexusTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/TheSkullsporeNexusTest.java @@ -65,4 +65,40 @@ public class TheSkullsporeNexusTest extends CardTestPlayerBase { assertTappedCount("Swamp", true, 2); assertTapped(nexus, true); } + + // This test is there as some of the cost reduction code has issue with + // counting/checking for the right player, when you cast a card you don't + // own. + @Test + public void test_costreduction_opp_card() { + setStrictChooseMode(true); + + skipInitShuffling(); + addCard(Zone.LIBRARY, playerB, nexus); + addCard(Zone.BATTLEFIELD, playerB, "Hill Giant"); // B has a 3/3 + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); // A has a 2/2 + addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 5 + 2); + addCard(Zone.HAND, playerA, "Underground Sea"); + + // Siphon Insight {U}{B} -- Instant + // Look at the top two cards of target opponent's library. + // Exile one of them face down and put the other on the bottom of that library. + // You may look at and play the exiled card for as long as it remains exiled, + // and you may spend mana as though it were mana of any color to cast that spell. + addCard(Zone.HAND, playerA, "Siphon Insight"); + + castSpell(1, PhaseStep.UPKEEP, playerA, "Siphon Insight", playerB); + setChoice(playerA, nexus); // choose nexus to exile + + // Nexus should cost 4GG, not 3GG + checkPlayableAbility("can't cast with 5 mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nexus, false); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Underground Sea"); + checkPlayableAbility("can cast with 6 mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nexus, true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nexus); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertTappedCount("Underground Sea", true, 8); + } }