Fix AI failing to pay Spree-like charm because it didn't see final cost (#5208)

Co-authored-by: tool4EvEr <tool4EvEr@192.168.0.60>
This commit is contained in:
tool4ever
2024-05-06 19:31:45 +02:00
committed by GitHub
parent 4532fab999
commit 96c517c49f
4 changed files with 12 additions and 7 deletions

View File

@@ -791,7 +791,7 @@ public class AiController {
}
int oldCMC = -1;
boolean xCost = sa.costHasX() || host.hasKeyword(Keyword.STRIVE);
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
@@ -820,7 +820,7 @@ public class AiController {
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;
xCost |= wardCost.getTotalMana().getCMC() > 0;
}
SpellAbilityAi topAI = new SpellAbilityAi() {};
if (!topAI.willPayCosts(player, sa, wardCost, host)) {

View File

@@ -966,8 +966,7 @@ public class PlayerControllerAi extends PlayerController {
* forge.game.player.PlayerController.BinaryChoiceType, java.util.Map)
*/
@Override
public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice,
Map<String, Object> params) {
public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, Map<String, Object> params) {
ApiType api = sa.getApi();
if (null == api) {
throw new InvalidParameterException("SA is not api-based, this is not supported yet");

View File

@@ -14,7 +14,6 @@ import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils;
import forge.game.ability.effects.CharmEffect;
import forge.game.card.Card;
import forge.game.keyword.Keyword;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
@@ -41,6 +40,7 @@ public class CharmAi extends SpellAbilityAi {
// Reset the chosen list otherwise it will be locked in forever by earlier calls
sa.setChosenList(null);
sa.setSubAbility(null);
List<AbilitySub> chosenList;
if (!ai.equals(sa.getActivatingPlayer())) {
@@ -51,7 +51,7 @@ public class CharmAi extends SpellAbilityAi {
chosenList = chooseTriskaidekaphobia(choices, ai);
} else {
// only randomize if not all possible together
if (num < choices.size() || source.hasKeyword(Keyword.ESCALATE)) {
if (num < choices.size()) {
Collections.shuffle(choices);
}
@@ -80,7 +80,13 @@ public class CharmAi extends SpellAbilityAi {
return false;
}
}
// store the choices so they'll get reused
sa.setChosenList(chosenList);
if (sa.isSpell()) {
// prebuild chain to improve cost calculation accuracy
CharmEffect.chainAbilities(sa, chosenList);
}
// prevent run-away activations - first time will always return true
return MyRandom.getRandom().nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn());

View File

@@ -249,7 +249,7 @@ public class CharmEffect extends SpellAbilityEffect {
return true;
}
private static void chainAbilities(SpellAbility sa, List<AbilitySub> chosen) {
public static void chainAbilities(SpellAbility sa, List<AbilitySub> chosen) {
if (chosen == null) {
return;
}