diff --git a/forge-game/src/main/java/forge/game/ability/AbilityKey.java b/forge-game/src/main/java/forge/game/ability/AbilityKey.java index b59c96e35d3..588e5f37712 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityKey.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityKey.java @@ -29,7 +29,6 @@ public enum AbilityKey { Blockers("Blockers"), CanReveal("CanReveal"), CastSA("CastSA"), - CastSACMC("CastSACMC"), Card("Card"), Cards("Cards"), CardLKI("CardLKI"), diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 0884b3598bd..b9816b409de 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -283,7 +283,7 @@ public class AbilityUtils { System.err.println("Warning: couldn't find trigger SA in the chain of SpellAbility " + sa); } } else if (defined.equals("FirstRemembered")) { - Object o = Iterables.getFirst(hostCard.getRemembered(), null); + Object o = hostCard.getFirstRemembered(); if (o != null && o instanceof Card) { cards.add(game.getCardState((Card) o)); } @@ -542,6 +542,9 @@ public class AbilityUtils { } } else if (calcX[0].equals("OriginalHost")) { val = xCount(ability.getOriginalHost(), calcX[1], ability); + } else if (calcX[0].equals("LastStateBattlefield") && ability instanceof SpellAbility) { + Card c = ((SpellAbility) ability).getLastStateBattlefield().get(card); + val = c == null ? 0 : xCount(c, calcX[1], ability); } else if (calcX[0].startsWith("Remembered")) { // Add whole Remembered list to handlePaid final CardCollection list = new CardCollection(); @@ -685,10 +688,9 @@ public class AbilityUtils { Object o = root.getTriggeringObject(AbilityKey.fromString(calcX[0].substring(9))); val = o instanceof Player ? playerXProperty((Player) o, calcX[1], card, ability) : 0; } - else if (calcX[0].equals("TriggeredSpellAbility")) { - final SpellAbility root = sa.getRootAbility(); - SpellAbility sat = (SpellAbility) root.getTriggeringObject(AbilityKey.SpellAbility); - val = calculateAmount(sat.getHostCard(), calcX[1], sat); + else if (calcX[0].equals("TriggeredSpellAbility") || calcX[0].equals("TriggeredStackInstance") || calcX[0].equals("SpellTargeted")) { + final SpellAbility sat = getDefinedSpellAbilities(card, calcX[0], sa).get(0); + val = xCount(sat.getHostCard(), calcX[1], sat); } else if (calcX[0].startsWith("TriggerCount")) { // TriggerCount is similar to a regular Count, but just @@ -728,7 +730,7 @@ public class AbilityUtils { else if (calcX[0].startsWith("Discarded")) { final SpellAbility root = sa.getRootAbility(); list = root.getPaidList("Discarded"); - if ((null == list) && root.isTrigger()) { + if (null == list && root.isTrigger()) { list = root.getHostCard().getSpellPermanent().getPaidList("Discarded"); } } @@ -1847,7 +1849,7 @@ public class AbilityUtils { return doXMath(0, expr, c, ctb); } } - list = CardLists.getValidCards(list, k[1], sa.getActivatingPlayer(), c, sa); + list = CardLists.getValidCards(list, k[1], player, c, sa); return doXMath(list.size(), expr, c, ctb); } @@ -1871,7 +1873,7 @@ public class AbilityUtils { return doXMath(0, expr, c, ctb); } } - list = CardLists.getValidCards(list, k[1], sa.getActivatingPlayer(), c, sa); + list = CardLists.getValidCards(list, k[1], player, c, sa); return doXMath(list.size(), expr, c, ctb); } @@ -1899,14 +1901,14 @@ public class AbilityUtils { // fallback if ctb isn't a spellability if (sq[0].startsWith("LastStateBattlefield")) { final String[] k = l[0].split(" "); - CardCollection list = new CardCollection(game.getLastStateBattlefield()); + CardCollectionView list = game.getLastStateBattlefield(); list = CardLists.getValidCards(list, k[1], player, c, ctb); return doXMath(list.size(), expr, c, ctb); } if (sq[0].startsWith("LastStateGraveyard")) { final String[] k = l[0].split(" "); - CardCollection list = new CardCollection(game.getLastStateGraveyard()); + CardCollectionView list = game.getLastStateGraveyard(); list = CardLists.getValidCards(list, k[1], player, c, ctb); return doXMath(list.size(), expr, c, ctb); } @@ -2165,17 +2167,22 @@ public class AbilityUtils { // Count$CardManaCost if (sq[0].contains("CardManaCost")) { Card ce; - if (sq[0].contains("Equipped") && c.isEquipping()) { - ce = c.getEquipping(); - } - else if (sq[0].contains("Remembered")) { + if (sq[0].contains("Remembered")) { ce = (Card) c.getFirstRemembered(); } else { ce = c; } - return doXMath(ce == null ? 0 : ce.getCMC(), expr, c, ctb); + int cmc = ce == null ? 0 : ce.getCMC(); + + if (sq[0].contains("LKI") && ctb instanceof SpellAbility && ce != null && !ce.isInZone(ZoneType.Stack) && ce.getManaCost() != null) { + if (((SpellAbility) ctb).getXManaCostPaid() != null) { + cmc += ((SpellAbility) ctb).getXManaCostPaid() * ce.getManaCost().countX(); + } + } + + return doXMath(cmc, expr, c, ctb); } if (sq[0].startsWith("RememberedSize")) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java index c0fe67d0440..0c1f4a9bef5 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java @@ -122,8 +122,9 @@ public class CounterEffect extends SpellAbilityEffect { CardZoneTable table = new CardZoneTable(); for (final SpellAbility tgtSA : sas) { final Card tgtSACard = tgtSA.getHostCard(); - // should remember even that spell cannot be countered, e.g. Dovescape - // TODO use LKI in case the spell gets countered before (else X amounts would be missing) + // should remember even that spell cannot be countered + // currently all effects using this are targeted in case the spell gets countered before + // so don't need to worry about LKI (else X amounts would be missing) if (sa.hasParam("RememberCounteredCMC")) { sa.getHostCard().addRemembered(Integer.valueOf(tgtSACard.getCMC())); } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java index e0a45949555..58441905bce 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -45,6 +45,7 @@ import forge.game.zone.Zone; import forge.game.zone.ZoneType; import forge.util.CardTranslation; import forge.util.Expressions; +import forge.util.FileSection; import forge.util.Lang; import forge.util.TextUtil; @@ -89,41 +90,12 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone * @return a {@link java.util.HashMap} object. */ private static Map parseParams(final String abString, final Card hostCard) { - final Map mapParameters = Maps.newHashMap(); - if (!(abString.length() > 0)) { throw new RuntimeException("StaticEffectFactory : getAbility -- abString too short in " + hostCard.getName() + ": [" + abString + "]"); } - final String[] a = abString.split("\\|"); - - for (int aCnt = 0; aCnt < a.length; aCnt++) { - a[aCnt] = a[aCnt].trim(); - } - - if (!(a.length > 0)) { - throw new RuntimeException("StaticEffectFactory : getAbility -- a[] too short in " + hostCard.getName()); - } - - for (final String element : a) { - final String[] aa = element.split("\\$"); - - for (int aaCnt = 0; aaCnt < aa.length; aaCnt++) { - aa[aaCnt] = aa[aaCnt].trim(); - } - - if (aa.length != 2) { - final StringBuilder sb = new StringBuilder(); - sb.append("StaticEffectFactory Parsing Error: Split length of "); - sb.append(element).append(" in ").append(hostCard.getName()).append(" is not 2."); - throw new RuntimeException(sb.toString()); - } - - mapParameters.put(aa[0], aa[1]); - } - - return mapParameters; + return FileSection.parseToMap(abString, FileSection.DOLLAR_SIGN_KV_SEPARATOR); } /** diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCastOrCopy.java b/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCastOrCopy.java index b253d660fe3..7c2a7c85189 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCastOrCopy.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCastOrCopy.java @@ -313,8 +313,7 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger { AbilityKey.Player, AbilityKey.Activator, AbilityKey.CurrentStormCount, - AbilityKey.CurrentCastSpells, - AbilityKey.CastSACMC + AbilityKey.CurrentCastSpells ); } diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java index 45112a2b2cf..7d500de6c50 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -308,7 +308,6 @@ public class MagicStack /* extends MyObservable */ implements Iterable