From 8be07d95f25baa8476c8e8945a57ad2c59d2cf72 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Wed, 3 Apr 2013 09:35:09 +0000 Subject: [PATCH] cleanup of AbilityUtils.calculateAmount - if amount is pure integer, it's returned right away (that means no svars may be named after valid numbers) former parseMath renamed and no longer returns an array of one string (just return the string) --- .../java/forge/card/ability/AbilityUtils.java | 499 +++++++++--------- .../card/cardfactory/CardFactoryUtil.java | 71 +-- src/main/java/forge/card/cost/CostPart.java | 9 +- .../java/forge/card/cost/CostPartMana.java | 11 +- .../spellability/HumanPlaySpellAbility.java | 4 +- .../forge/card/spellability/SpellAbility.java | 17 + .../java/forge/card/spellability/Target.java | 2 +- 7 files changed, 295 insertions(+), 318 deletions(-) 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; }