diff --git a/Mage/src/mage/ManaSymbol.java b/Mage/src/mage/ManaSymbol.java new file mode 100644 index 00000000000..befde22923a --- /dev/null +++ b/Mage/src/mage/ManaSymbol.java @@ -0,0 +1,236 @@ +package mage; + +/** + * Enum representing the mana symbols. + * + * 107.4. The mana symbols are {W}, {U}, {B}, {R}, {G}, and {X}; the numerals + * {0}, {1}, {2}, {3}, {4}, and so on; the hybrid symbols {W/U}, {W/B}, {U/B}, + * {U/R}, {B/R}, {B/G}, {R/G}, {R/W}, {G/W}, and {G/U}; the monocolored hybrid + * symbols {2/W}, {2/U}, {2/B}, {2/R}, and {2/G}; the Phyrexian mana symbols + * {W/P}, {U/P}, {B/P}, {R/P}, and {G/P}; and the snow symbol {S}. + * + * 107.4a. There are five primary colored mana symbols: {W} is white, {U} blue, + * {B} black, {R} red, and {G} green. These symbols are used to represent colored + * mana, and also to represent colored mana in costs. Colored mana in costs can + * be paid only with the appropriate color of mana. See rule 202, "Mana Cost and + * Color." + * + * 107.4b. Numeral symbols (such as {1}) and variable symbols (such as {X}) + * represent generic mana in costs. Generic mana in costs can be paid with any + * type of mana. For more information about {X}, see rule 107.3. + * + * 107.4c. Numeral symbols (such as {1}) and variable symbols (such as {X}) can + * also represent colorless mana if they appear in the effect of a spell or + * ability that reads "add [mana symbol] to your mana pool" or something similar. + * (See rule 107.3e.) + * + * 107.4d. The symbol {0} represents zero mana and is used as a placeholder for a + * cost that can be paid with no resources. (See rule 117.5.) + * + * 107.4e. Hybrid mana symbols are also colored mana symbols. Each one represents + * a cost that can be paid in one of two ways, as represented by the two halves + * of the symbol. A hybrid symbol such as {W/U} can be paid with either white or + * blue mana, and a monocolored hybrid symbol such as {2/B} can be paid with + * either one black mana or two mana of any type. A hybrid mana symbol is all of + * its component colors. Example: {G/W}{G/W} can be paid by spending {G}{G}, + * {G}{W}, or {W}{W}. + * + * 107.4f. Phyrexian mana symbols are colored mana symbols: {W/P} is white, {U/P} + * is blue, {B/P} is black, {R/P} is red, and {G/P} is green. A Phyrexian mana + * symbol represents a cost that can be paid either with one mana of its color or + * by paying 2 life. Example: {W/P}{W/P} can be paid by spending {W}{W}, by + * spending {W} and paying 2 life, or by paying 4 life. + * + * 107.4g. In rules text, the Phyrexian symbol {P} with no colored background + * means any of the five Phyrexian mana symbols. + * + * 107.4h. The snow mana symbol {S} represents one generic mana in a cost. This + * generic mana can be paid with one mana of any type produced by a snow + * permanent (see rule 205.4f). Effects that reduce the amount of generic mana + * you pay don't affect {S} costs. (There is no such thing as "snow mana"; "snow" + * is not a type of mana.) + * + * + * @author noxx + */ +public enum ManaSymbol { + + W("{W}", Type.PRIMARY, Type.COLORED), + U("{U}", Type.PRIMARY, Type.COLORED), + B("{B}", Type.PRIMARY, Type.COLORED), + R("{R}", Type.PRIMARY, Type.COLORED), + G("{G}", Type.PRIMARY, Type.COLORED), + X("{X}", Type.GENERIC, Type.COLORLESS), + NUMERIC("{N/A}", Type.GENERIC, Type.COLORLESS), + HYBRID_WU("{W/U}", W, U, Type.HYBRID, Type.COLORED), + HYBRID_WB("{W/B}", W, B, Type.HYBRID, Type.COLORED), + HYBRID_UB("{U/B}", U, B, Type.HYBRID, Type.COLORED), + HYBRID_UR("{U/R}", U, R, Type.HYBRID, Type.COLORED), + HYBRID_BR("{B/R}", B, R, Type.HYBRID, Type.COLORED), + HYBRID_BG("{B/G}", B, G, Type.HYBRID, Type.COLORED), + HYBRID_RG("{R/G}", R, G, Type.HYBRID, Type.COLORED), + HYBRID_RW("{R/W}", R, W, Type.HYBRID, Type.COLORED), + HYBRID_GW("{G/W}", G, W, Type.HYBRID, Type.COLORED), + HYBRID_GU("{G/U}", G, U, Type.HYBRID, Type.COLORED), + MONOCOLORED_HYBRID_W("{2/W}", W, Type.HYBRID, Type.MONOCOLORED), + MONOCOLORED_HYBRID_U("{2/U}", U, Type.HYBRID, Type.MONOCOLORED), + MONOCOLORED_HYBRID_B("{2/B}", B, Type.HYBRID, Type.MONOCOLORED), + MONOCOLORED_HYBRID_R("{2/R}", R, Type.HYBRID, Type.MONOCOLORED), + MONOCOLORED_HYBRID_G("{2/G}", G, Type.HYBRID, Type.MONOCOLORED), + PHYREXIAN_W("{W/P}", W, Type.PHYREXIAN, Type.COLORED), + PHYREXIAN_G("{G/P}", G, Type.PHYREXIAN, Type.COLORED), + PHYREXIAN_R("{R/P}", R, Type.PHYREXIAN, Type.COLORED), + PHYREXIAN_B("{B/P}", B, Type.PHYREXIAN, Type.COLORED), + PHYREXIAN_U("{U/P}", U, Type.PHYREXIAN, Type.COLORED), + SNOW("{S}", Type.SNOW); + + private enum Type { + PRIMARY, + COLORED, + GENERIC, + COLORLESS, + MONOCOLORED, + HYBRID, + PHYREXIAN, + SNOW + } + + private final String symbol; + private final boolean primary; + private final boolean colored; + private final boolean generic; + private final boolean colorless; + private final boolean monocolored; + private final boolean hybrid; + private final boolean phyrexian; + private final boolean snow; + + private final boolean white; + private final boolean blue; + private final boolean black; + private final boolean red; + private final boolean green; + + private final ManaSymbol manaSymbol1; + private final ManaSymbol manaSymbol2; + + /** + * + * @param symbol + * @param manaSymbol1 First associated mana symbol. For hybrid mana symbol. + * @param manaSymbol2 Second associated mana symbol. For hybrid mana symbol. + * @param types + */ + private ManaSymbol(String symbol, ManaSymbol manaSymbol1, ManaSymbol manaSymbol2, Type... types) { + this.symbol = symbol; + boolean lPrimary = false, lColored = false, lGeneric = false, lColorless = false; + boolean lMonocolored = false, lHybrid = false, lPhyrexian = false, lSnow = false; + for (Type type : types) { + switch (type) { + case PRIMARY: lPrimary = true; break; + case COLORED: lColored = true; break; + case GENERIC: lGeneric = true; break; + case COLORLESS: lColorless = true; break; + case MONOCOLORED: lMonocolored = true; break; + case HYBRID: lHybrid = true; break; + case PHYREXIAN: lPhyrexian = true; break; + case SNOW: lSnow = true; break; + } + } + primary = lPrimary; + colored = lColored; + generic = lGeneric; + colorless = lColorless; + monocolored = lMonocolored; + hybrid = lHybrid; + phyrexian = lPhyrexian; + snow = lSnow; + white = symbol.contains("W"); + blue = symbol.contains("U"); + black = symbol.contains("B"); + red = symbol.contains("R"); + green = symbol.contains("G"); + this.manaSymbol1 = manaSymbol1; + this.manaSymbol2 = manaSymbol2; + } + + /** + * + * @param symbol + * @param manaSymbol Associated mana symbol. For monocolored hybrid and phyrexian mana. + * @param types + */ + private ManaSymbol(String symbol, ManaSymbol manaSymbol, Type... types) { + this(symbol, manaSymbol, null, types); + } + + private ManaSymbol(String symbol, Type... types) { + this(symbol, null, null, types); + } + + public boolean isPrimary() { + return primary; + } + + public boolean isColored() { + return colored; + } + + public boolean isGeneric() { + return generic; + } + + public boolean isColorless() { + return colorless; + } + + public boolean isMonocolored() { + return monocolored; + } + + public boolean isHybrid() { + return hybrid; + } + + public boolean isPhyrexian() { + return phyrexian; + } + + public boolean isSnow() { + return snow; + } + + public boolean isWhite() { + return white; + } + + public boolean isBlue() { + return blue; + } + + public boolean isBlack() { + return black; + } + + public boolean isRed() { + return red; + } + + public boolean isGreen() { + return green; + } + + public ManaSymbol getManaSymbol1() { + return manaSymbol1; + } + + public ManaSymbol getManaSymbol2() { + return manaSymbol2; + } + + @Override + public String toString() { + return symbol; + } + +} diff --git a/Mage/src/mage/abilities/costs/mana/ManaSymbols.java b/Mage/src/mage/abilities/costs/mana/ManaSymbols.java new file mode 100644 index 00000000000..83aec80836b --- /dev/null +++ b/Mage/src/mage/abilities/costs/mana/ManaSymbols.java @@ -0,0 +1,122 @@ +/* +* 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 mage.ManaSymbol; +import mage.constants.ColoredManaSymbol; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Represents the mana symbols on a card. + * + * @author noxx + */ +public class ManaSymbols extends ArrayList { + + private final static Map coloredManaMap = new HashMap() {{ + put(ColoredManaSymbol.W, ManaSymbol.W); + put(ColoredManaSymbol.U, ManaSymbol.U); + put(ColoredManaSymbol.B, ManaSymbol.B); + put(ColoredManaSymbol.R, ManaSymbol.R); + put(ColoredManaSymbol.G, ManaSymbol.G); + }}; + + /** + * Contains all possible hybrid mana costs (each represents different hybrid mana symbol) + * We'll use it for converting from hybrid mana cost to hybrid mana symbol. + */ + private final static Map hybridManaMap = new HashMap<>(); + + /** + * Build map of all possible hybrid mana symbols assigning corresponding instance of hybrid mana cost. + */ + static { + hybridManaMap.put(ManaSymbol.HYBRID_BG, new HybridManaCost(ColoredManaSymbol.B, ColoredManaSymbol.G)); + hybridManaMap.put(ManaSymbol.HYBRID_BR, new HybridManaCost(ColoredManaSymbol.B, ColoredManaSymbol.R)); + hybridManaMap.put(ManaSymbol.HYBRID_GU, new HybridManaCost(ColoredManaSymbol.G, ColoredManaSymbol.U)); + hybridManaMap.put(ManaSymbol.HYBRID_GW, new HybridManaCost(ColoredManaSymbol.G, ColoredManaSymbol.W)); + hybridManaMap.put(ManaSymbol.HYBRID_RG, new HybridManaCost(ColoredManaSymbol.R, ColoredManaSymbol.G)); + hybridManaMap.put(ManaSymbol.HYBRID_RW, new HybridManaCost(ColoredManaSymbol.R, ColoredManaSymbol.W)); + hybridManaMap.put(ManaSymbol.HYBRID_UB, new HybridManaCost(ColoredManaSymbol.U, ColoredManaSymbol.B)); + hybridManaMap.put(ManaSymbol.HYBRID_UR, new HybridManaCost(ColoredManaSymbol.U, ColoredManaSymbol.R)); + hybridManaMap.put(ManaSymbol.HYBRID_WB, new HybridManaCost(ColoredManaSymbol.W, ColoredManaSymbol.B)); + hybridManaMap.put(ManaSymbol.HYBRID_WU, new HybridManaCost(ColoredManaSymbol.W, ColoredManaSymbol.U)); + } + + /** + * Extracts mana symbols from {@link ManaCost} using {@link mage.ManaSymbol} as a base class for the mana symbols. + * + * @param manaCost + * @return + */ + public static ManaSymbols buildFromManaCost(ManaCost manaCost) { + + ManaSymbols manaSymbols = new ManaSymbols(); + + if (manaCost instanceof ManaCostsImpl) { + ManaCostsImpl manaCosts = (ManaCostsImpl)manaCost; + for (int i = 0; i < manaCosts.size(); i++) { + ManaCost mc = (ManaCost) manaCosts.get(i); + if (mc instanceof ColoredManaCost) { + for (Map.Entry entry : coloredManaMap.entrySet()) { + if (mc.containsColor(entry.getKey())) { + manaSymbols.add(entry.getValue()); + break; + } + } + } else if (mc instanceof HybridManaCost) { + for (Map.Entry entry : hybridManaMap.entrySet()) { + if (compareHybridCosts((HybridManaCost) mc, entry.getValue())) { + manaSymbols.add(entry.getKey()); + break; + } + } + } + } + } + + return manaSymbols; + } + + /** + * Compare two instance of hybrid mana cost. + * + * @param h1 + * @param h2 + * + * @return + */ + private static boolean compareHybridCosts(HybridManaCost h1, HybridManaCost h2) { + return h1.getMana1().equals(h2.getMana1()) && h1.getMana2().equals(h2.getMana2()) + || h1.getMana1().equals(h2.getMana2()) && h1.getMana2().equals(h2.getMana1()); + } +}