From 0e3d4b335a66c902430a62c87b7966f9119e8da7 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 12 Jul 2015 09:11:13 +0200 Subject: [PATCH] Some fixes/improvements to generation of available mana. --- .../mage/test/AI/basic/CastCreaturesTest.java | 87 +++++- .../test/AI/basic/CastDestroySpellsTest.java | 68 +++++ .../org/mage/test/utils/ManaOptionsTest.java | 113 ++++++-- Mage/src/mage/Mana.java | 148 +++++----- .../mage/abilities/ActivatedAbilityImpl.java | 100 ++++--- Mage/src/mage/abilities/SpellAbility.java | 71 +++-- .../abilities/costs/mana/HybridManaCost.java | 10 + .../mage/abilities/costs/mana/ManaCost.java | 66 +++-- .../abilities/costs/mana/ManaCostImpl.java | 72 ++--- .../mage/abilities/costs/mana/ManaCosts.java | 1 + .../abilities/costs/mana/ManaCostsImpl.java | 9 + .../costs/mana/MonoHybridManaCost.java | 10 + .../CommanderColorIdentityManaAbility.java | 12 +- Mage/src/mage/abilities/mana/ManaOptions.java | 261 ++++++++++++------ 14 files changed, 674 insertions(+), 354 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/AI/basic/CastDestroySpellsTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastCreaturesTest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastCreaturesTest.java index f65e7655177..d14393676f2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastCreaturesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastCreaturesTest.java @@ -29,7 +29,6 @@ package org.mage.test.AI.basic; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBaseAI; @@ -52,7 +51,7 @@ public class CastCreaturesTest extends CardTestPlayerBaseAI { assertPermanentCount(playerA, "Silvercoat Lion", 1); } - + @Test public void testSimpleCast2() { addCard(Zone.HAND, playerA, "Silvercoat Lion"); @@ -65,9 +64,8 @@ public class CastCreaturesTest extends CardTestPlayerBaseAI { assertPermanentCount(playerA, "Silvercoat Lion", 2); } - + @Test - @Ignore // AI should cast Myr Enforcer -> Check why it does not public void testSimpleCast3() { // Affinity for artifacts (This spell costs less to cast for each artifact you control.) addCard(Zone.HAND, playerA, "Myr Enforcer"); @@ -80,5 +78,84 @@ public class CastCreaturesTest extends CardTestPlayerBaseAI { execute(); assertPermanentCount(playerA, "Myr Enforcer", 1); - } + } + + @Test + public void testSimpleCast4() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain"); + addCard(Zone.HAND, playerA, "Plains"); + skipInitShuffling(); + + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + + addCard(Zone.HAND, playerA, "Fireshrieker"); + addCard(Zone.HAND, playerA, "Blazing Specter"); // {2}{R}{B} + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Plains", 2); + assertPermanentCount(playerA, "Fireshrieker", 0); + assertPermanentCount(playerA, "Blazing Specter", 1); + } + + @Test + public void testCast4Creature() { + addCard(Zone.LIBRARY, playerA, "Swamp", 1); + addCard(Zone.LIBRARY, playerA, "Mountain", 1); + addCard(Zone.LIBRARY, playerA, "Island", 1); + addCard(Zone.HAND, playerA, "Plains"); + skipInitShuffling(); + + addCard(Zone.HAND, playerA, "Loyal Sentry"); // {W} 1/1 + addCard(Zone.HAND, playerA, "Silvercoat Lion"); // {1}{W} 2/2 + addCard(Zone.HAND, playerA, "Rootwater Commando"); // {2}{U} 2/2 + addCard(Zone.HAND, playerA, "Bog Wraith"); // {3}{B} 3/3 + + setStopAt(7, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Plains", 1); + assertPermanentCount(playerA, "Mountain", 1); + assertPermanentCount(playerA, "Island", 1); + assertPermanentCount(playerA, "Swamp", 1); + + // assertLife(playerB, 11); // 1 + 1+2 + 1+2+2 = + assertPermanentCount(playerA, "Loyal Sentry", 1); + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertPermanentCount(playerA, "Rootwater Commando", 1); + assertPermanentCount(playerA, "Bog Wraith", 1); + + } + + @Test + public void testCast4Creature2() { + addCard(Zone.LIBRARY, playerA, "Swamp", 1); + addCard(Zone.LIBRARY, playerA, "Swamp", 1); + addCard(Zone.LIBRARY, playerA, "Plains", 1); + + addCard(Zone.HAND, playerA, "Island", 1); + addCard(Zone.HAND, playerA, "Plains"); + skipInitShuffling(); + + addCard(Zone.HAND, playerA, "Loyal Sentry"); // {W} 1/1 + addCard(Zone.HAND, playerA, "Steadfast Guard"); // {W}{W} 2/2 + addCard(Zone.HAND, playerA, "Rootwater Commando"); // {2}{U} 2/2 + addCard(Zone.HAND, playerA, "Bog Wraith"); // {3}{B} 3/3 + + setStopAt(7, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Plains", 2); + assertPermanentCount(playerA, "Island", 1); + assertPermanentCount(playerA, "Swamp", 1); + + // assertLife(playerB, 11); // 1 + 1+2 + 1+2+2 = + assertPermanentCount(playerA, "Loyal Sentry", 1); + assertPermanentCount(playerA, "Steadfast Guard", 1); + assertPermanentCount(playerA, "Rootwater Commando", 1); + assertPermanentCount(playerA, "Bog Wraith", 1); + + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastDestroySpellsTest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastDestroySpellsTest.java new file mode 100644 index 00000000000..458bd5012f9 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastDestroySpellsTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.AI.basic; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBaseAI; + +/** + * + * @author LevelX2 + */ +public class CastDestroySpellsTest extends CardTestPlayerBaseAI { + + /** + * + * + */ + @Test + public void testOrzhovCharm() { + // Choose one - + // Return target creature you control and all Auras you control attached to it to their owner's hand; + // or destroy target creature and you lose life equal to its toughness; + // or return target creature card with converted mana cost 1 or less from your graveyard to the battlefield. + addCard(Zone.HAND, playerA, "Orzhov Charm"); // {W}{B} + + addCard(Zone.BATTLEFIELD, playerA, "Fetid Heath", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + + // Cycling abilities you activate cost you up to {2} less to activate. + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 18); + + assertGraveyardCount(playerA, "Orzhov Charm", 1); + assertGraveyardCount(playerB, "Silvercoat Lion", 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTest.java index b1e78318af3..71a7eed710e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTest.java @@ -35,8 +35,9 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * This test checks if the calculated possible mana options are correct related to the given mana sources available. - * + * This test checks if the calculated possible mana options are correct related + * to the given mana sources available. + * * @author LevelX2 */ public class ManaOptionsTest extends CardTestPlayerBase { @@ -45,12 +46,12 @@ public class ManaOptionsTest extends CardTestPlayerBase { public void testSimpleMana() { addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); - setStopAt(1, PhaseStep. UPKEEP); + setStopAt(1, PhaseStep.UPKEEP); execute(); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit",1, manaOptions.size()); + Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); Assert.assertEquals("{G}{G}{G}", getManaOption(0, manaOptions)); } @@ -62,12 +63,12 @@ public class ManaOptionsTest extends CardTestPlayerBase { public void testTinderFarm() { addCard(Zone.BATTLEFIELD, playerA, "Tinder Farm", 3); - setStopAt(2, PhaseStep. UPKEEP); + setStopAt(2, PhaseStep.UPKEEP); execute(); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit",4, manaOptions.size()); + Assert.assertEquals("mana variations don't fit", 4, manaOptions.size()); Assert.assertEquals("{G}{G}{G}", getManaOption(0, manaOptions)); Assert.assertEquals("{R}{G}{G}{W}", getManaOption(1, manaOptions)); Assert.assertEquals("{R}{R}{G}{W}{W}", getManaOption(2, manaOptions)); @@ -82,12 +83,12 @@ public class ManaOptionsTest extends CardTestPlayerBase { public void testAdarkarWastes() { addCard(Zone.BATTLEFIELD, playerA, "Adarkar Wastes", 3); - setStopAt(1, PhaseStep. UPKEEP); + setStopAt(1, PhaseStep.UPKEEP); execute(); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit",4, manaOptions.size()); + Assert.assertEquals("mana variations don't fit", 4, manaOptions.size()); Assert.assertEquals("{W}{W}{W}", getManaOption(0, manaOptions)); Assert.assertEquals("{U}{W}{W}", getManaOption(1, manaOptions)); Assert.assertEquals("{U}{U}{W}", getManaOption(2, manaOptions)); @@ -95,7 +96,6 @@ public class ManaOptionsTest extends CardTestPlayerBase { } - // Chromatic Sphere // {1}, {T}, Sacrifice Chromatic Sphere: Add one mana of any color to your mana pool. Draw a card. @Test @@ -103,12 +103,12 @@ public class ManaOptionsTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); addCard(Zone.BATTLEFIELD, playerA, "Chromatic Sphere", 2); - setStopAt(1, PhaseStep. UPKEEP); + setStopAt(1, PhaseStep.UPKEEP); execute(); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit",1, manaOptions.size()); + Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); Assert.assertEquals("{Any}{Any}", getManaOption(0, manaOptions)); } @@ -120,12 +120,12 @@ public class ManaOptionsTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); addCard(Zone.BATTLEFIELD, playerA, "Orochi Leafcaller", 1); - setStopAt(1, PhaseStep. UPKEEP); + setStopAt(1, PhaseStep.UPKEEP); execute(); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit",1, manaOptions.size()); + Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); Assert.assertEquals("{W}{W}{Any}{Any}", getManaOption(0, manaOptions)); } @@ -138,14 +138,15 @@ public class ManaOptionsTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); addCard(Zone.BATTLEFIELD, playerA, "Crystal Quarry", 1); - setStopAt(1, PhaseStep. UPKEEP); + setStopAt(1, PhaseStep.UPKEEP); execute(); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit",1, manaOptions.size()); + Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); Assert.assertEquals("{1}{G}{G}{W}{W}", getManaOption(0, manaOptions)); } + // Crystal Quarry // {T}: {1} Add to your mana pool. // {5}, {T}: Add {W}{U}{B}{R}{G} to your mana pool. @@ -155,12 +156,12 @@ public class ManaOptionsTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); addCard(Zone.BATTLEFIELD, playerA, "Crystal Quarry", 1); - setStopAt(1, PhaseStep. UPKEEP); + setStopAt(1, PhaseStep.UPKEEP); execute(); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit",2, manaOptions.size()); + Assert.assertEquals("mana variations don't fit", 2, manaOptions.size()); Assert.assertEquals("{1}{G}{G}{G}{W}{W}", getManaOption(0, manaOptions)); Assert.assertEquals("{R}{G}{U}{W}{B}", getManaOption(1, manaOptions)); } @@ -174,15 +175,15 @@ public class ManaOptionsTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); addCard(Zone.BATTLEFIELD, playerA, "Nykthos, Shrine to Nyx", 1); - setStopAt(1, PhaseStep. UPKEEP); + setStopAt(1, PhaseStep.UPKEEP); execute(); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit",1, manaOptions.size()); + Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); Assert.assertEquals("{G}{G}{G}{G}{G}", getManaOption(0, manaOptions)); } - + @Test public void testNykthos2() { addCard(Zone.BATTLEFIELD, playerA, "Sedge Scorpion", 4); @@ -190,12 +191,12 @@ public class ManaOptionsTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); addCard(Zone.BATTLEFIELD, playerA, "Nykthos, Shrine to Nyx", 1); - setStopAt(1, PhaseStep. UPKEEP); + setStopAt(1, PhaseStep.UPKEEP); execute(); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit",2, manaOptions.size()); + Assert.assertEquals("mana variations don't fit", 2, manaOptions.size()); Assert.assertEquals("{G}{G}{G}{G}{G}", getManaOption(0, manaOptions)); Assert.assertEquals("{R}{R}{R}{G}", getManaOption(1, manaOptions)); } @@ -206,36 +207,92 @@ public class ManaOptionsTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); addCard(Zone.BATTLEFIELD, playerA, "Nykthos, Shrine to Nyx", 1); - setStopAt(1, PhaseStep. UPKEEP); + setStopAt(1, PhaseStep.UPKEEP); execute(); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit",1, manaOptions.size()); + Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); Assert.assertEquals("{1}{G}{Any}", getManaOption(0, manaOptions)); } @Test public void testMix1() { + // {1}, {T}, Sacrifice Chromatic Star: Add one mana of any color to your mana pool. + // When Chromatic Star is put into a graveyard from the battlefield, draw a card. addCard(Zone.BATTLEFIELD, playerA, "Chromatic Star", 1); + // {1}, {T}, Sacrifice Chromatic Sphere: Add one mana of any color to your mana pool. Draw a card. addCard(Zone.BATTLEFIELD, playerA, "Chromatic Sphere", 1); + // {T}: Add {1} to your mana pool. If you control an Urza's Mine and an Urza's Power-Plant, add {3} to your mana pool instead. addCard(Zone.BATTLEFIELD, playerA, "Urza's Tower", 1); + // {T}: Add {1} to your mana pool. + // {T}: Add {R} or {G} to your mana pool. Each opponent gains 1 life. addCard(Zone.BATTLEFIELD, playerA, "Grove of the Burnwillows", 1); - setStopAt(1, PhaseStep. UPKEEP); + setStopAt(1, PhaseStep.UPKEEP); execute(); ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); - Assert.assertEquals("mana variations don't fit",2, manaOptions.size()); + Assert.assertEquals("mana variations don't fit", 2, manaOptions.size()); Assert.assertEquals("{Any}{Any}", getManaOption(0, manaOptions)); Assert.assertEquals("{Any}{Any}", getManaOption(1, manaOptions)); } - private String getManaOption(int index, ManaOptions manaOptions) { + @Test + public void testFetidHeath() { + addCard(Zone.BATTLEFIELD, playerA, "Fetid Heath", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + + setStopAt(1, PhaseStep.UPKEEP); + execute(); + + ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); + + Assert.assertEquals("mana variations don't fit", 3, manaOptions.size()); + Assert.assertEquals("{W}{W}", getManaOption(0, manaOptions)); + Assert.assertEquals("{W}{B}", getManaOption(1, manaOptions)); + Assert.assertEquals("{B}{B}", getManaOption(2, manaOptions)); + } + + /** + * Don't use mana sources that only reduce available mana + */ + @Test + public void testCabalCoffers1() { + addCard(Zone.BATTLEFIELD, playerA, "Cabal Coffers", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + + setStopAt(1, PhaseStep.UPKEEP); + execute(); + + ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); + + Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); + Assert.assertEquals("{W}{B}", getManaOption(0, manaOptions)); + } + + @Test + public void testCabalCoffers2() { + addCard(Zone.BATTLEFIELD, playerA, "Cabal Coffers", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + + setStopAt(1, PhaseStep.UPKEEP); + execute(); + + ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); + + Assert.assertEquals("mana variations don't fit", 2, manaOptions.size()); + Assert.assertEquals("{W}{B}{B}", getManaOption(0, manaOptions)); + Assert.assertEquals("{B}{B}{B}", getManaOption(1, manaOptions)); + } + + private String getManaOption(int index, ManaOptions manaOptions) { if (manaOptions.size() < index + 1) { return ""; } return manaOptions.get(index).toString(); } -} \ No newline at end of file +} diff --git a/Mage/src/mage/Mana.java b/Mage/src/mage/Mana.java index 5708e081e5b..4985b1d7047 100644 --- a/Mage/src/mage/Mana.java +++ b/Mage/src/mage/Mana.java @@ -1,36 +1,36 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage; import java.io.Serializable; import mage.constants.ColoredManaSymbol; import mage.constants.ManaType; +import static mage.constants.ManaType.COLORLESS; import mage.filter.FilterMana; import mage.util.Copyable; import mage.util.ThreadLocalStringBuilder; @@ -57,7 +57,8 @@ public class Mana implements Comparable, Serializable, Copyable { public static final Mana BlackMana = BlackMana(1); public static final Mana ColorlessMana = ColorlessMana(1); - public Mana() {} + public Mana() { + } public Mana(final Mana mana) { this.red = mana.red; @@ -212,11 +213,10 @@ public class Mana implements Comparable, Serializable, Copyable { } } - public int count() { return red + green + blue + white + black + colorless + any; } - + public int countColored() { return red + green + blue + white + black + any; } @@ -283,9 +283,9 @@ public class Mana implements Comparable, Serializable, Copyable { } return sbMana.toString(); } - + private static final transient ThreadLocalStringBuilder threadLocalBuilder = new ThreadLocalStringBuilder(10); - + @Override public Mana copy() { return new Mana(this); @@ -342,38 +342,38 @@ public class Mana implements Comparable, Serializable, Copyable { Mana compare = avail.copy(); compare.subtract(this); if (compare.getRed() < 0 && compare.getAny() > 0) { - int diff = Math.min( compare.getAny(), Math.abs(compare.getRed())); + int diff = Math.min(compare.getAny(), Math.abs(compare.getRed())); compare.setAny(compare.getAny() - diff); compare.setRed(compare.getRed() + diff); } if (compare.getGreen() < 0 && compare.getAny() > 0) { - int diff = Math.min( compare.getAny(), Math.abs(compare.getGreen())); + int diff = Math.min(compare.getAny(), Math.abs(compare.getGreen())); compare.setAny(compare.getAny() - diff); compare.setGreen(compare.getGreen() + diff); } if (compare.getBlue() < 0 && compare.getAny() > 0) { - int diff = Math.min( compare.getAny(), Math.abs(compare.getBlue())); + int diff = Math.min(compare.getAny(), Math.abs(compare.getBlue())); compare.setAny(compare.getAny() - diff); compare.setBlue(compare.getBlue() + diff); } if (compare.getBlack() < 0 && compare.getAny() > 0) { - int diff = Math.min( compare.getAny(), Math.abs(compare.getBlack())); + int diff = Math.min(compare.getAny(), Math.abs(compare.getBlack())); compare.setAny(compare.getAny() - diff); compare.setBlack(compare.getBlack() + diff); } if (compare.getWhite() < 0 && compare.getAny() > 0) { - int diff = Math.min( compare.getAny(), Math.abs(compare.getWhite())); + int diff = Math.min(compare.getAny(), Math.abs(compare.getWhite())); compare.setAny(compare.getAny() - diff); compare.setWhite(compare.getWhite() + diff); } if (compare.getColorless() < 0) { int remaining = 0; - remaining += Math.min(0,compare.getRed()); - remaining += Math.min(0,compare.getWhite()); - remaining += Math.min(0,compare.getGreen()); - remaining += Math.min(0,compare.getBlack()); - remaining += Math.min(0,compare.getBlue()); - remaining += Math.min(0,compare.getAny()); + remaining += Math.min(0, compare.getRed()); + remaining += Math.min(0, compare.getWhite()); + remaining += Math.min(0, compare.getGreen()); + remaining += Math.min(0, compare.getBlack()); + remaining += Math.min(0, compare.getBlue()); + remaining += Math.min(0, compare.getAny()); if (remaining > 0) { int diff = Math.min(remaining, Math.abs(compare.getColorless())); compare.setColorless(compare.getColorless() + diff); @@ -510,7 +510,7 @@ public class Mana implements Comparable, Serializable, Copyable { } public int get(ManaType manaType) { - switch(manaType) { + switch (manaType) { case BLACK: return black; case BLUE: @@ -528,7 +528,7 @@ public class Mana implements Comparable, Serializable, Copyable { } public void set(ManaType manaType, int amount) { - switch(manaType) { + switch (manaType) { case BLACK: black = amount; break; @@ -569,39 +569,38 @@ public class Mana implements Comparable, Serializable, Copyable { } public boolean equalManaValue(Mana mana) { - return this.any == mana.any && - this.red == mana.red && - this.green == mana.green && - this.white == mana.white && - this.blue == mana.blue && - this.black == mana.black && - this.colorless == mana.colorless; + return this.any == mana.any + && this.red == mana.red + && this.green == mana.green + && this.white == mana.white + && this.blue == mana.blue + && this.black == mana.black + && this.colorless == mana.colorless; } /** - * Don't takes any mana into account to be usable in calculating available mana + * Don't takes any mana into account to be usable in calculating available + * mana + * * @param mana - * @return + * @return */ public boolean includesMana(Mana mana) { - return this.green >= mana.green && - this.blue >= mana.blue && - this.white >= mana.white && - this.black >= mana.black && - this.red >= mana.red && - ( - this.colorless >= mana.colorless || - this.countColored() >= mana.countColored() + mana.colorless - ); + return this.green >= mana.green + && this.blue >= mana.blue + && this.white >= mana.white + && this.black >= mana.black + && this.red >= mana.red + && (this.colorless >= mana.colorless + || this.countColored() >= mana.countColored() + mana.colorless); } /** - * Returns the mana that is more colored but does not contain - * one less mana in any color but colorless - * if you call with {1}{W}{R} and {G}{W}{R} you get back {G}{W}{R} - * if you call with {G}{W}{R} and {G}{W}{R} you get back {G}{W}{R} - * if you call with {G}{W}{B} and {G}{W}{R} you get back null + * Returns the mana that is more colored but does not contain one less mana + * in any color but colorless if you call with {1}{W}{R} and {G}{W}{R} you + * get back {G}{W}{R} if you call with {G}{W}{R} and {G}{W}{R} you get back + * {G}{W}{R} if you call with {G}{W}{B} and {G}{W}{R} you get back null * * @param mana1 * @param mana2 @@ -617,13 +616,12 @@ public class Mana implements Comparable, Serializable, Copyable { moreMana = mana1; lessMana = mana2; } - if (lessMana.getWhite() > moreMana.getWhite() || - lessMana.getRed() > moreMana.getRed() || - lessMana.getGreen() > moreMana.getGreen() || - lessMana.getBlue() > moreMana.getBlue() || - lessMana.getBlack() > moreMana.getBlack() || - lessMana.getAny() > moreMana.getAny() - ) { + if (lessMana.getWhite() > moreMana.getWhite() + || lessMana.getRed() > moreMana.getRed() + || lessMana.getGreen() > moreMana.getGreen() + || lessMana.getBlue() > moreMana.getBlue() + || lessMana.getBlack() > moreMana.getBlack() + || lessMana.getAny() > moreMana.getAny()) { return null; } return moreMana; diff --git a/Mage/src/mage/abilities/ActivatedAbilityImpl.java b/Mage/src/mage/abilities/ActivatedAbilityImpl.java index e5e1b819a53..ffdc3d4e019 100644 --- a/Mage/src/mage/abilities/ActivatedAbilityImpl.java +++ b/Mage/src/mage/abilities/ActivatedAbilityImpl.java @@ -1,38 +1,33 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities; import java.util.UUID; - -import mage.constants.AbilityType; -import mage.constants.TimingRule; -import mage.constants.Zone; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; import mage.abilities.costs.mana.ManaCosts; @@ -40,12 +35,14 @@ import mage.abilities.costs.mana.PhyrexianManaCost; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.cards.Card; +import mage.constants.AbilityType; import mage.constants.AsThoughEffectType; import mage.constants.TargetController; +import mage.constants.TimingRule; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; - /** * * @author BetaSteward_at_googlemail.com @@ -62,7 +59,7 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa this.checkPlayableMode = false; } - public ActivatedAbilityImpl(ActivatedAbilityImpl ability) { + public ActivatedAbilityImpl(final ActivatedAbilityImpl ability) { super(ability); timing = ability.timing; mayActivate = ability.mayActivate; @@ -94,7 +91,7 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa public ActivatedAbilityImpl(Zone zone, Effects effects, ManaCosts cost) { super(AbilityType.ACTIVATED, zone); if (effects != null) { - for (Effect effect: effects) { + for (Effect effect : effects) { this.addEffect(effect); } } @@ -110,7 +107,7 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa } if (cost != null) { if (cost instanceof PhyrexianManaCost) { - this.addManaCost((PhyrexianManaCost)cost); + this.addManaCost((PhyrexianManaCost) cost); } else { this.addCost(cost); } @@ -123,7 +120,7 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa this.addEffect(effect); } if (costs != null) { - for (Cost cost: costs) { + for (Cost cost : costs) { this.addCost(cost); } } @@ -132,7 +129,7 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa public ActivatedAbilityImpl(Zone zone, Effects effects, Cost cost) { super(AbilityType.ACTIVATED, zone); if (effects != null) { - for (Effect effect: effects) { + for (Effect effect : effects) { this.addEffect(effect); } } @@ -143,13 +140,13 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa public ActivatedAbilityImpl(Zone zone, Effects effects, Costs costs) { super(AbilityType.ACTIVATED, zone); - for (Effect effect: effects) { + for (Effect effect : effects) { if (effect != null) { this.addEffect(effect); } } if (costs != null) { - for (Cost cost: costs) { + for (Cost cost : costs) { this.addCost(cost); } } @@ -161,23 +158,23 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa @Override public boolean canActivate(UUID playerId, Game game) { //20091005 - 602.2 - switch(mayActivate){ + switch (mayActivate) { case ANY: break; - + case NOT_YOU: - if(controlsAbility(playerId, game)){ + if (controlsAbility(playerId, game)) { return false; } break; - + case OPPONENT: - if (! game.getPlayer(controllerId).hasOpponent(playerId, game)){ + if (!game.getPlayer(controllerId).hasOpponent(playerId, game)) { return false; } - break; + break; case YOU: - if(!controlsAbility(playerId, game)){ + if (!controlsAbility(playerId, game)) { return false; } break; @@ -192,8 +189,8 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa return false; } //20091005 - 602.5d/602.5e - if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId) || - game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) { + if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId) + || game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) { if (costs.canPay(this, sourceId, controllerId, game) && canChooseTarget(game)) { this.activatorId = playerId; return true; @@ -205,9 +202,8 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa protected boolean controlsAbility(UUID playerId, Game game) { if (this.controllerId != null && this.controllerId.equals(playerId)) { return true; - } - else { - Card card = (Card)game.getObject(this.sourceId); + } else { + Card card = (Card) game.getObject(this.sourceId); if (card != null && game.getState().getZone(this.sourceId) != Zone.BATTLEFIELD) { return card.getOwnerId().equals(playerId); } @@ -240,5 +236,5 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa public boolean isCheckPlayableMode() { return checkPlayableMode; } - + } diff --git a/Mage/src/mage/abilities/SpellAbility.java b/Mage/src/mage/abilities/SpellAbility.java index 2c2d9c0fa2d..1dedf4b81e7 100644 --- a/Mage/src/mage/abilities/SpellAbility.java +++ b/Mage/src/mage/abilities/SpellAbility.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities; import java.util.UUID; @@ -65,17 +64,17 @@ public class SpellAbility extends ActivatedAbilityImpl { this.cardName = cardName; this.spellAbilityType = spellAbilityType; this.addManaCost(cost); - switch(spellAbilityType) { + switch (spellAbilityType) { case SPLIT_FUSED: this.name = "Cast fused " + cardName; break; default: this.name = "Cast " + cardName; } - + } - public SpellAbility(SpellAbility ability) { + public SpellAbility(final SpellAbility ability) { super(ability); this.spellAbilityType = ability.spellAbilityType; this.cardName = ability.cardName; @@ -83,9 +82,9 @@ public class SpellAbility extends ActivatedAbilityImpl { public boolean spellCanBeActivatedRegularlyNow(UUID playerId, Game game) { MageObject object = game.getObject(sourceId); - return timing == TimingRule.INSTANT || - object.hasAbility(FlashAbility.getInstance().getId(), game) || - game.canPlaySorcery(playerId); + return timing == TimingRule.INSTANT + || object.hasAbility(FlashAbility.getInstance().getId(), game) + || game.canPlaySorcery(playerId); } @Override @@ -96,7 +95,7 @@ public class SpellAbility extends ActivatedAbilityImpl { return false; } // fix for Gitaxian Probe and casting opponent's spells - if (!game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game) + if (!game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game) && !controllerId.equals(playerId)) { return false; } @@ -122,13 +121,13 @@ public class SpellAbility extends ActivatedAbilityImpl { if (getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) { SplitCard splitCard = (SplitCard) game.getCard(getSourceId()); if (splitCard != null) { - return (splitCard.getLeftHalfCard().getSpellAbility().canChooseTarget(game) + return (splitCard.getLeftHalfCard().getSpellAbility().canChooseTarget(game) && splitCard.getRightHalfCard().getSpellAbility().canChooseTarget(game)); } return false; } else { - return canChooseTarget(game); + return canChooseTarget(game); } } } diff --git a/Mage/src/mage/abilities/costs/mana/HybridManaCost.java b/Mage/src/mage/abilities/costs/mana/HybridManaCost.java index 0658d9e68c9..b8f9cdedb93 100644 --- a/Mage/src/mage/abilities/costs/mana/HybridManaCost.java +++ b/Mage/src/mage/abilities/costs/mana/HybridManaCost.java @@ -27,6 +27,8 @@ */ package mage.abilities.costs.mana; +import java.util.ArrayList; +import java.util.List; import mage.Mana; import mage.abilities.Ability; import mage.constants.ColoredManaSymbol; @@ -130,6 +132,14 @@ public class HybridManaCost extends ManaCostImpl { return mana1.equals(coloredManaSymbol) || mana2.equals(coloredManaSymbol); } + @Override + public List getManaOptions() { + List manaList = new ArrayList<>(); + manaList.add(new Mana(mana1)); + manaList.add(new Mana(mana2)); + return manaList; + } + public ColoredManaSymbol getMana1() { return mana1; } diff --git a/Mage/src/mage/abilities/costs/mana/ManaCost.java b/Mage/src/mage/abilities/costs/mana/ManaCost.java index 58d6aa1aa6f..b1616aaa577 100644 --- a/Mage/src/mage/abilities/costs/mana/ManaCost.java +++ b/Mage/src/mage/abilities/costs/mana/ManaCost.java @@ -1,33 +1,33 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.costs.mana; +import java.util.List; import mage.Mana; import mage.abilities.Ability; import mage.abilities.costs.Cost; @@ -40,15 +40,27 @@ import mage.players.ManaPool; public interface ManaCost extends Cost { int convertedManaCost(); + Mana getMana(); + + List getManaOptions(); + Mana getPayment(); + void assignPayment(Game game, Ability ability, ManaPool pool); + void setPayment(Mana mana); + ManaCost getUnpaid(); + ManaOptions getOptions(); + boolean testPay(Mana testMana); + Filter getSourceFilter(); + void setSourceFilter(Filter filter); + boolean containsColor(ColoredManaSymbol coloredManaSymbol); @Override diff --git a/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java b/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java index e22723c32fe..60e9fcb22d1 100644 --- a/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java +++ b/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java @@ -1,47 +1,47 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.costs.mana; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; -import mage.constants.ColoredManaSymbol; -import mage.constants.ManaType; import mage.Mana; import mage.abilities.Ability; import mage.abilities.costs.CostImpl; import mage.abilities.mana.ManaOptions; +import mage.constants.ColoredManaSymbol; +import mage.constants.ManaType; import mage.filter.Filter; import mage.game.Game; import mage.players.ManaPool; import mage.players.Player; import mage.util.ManaUtil; - public abstract class ManaCostImpl extends CostImpl implements ManaCost { protected Mana payment; @@ -74,6 +74,13 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost { return cost; } + @Override + public List getManaOptions() { + List manaList = new ArrayList<>(); + manaList.add(cost); + return manaList; + } + @Override public ManaOptions getOptions() { return options; @@ -211,11 +218,10 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost { game.getState().getSpecialActions().removeManaActions(); while (!isPaid()) { ManaCost unpaid = this.getUnpaid(); - String promptText = ManaUtil.addSpecialManaPayAbilities(ability, game, unpaid); + String promptText = ManaUtil.addSpecialManaPayAbilities(ability, game, unpaid); if (player.playMana(unpaid, promptText, game)) { assignPayment(game, ability, player.getManaPool()); - } - else { + } else { return false; } game.getState().getSpecialActions().removeManaActions(); diff --git a/Mage/src/mage/abilities/costs/mana/ManaCosts.java b/Mage/src/mage/abilities/costs/mana/ManaCosts.java index e21c8fa2aca..2fe86c5345a 100644 --- a/Mage/src/mage/abilities/costs/mana/ManaCosts.java +++ b/Mage/src/mage/abilities/costs/mana/ManaCosts.java @@ -60,4 +60,5 @@ public interface ManaCosts extends List, ManaCost { @Override ManaCosts copy(); + } diff --git a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java index 4b610c2af3f..02e6f4682ba 100644 --- a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java +++ b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java @@ -100,6 +100,15 @@ public class ManaCostsImpl extends ArrayList implements M return mana; } + @Override + public List getManaOptions() { + List manaVariants = new ArrayList<>(); + for (ManaCost cost : this) { + manaVariants.addAll(cost.getManaOptions()); + } + return manaVariants; + } + @Override public Mana getPayment() { Mana manaTotal = new Mana(); diff --git a/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java b/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java index 44c207a159e..1d4a6170140 100644 --- a/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java +++ b/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java @@ -27,6 +27,8 @@ */ package mage.abilities.costs.mana; +import java.util.ArrayList; +import java.util.List; import mage.Mana; import mage.abilities.Ability; import mage.constants.ColoredManaSymbol; @@ -118,4 +120,12 @@ public class MonoHybridManaCost extends ManaCostImpl { public boolean containsColor(ColoredManaSymbol coloredManaSymbol) { return mana.equals(coloredManaSymbol); } + + @Override + public List getManaOptions() { + List manaList = new ArrayList<>(); + manaList.add(new Mana(mana)); + manaList.add(Mana.ColorlessMana(2)); + return manaList; + } } diff --git a/Mage/src/mage/abilities/mana/CommanderColorIdentityManaAbility.java b/Mage/src/mage/abilities/mana/CommanderColorIdentityManaAbility.java index e3d1110c2d7..b3bb8d035cd 100644 --- a/Mage/src/mage/abilities/mana/CommanderColorIdentityManaAbility.java +++ b/Mage/src/mage/abilities/mana/CommanderColorIdentityManaAbility.java @@ -47,20 +47,19 @@ import mage.util.CardUtil; * * @author LevelX2 */ - public class CommanderColorIdentityManaAbility extends ManaAbility { private FilterMana commanderMana; public CommanderColorIdentityManaAbility() { - super(Zone.BATTLEFIELD, new CommanderIdentityManaEffect(),new TapSourceCost()); + super(Zone.BATTLEFIELD, new CommanderIdentityManaEffect(), new TapSourceCost()); } - + public CommanderColorIdentityManaAbility(Cost cost) { super(Zone.BATTLEFIELD, new CommanderIdentityManaEffect(), cost); commanderMana = null; } - + public CommanderColorIdentityManaAbility(final CommanderColorIdentityManaAbility ability) { super(ability); this.commanderMana = ability.commanderMana; @@ -73,7 +72,7 @@ public class CommanderColorIdentityManaAbility extends ManaAbility { @Override public List getNetMana(Game game) { - if (netMana.isEmpty()) { + if (netMana.isEmpty() && game != null) { Player controller = game.getPlayer(getControllerId()); if (controller != null) { if (commanderMana == null) { @@ -110,7 +109,6 @@ public class CommanderColorIdentityManaAbility extends ManaAbility { return true; } - } class CommanderIdentityManaEffect extends ManaEffect { @@ -190,7 +188,7 @@ class CommanderIdentityManaEffect extends ManaEffect { break; } checkToFirePossibleEvents(mana, game, source); - controller.getManaPool().addMana(mana, game, source); + controller.getManaPool().addMana(mana, game, source); return true; } } diff --git a/Mage/src/mage/abilities/mana/ManaOptions.java b/Mage/src/mage/abilities/mana/ManaOptions.java index dbadf31cfb7..4965a650b13 100644 --- a/Mage/src/mage/abilities/mana/ManaOptions.java +++ b/Mage/src/mage/abilities/mana/ManaOptions.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.mana; import java.util.ArrayList; @@ -37,17 +36,20 @@ import mage.game.Game; * * @author BetaSteward_at_googlemail.com * - * this class is used to build a list of all possible mana combinations - * it can be used to find all the ways to pay a mana cost - * or all the different mana combinations available to a player + * this class is used to build a list of all possible mana combinations it can + * be used to find all the ways to pay a mana cost or all the different mana + * combinations available to a player * */ public class ManaOptions extends ArrayList { - public ManaOptions () {}; + public ManaOptions() { + } + + ; public ManaOptions(final ManaOptions options) { - for (Mana mana: options) { + for (Mana mana : options) { this.add(mana.copy()); } } @@ -59,37 +61,36 @@ public class ManaOptions extends ArrayList { if (!abilities.isEmpty()) { if (abilities.size() == 1) { //if there is only one mana option available add it to all the existing options - List netManas = abilities.get(0).getNetMana(game); + List netManas = abilities.get(0).getNetMana(game); if (netManas.size() == 1) { addMana(netManas.get(0)); } else { List copy = copy(); this.clear(); - for (Mana netMana: netManas) { - for (Mana mana: copy) { + for (Mana netMana : netManas) { + for (Mana mana : copy) { Mana newMana = new Mana(); newMana.add(mana); newMana.add(netMana); this.add(newMana); - } - } + } + } } - - } - else if (abilities.size() > 1) { + + } else if (abilities.size() > 1) { //perform a union of all existing options and the new options List copy = copy(); this.clear(); - for (ManaAbility ability: abilities) { - for (Mana netMana: ability.getNetMana(game)) { + for (ManaAbility ability : abilities) { + for (Mana netMana : ability.getNetMana(game)) { SkipAddMana: - for (Mana mana: copy) { + for (Mana mana : copy) { Mana newMana = new Mana(); newMana.add(mana); newMana.add(netMana); - for(Mana existingMana: this) { + for (Mana existingMana : this) { if (existingMana.equalManaValue(newMana)) { - continue SkipAddMana; + continue SkipAddMana; } Mana moreValuable = Mana.getMoreValuableMana(newMana, existingMana); if (moreValuable != null) { @@ -114,7 +115,7 @@ public class ManaOptions extends ArrayList { if (abilities.size() == 1) { //if there is only one mana option available add it to all the existing options ManaAbility ability = abilities.get(0); - List netManas = abilities.get(0).getNetMana(game); + List netManas = abilities.get(0).getNetMana(game); // no mana costs if (ability.getManaCosts().isEmpty()) { if (netManas.size() == 1) { @@ -122,15 +123,15 @@ public class ManaOptions extends ArrayList { } else { List copy = copy(); this.clear(); - for (Mana netMana: netManas) { - for (Mana mana: copy) { + for (Mana netMana : netManas) { + for (Mana mana : copy) { Mana newMana = new Mana(); newMana.add(mana); newMana.add(netMana); this.add(newMana); - } - } - } + } + } + } } else { // the ability has mana costs if (netManas.size() == 1) { @@ -138,27 +139,27 @@ public class ManaOptions extends ArrayList { } else { List copy = copy(); this.clear(); - for (Mana netMana: netManas) { - for (Mana mana: copy) { + for (Mana netMana : netManas) { + for (Mana mana : copy) { Mana newMana = new Mana(); newMana.add(mana); newMana.add(netMana); subtractCostAddMana(ability.getManaCosts().getMana(), netMana, ability.getCosts().isEmpty()); - } - } - } + } + } + } } } else if (abilities.size() > 1) { //perform a union of all existing options and the new options List copy = copy(); this.clear(); - for (ManaAbility ability: abilities) { - - List netManas = ability.getNetMana(game); - + for (ManaAbility ability : abilities) { + + List netManas = ability.getNetMana(game); + if (ability.getManaCosts().isEmpty()) { - for (Mana netMana: netManas) { - for (Mana mana: copy) { + for (Mana netMana : netManas) { + for (Mana mana : copy) { Mana newMana = new Mana(); newMana.add(mana); newMana.add(netMana); @@ -166,24 +167,26 @@ public class ManaOptions extends ArrayList { } } } else { - for (Mana netMana: netManas) { - CombineWithExisting: - for (Mana previousMana: copy) { - Mana newMana = new Mana(previousMana); - if (previousMana.includesMana(ability.getManaCosts().getMana())) { // costs can be paid - newMana.subtractCost(ability.getManaCosts().getMana()); - newMana.add(netMana); - // if the new mana is in all colors more than another already existing than replace - for (Mana existingMana: this) { - Mana moreValuable = Mana.getMoreValuableMana(newMana, existingMana); - if (moreValuable != null) { - existingMana.setToMana(moreValuable); - continue CombineWithExisting; - } + for (Mana netMana : netManas) { + for (Mana previousMana : copy) { + CombineWithExisting: + for (Mana manaOption : ability.getManaCosts().getManaOptions()) { + Mana newMana = new Mana(previousMana); + if (previousMana.includesMana(manaOption)) { // costs can be paid + newMana.subtractCost(manaOption); + newMana.add(netMana); + // if the new mana is in all colors more than another already existing than replace + for (Mana existingMana : this) { + Mana moreValuable = Mana.getMoreValuableMana(newMana, existingMana); + if (moreValuable != null) { + existingMana.setToMana(moreValuable); + continue CombineWithExisting; + } + } + // no existing Mana includes this new mana so add + this.add(newMana); } - // no existing Mana includes this new mana so add - this.add(newMana); - } + } } } } @@ -197,7 +200,7 @@ public class ManaOptions extends ArrayList { if (isEmpty()) { this.add(new Mana()); } - for (Mana mana: this) { + for (Mana mana : this) { mana.add(addMana); } } @@ -210,13 +213,12 @@ public class ManaOptions extends ArrayList { if (options.size() == 1) { //if there is only one mana option available add it to all the existing options addMana(options.get(0)); - } - else if (options.size() > 1) { + } else if (options.size() > 1) { //perform a union of all existing options and the new options List copy = copy(); this.clear(); - for (Mana addMana: options) { - for (Mana mana: copy) { + for (Mana addMana : options) { + for (Mana mana : copy) { Mana newMana = new Mana(); newMana.add(mana); newMana.add(addMana); @@ -240,15 +242,92 @@ public class ManaOptions extends ArrayList { // deactivated because it does cause loops TODO: Find reason repeatable = true; // only replace to any with mana costs only will be repeated if able } - for (Mana mana: this) { - while (mana.includesMana(cost)) { - mana.subtractCost(cost); - mana.add(addMana); - if (!repeatable) { - break; + List copy = copy(); + this.clear(); + for (Mana mana : copy) { + Mana oldMan = mana.copy(); + if (mana.includesMana(cost)) { + // colorless costs can be paid with different colored mana, can lead to different color combinations + if (cost.getColorless() > 0 && cost.getColorless() > mana.getColorless()) { + Mana coloredCost = cost.copy(); + coloredCost.setColorless(0); + mana.subtract(coloredCost); + for (Mana payCombination : getPossiblePayCombinations(cost.getColorless(), mana)) { + Mana newMana = mana.copy(); + newMana.subtract(payCombination); + newMana.add(addMana); + if (oldMan.contains(newMana) && oldMan.count() > newMana.count()) { + newMana.setToMana(oldMan); + } + this.add(newMana); + } + } else { + while (mana.includesMana(cost)) { + mana.subtractCost(cost); + mana.add(addMana); + if (!repeatable) { + break; + } + } + // Don't use mana that only reduce the available mana + if (oldMan.contains(mana) && oldMan.count() > mana.count()) { + mana.setToMana(oldMan); + } + this.add(mana); } } } } -} \ No newline at end of file + private List getPossiblePayCombinations(int number, Mana manaAvailable) { + List payCombinations = new ArrayList<>(); + List payCombinationsStrings = new ArrayList<>(); + if (manaAvailable.countColored() > 0) { + + for (int i = 0; i < number; i++) { + List existingManas = new ArrayList<>(); + if (i > 0) { + existingManas.addAll(payCombinations); + payCombinations.clear(); + payCombinationsStrings.clear(); + } else { + existingManas.add(new Mana()); + } + for (Mana existingMana : existingManas) { + Mana manaToPay = manaAvailable.copy(); + manaToPay.subtract(existingMana); + if (manaToPay.getBlack() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlackMana.toString())) { + manaToPay.subtract(Mana.BlackMana); + addManaCombination(Mana.BlackMana, existingMana, payCombinations, payCombinationsStrings); + } + if (manaToPay.getBlue() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlueMana.toString())) { + manaToPay.subtract(Mana.BlueMana); + addManaCombination(Mana.BlueMana, existingMana, payCombinations, payCombinationsStrings); + } + if (manaToPay.getGreen() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.GreenMana.toString())) { + manaToPay.subtract(Mana.GreenMana); + addManaCombination(Mana.GreenMana, existingMana, payCombinations, payCombinationsStrings); + } + if (manaToPay.getRed() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.RedMana.toString())) { + manaToPay.subtract(Mana.RedMana); + addManaCombination(Mana.RedMana, existingMana, payCombinations, payCombinationsStrings); + } + if (manaToPay.getWhite() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.WhiteMana.toString())) { + manaToPay.subtract(Mana.WhiteMana); + addManaCombination(Mana.WhiteMana, existingMana, payCombinations, payCombinationsStrings); + } + } + } + } else { + payCombinations.add(new Mana(0, 0, 0, 0, 0, number, 0)); + } + return payCombinations; + } + + private void addManaCombination(Mana mana, Mana existingMana, List payCombinations, List payCombinationsStrings) { + Mana newMana = existingMana.copy(); + newMana.add(mana); + payCombinations.add(newMana); + payCombinationsStrings.add(newMana.toString()); + } +}