diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/flip/SasayaOrochiAscendantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/flip/SasayaOrochiAscendantTest.java index d5f327daf97..60a93062f66 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/flip/SasayaOrochiAscendantTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/flip/SasayaOrochiAscendantTest.java @@ -129,7 +129,7 @@ public class SasayaOrochiAscendantTest extends CardTestPlayerBase { assertManaOptions("{R}{R}{R}{R}{G}{G}{G}{G}{G}", manaOptions); assertManaOptions("{R}{R}{R}{G}{G}{G}{G}{G}{G}", manaOptions); assertManaOptions("{R}{R}{G}{G}{G}{G}{G}{G}{G}", manaOptions); - assertManaOptions("{R}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions); + assertManaOptions("{R}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions); } } 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 0f98be25cbd..26f3a1a02dc 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 @@ -108,6 +108,7 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase { assertManaOptions("{W}{B}{B}{B}", manaOptions); assertManaOptions("{B}{B}{B}{B}", manaOptions); } + @Test public void TestCrystallineCrawler() { setStrictChooseMode(true); @@ -126,5 +127,58 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase { Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); 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); + + // {3}, Sacrifice Coal Golem: Add {R}{R}{R}. + addCard(Zone.BATTLEFIELD, playerA, "Coal Golem", 1); + + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertAllCommandsUsed(); + + ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); + Assert.assertEquals("mana variations don't fit", 3, manaOptions.size()); + assertManaOptions("{G}", manaOptions); + 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. + */ + @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); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertAllCommandsUsed(); + + ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); + Assert.assertEquals("mana variations don't fit", 3, manaOptions.size()); + assertManaOptions("{G}", manaOptions); + assertManaOptions("{W}{U}{B}", manaOptions); + assertManaOptions("{R}{R}{R}", manaOptions); + } + } \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/mana/ManaOptions.java b/Mage/src/main/java/mage/abilities/mana/ManaOptions.java index 501471adcd9..4fae1febde1 100644 --- a/Mage/src/main/java/mage/abilities/mana/ManaOptions.java +++ b/Mage/src/main/java/mage/abilities/mana/ManaOptions.java @@ -146,7 +146,16 @@ public class ManaOptions extends ArrayList { return false; } - public void addManaWithCost(List abilities, Game game) { + /** + * This adds the mana the abilities can produce to the possible mana + * variabtion. + * + * @param abilities + * @param game + * @return false if the costs could not be paid + */ + public boolean addManaWithCost(List abilities, Game game) { + boolean wasUsable = false; int replaces = 0; if (isEmpty()) { this.add(new Mana()); // needed if this is the first available mana, otherwise looping over existing options woold not loop @@ -185,8 +194,15 @@ public class ManaOptions extends ArrayList { for (Mana triggeredManaVariation : getTriggeredManaVariations(game, ability, netMana)) { for (Mana prevMana : copy) { Mana startingMana = prevMana.copy(); - if (!subtractCostAddMana(ability.getManaCosts().getMana(), triggeredManaVariation, ability.getCosts().isEmpty(), startingMana)) { - // the starting mana includes mana parts that the increased mana does not include, so add starting mana also as an option + Mana manaCosts = ability.getManaCosts().getMana(); + if (startingMana.includesMana(manaCosts)) { // can pay the mana costs to use the ability + if (!subtractCostAddMana(manaCosts, triggeredManaVariation, ability.getCosts().isEmpty(), startingMana)) { + // the starting mana includes mana parts that the increased mana does not include, so add starting mana also as an option + add(prevMana); + } + wasUsable = true; + } else { + // mana costs can't be paid so keep starting mana add(prevMana); } } @@ -248,6 +264,7 @@ public class ManaOptions extends ArrayList { logger.trace("ManaOptionsCosts " + this.size() + " Ign:" + replaces + " => " + this.toString()); logger.trace("Abilities: " + abilities.toString()); } + return wasUsable; } private List getTriggeredManaVariations(Game game, Ability ability, Mana baseMana) { @@ -353,54 +370,52 @@ public class ManaOptions extends ArrayList { repeatable = true; // only replace to any with mana costs only will be repeated if able } Mana prevMana = currentMana.copy(); - if (currentMana.includesMana(cost)) { // cost can be paid - // generic mana costs can be paid with different colored mana, can lead to different color combinations - if (cost.getGeneric() > 0 && cost.getGeneric() > (currentMana.getGeneric() + currentMana.getColorless())) { - for (Mana payCombination : getPossiblePayCombinations(cost.getGeneric(), currentMana)) { - Mana currentManaCopy = currentMana.copy(); - while (currentManaCopy.includesMana(payCombination)) { // loop for multiple usage if possible - boolean newCombinations = false; + // generic mana costs can be paid with different colored mana, can lead to different color combinations + if (cost.getGeneric() > 0 && cost.getGeneric() > (currentMana.getGeneric() + currentMana.getColorless())) { + for (Mana payCombination : getPossiblePayCombinations(cost.getGeneric(), currentMana)) { + Mana currentManaCopy = currentMana.copy(); + while (currentManaCopy.includesMana(payCombination)) { // loop for multiple usage if possible + boolean newCombinations = false; - Mana newMana = currentManaCopy.copy(); - newMana.subtract(payCombination); - newMana.add(manaToAdd); - // Mana moreValuable = Mana.getMoreValuableMana(currentMana, newMana); - if (!isExistingManaCombination(newMana)) { - this.add(newMana); // add the new combination - newCombinations = true; // repeat the while as long there are new combinations and usage is repeatable - currentManaCopy = newMana.copy(); - Mana moreValuable = Mana.getMoreValuableMana(currentMana, newMana); - if (!oldManaWasReplaced && newMana.equals(moreValuable)) { - oldManaWasReplaced = true; // the new mana includes all possibilities of the old one, so no need to add it after return - } - } - if (!newCombinations || !repeatable) { - break; + Mana newMana = currentManaCopy.copy(); + newMana.subtract(payCombination); + newMana.add(manaToAdd); + // Mana moreValuable = Mana.getMoreValuableMana(currentMana, newMana); + if (!isExistingManaCombination(newMana)) { + this.add(newMana); // add the new combination + newCombinations = true; // repeat the while as long there are new combinations and usage is repeatable + currentManaCopy = newMana.copy(); + Mana moreValuable = Mana.getMoreValuableMana(currentMana, newMana); + if (!oldManaWasReplaced && newMana.equals(moreValuable)) { + oldManaWasReplaced = true; // the new mana includes all possibilities of the old one, so no need to add it after return } } - - } - } else { - while (currentMana.includesMana(cost)) { // loop for multiple usage if possible - currentMana.subtractCost(cost); - currentMana.add(manaToAdd); - if (!repeatable) { - break; // Stop adding multiple usages of the ability - } - } - // Don't use mana that only reduce the available mana - if (prevMana.contains(currentMana) && prevMana.count() > currentMana.count()) { - currentMana.setToMana(prevMana); - } - Mana moreValuable = Mana.getMoreValuableMana(prevMana, currentMana); - if (!prevMana.equals(moreValuable)) { - this.add(currentMana); - if (moreValuable != null) { - oldManaWasReplaced = true; // the new mana includes all possibilities of the old one + if (!newCombinations || !repeatable) { + break; } } } + } else { + while (currentMana.includesMana(cost)) { // loop for multiple usage if possible + currentMana.subtractCost(cost); + currentMana.add(manaToAdd); + if (!repeatable) { + break; // Stop adding multiple usages of the ability + } + } + // Don't use mana that only reduce the available mana + if (prevMana.contains(currentMana) && prevMana.count() > currentMana.count()) { + currentMana.setToMana(prevMana); + } + Mana moreValuable = Mana.getMoreValuableMana(prevMana, currentMana); + if (!prevMana.equals(moreValuable)) { + this.add(currentMana); + if (moreValuable != null) { + oldManaWasReplaced = true; // the new mana includes all possibilities of the old one + } + } + } return oldManaWasReplaced; } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index d12a0c3e918..d7e6e680663 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -2936,9 +2936,19 @@ public abstract class PlayerImpl implements Player, Serializable { for (Abilities manaAbilities : sourceWithoutManaCosts) { availableMana.addMana(manaAbilities, game); } - for (Abilities manaAbilities : sourceWithCosts) { - availableMana.removeDuplicated(); - availableMana.addManaWithCost(manaAbilities, game); + + boolean anAbilityWasUsed = true; + while (anAbilityWasUsed && !sourceWithCosts.isEmpty()) { + anAbilityWasUsed = false; + for (Iterator> iterator = sourceWithCosts.iterator(); iterator.hasNext();) { + Abilities manaAbilities = iterator.next(); + boolean used = availableMana.addManaWithCost(manaAbilities, game); + if (used) { + iterator.remove(); + availableMana.removeDuplicated(); + anAbilityWasUsed = true; + } + } } // remove duplicated variants (see ManaOptionsTest for info - when that rises)