diff --git a/forge-ai/src/main/java/forge/ai/AiCostDecision.java b/forge-ai/src/main/java/forge/ai/AiCostDecision.java index cf6aad33959..fe715d5ab2f 100644 --- a/forge-ai/src/main/java/forge/ai/AiCostDecision.java +++ b/forge-ai/src/main/java/forge/ai/AiCostDecision.java @@ -514,14 +514,18 @@ public class AiCostDecision extends CostDecisionMakerBase { Integer c = cost.convertAmount(); if (c == null) { if (ability.getSVar(cost.getAmount()).equals("XChoice")) { - if ("SacToReduceCost".equals(ability.getParam("AILogic"))) { + String logic = ability.getParamOrDefault("AILogic", ""); + if ("SacToReduceCost".equals(logic)) { // e.g. Torgaar, Famine Incarnate // TODO: currently returns an empty list, so the AI doesn't sacrifice anything. Trying to make // the AI decide on creatures to sac makes the AI sacrifice them, but the cost is not reduced and the // AI pays the full mana cost anyway (despite sacrificing creatures). return PaymentDecision.card(new CardCollection()); - } else if ("AsChosen".equals(ability.getParam("AILogic"))) { - // Honor the ChosenX value set earlier by the AI ability processing code. + } else if (!logic.isEmpty() && !logic.equals("Never")) { + // If at least some other AI logic is specified, assume that the AI for that API knows how + // to define ChosenX and thus honor that value. + // Cards which have no special logic for this yet but which do work in a simple/suboptimal way + // are currently conventionally flagged with AILogic$ DoSacrifice. c = AbilityUtils.calculateAmount(source, source.getSVar("ChosenX"), null); } else { // Other cards are assumed to be flagged RemAIDeck for now diff --git a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java index 42244fbfd36..23bb526c041 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java @@ -26,10 +26,7 @@ import forge.game.card.Card; import forge.game.card.CardLists; import forge.game.card.CardPredicates; import forge.game.card.CounterType; -import forge.game.cost.Cost; -import forge.game.cost.CostDiscard; -import forge.game.cost.CostPart; -import forge.game.cost.PaymentDecision; +import forge.game.cost.*; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; @@ -252,22 +249,32 @@ public class DrawAi extends SpellAbilityAi { } if (num != null && num.equals("ChosenX")) { - // Necrologia, Pay X Life : Draw X Cards if (sa.getSVar("X").equals("XChoice")) { // Draw up to max hand size but leave at least 3 in library numCards = Math.min(computerMaxHandSize - computerHandSize, computerLibrarySize - 3); - // But no more than what's "safe" and doesn't risk a near death experience - // Maybe would be better to check for "serious danger" and take more risk? - while ((ComputerUtil.aiLifeInDanger(ai, false, numCards) && (numCards > 0))) { - numCards--; + + if (sa.getPayCosts() != null) { + if (sa.getPayCosts().hasSpecificCostType(CostPayLife.class)) { + // [Necrologia, Pay X Life : Draw X Cards] + // Don't draw more than what's "safe" and don't risk a near death experience + // Maybe would be better to check for "serious danger" and take more risk? + while ((ComputerUtil.aiLifeInDanger(ai, false, numCards) && (numCards > 0))) { + numCards--; + } + } else if (sa.getPayCosts().hasSpecificCostType(CostSacrifice.class)) { + // [e.g. Krav, the Unredeemed and other cases which say "Sacrifice X creatures: draw X cards] + // TODO: Add special logic to limit/otherwise modify the ChosenX value here + + // Skip this ability if nothing is to be chosen for sacrifice + if (numCards <= 0) { + return false; + } + } } + sa.setSVar("ChosenX", Integer.toString(numCards)); source.setSVar("ChosenX", Integer.toString(numCards)); - // If the logic is set to AsChosen, then skip the ability if nothing is to be chosen - if ("AsChosen".equals(sa.getParam("AILogic")) && numCards <= 0) { - return false; - } } } // Logic for cards that require special handling diff --git a/forge-gui/res/cardsfolder/upcoming/krav_the_unredeemed.txt b/forge-gui/res/cardsfolder/upcoming/krav_the_unredeemed.txt index 519bfd668b2..b3f82d1668e 100644 --- a/forge-gui/res/cardsfolder/upcoming/krav_the_unredeemed.txt +++ b/forge-gui/res/cardsfolder/upcoming/krav_the_unredeemed.txt @@ -3,7 +3,9 @@ ManaCost:4 B Types:Legendary Creature Demon PT:3/3 K:Partner:Regna, the Redeemer:Regna -A:AB$Draw | Cost$ B Sac | NumCards$ ChosenX | ValidTgts$ Player | TgtPrompt$ Choose a player | References$ X | SubAbility$ DBGainLife | AILogic$ AsChosen | SpellDescription$ Target player draws X cards and gains X life. Put X +1/+1 counters on CARDNAME. +# TODO: AILogic$ DoSacrifice is a placeholder which signals AiCostDecision that the API knows how to properly determine +# the number of creatures to sacrifice. Currently DrawAi doesn't handle it too optimally and this can be improved. +A:AB$Draw | Cost$ B Sac | NumCards$ ChosenX | ValidTgts$ Player | TgtPrompt$ Choose a player | References$ X | SubAbility$ DBGainLife | AILogic$ DoSacrifice | SpellDescription$ Target player draws X cards and gains X life. Put X +1/+1 counters on CARDNAME. SVar:DBGainLife:DB$GainLife | Defined$ Targeted | LifeAmount$ ChosenX | SubAbility$ DBPutCounter SVar:DBPutCounter:DB$PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ ChosenX SVar:X:XChoice