package forge.card.mana; import forge.Constant; import forge.gui.input.Input_PayManaCostUtil; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.StringTokenizer; /** * <p>ManaCost class.</p> * * @author Forge * @version $Id: $ */ public class ManaCost { //holds Mana_Part objects //ManaPartColor is stored before ManaPartColorless private ArrayList<Object> manaPart; private HashMap<String, Integer> sunburstMap = new HashMap<String, Integer>(); private int xcounter = 0; //manaCost can be like "0", "3", "G", "GW", "10", "3 GW", "10 GW" //or "split hybrid mana" like "2/G 2/G", "2/B 2/B 2/B" //"GW" can be paid with either G or W /** * <p>Constructor for ManaCost.</p> * * @param manaCost a {@link java.lang.String} object. */ public ManaCost(String manaCost) { if (manaCost.equals("")) manaCost = "0"; while (manaCost.contains("X")) { if (manaCost.length() < 2) manaCost = "0"; else manaCost = manaCost.replaceFirst("X ", ""); setXcounter(getXcounter() + 1); } manaPart = split(manaCost); } /** * <p>getSunburst.</p> * * @return a int. */ public int getSunburst() { int ret = sunburstMap.size(); sunburstMap.clear(); return ret; } /** * <p>getColorsPaid.</p> * * @return a String. */ public String getColorsPaid() { String s = ""; for (String key: sunburstMap.keySet()) { if(key.equals("black")) s+= "B"; if(key.equals("blue")) s+= "U"; if(key.equals("green")) s+= "G"; if(key.equals("red")) s+= "R"; if(key.equals("white")) s+= "W"; } return s; } /** * <p>getUnpaidPhyrexianMana.</p> * * @return a {@link java.util.ArrayList} object. */ private ArrayList<Mana_PartPhyrexian> getUnpaidPhyrexianMana() { ArrayList<Mana_PartPhyrexian> res = new ArrayList<Mana_PartPhyrexian>(); for (Object o : manaPart) { if (o instanceof Mana_PartPhyrexian) { Mana_PartPhyrexian phy = (Mana_PartPhyrexian) o; if (!phy.isPaid()) res.add(phy); } } return res; } /** * <p>containsPhyrexianMana.</p> * * @return a boolean. */ public boolean containsPhyrexianMana() { for (Object o : manaPart) { if (o instanceof Mana_PartPhyrexian) { return true; } } return false; } /** * <p>payPhyrexian.</p> * * @return a boolean. */ public boolean payPhyrexian() { ArrayList<Mana_PartPhyrexian> Phy = getUnpaidPhyrexianMana(); if (Phy.size() > 0) { Phy.get(0).payLife(); return true; } return false; } // takes a Short Color and returns true if it exists in the mana cost. Easier for split costs /** * <p>isColor.</p> * * @param color a {@link java.lang.String} object. * @return a boolean. */ public boolean isColor(String color) { for (Object s : manaPart) { if (s.toString().contains(color)) return true; } return false; } // isNeeded(String) still used by the Computer, might have problems activating Snow abilities /** * <p>isNeeded.</p> * * @param mana a {@link java.lang.String} object. * @return a boolean. */ public boolean isNeeded(String mana) { if (mana.length() > 1) mana = Input_PayManaCostUtil.getShortColorString(mana); Mana_Part m; for (int i = 0; i < manaPart.size(); i++) { m = (Mana_Part) manaPart.get(i); if (m.isNeeded(mana)) return true; } return false; } /** * <p>isNeeded.</p> * * @param mana a {@link forge.card.mana.Mana} object. * @return a boolean. */ public boolean isNeeded(Mana mana) { Mana_Part m; for (int i = 0; i < manaPart.size(); i++) { m = (Mana_Part) manaPart.get(i); if (m.isNeeded(mana)) return true; if (m instanceof Mana_PartSnow && mana.isSnow()) return true; } return false; } /** * <p>isPaid.</p> * * @return a boolean. */ public boolean isPaid() { Mana_Part m; for (int i = 0; i < manaPart.size(); i++) { m = (Mana_Part) manaPart.get(i); if (!m.isPaid()) return false; } return true; }//isPaid() /** * <p>payMana.</p> * * @param mana a {@link forge.card.mana.Mana} object. * @return a boolean. */ public boolean payMana(Mana mana) { return addMana(mana); } /** * <p>payMana.</p> * * @param color a {@link java.lang.String} object. * @return a boolean. */ public boolean payMana(String color) { color = Input_PayManaCostUtil.getShortColorString(color); return addMana(color); } /** * <p>increaseColorlessMana.</p> * * @param manaToAdd a int. */ public void increaseColorlessMana(int manaToAdd) { if (manaToAdd <= 0) return; Mana_Part m; for (int i = 0; i < manaPart.size(); i++) { m = (Mana_Part) manaPart.get(i); if (m instanceof Mana_PartColorless) { ((Mana_PartColorless) m).addToManaNeeded(manaToAdd); return; } } manaPart.add(new Mana_PartColorless(manaToAdd)); } /** * <p>addMana.</p> * * @param mana a {@link java.lang.String} object. * @return a boolean. */ public boolean addMana(String mana) { if (!isNeeded(mana)) throw new RuntimeException("ManaCost : addMana() error, mana not needed - " + mana); Mana_Part choice = null; for (int i = 0; i < manaPart.size(); i++) { Mana_Part m = (Mana_Part) manaPart.get(i); if (m.isNeeded(mana)) { // if m is a better to pay than choice if (choice == null) { choice = m; continue; } if (m.isColor(mana) && choice.isEasierToPay(m)) { choice = m; } } }//for if (choice == null) return false; choice.reduce(mana); if (!mana.equals(Constant.Color.Colorless)) { if (sunburstMap.containsKey(mana)) sunburstMap.put(mana, sunburstMap.get(mana) + 1); else sunburstMap.put(mana, 1); } return true; } /** * <p>addMana.</p> * * @param mana a {@link forge.card.mana.Mana} object. * @return a boolean. */ public boolean addMana(Mana mana) { if (!isNeeded(mana)) throw new RuntimeException("ManaCost : addMana() error, mana not needed - " + mana); Mana_Part choice = null; for (int i = 0; i < manaPart.size(); i++) { Mana_Part m = (Mana_Part) manaPart.get(i); if (m.isNeeded(mana)) { // if m is a better to pay than choice if (choice == null) { choice = m; continue; } if (m.isColor(mana) && choice.isEasierToPay(m)) { choice = m; } } }//for if (choice == null) return false; choice.reduce(mana); if (!mana.isColor(Constant.Color.Colorless)) { if (sunburstMap.containsKey(mana.getColor())) sunburstMap.put(mana.getColor(), sunburstMap.get(mana.getColor()) + 1); else sunburstMap.put(mana.getColor(), 1); } return true; } /** * <p>combineManaCost.</p> * * @param extra a {@link java.lang.String} object. */ public void combineManaCost(String extra) { ArrayList<Object> extraParts = split(extra); Mana_PartColorless part = null; for (int i = 0; i < manaPart.size(); i++) { Object o = manaPart.get(i); if (o instanceof Mana_PartColorless) part = (Mana_PartColorless) o; } if (part != null) { manaPart.remove(part); } while (extraParts.size() > 0) { Object o = extraParts.get(0); if (o instanceof Mana_PartColorless) { if (part == null) part = (Mana_PartColorless) o; else { part.addToManaNeeded(((Mana_PartColorless) o).getManaNeeded()); } } else { manaPart.add(o); } extraParts.remove(o); } if (part != null) manaPart.add(part); } /** {@inheritDoc} */ @Override public String toString() { StringBuilder sb = new StringBuilder(); ArrayList<Object> list = new ArrayList<Object>(manaPart); //need to reverse everything since the colored mana is stored first Collections.reverse(list); for (int i = 0; i < getXcounter(); i++) sb.append(" ").append("X"); for (int i = 0; i < list.size(); i++) { sb.append(" "); sb.append(list.get(i).toString()); } return sb.toString().trim(); } /** * <p>getConvertedManaCost.</p> * * @return a int. */ public int getConvertedManaCost() { int cmc = 0; for (Object s : manaPart) { cmc += ((Mana_Part) s).getConvertedManaCost(); } return cmc; } /** * Returns Mana cost, adjusted slightly to make colored mana parts more significant. * Should only be used for comparison purposes; using this method allows the sort: * 2 < X 2 < 1 U < U U == UR U < X U U < X X U U * * @return The converted cost + 0.0001* the number of colored mana in the cost + 0.00001 * * the number of X's in the cost */ public double getWeightedManaCost() { double cmc = 0; for (Object s : manaPart) { cmc += ((Mana_Part) s).getConvertedManaCost(); if (s instanceof Mana_PartColor) { cmc += 0.0001; } } cmc += 0.00001 * getXcounter(); return cmc; } /** * <p>split.</p> * * @param cost a {@link java.lang.String} object. * @return a {@link java.util.ArrayList} object. */ private ArrayList<Object> split(String cost) { ArrayList<Object> list = new ArrayList<Object>(); //handles costs like "3", "G", "GW", "10", "S" if (cost.length() == 1 || cost.length() == 2) { if (Character.isDigit(cost.charAt(0))) list.add(new Mana_PartColorless(cost)); else if (cost.charAt(0) == 'S') list.add(new Mana_PartSnow()); else if (cost.charAt(0) == 'P') list.add(new Mana_PartPhyrexian(cost)); else list.add(new Mana_PartColor(cost)); } else//handles "3 GW", "10 GW", "1 G G", "G G", "S 1" { //all costs that have a length greater than 2 have a space StringTokenizer tok = new StringTokenizer(cost); while (tok.hasMoreTokens()) list.add(getManaPart(tok.nextToken())); //ManaPartColorless needs to be added AFTER the colored mana //in order for isNeeded() and addMana() to work correctly Object o = list.get(0); if (o instanceof Mana_PartSnow) { //move snow cost to the end of the list list.remove(0); list.add(o); } o = list.get(0); if (o instanceof Mana_PartColorless) { //move colorless cost to the end of the list list.remove(0); list.add(o); } }//else return list; }//split() /** * <p>Getter for the field <code>manaPart</code>.</p> * * @param partCost a {@link java.lang.String} object. * @return a {@link forge.card.mana.Mana_Part} object. */ private Mana_Part getManaPart(String partCost) { if (partCost.length() == 3) { return new Mana_PartSplit(partCost); } else if (Character.isDigit(partCost.charAt(0))) { return new Mana_PartColorless(partCost); } else if (partCost.equals("S")) { return new Mana_PartSnow(); } else if (partCost.startsWith("P")) { return new Mana_PartPhyrexian(partCost); } else { return new Mana_PartColor(partCost); } } /** * <p>Setter for the field <code>xcounter</code>.</p> * * @param xcounter a int. */ public void setXcounter(int xcounter) { this.xcounter = xcounter; } /** * <p>Getter for the field <code>xcounter</code>.</p> * * @return a int. */ public int getXcounter() { return xcounter; } /** * <p>removeColorlessMana.</p> * * @since 1.0.15 */ public void removeColorlessMana() { for (int i = 0; i < manaPart.size(); i++) { if (manaPart.get(i) instanceof Mana_PartColorless) manaPart.remove(manaPart.get(i)); } } }