diff --git a/src/main/java/forge/card/ability/AbilityUtils.java b/src/main/java/forge/card/ability/AbilityUtils.java index eecefd1e829..774226d6520 100644 --- a/src/main/java/forge/card/ability/AbilityUtils.java +++ b/src/main/java/forge/card/ability/AbilityUtils.java @@ -290,250 +290,18 @@ public class AbilityUtils { * @return a int. */ public static int calculateAmount(final Card card, String amount, final SpellAbility ability) { - // amount can be anything, not just 'X' as long as sVar exists + // return empty strings and constants + if (StringUtils.isBlank(amount)) return 0; + if (StringUtils.isNumeric(amount)) return Integer.parseInt(amount); - if (amount == null || amount.isEmpty()) { - return 0; - } - - // If Amount is -X, strip the minus sign before looking for an SVar of - // that kind - int multiplier = 1; - if (amount.startsWith("-")) { - multiplier = -1; + // Strip and save sign for calculations + boolean startsWithPlus = amount.charAt(0) == '+'; + boolean startsWithMinus = amount.charAt(0) == '-'; + int multiplier = startsWithMinus ? -1 : 1; + if(startsWithMinus || startsWithPlus ) amount = amount.substring(1); - } else if (amount.startsWith("+")) { - amount = amount.substring(1); - } - String svarval; - if (ability != null) { - - svarval = ability.getSVar(amount); - if (svarval.equals("")) { - try { - Integer.parseInt(amount); - } - catch (NumberFormatException ignored) { - //If this is reached, amount wasn't an integer - //Print a warning to console to help debug if an ability is not stolen properly. - StringBuilder sb = new StringBuilder("WARNING:SVar fallback to Card ("); - sb.append(card.getName()).append(") and Ability(").append(ability.toString()).append(")"); - System.out.println(sb.toString()); - svarval = card.getSVar(amount); - } - } - } else { - svarval = card.getSVar(amount); - } - - if (!svarval.equals("")) { - final String[] calcX = svarval.split("\\$"); - if ((calcX.length == 1) || calcX[1].equals("none")) { - return 0; - } - - if (calcX[0].startsWith("Count")) { - return AbilityUtils.xCount(card, calcX[1], ability) * multiplier; - } else if (calcX[0].startsWith("Number")) { - return CardFactoryUtil.xCount(card, svarval) * multiplier; - } else if (calcX[0].startsWith("SVar")) { - final String[] l = calcX[1].split("/"); - final String[] m = CardFactoryUtil.parseMath(l); - return CardFactoryUtil.doXMath(AbilityUtils.calculateAmount(card, l[0], ability), m, card) - * multiplier; - } else if (calcX[0].startsWith("PlayerCount")) { - final String hType = calcX[0].substring(11); - final ArrayList players = new ArrayList(); - if (hType.equals("Players") || hType.equals("")) { - players.addAll(Singletons.getModel().getGame().getPlayers()); - return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; - } else if (hType.equals("Opponents")) { - players.addAll(card.getController().getOpponents()); - return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; - } else if (hType.equals("Other")) { - players.addAll(card.getController().getAllOtherPlayers()); - return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; - } else if (hType.equals("Remembered")) { - for (final Object o : card.getRemembered()) { - if (o instanceof Player) { - players.add((Player) o); - } - } - return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; - } else if (hType.equals("NonActive")) { - players.addAll(Singletons.getModel().getGame().getPlayers()); - players.remove(Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn()); - return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; - } - } else if (calcX[0].startsWith("Remembered")) { - // Add whole Remembered list to handlePaid - final List list = new ArrayList(); - if (card.getRemembered().isEmpty()) { - final Card newCard = Singletons.getModel().getGame().getCardState(card); - for (final Object o : newCard.getRemembered()) { - if (o instanceof Card) { - list.add(Singletons.getModel().getGame().getCardState((Card) o)); - } - } - } - - if (calcX[0].endsWith("LKI")) { // last known information - for (final Object o : card.getRemembered()) { - if (o instanceof Card) { - list.add((Card) o); - } - } - } else { - for (final Object o : card.getRemembered()) { - if (o instanceof Card) { - list.add(Singletons.getModel().getGame().getCardState((Card) o)); - } - } - } - - return CardFactoryUtil.handlePaid(list, calcX[1], card) * multiplier; - } else if (calcX[0].startsWith("Imprinted")) { - // Add whole Imprinted list to handlePaid - final List list = new ArrayList(); - for (final Card c : card.getImprinted()) { - list.add(Singletons.getModel().getGame().getCardState(c)); - } - - return CardFactoryUtil.handlePaid(list, calcX[1], card) * multiplier; - } else if (calcX[0].matches("Enchanted")) { - // Add whole Enchanted list to handlePaid - final List list = new ArrayList(); - if (card.isEnchanting()) { - Object o = card.getEnchanting(); - if (o instanceof Card) { - list.add(Singletons.getModel().getGame().getCardState((Card) o)); - } - } - return CardFactoryUtil.handlePaid(list, calcX[1], card) * multiplier; - } else if (ability != null) { - // Player attribute counting - if (calcX[0].startsWith("TargetedPlayer")) { - final ArrayList players = new ArrayList(); - final SpellAbility saTargeting = ability.getSATargetingPlayer(); - if (null != saTargeting) { - players.addAll(saTargeting.getTarget().getTargetPlayers()); - } - return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; - } - if (calcX[0].startsWith("TargetedObjects")) { - final ArrayList objects = new ArrayList(); - // Make list of all targeted objects starting with the root SpellAbility - SpellAbility loopSA = ability.getRootAbility(); - while (loopSA != null) { - if (loopSA.getTarget() != null) { - objects.addAll(loopSA.getTarget().getTargets()); - } - loopSA = loopSA.getSubAbility(); - } - return CardFactoryUtil.objectXCount(objects, calcX[1], card) * multiplier; - } - if (calcX[0].startsWith("TargetedController")) { - final ArrayList players = new ArrayList(); - final List list = getDefinedCards(card, "Targeted", ability); - final List sas = AbilityUtils.getDefinedSpellAbilities(card, "Targeted", - ability); - - for (final Card c : list) { - final Player p = c.getController(); - if (!players.contains(p)) { - players.add(p); - } - } - for (final SpellAbility s : sas) { - final Player p = s.getSourceCard().getController(); - if (!players.contains(p)) { - players.add(p); - } - } - return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; - } - if (calcX[0].startsWith("TargetedByTarget")) { - final List tgtList = new ArrayList(); - final List saList = getDefinedSpellAbilities(card, "Targeted", ability); - - for (final SpellAbility s : saList) { - tgtList.addAll(getDefinedCards(s.getSourceCard(), "Targeted", s)); - } - return CardFactoryUtil.handlePaid(tgtList, calcX[1], card) * multiplier; - } - if (calcX[0].startsWith("TriggeredPlayer") || calcX[0].startsWith("TriggeredTarget")) { - final SpellAbility root = ability.getRootAbility(); - Object o = root.getTriggeringObject(calcX[0].substring(9)); - final List players = new ArrayList(); - if (o instanceof Player) { - players.add((Player) o); - } - return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; - } - // Added on 9/30/12 (ArsenalNut) - Ended up not using but might be useful in future - /* - if (calcX[0].startsWith("EnchantedController")) { - final ArrayList players = new ArrayList(); - players.addAll(AbilityFactory.getDefinedPlayers(card, "EnchantedController", ability)); - return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; - } - */ - - List list = new ArrayList(); - if (calcX[0].startsWith("Sacrificed")) { - list = ability.getRootAbility().getPaidList("Sacrificed"); - } else if (calcX[0].startsWith("Discarded")) { - final SpellAbility root = ability.getRootAbility(); - list = root.getPaidList("Discarded"); - if ((null == list) && root.isTrigger()) { - list = root.getSourceCard().getSpellPermanent().getPaidList("Discarded"); - } - } else if (calcX[0].startsWith("Exiled")) { - list = ability.getRootAbility().getPaidList("Exiled"); - } else if (calcX[0].startsWith("Tapped")) { - list = ability.getRootAbility().getPaidList("Tapped"); - } else if (calcX[0].startsWith("Revealed")) { - list = ability.getRootAbility().getPaidList("Revealed"); - } else if (calcX[0].startsWith("Targeted")) { - list = ability.findTargetedCards(); - } else if (calcX[0].startsWith("Triggered")) { - final SpellAbility root = ability.getRootAbility(); - list = new ArrayList(); - list.add((Card) root.getTriggeringObject(calcX[0].substring(9))); - } else if (calcX[0].startsWith("TriggerCount")) { - // TriggerCount is similar to a regular Count, but just - // pulls Integer Values from Trigger objects - final SpellAbility root = ability.getRootAbility(); - final String[] l = calcX[1].split("/"); - final String[] m = CardFactoryUtil.parseMath(l); - final int count = (Integer) root.getTriggeringObject(l[0]); - - return CardFactoryUtil.doXMath(count, m, card) * multiplier; - } else if (calcX[0].startsWith("Replaced")) { - final SpellAbility root = ability.getRootAbility(); - list = new ArrayList(); - list.add((Card) root.getReplacingObject(calcX[0].substring(8))); - } else if (calcX[0].startsWith("ReplaceCount")) { - // ReplaceCount is similar to a regular Count, but just - // pulls Integer Values from Replacement objects - final SpellAbility root = ability.getRootAbility(); - final String[] l = calcX[1].split("/"); - final String[] m = CardFactoryUtil.parseMath(l); - final int count = (Integer) root.getReplacingObject(l[0]); - - return CardFactoryUtil.doXMath(count, m, card) * multiplier; - } else { - - return 0; - } - - return CardFactoryUtil.handlePaid(list, calcX[1], card) * multiplier; - - } else { - return 0; - } - } + // These are some special cases - who is implementing them? if (amount.equals("ChosenX") || amount.equals("ChosenY")) { // isn't made yet return 0; @@ -543,7 +311,244 @@ public class AbilityUtils { return 0; } - return Integer.parseInt(amount) * multiplier; + // Try to fetch variable, try ability first, then card. + String svarval = null; + if (ability != null) { + svarval = ability.getSVar(amount); + } + if (StringUtils.isBlank(svarval)) { + if( ability != null) { + System.err.printf("SVar '%s' not found in ability, fallback to Card (%s). Ability is (%s)%n", amount, card.getName(), ability); + } + svarval = card.getSVar(amount); + } + + // Nothing to do here if value is missing or blank + if (StringUtils.isBlank(svarval)) { + System.err.printf("SVar '%s' not defined in Card (%s)%n", amount, card.getName()); + return 0; + } + + // Handle numeric constant coming in svar value + if( StringUtils.isNumeric(svarval) ) + return multiplier * Integer.parseInt(svarval); + + // Parse Object$Property string + final String[] calcX = svarval.split("\\$"); + + // Incorrect parses mean zero. + if ((calcX.length == 1) || calcX[1].equals("none")) + return 0; + + if (calcX[0].startsWith("Count")) + return AbilityUtils.xCount(card, calcX[1], ability) * multiplier; + + if (calcX[0].startsWith("Number")) + return CardFactoryUtil.xCount(card, svarval) * multiplier; + + if (calcX[0].startsWith("SVar")) { + final String[] l = calcX[1].split("/"); + final String m = CardFactoryUtil.extractOperators(calcX[1]); + return CardFactoryUtil.doXMath(AbilityUtils.calculateAmount(card, l[0], ability), m, card) * multiplier; + } + + if (calcX[0].startsWith("PlayerCount")) { + final String hType = calcX[0].substring(11); + final ArrayList players = new ArrayList(); + if (hType.equals("Players") || hType.equals("")) { + players.addAll(Singletons.getModel().getGame().getPlayers()); + return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; + } else if (hType.equals("Opponents")) { + players.addAll(card.getController().getOpponents()); + return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; + } else if (hType.equals("Other")) { + players.addAll(card.getController().getAllOtherPlayers()); + return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; + } else if (hType.equals("Remembered")) { + for (final Object o : card.getRemembered()) { + if (o instanceof Player) { + players.add((Player) o); + } + } + return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; + } else if (hType.equals("NonActive")) { + players.addAll(Singletons.getModel().getGame().getPlayers()); + players.remove(Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn()); + return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; + } + return 0; + } + + if (calcX[0].startsWith("Remembered")) { + // Add whole Remembered list to handlePaid + final List list = new ArrayList(); + if (card.getRemembered().isEmpty()) { + final Card newCard = Singletons.getModel().getGame().getCardState(card); + for (final Object o : newCard.getRemembered()) { + if (o instanceof Card) { + list.add(Singletons.getModel().getGame().getCardState((Card) o)); + } + } + } + + if (calcX[0].endsWith("LKI")) { // last known information + for (final Object o : card.getRemembered()) { + if (o instanceof Card) { + list.add((Card) o); + } + } + } else { + for (final Object o : card.getRemembered()) { + if (o instanceof Card) { + list.add(Singletons.getModel().getGame().getCardState((Card) o)); + } + } + } + + return CardFactoryUtil.handlePaid(list, calcX[1], card) * multiplier; + } + + if (calcX[0].startsWith("Imprinted")) { + // Add whole Imprinted list to handlePaid + final List list = new ArrayList(); + for (final Card c : card.getImprinted()) { + list.add(Singletons.getModel().getGame().getCardState(c)); + } + + return CardFactoryUtil.handlePaid(list, calcX[1], card) * multiplier; + } + + if (calcX[0].matches("Enchanted")) { + // Add whole Enchanted list to handlePaid + final List list = new ArrayList(); + if (card.isEnchanting()) { + Object o = card.getEnchanting(); + if (o instanceof Card) { + list.add(Singletons.getModel().getGame().getCardState((Card) o)); + } + } + return CardFactoryUtil.handlePaid(list, calcX[1], card) * multiplier; + } + + if (ability == null) + return 0; + + // Player attribute counting + if (calcX[0].startsWith("TargetedPlayer")) { + final ArrayList players = new ArrayList(); + final SpellAbility saTargeting = ability.getSATargetingPlayer(); + if (null != saTargeting) { + players.addAll(saTargeting.getTarget().getTargetPlayers()); + } + return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; + } + if (calcX[0].startsWith("TargetedObjects")) { + final ArrayList objects = new ArrayList(); + // Make list of all targeted objects starting with the root SpellAbility + SpellAbility loopSA = ability.getRootAbility(); + while (loopSA != null) { + if (loopSA.getTarget() != null) { + objects.addAll(loopSA.getTarget().getTargets()); + } + loopSA = loopSA.getSubAbility(); + } + return CardFactoryUtil.objectXCount(objects, calcX[1], card) * multiplier; + } + if (calcX[0].startsWith("TargetedController")) { + final ArrayList players = new ArrayList(); + final List list = getDefinedCards(card, "Targeted", ability); + final List sas = AbilityUtils.getDefinedSpellAbilities(card, "Targeted", + ability); + + for (final Card c : list) { + final Player p = c.getController(); + if (!players.contains(p)) { + players.add(p); + } + } + for (final SpellAbility s : sas) { + final Player p = s.getSourceCard().getController(); + if (!players.contains(p)) { + players.add(p); + } + } + return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; + } + if (calcX[0].startsWith("TargetedByTarget")) { + final List tgtList = new ArrayList(); + final List saList = getDefinedSpellAbilities(card, "Targeted", ability); + + for (final SpellAbility s : saList) { + tgtList.addAll(getDefinedCards(s.getSourceCard(), "Targeted", s)); + } + return CardFactoryUtil.handlePaid(tgtList, calcX[1], card) * multiplier; + } + if (calcX[0].startsWith("TriggeredPlayer") || calcX[0].startsWith("TriggeredTarget")) { + final SpellAbility root = ability.getRootAbility(); + Object o = root.getTriggeringObject(calcX[0].substring(9)); + final List players = new ArrayList(); + if (o instanceof Player) { + players.add((Player) o); + } + return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; + } + // Added on 9/30/12 (ArsenalNut) - Ended up not using but might be useful in future + /* + if (calcX[0].startsWith("EnchantedController")) { + final ArrayList players = new ArrayList(); + players.addAll(AbilityFactory.getDefinedPlayers(card, "EnchantedController", ability)); + return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; + } + */ + + List list = new ArrayList(); + if (calcX[0].startsWith("Sacrificed")) { + list = ability.getRootAbility().getPaidList("Sacrificed"); + } else if (calcX[0].startsWith("Discarded")) { + final SpellAbility root = ability.getRootAbility(); + list = root.getPaidList("Discarded"); + if ((null == list) && root.isTrigger()) { + list = root.getSourceCard().getSpellPermanent().getPaidList("Discarded"); + } + } else if (calcX[0].startsWith("Exiled")) { + list = ability.getRootAbility().getPaidList("Exiled"); + } else if (calcX[0].startsWith("Tapped")) { + list = ability.getRootAbility().getPaidList("Tapped"); + } else if (calcX[0].startsWith("Revealed")) { + list = ability.getRootAbility().getPaidList("Revealed"); + } else if (calcX[0].startsWith("Targeted")) { + list = ability.findTargetedCards(); + } else if (calcX[0].startsWith("Triggered")) { + final SpellAbility root = ability.getRootAbility(); + list = new ArrayList(); + list.add((Card) root.getTriggeringObject(calcX[0].substring(9))); + } else if (calcX[0].startsWith("TriggerCount")) { + // TriggerCount is similar to a regular Count, but just + // pulls Integer Values from Trigger objects + final SpellAbility root = ability.getRootAbility(); + final String[] l = calcX[1].split("/"); + final String m = CardFactoryUtil.extractOperators(calcX[1]); + final int count = (Integer) root.getTriggeringObject(l[0]); + + return CardFactoryUtil.doXMath(count, m, card) * multiplier; + } else if (calcX[0].startsWith("Replaced")) { + final SpellAbility root = ability.getRootAbility(); + list = new ArrayList(); + list.add((Card) root.getReplacingObject(calcX[0].substring(8))); + } else if (calcX[0].startsWith("ReplaceCount")) { + // ReplaceCount is similar to a regular Count, but just + // pulls Integer Values from Replacement objects + final SpellAbility root = ability.getRootAbility(); + final String[] l = calcX[1].split("/"); + final String m = CardFactoryUtil.extractOperators(calcX[1]); + final int count = (Integer) root.getReplacingObject(l[0]); + + return CardFactoryUtil.doXMath(count, m, card) * multiplier; + } else { + return 0; + } + + return CardFactoryUtil.handlePaid(list, calcX[1], card) * multiplier; } /** @@ -1231,7 +1236,7 @@ public class AbilityUtils { public static int xCount(final Card c, final String s, final SpellAbility sa) { final String[] l = s.split("/"); - final String[] m = CardFactoryUtil.parseMath(l); + final String expr = CardFactoryUtil.extractOperators(s); final String[] sq; sq = l[0].split("\\."); @@ -1240,9 +1245,9 @@ public class AbilityUtils { // Count$Kicked.. if (sq[0].startsWith("Kicked")) { if (sa.isKicked()) { - return CardFactoryUtil.doXMath(Integer.parseInt(sq[1]), m, c); // Kicked + return CardFactoryUtil.doXMath(Integer.parseInt(sq[1]), expr, c); // Kicked } else { - return CardFactoryUtil.doXMath(Integer.parseInt(sq[2]), m, c); // not Kicked + return CardFactoryUtil.doXMath(Integer.parseInt(sq[2]), expr, c); // not Kicked } } @@ -1252,9 +1257,9 @@ public class AbilityUtils { final int lhs = calculateAmount(c, compString[1], sa); final int rhs = calculateAmount(c, compString[2].substring(2), sa); if (Expressions.compare(lhs, compString[2], rhs)) { - return CardFactoryUtil.doXMath(Integer.parseInt(sq[1]), m, c); + return CardFactoryUtil.doXMath(Integer.parseInt(sq[1]), expr, c); } else { - return CardFactoryUtil.doXMath(Integer.parseInt(sq[2]), m, c); + return CardFactoryUtil.doXMath(Integer.parseInt(sq[2]), expr, c); } } } diff --git a/src/main/java/forge/card/cardfactory/CardFactoryUtil.java b/src/main/java/forge/card/cardfactory/CardFactoryUtil.java index 4fd6836501e..98595d32235 100644 --- a/src/main/java/forge/card/cardfactory/CardFactoryUtil.java +++ b/src/main/java/forge/card/cardfactory/CardFactoryUtil.java @@ -866,13 +866,9 @@ public class CardFactoryUtil { * an array of {@link java.lang.String} objects. * @return an array of {@link java.lang.String} objects. */ - public static String[] parseMath(final String[] l) { - final String[] m = { "none" }; - if (l.length > 1) { - m[0] = l[1]; - } - - return m; + public static String extractOperators(final String expression) { + String[] l = expression.split("/"); + return l.length > 1 ? l[1] : null; } /** @@ -889,20 +885,12 @@ public class CardFactoryUtil { * @return a int. */ public static int objectXCount(final ArrayList objects, final String s, final Card source) { - if (objects.size() == 0) { + if (objects.isEmpty()) { return 0; } - final String[] l = s.split("/"); - final String[] m = CardFactoryUtil.parseMath(l); - - int n = 0; - - if (s.startsWith("Amount")) { - n = objects.size(); - } - - return CardFactoryUtil.doXMath(n, m, source); + int n = s.startsWith("Amount") ? objects.size() : 0; + return CardFactoryUtil.doXMath(n, CardFactoryUtil.extractOperators(s), source); } /** @@ -924,7 +912,7 @@ public class CardFactoryUtil { } final String[] l = s.split("/"); - final String[] m = CardFactoryUtil.parseMath(l); + final String m = CardFactoryUtil.extractOperators(s); int n = 0; @@ -1115,19 +1103,19 @@ public class CardFactoryUtil { * * @param c * a {@link forge.Card} object. - * @param s + * @param expression * a {@link java.lang.String} object. * @return a int. */ - public static int xCount(final Card c, final String s) { + public static int xCount(final Card c, final String expression) { int n = 0; final Player cardController = c.getController(); final Player oppController = cardController.getOpponent(); final Player activePlayer = Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn(); - final String[] l = s.split("/"); - final String[] m = CardFactoryUtil.parseMath(l); + final String[] l = expression.split("/"); + final String m = CardFactoryUtil.extractOperators(expression); // accept straight numbers if (l[0].startsWith("Number$")) { @@ -2028,12 +2016,12 @@ public class CardFactoryUtil { return CardFactoryUtil.doXMath(n, m, c); } - private static int doXMath(final int num, final String m, final Card c) { - if (m.equals("none")) { + public static int doXMath(final int num, final String operators, final Card c) { + if (operators == null || operators.equals("none")) { return num; } - final String[] s = m.split("\\."); + final String[] s = operators.split("\\."); int secondaryNum = 0; try { @@ -2092,27 +2080,6 @@ public class CardFactoryUtil { } } - /** - *

- * doXMath. - *

- * - * @param num - * a int. - * @param m - * an array of {@link java.lang.String} objects. - * @param c - * a {@link forge.Card} object. - * @return a int. - */ - public static int doXMath(final int num, final String[] m, final Card c) { - if (m.length == 0) { - return num; - } - - return CardFactoryUtil.doXMath(num, m[0], c); - } - /** *

* handlePaid. @@ -2145,17 +2112,9 @@ public class CardFactoryUtil { } if (string.startsWith("Valid")) { - final String[] m = { "none" }; - String valid = string.substring(6); - final String[] l; - l = valid.split("/"); // separate the specification from any math - valid = l[0]; - if (l.length > 1) { - m[0] = l[1]; - } final List list = CardLists.getValidCards(paidList, valid, source.getController(), source); - return CardFactoryUtil.doXMath(list.size(), m, source); + return CardFactoryUtil.doXMath(list.size(), CardFactoryUtil.extractOperators(valid), source); } int tot = 0; diff --git a/src/main/java/forge/card/cost/CostPart.java b/src/main/java/forge/card/cost/CostPart.java index 703c0e0d648..a8c0db3ff8b 100644 --- a/src/main/java/forge/card/cost/CostPart.java +++ b/src/main/java/forge/card/cost/CostPart.java @@ -18,6 +18,8 @@ package forge.card.cost; +import org.apache.commons.lang3.StringUtils; + import forge.Card; import forge.card.spellability.SpellAbility; import forge.game.GameState; @@ -120,12 +122,7 @@ public abstract class CostPart { * @return the integer */ public final Integer convertAmount() { - Integer i = null; - try { - i = Integer.parseInt(this.getAmount()); - } catch (final NumberFormatException e) { - } - return i; + return StringUtils.isNumeric(amount) ? Integer.parseInt(amount) : null; } /** diff --git a/src/main/java/forge/card/cost/CostPartMana.java b/src/main/java/forge/card/cost/CostPartMana.java index 30314241d91..d962268e0fe 100644 --- a/src/main/java/forge/card/cost/CostPartMana.java +++ b/src/main/java/forge/card/cost/CostPartMana.java @@ -209,10 +209,10 @@ public class CostPartMana extends CostPart { // if X cost is a defined value, other than xPaid if (!ability.getSVar("X").equals("Count$xPaid")) { // this currently only works for things about Targeted object - manaToAdd = AbilityUtils.calculateAmount(source, "X", ability) * this.getAmountOfX(); + manaToAdd += AbilityUtils.calculateAmount(source, "X", ability) * this.getAmountOfX(); } } - + if (!"0".equals(this.getManaToPay()) || manaToAdd > 0) { InputPayment inpPayment = new InputPayManaOfCostPayment(game, this, ability, manaToAdd); @@ -221,16 +221,15 @@ public class CostPartMana extends CostPart { return false; } if (this.getAmountOfX() > 0) { - if( !"X".equals(ability.getParam("Announce")) ) { + if( !ability.isAnnouncing("X") ) { source.setXManaCostPaid(0); InputPayment inpPayment = new InputPayManaX(ability, this.getAmountOfX(), this.canXbe0()); FThreads.setInputAndWait(inpPayment); if(!inpPayment.isPaid()) return false; } else { - String xVar = ability.getSVar("X"); - String xVal = xVar.split("\\$")[1]; - source.setXManaCostPaid(Integer.parseInt(xVal)); + int x = AbilityUtils.calculateAmount(source, ability.getSVar("X"), ability); + source.setXManaCostPaid(x); } } return true; diff --git a/src/main/java/forge/card/spellability/HumanPlaySpellAbility.java b/src/main/java/forge/card/spellability/HumanPlaySpellAbility.java index 171ce0d12ce..17791afea16 100644 --- a/src/main/java/forge/card/spellability/HumanPlaySpellAbility.java +++ b/src/main/java/forge/card/spellability/HumanPlaySpellAbility.java @@ -158,8 +158,8 @@ public class HumanPlaySpellAbility { Integer value = ability.getActivatingPlayer().getController().announceRequirements(ability, aVar, ability.getPayCosts().getCostMana().canXbe0()); if ( null == value ) return false; - ability.setSVar(aVar, "Number$" + value); - ability.getSourceCard().setSVar(aVar, "Number$" + value); + ability.setSVar(aVar, value.toString()); + ability.getSourceCard().setSVar(aVar, value.toString()); } } return true; diff --git a/src/main/java/forge/card/spellability/SpellAbility.java b/src/main/java/forge/card/spellability/SpellAbility.java index 8fcd9d76429..d3e8468d0f2 100644 --- a/src/main/java/forge/card/spellability/SpellAbility.java +++ b/src/main/java/forge/card/spellability/SpellAbility.java @@ -23,6 +23,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.commons.lang3.StringUtils; + import forge.Card; import forge.GameEntity; import forge.Singletons; @@ -35,6 +37,7 @@ import forge.card.mana.Mana; import forge.card.mana.ManaCost; import forge.game.player.AIPlayer; import forge.game.player.Player; +import forge.util.TextUtil; //only SpellAbility can go on the stack //override any methods as needed @@ -1739,6 +1742,20 @@ public abstract class SpellAbility implements ISpellAbility { } } + return false; + } + + /** + * Returns whether variable was present in the announce list. + */ + public boolean isAnnouncing(String variable) { + String announce = getParam("Announce"); + if (StringUtils.isBlank(announce)) return false; + String[] announcedOnes = TextUtil.split(announce, ','); + for(String a : announcedOnes) { + if( a.trim().equalsIgnoreCase(variable)) + return true; + } return false; } } diff --git a/src/main/java/forge/card/spellability/Target.java b/src/main/java/forge/card/spellability/Target.java index 99dc9117bbf..e5300e48c41 100644 --- a/src/main/java/forge/card/spellability/Target.java +++ b/src/main/java/forge/card/spellability/Target.java @@ -281,7 +281,7 @@ public class Target { * * @return the max targets */ - public final String getMaxTargets() { + private final String getMaxTargets() { return this.maxTargets; }