diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/OmniscienceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/OmniscienceTest.java index 02ab0f8a23..c0c755ef3a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/OmniscienceTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/OmniscienceTest.java @@ -41,4 +41,27 @@ public class OmniscienceTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Knight of the White Orchid", 0); } + /** + * If you cast a card with monocolored hybrid mana with Omniscience's + * alternate casting cost, you will be asked to pay 1 colorless mana per + * monocolored hybrid mana in its cost. For example, while casting Beseech + * the Queen, you are asked to pay {1}{1}{1}. + */ + @Test + public void testMonocoloredHybridMana() { + // You may cast nonland cards from your hand without paying their mana costs. + addCard(Zone.BATTLEFIELD, playerA, "Omniscience", 1); + + // ({2B} can be paid with any two mana or with {B}. This card's converted mana cost is 6.) + // Search your library for a card with converted mana cost less than or equal to the number of lands you control, reveal it, and put it into your hand. Then shuffle your library. + addCard(Zone.HAND, playerA, "Beseech the Queen", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Beseech the Queen"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + // Beseech the Queen is cast because it is free + assertGraveyardCount(playerA, "Beseech the Queen", 1); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/ManaUtilTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/ManaUtilTest.java index fbc1cd7518..c27f28e03d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/utils/ManaUtilTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/utils/ManaUtilTest.java @@ -5,6 +5,7 @@ import java.util.LinkedHashMap; import java.util.UUID; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.mana.BasicManaAbility; @@ -14,6 +15,7 @@ import mage.abilities.mana.RedManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.Card; import mage.cards.repository.CardRepository; +import mage.util.CardUtil; import mage.util.ManaUtil; import org.junit.Assert; import org.junit.Test; @@ -125,6 +127,49 @@ public class ManaUtilTest extends CardTestPlayerBase { } + /** + * Mana.enough is used to check if a spell can be cast with an given amount + * of avalable mana + */ + @Test + public void testManaIncrease() { + // cost - reduction - rest + testManaReduction("{G}{G}", "{G}", "{G}"); + testManaReduction("{1}{G}{G}", "{G}", "{1}{G}"); + testManaReduction("{B}{B}", "{B}", "{B}"); + testManaReduction("{1}{B}{B}", "{B}", "{1}{B}"); + testManaReduction("{W}{W}", "{W}", "{W}"); + testManaReduction("{1}{W}{W}", "{W}", "{1}{W}"); + testManaReduction("{U}{U}", "{U}", "{U}"); + testManaReduction("{1}{U}{U}", "{U}", "{1}{U}"); + testManaReduction("{R}{R}", "{R}", "{R}"); + testManaReduction("{1}{R}{R}", "{R}", "{1}{R}"); + + testManaReduction("{R}{G}{B}{U}{W}", "{R}{G}{B}{U}{W}", "{0}"); + + // Hybrid Mana + testManaReduction("{2/B}{2/B}{2/B}", "{B}{B}", "{2/B}"); + testManaReduction("{2/B}{2/B}{2/B}", "{B}{B}{B}", "{0}"); + testManaReduction("{2/W}{2/W}{2/W}", "{W}{W}", "{2/W}"); + testManaReduction("{2/W}{2/W}{2/W}", "{W}{W}{W}", "{0}"); + + testManaReduction("{G/B}{G/B}{G/B}", "{B}{G}{B}", "{0}"); + } + + /** + * Checks if a given mana reduction left the expected amount of mana costs + * + * @param manaCostsToPay + * @param availablyAny + * @param available + * @param expected + */ + private void testManaReduction(String manaCostsToPay, String manaToReduce, String restMana) { + SpellAbility spellAbility = new SpellAbility(new ManaCostsImpl(manaCostsToPay), "Test"); + CardUtil.adjustCost(spellAbility, new ManaCostsImpl(manaToReduce), true); + Assert.assertTrue("The mana cost to pay " + manaCostsToPay + " reduced by " + manaToReduce + " should left " + restMana + " but the rest was " + spellAbility.getManaCostsToPay().getText(), spellAbility.getManaCostsToPay().getText().equals(restMana)); + } + /** * Common way to test ManaUtil.tryToAutoPay * diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 807c515c91..1b4c5e9d26 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -45,6 +45,7 @@ import mage.abilities.costs.mana.HybridManaCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.MonoHybridManaCost; import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.keyword.ChangelingAbility; import mage.cards.Card; @@ -292,14 +293,21 @@ public class CardUtil { Mana reduceMana = new Mana(); for (ManaCost manaCost : manaCostsToReduce) { - reduceMana.add(manaCost.getMana()); + if (manaCost instanceof MonoHybridManaCost) { + reduceMana.add(Mana.ColorlessMana(2)); + } else { + reduceMana.add(manaCost.getMana()); + } } + ManaCosts manaCostToCheckForColorless = new ManaCostsImpl<>(); // subtract colored mana for (ManaCost newManaCost : previousCost) { Mana mana = newManaCost.getMana(); - if (mana.getColorless() > 0) { + if (!(newManaCost instanceof MonoHybridManaCost) && mana.getColorless() > 0) { + manaCostToCheckForColorless.add(newManaCost); continue; } + boolean hybridMana = newManaCost instanceof HybridManaCost; if (mana.getBlack() > 0 && reduceMana.getBlack() > 0) { if (reduceMana.getBlack() > mana.getBlack()) { reduceMana.setBlack(reduceMana.getBlack() - mana.getBlack()); @@ -308,6 +316,9 @@ public class CardUtil { mana.setBlack(mana.getBlack() - reduceMana.getBlack()); reduceMana.setBlack(0); } + if (hybridMana) { + continue; + } } if (mana.getRed() > 0 && reduceMana.getRed() > 0) { if (reduceMana.getRed() > mana.getRed()) { @@ -317,6 +328,9 @@ public class CardUtil { mana.setRed(mana.getRed() - reduceMana.getRed()); reduceMana.setRed(0); } + if (hybridMana) { + continue; + } } if (mana.getBlue() > 0 && reduceMana.getBlue() > 0) { if (reduceMana.getBlue() > mana.getBlue()) { @@ -326,6 +340,9 @@ public class CardUtil { mana.setBlue(mana.getBlue() - reduceMana.getBlue()); reduceMana.setBlue(0); } + if (hybridMana) { + continue; + } } if (mana.getGreen() > 0 && reduceMana.getGreen() > 0) { if (reduceMana.getGreen() > mana.getGreen()) { @@ -335,6 +352,9 @@ public class CardUtil { mana.setGreen(mana.getGreen() - reduceMana.getGreen()); reduceMana.setGreen(0); } + if (hybridMana) { + continue; + } } if (mana.getWhite() > 0 && reduceMana.getWhite() > 0) { if (reduceMana.getWhite() > mana.getWhite()) { @@ -344,15 +364,22 @@ public class CardUtil { mana.setWhite(mana.getWhite() - reduceMana.getWhite()); reduceMana.setWhite(0); } - } - if (newManaCost instanceof HybridManaCost) { - if (mana.count() > 1) { - adjustedCost.add(newManaCost); + if (hybridMana) { + continue; } - } else if (mana.count() > 0) { - adjustedCost.add(newManaCost); } + if (mana.count() > 0) { + if (newManaCost instanceof MonoHybridManaCost) { + if (mana.count() == 2) { + reduceMana.setColorless(reduceMana.getColorless() - 2); + continue; + } + } + manaCostToCheckForColorless.add(newManaCost); + } + } + // subtract colorless mana, use all mana that is left int reduceAmount; if (convertToGeneric) { @@ -360,23 +387,38 @@ public class CardUtil { } else { reduceAmount = reduceMana.getColorless(); } - for (ManaCost newManaCost : previousCost) { - Mana mana = newManaCost.getMana(); - if (mana.getColorless() == 0) { - continue; - } - if (mana.getColorless() > 0 && reduceAmount > 0) { - if (reduceAmount > mana.getColorless()) { - reduceAmount -= mana.getColorless(); - mana.setColorless(0); - } else { - mana.setColorless(mana.getColorless() - reduceAmount); - reduceAmount = 0; + if (reduceAmount > 0) { + for (ManaCost newManaCost : manaCostToCheckForColorless) { + Mana mana = newManaCost.getMana(); + if (mana.getColorless() == 0 || reduceAmount == 0) { + adjustedCost.add(newManaCost); + continue; + } + if (newManaCost instanceof MonoHybridManaCost) { + if (reduceAmount > 1) { + reduceAmount -= 2; + mana.clear(); + } + continue; + } + if (mana.getColorless() > 0) { + if (reduceAmount > mana.getColorless()) { + reduceAmount -= mana.getColorless(); + mana.setColorless(0); + } else { + mana.setColorless(mana.getColorless() - reduceAmount); + reduceAmount = 0; + } + } + if (mana.count() > 0) { + adjustedCost.add(0, new GenericManaCost(mana.count())); } } - if (mana.count() > 0) { - adjustedCost.add(0, new GenericManaCost(mana.count())); - } + } else { + adjustedCost.addAll(manaCostToCheckForColorless); + } + if (adjustedCost.isEmpty()) { + adjustedCost.add(new GenericManaCost(0)); // neede to check if cost was reduced to 0 } adjustedCost.setSourceFilter(previousCost.getSourceFilter()); // keep mana source restrictions spellAbility.getManaCostsToPay().clear();