diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index 4fdc3a21197..ce0ed8fb8ba 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -12,6 +12,7 @@ import forge.card.ColorSet; import forge.card.MagicColor; import forge.card.mana.ManaAtom; import forge.card.mana.ManaCost; +import forge.card.mana.ManaCostParser; import forge.card.mana.ManaCostShard; import forge.game.Game; import forge.game.GameActionUtil; @@ -1295,6 +1296,34 @@ public class ComputerUtilMana { return 99; } + /** + *
+ * determineLeftoverMana. + *
+ * + * @param sa + * a {@link forge.game.spellability.SpellAbility} object. + * @param player + * a {@link forge.game.player.Player} object. + * @param shardColor + * a mana shard to specifically test for. + * @return a int. + * @since 1.0.15 + */ + public static int determineLeftoverMana(final SpellAbility sa, final Player player, final String shardColor) { + ManaCost origCost = sa.getPayCosts().getTotalMana(); + + String shardSurplus = shardColor; + for (int i = 1; i < 100; i++) { + ManaCost extra = new ManaCost(new ManaCostParser(shardSurplus)); + if (!canPayManaCost(new ManaCostBeingPaid(ManaCost.combine(origCost, extra)), sa, player)) { + return i - 1; + } + shardSurplus += " " + shardColor; + } + return 99; + } + // Returns basic mana abilities plus "reflected mana" abilities /** *
diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java
index 4a5e261629e..90dec2c7905 100644
--- a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java
@@ -23,8 +23,10 @@ import forge.game.spellability.TargetChoices;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class DamageDealAi extends DamageAiBase {
@Override
@@ -57,14 +59,14 @@ public class DamageDealAi extends DamageAiBase {
}
if (damage.equals("X")) {
if (sa.getSVar(damage).equals("Count$xPaid")) {
+ // Life Drain
+ if ("XLifeDrain".equals(logic)) {
+ return doXLifeDrainLogic(ai, sa);
+ }
+
// Set PayX here to maximum value.
dmg = ComputerUtilMana.determineLeftoverMana(sa, ai);
source.setSVar("PayX", Integer.toString(dmg));
-
- // Life Drain
- if ("XLifeDrain".equals(logic)) {
- return doXLifeDrainLogic(ai, sa, dmg);
- }
} else if (sa.getSVar(damage).equals("Count$CardsInYourHand") && source.getZone().is(ZoneType.Hand)) {
dmg--; // the card will be spent casting the spell, so actual damage is 1 less
}
@@ -702,7 +704,7 @@ public class DamageDealAi extends DamageAiBase {
return true;
}
- private boolean doXLifeDrainLogic(Player ai, SpellAbility sa, int origDmg) {
+ private boolean doXLifeDrainLogic(Player ai, SpellAbility sa) {
Card source = sa.getHostCard();
// detect the top ability that actually targets in Drain Life and Soul Burn scripts
@@ -711,10 +713,20 @@ public class DamageDealAi extends DamageAiBase {
saTgt = saTgt.getParent();
}
- // TODO: somehow account for the cost reduction?
- int dmg = origDmg - saTgt.getPayCosts().getTotalMana().getCMC(); // otherwise AI incorrectly calculates mana it can afford
Player opponent = ai.getOpponents().min(PlayerPredicates.compareByLife());
+ // TODO: somehow account for the possible cost reduction?
+ int xColorRemaining = ComputerUtilMana.determineLeftoverMana(sa, ai, saTgt.getParam("XColor"));
+ int dmg = xColorRemaining - saTgt.getPayCosts().getTotalMana().getCMC(); // otherwise AI incorrectly calculates mana it can afford
+
+ // set the color map for black X for the purpose of Soul Burn
+ // TODO: somehow generalize this calculation to allow other potential similar cards to function in the future
+ if ("Soul Burn".equals(source.getName())) {
+ Map