diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index d9c5907f2a5..64abbaa520d 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -911,21 +911,8 @@ public class AiController { } } - int oldCMC = -1; - boolean xCost = sa.costHasX() || host.hasKeyword(Keyword.STRIVE) || sa.getApi() == ApiType.Charm; - if (!xCost) { - if (!ComputerUtilCost.canPayCost(sa, player, sa.isTrigger())) { - // for most costs, it's OK to check if they can be paid early in order to avoid running a heavy API check - // when the AI won't even be able to play the spell in the first place (even if it could afford it) - return AiPlayDecision.CantAfford; - } - // TODO check for Reduce too, e.g. Battlefield Thaumaturge could make it castable - if (!sa.getAllTargetChoices().isEmpty()) { - oldCMC = CostAdjustment.adjust(sa.getPayCosts(), sa, false).getTotalMana().getCMC(); - } - } - - AiPlayDecision canPlay = canPlaySa(sa); // this is the "heaviest" check, which also sets up targets, defines X, etc. + // this is the "heaviest" check, which also sets up targets, defines X, etc. + AiPlayDecision canPlay = canPlaySa(sa); if (canPlay != AiPlayDecision.WillPlay) { return canPlay; @@ -940,9 +927,6 @@ public class AiController { // TODO some older cards don't use the keyword, so check for trigger instead if (tgt.hasKeyword(Keyword.WARD) && tgt.isInPlay() && tgt.getController().isOpponentOf(host.getController())) { Cost wardCost = ComputerUtilCard.getTotalWardCost(tgt); - if (wardCost.hasManaCost()) { - xCost |= wardCost.getTotalMana().getCMC() > 0; - } SpellAbilityAi topAI = new SpellAbilityAi() {}; if (!topAI.willPayCosts(player, sa, wardCost, host)) { return AiPlayDecision.CostNotAcceptable; @@ -952,15 +936,7 @@ public class AiController { } } - // check if some target raised cost - if (!xCost && oldCMC > -1) { - int finalCMC = CostAdjustment.adjust(sa.getPayCosts(), sa, false).getTotalMana().getCMC(); - if (finalCMC > oldCMC) { - xCost = true; - } - } - - if (xCost && !ComputerUtilCost.canPayCost(sa, player, sa.isTrigger())) { + if (!ComputerUtilCost.canPayCost(sa, player, sa.isTrigger())) { // for dependent costs with X, e.g. Repeal, which require a valid target to be specified before a decision can be made // on whether the cost can be paid, this can only be checked late after canPlaySa has been run (or the AI will misplay) return AiPlayDecision.CantAfford; @@ -973,8 +949,6 @@ public class AiController { return AiPlayDecision.CantAfford; } - // if we got here, looks like we can play the final cost and we could properly set up and target the API and - // are willing to play the SA return AiPlayDecision.WillPlay; } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index acac8b4dada..3fdf95ef66c 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -666,6 +666,7 @@ public class ComputerUtilMana { return true; } + int phyLifeToPay = 2; boolean purePhyrexian = cost.containsOnlyPhyrexianMana(); boolean hasConverge = sa.getHostCard().hasConverge(); ListMultimap sourcesForShards = getSourcesForShards(cost, sa, ai, test, checkPlayable, hasConverge); @@ -693,13 +694,12 @@ public class ComputerUtilMana { } if (sourcesForShards == null && !purePhyrexian) { - break; // no mana abilities to use for paying + // no mana abilities to use for paying + break; } toPay = getNextShardToPay(cost, sourcesForShards); - boolean lifeInsteadOfBlack = toPay.isBlack() && ai.hasKeyword("PayLifeInsteadOf:B"); - Collection saList = null; if (hasConverge && (toPay == ManaCostShard.GENERIC || toPay == ManaCostShard.X)) { @@ -752,9 +752,14 @@ public class ComputerUtilMana { } if (saPayment == null) { - if ((!toPay.isPhyrexian() && !lifeInsteadOfBlack) || !ai.canPayLife(2, false, sa) - || (ai.getLife() <= 2 && !ai.cantLoseForZeroOrLessLife())) { - break; // cannot pay + boolean lifeInsteadOfBlack = toPay.isBlack() && ai.hasKeyword("PayLifeInsteadOf:B"); + if ((!toPay.isPhyrexian() && !lifeInsteadOfBlack) || !ai.canPayLife(phyLifeToPay, false, sa) + || (ai.getLife() <= phyLifeToPay && !ai.cantLoseForZeroOrLessLife())) { + // cannot pay + break; + } + if (test) { + phyLifeToPay += 2; } if (sa.hasParam("AIPhyrexianPayment")) { diff --git a/forge-game/src/main/java/forge/game/mana/ManaCostBeingPaid.java b/forge-game/src/main/java/forge/game/mana/ManaCostBeingPaid.java index 677b11f8709..130c288720f 100644 --- a/forge-game/src/main/java/forge/game/mana/ManaCostBeingPaid.java +++ b/forge-game/src/main/java/forge/game/mana/ManaCostBeingPaid.java @@ -551,10 +551,10 @@ public class ManaCostBeingPaid { // The generic portion of a 2/Colored mana, should be lower priority than generic mana return !ColorSet.fromMask(bill.getColorMask() & paymentColor).isColorless() ? 9 : 1; } - if (!bill.isPhyrexian()) { - return 10; + if (bill.isPhyrexian()) { + return 8; } - return 8; + return 10; } return 5; } diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java index 253c1d3992c..73926b484fe 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java @@ -47,11 +47,9 @@ public class InputPayManaOfCostPayment extends InputPayMana { if (manaCost.payPhyrexian()) { saPaidFor.setSpendPhyrexianMana(true); this.phyLifeToLose += 2; - } else { - if (player.hasKeyword("PayLifeInsteadOf:B") && manaCost.hasAnyKind(ManaAtom.BLACK)) { - manaCost.decreaseShard(ManaCostShard.BLACK, 1); - this.phyLifeToLose += 2; - } + } else if (player.hasKeyword("PayLifeInsteadOf:B") && manaCost.hasAnyKind(ManaAtom.BLACK)) { + manaCost.decreaseShard(ManaCostShard.BLACK, 1); + this.phyLifeToLose += 2; } }