From 723a607c9f6767bd7a070b5160e426cee5528a67 Mon Sep 17 00:00:00 2001 From: Agetian Date: Mon, 21 Sep 2015 16:34:53 +0000 Subject: [PATCH] - Added code support for cards dependent on the maximum total CMC of targets (e.g. March from the Tomb). Basic AI support also added (but can most likely be made smarter, feel free to improve). - Note that the relevant SA parameter has been renamed to "MaxTotalTargetCMC" (from "WithTotalCMC") to avoid confusion with the ChangeZone parameter "WithTotalCMC" that means "the total CMC of a single card". --- .../java/forge/ai/ability/ChangeZoneAi.java | 8 +++++ .../forge/game/ability/AbilityFactory.java | 5 ++++ .../main/java/forge/game/card/CardUtil.java | 18 ++++++++++++ .../game/spellability/TargetChoices.java | 8 +++++ .../game/spellability/TargetRestrictions.java | 29 +++++++++++++++++++ .../java/forge/player/TargetSelection.java | 1 + 6 files changed, 69 insertions(+) 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;