diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java index 08ea8b31b46..9ee28cc4a9a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java @@ -1021,6 +1021,14 @@ public class ChangeZoneAi extends SpellAbilityAi { } } + // if max CMC exceeded, stop choosing + if (sa.hasParam("MaxTotalTargetCMC")) { + if (choice.getCMC() > sa.getTargetRestrictions().getMaxTotalCMC(choice, sa) - sa.getTargets().getTotalTargetedCMC()) { + list.remove(choice); + continue; + } + } + list.remove(choice); sa.getTargets().add(choice); } diff --git a/forge-game/src/main/java/forge/game/ability/AbilityFactory.java b/forge-game/src/main/java/forge/game/ability/AbilityFactory.java index c0f221d1d58..d5cf47ada20 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityFactory.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityFactory.java @@ -230,6 +230,11 @@ public final class AbilityFactory { abTgt.setZone(ZoneType.listValueOf(mapParams.get("TgtZone"))); } + if (mapParams.containsKey("MaxTotalTargetCMC")) { + // only target cards up to a certain total max CMC + abTgt.setMaxTotalCMC(mapParams.get("MaxTotalTargetCMC")); + } + // TargetValidTargeting most for Counter: e.g. target spell that // targets X. if (mapParams.containsKey("TargetValidTargeting")) { diff --git a/forge-game/src/main/java/forge/game/card/CardUtil.java b/forge-game/src/main/java/forge/game/card/CardUtil.java index 7c9f40af04d..518bf7b1ce3 100644 --- a/forge-game/src/main/java/forge/game/card/CardUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardUtil.java @@ -464,6 +464,24 @@ public final class CardUtil { } } + // Remove cards exceeding total CMC + if (ability.hasParam("MaxTotalTargetCMC")) { + int totalCMCTargeted = 0; + for (final Card c : targeted) { + totalCMCTargeted += c.getCMC(); + } + + final List choicesCopy = Lists.newArrayList(choices); + for (final Card c : choicesCopy) { + if (c.getCMC() > tgt.getMaxTotalCMC(c, ability)) { + choices.remove(c); + } + if (c.getCMC() > tgt.getMaxTotalCMC(c, ability) - totalCMCTargeted) { + choices.remove(c); + } + } + } + // If all cards (including subability targets) must have the same controller if (tgt.isSameController() && !targetedObjects.isEmpty()) { final List list = new ArrayList(); diff --git a/forge-game/src/main/java/forge/game/spellability/TargetChoices.java b/forge-game/src/main/java/forge/game/spellability/TargetChoices.java index d47c06dc63e..1d40283adc2 100644 --- a/forge-game/src/main/java/forge/game/spellability/TargetChoices.java +++ b/forge-game/src/main/java/forge/game/spellability/TargetChoices.java @@ -48,6 +48,14 @@ public class TargetChoices implements Cloneable { return numTargeted; } + public final int getTotalTargetedCMC() { + int totalCMC = 0; + for (Card c : targetCards) { + totalCMC += c.getCMC(); + } + return totalCMC; + } + public final boolean add(final GameObject o) { if (o instanceof Player) { return addTarget((Player) o); diff --git a/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java b/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java index c2d94b48dff..ec1924cbb5b 100644 --- a/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java +++ b/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java @@ -70,6 +70,9 @@ public class TargetRestrictions { private String minTargets; private String maxTargets; + // What's the max CMC of targeted? + private String maxTotalCMC; + // For "Divided" cards. Is this better in TargetChoices? private boolean dividedAsYouChoose = false; private HashMap dividedMap = new HashMap(); @@ -93,6 +96,7 @@ public class TargetRestrictions { this.validTgts = this.originalValidTgts.clone(); this.minTargets = target.getMinTargets(); this.maxTargets = target.getMaxTargets(); + this.maxTotalCMC = target.getMaxTotalCMC(); this.tgtZone = target.getZone(); this.saValidTargeting = target.getSAValidTargeting(); this.dividedAsYouChoose = target.isDividedAsYouChoose(); @@ -153,6 +157,18 @@ public class TargetRestrictions { this.bMandatory = m; } + /** + *

+ * setMaxTotalCMC. + *

+ * + * @param cmc + * a String. + */ + public final void setMaxTotalCMC(final String cmc) { + this.maxTotalCMC = cmc; + } + /** *

* doesTarget. @@ -204,6 +220,19 @@ public class TargetRestrictions { return this.maxTargets; } + /** + * Gets the max targets. + * + * @return the max targets + */ + private final String getMaxTotalCMC() { + return this.maxTotalCMC; + } + + public final int getMaxTotalCMC(final Card c, final SpellAbility sa) { + return AbilityUtils.calculateAmount(c, this.maxTotalCMC, sa); + } + /** *

* Getter for the field minTargets. diff --git a/forge-gui/src/main/java/forge/player/TargetSelection.java b/forge-gui/src/main/java/forge/player/TargetSelection.java index e68e54136f5..01e4d9c9059 100644 --- a/forge-gui/src/main/java/forge/player/TargetSelection.java +++ b/forge-gui/src/main/java/forge/player/TargetSelection.java @@ -71,6 +71,7 @@ public class TargetSelection { // Number of targets is explicitly set only if spell is being redirected (ex. Swerve or Redirect) final int minTargets = numTargets != null ? numTargets.intValue() : tgt.getMinTargets(ability.getHostCard(), ability); final int maxTargets = numTargets != null ? numTargets.intValue() : tgt.getMaxTargets(ability.getHostCard(), ability); + final int maxTotalCMC = tgt.getMaxTotalCMC(ability.getHostCard(), ability); final int numTargeted = ability.getTargets().getNumTargeted(); final boolean hasEnoughTargets = minTargets == 0 || numTargeted >= minTargets;