From c343767e8ead3288f9c5e5d9a297de9cd4320406 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 31 Jul 2020 13:53:07 +0200 Subject: [PATCH] * Fixed available mana generation of Jungle Patrol (was no mana ability) and Priest of Yawgmoth (#6698). --- Mage.Sets/src/mage/cards/j/JunglePatrol.java | 5 +- .../src/mage/cards/p/PriestOfYawgmoth.java | 13 +++- .../mana/NonTappingManaAbilitiesTest.java | 78 ++++++++++++------- .../cards/mana/TappedForManaRelatedTest.java | 20 +++++ .../common/HighestCMCOfPermanentValue.java | 67 ++++++++++++++++ 5 files changed, 149 insertions(+), 34 deletions(-) create mode 100644 Mage/src/main/java/mage/abilities/dynamicvalue/common/HighestCMCOfPermanentValue.java diff --git a/Mage.Sets/src/mage/cards/j/JunglePatrol.java b/Mage.Sets/src/mage/cards/j/JunglePatrol.java index 3a16b86acc..b421756526 100644 --- a/Mage.Sets/src/mage/cards/j/JunglePatrol.java +++ b/Mage.Sets/src/mage/cards/j/JunglePatrol.java @@ -12,6 +12,7 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -43,13 +44,13 @@ public final class JunglePatrol extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(2); - // {1}{G}, {tap}: Create a 0/1 green Wall creature token with defender named Wood. + // {1}{G}, {T}: Create a 0/1 green Wall creature token with defender named Wood. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new WoodToken()), new ManaCostsImpl("{1}{G}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); // Sacrifice a token named Wood: Add {R}. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(Mana.RedMana(1), new PermanentsOnBattlefieldCount(filter)), new SacrificeTargetCost(new TargetControlledPermanent(1, 1, filter, true)))); } diff --git a/Mage.Sets/src/mage/cards/p/PriestOfYawgmoth.java b/Mage.Sets/src/mage/cards/p/PriestOfYawgmoth.java index 1a157bbc6e..c3d267f29e 100644 --- a/Mage.Sets/src/mage/cards/p/PriestOfYawgmoth.java +++ b/Mage.Sets/src/mage/cards/p/PriestOfYawgmoth.java @@ -6,12 +6,15 @@ import mage.MageInt; import mage.Mana; import mage.abilities.Ability; import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.HighestCMCOfPermanentValue; import mage.abilities.dynamicvalue.common.SacrificeCostConvertedMana; import mage.abilities.mana.DynamicManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledArtifactPermanent; import mage.target.common.TargetControlledPermanent; @@ -28,10 +31,14 @@ public final class PriestOfYawgmoth extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(2); - // {T}, Sacrifice an artifact: Add an amount of {B} equal to the sacrificed artifact's converted mana cost. + // {T}, Sacrifice an artifact: Add an amount of {B} equal to the sacrificed artifact's converted mana cost. Ability ability = new DynamicManaAbility(Mana.BlackMana(1), new SacrificeCostConvertedMana("artifact"), - "add an amount of {B} equal to the sacrificed artifact's converted mana cost"); - ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledArtifactPermanent()))); + new TapSourceCost(), + "add an amount of {B} equal to the sacrificed artifact's converted mana cost", + false, + new HighestCMCOfPermanentValue(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, true) + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT))); this.addAbility(ability); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/NonTappingManaAbilitiesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/NonTappingManaAbilitiesTest.java index 26f3a1a02d..81cc312023 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/mana/NonTappingManaAbilitiesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/NonTappingManaAbilitiesTest.java @@ -13,15 +13,14 @@ import static org.mage.test.utils.ManaOptionsTestUtils.assertManaOptions; * * @author LevelX2 */ - public class NonTappingManaAbilitiesTest extends CardTestPlayerBase { @Test public void druidsRepositoryTest() { setStrictChooseMode(true); - + addCard(Zone.HAND, playerA, "Alaborn Grenadier", 1); //Creature {W}{W} - + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 2); // Whenever a creature you control attacks, put a charge counter on Druids' Repository. // Remove a charge counter from Druids' Repository: Add one mana of any color. @@ -30,36 +29,36 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase { attack(1, playerA, "Silvercoat Lion"); attack(1, playerA, "Silvercoat Lion"); setChoice(playerA, "Whenever a creature you control"); - + setStopAt(1, PhaseStep.END_COMBAT); execute(); - - assertTappedCount("Silvercoat Lion", true, 2); - assertCounterCount(playerA,"Druids' Repository", CounterType.CHARGE, 2); + + assertTappedCount("Silvercoat Lion", true, 2); + assertCounterCount(playerA, "Druids' Repository", CounterType.CHARGE, 2); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); - assertManaOptions("{Any}{Any}", manaOptions); - + assertManaOptions("{Any}{Any}", manaOptions); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Alaborn Grenadier"); setChoice(playerA, "White"); setChoice(playerA, "White"); - + setStopAt(1, PhaseStep.END_TURN); execute(); - assertCounterCount(playerA,"Druids' Repository", CounterType.CHARGE, 0); + assertCounterCount(playerA, "Druids' Repository", CounterType.CHARGE, 0); assertPermanentCount(playerA, "Alaborn Grenadier", 1); } - @Test + @Test public void TestWorkhorse() { setStrictChooseMode(true); - + // Workhorse enters the battlefield with four +1/+1 counters on it. // Remove a +1/+1 counter from Workhorse: Add {C}. addCard(Zone.BATTLEFIELD, playerA, "Workhorse", 1); - + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); execute(); @@ -68,7 +67,7 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase { ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); assertManaOptions("{C}{C}{C}{C}", manaOptions); - } + } @Test public void TestMorselhoarder() { @@ -108,7 +107,7 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase { assertManaOptions("{W}{B}{B}{B}", manaOptions); assertManaOptions("{B}{B}{B}{B}", manaOptions); } - + @Test public void TestCrystallineCrawler() { setStrictChooseMode(true); @@ -128,19 +127,17 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase { assertManaOptions("{Any}{Any}", manaOptions); } - @Test public void TestCoalGolemAndDromarsAttendant() { setStrictChooseMode(true); addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); - + // {1}, Sacrifice Dromar's Attendant: Add {W}{U}{B}. - addCard(Zone.BATTLEFIELD, playerA, "Dromar's Attendant", 1); - + addCard(Zone.BATTLEFIELD, playerA, "Dromar's Attendant", 1); + // {3}, Sacrifice Coal Golem: Add {R}{R}{R}. addCard(Zone.BATTLEFIELD, playerA, "Coal Golem", 1); - setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -152,23 +149,23 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase { assertManaOptions("{W}{U}{B}", manaOptions); assertManaOptions("{R}{R}{R}", manaOptions); } - - + /** - * The order the mana abilities are checked during available mana calculation does matter. - * Because Coal Golem can not be used as long as Dromar's Attendant is not used yet to produce the 3 mana. + * The order the mana abilities are checked during available mana + * calculation does matter. Because Coal Golem can not be used as long as + * Dromar's Attendant is not used yet to produce the 3 mana. */ @Test public void TestCoalGolemAndDromarsAttendantOrder2() { setStrictChooseMode(true); addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); - + // {3}, Sacrifice Coal Golem: Add {R}{R}{R}. addCard(Zone.BATTLEFIELD, playerA, "Coal Golem", 1); // {1}, Sacrifice Dromar's Attendant: Add {W}{U}{B}. - addCard(Zone.BATTLEFIELD, playerA, "Dromar's Attendant", 1); - + addCard(Zone.BATTLEFIELD, playerA, "Dromar's Attendant", 1); + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -180,5 +177,28 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase { assertManaOptions("{W}{U}{B}", manaOptions); assertManaOptions("{R}{R}{R}", manaOptions); } + + @Test + public void TestJunglePatrol() { + setStrictChooseMode(true); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + // {1}{G}, {T}: Create a 0/1 green Wall creature token with defender named Wood. + // Sacrifice a token named Wood: Add {R}. + addCard(Zone.BATTLEFIELD, playerA, "Jungle Patrol", 1); -} \ No newline at end of file + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G}, {T}: Create"); + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G}, {T}: Create"); + activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G}, {T}: Create"); + + setStopAt(5, PhaseStep.BEGIN_COMBAT); + execute(); + + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Wood", 3); + + ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); + Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); + assertManaOptions("{R}{R}{R}", manaOptions); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/TappedForManaRelatedTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/TappedForManaRelatedTest.java index 39bdcdd1f2..6e941e49d2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/mana/TappedForManaRelatedTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/TappedForManaRelatedTest.java @@ -289,5 +289,25 @@ public class TappedForManaRelatedTest extends CardTestPlayerBase { assertManaOptions("{G}{G}{G}{G}{G}{G}{G}", manaOptions); } + @Test + public void TestPriestOfYawgmoth() { + setStrictChooseMode(true); + + // {T}, Sacrifice an artifact: Add an amount of {B} equal to the sacrificed artifact's converted mana cost. + addCard(Zone.BATTLEFIELD, playerA, "Priest of Yawgmoth", 1); // Creature {1}{B} 1/2 + + addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus", 1); // {3} + addCard(Zone.BATTLEFIELD, playerA, "Accorder's Shield", 1); // {0} + addCard(Zone.BATTLEFIELD, playerA, "Adarkar Sentinel", 1); // {5} + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertAllCommandsUsed(); + + ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); + Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); + assertManaOptions("{B}{B}{B}{B}{B}", manaOptions); + } } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/HighestCMCOfPermanentValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/HighestCMCOfPermanentValue.java new file mode 100644 index 0000000000..c83a523b29 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/HighestCMCOfPermanentValue.java @@ -0,0 +1,67 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.dynamicvalue.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class HighestCMCOfPermanentValue implements DynamicValue { + + private final FilterPermanent filter; + private final boolean onlyIfCanBeSacrificed; + + public HighestCMCOfPermanentValue(FilterPermanent filter, boolean onlyIfCanBeSacrificed) { + super(); + this.filter = filter; + this.onlyIfCanBeSacrificed = onlyIfCanBeSacrificed; + } + + public HighestCMCOfPermanentValue(final HighestCMCOfPermanentValue dynamicValue) { + this.filter = dynamicValue.filter; + this.onlyIfCanBeSacrificed = dynamicValue.onlyIfCanBeSacrificed; + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int value = 0; + Player controller = game.getPlayer(sourceAbility.getControllerId()); + if (controller != null) { + for (Permanent permanent : game.getBattlefield() + .getActivePermanents(filter, sourceAbility.getControllerId(), sourceAbility.getSourceId(), game)) { + if ((!onlyIfCanBeSacrificed || controller.canPaySacrificeCost(permanent, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game)) + && permanent.getConvertedManaCost() > value) { + value = permanent.getConvertedManaCost(); + } + + } + } + return value; + } + + @Override + public HighestCMCOfPermanentValue copy() { + return new HighestCMCOfPermanentValue(this); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return filter.getMessage(); + } +}