Some fixes (#8816)

This commit is contained in:
tool4ever
2025-10-01 16:54:46 +02:00
committed by GitHub
parent c0fe93ee30
commit 31f8da5687
11 changed files with 43 additions and 77 deletions

View File

@@ -887,27 +887,8 @@ public class AiController {
private AiPlayDecision canPlayAndPayForFace(final SpellAbility sa) {
final Card host = sa.getHostCard();
// Check a predefined condition
if (sa.hasParam("AICheckSVar")) {
final String svarToCheck = sa.getParam("AICheckSVar");
String comparator = "GE";
int compareTo = 1;
if (sa.hasParam("AISVarCompare")) {
final String fullCmp = sa.getParam("AISVarCompare");
comparator = fullCmp.substring(0, 2);
final String strCmpTo = fullCmp.substring(2);
try {
compareTo = Integer.parseInt(strCmpTo);
} catch (final Exception ignored) {
compareTo = AbilityUtils.calculateAmount(host, host.getSVar(strCmpTo), sa);
}
}
int left = AbilityUtils.calculateAmount(host, svarToCheck, sa);
if (!Expressions.compare(left, comparator, compareTo)) {
return AiPlayDecision.AnotherTime;
}
if (sa.hasParam("AICheckSVar") && !aiShouldRun(sa, sa, host, null)) {
return AiPlayDecision.AnotherTime;
}
// this is the "heaviest" check, which also sets up targets, defines X, etc.
@@ -1817,14 +1798,9 @@ public class AiController {
* @param sa the sa
* @return true, if successful
*/
public final boolean aiShouldRun(final ReplacementEffect effect, final SpellAbility sa, GameEntity affected) {
Card hostCard = effect.getHostCard();
if (hostCard.hasAlternateState()) {
hostCard = game.getCardState(hostCard);
}
public final boolean aiShouldRun(final CardTraitBase effect, final SpellAbility sa, final Card host, final GameEntity affected) {
if (effect.hasParam("AILogic") && effect.getParam("AILogic").equalsIgnoreCase("ProtectFriendly")) {
final Player controller = hostCard.getController();
final Player controller = host.getController();
if (affected instanceof Player) {
return !((Player) affected).isOpponentOf(controller);
}
@@ -1833,7 +1809,6 @@ public class AiController {
}
}
if (effect.hasParam("AICheckSVar")) {
System.out.println("aiShouldRun?" + sa);
final String svarToCheck = effect.getParam("AICheckSVar");
String comparator = "GE";
int compareTo = 1;
@@ -1846,9 +1821,9 @@ public class AiController {
compareTo = Integer.parseInt(strCmpTo);
} catch (final Exception ignored) {
if (sa == null) {
compareTo = AbilityUtils.calculateAmount(hostCard, hostCard.getSVar(strCmpTo), effect);
compareTo = AbilityUtils.calculateAmount(host, host.getSVar(strCmpTo), effect);
} else {
compareTo = AbilityUtils.calculateAmount(hostCard, hostCard.getSVar(strCmpTo), sa);
compareTo = AbilityUtils.calculateAmount(host, host.getSVar(strCmpTo), sa);
}
}
}
@@ -1856,13 +1831,12 @@ public class AiController {
int left = 0;
if (sa == null) {
left = AbilityUtils.calculateAmount(hostCard, svarToCheck, effect);
left = AbilityUtils.calculateAmount(host, svarToCheck, effect);
} else {
left = AbilityUtils.calculateAmount(hostCard, svarToCheck, sa);
left = AbilityUtils.calculateAmount(host, svarToCheck, sa);
}
System.out.println("aiShouldRun?" + left + comparator + compareTo);
return Expressions.compare(left, comparator, compareTo);
} else if (effect.hasParam("AICheckDredge")) {
} else if (effect.isKeyword(Keyword.DREDGE)) {
return player.getCardsIn(ZoneType.Library).size() > 8 || player.isCardInPlay("Laboratory Maniac");
} else return sa != null && doTrigger(sa, false);
}

View File

@@ -460,7 +460,11 @@ public class PlayerControllerAi extends PlayerController {
@Override
public boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, GameEntity affected, String question) {
return brains.aiShouldRun(replacementEffect, effectSA, affected);
Card host = replacementEffect.getHostCard();
if (host.hasAlternateState()) {
host = host.getGame().getCardState(host);
}
return brains.aiShouldRun(replacementEffect, effectSA, host, affected);
}
@Override

View File

@@ -96,6 +96,10 @@ public class CloneAi extends SpellAbilityAi {
if (sa.usesTargeting()) {
chance = cloneTgtAI(sa);
} else {
if (sa.isReplacementAbility() && host.isCloned()) {
// prevent StackOverflow from infinite loop copying another ETB RE
return new AiAbilityDecision(0, AiPlayDecision.StopRunawayActivations);
}
if (sa.hasParam("Choices")) {
CardCollectionView choices = CardLists.getValidCards(host.getGame().getCardsIn(ZoneType.Battlefield),
sa.getParam("Choices"), host.getController(), host, sa);

View File

@@ -92,9 +92,8 @@ public class CountersPutAi extends CountersAi {
return false;
}
return chance > MyRandom.getRandom().nextFloat();
} else {
return false;
}
return false;
}
if (sa.isKeyword(Keyword.LEVEL_UP)) {
@@ -124,7 +123,6 @@ public class CountersPutAi extends CountersAi {
final Cost abCost = sa.getPayCosts();
final Card source = sa.getHostCard();
final String sourceName = ComputerUtilAbility.getAbilitySourceName(sa);
CardCollection list;
Card choice = null;
final String amountStr = sa.getParamOrDefault("CounterNum", "1");
final boolean divided = sa.isDividedAsYouChoose();
@@ -292,10 +290,8 @@ public class CountersPutAi extends CountersAi {
if (willActivate) {
return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
} else {
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
}
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
} else if (logic.equals("ChargeToBestCMC")) {
return doChargeToCMCLogic(ai, sa);
} else if (logic.equals("ChargeToBestOppControlledCMC")) {
@@ -348,7 +344,7 @@ public class CountersPutAi extends CountersAi {
if (type.equals("P1P1")) {
nPump = amount;
}
return FightAi.canFightAi(ai, sa, nPump, nPump);
return FightAi.canFight(ai, sa, nPump, nPump);
}
if (amountStr.equals("X")) {
@@ -451,6 +447,7 @@ public class CountersPutAi extends CountersAi {
sa.resetTargets();
CardCollection list;
if (sa.isCurse()) {
list = ai.getOpponents().getCardsIn(ZoneType.Battlefield);
} else {
@@ -746,7 +743,7 @@ public class CountersPutAi extends CountersAi {
protected AiAbilityDecision doTriggerNoCost(Player ai, SpellAbility sa, boolean mandatory) {
final SpellAbility root = sa.getRootAbility();
final Card source = sa.getHostCard();
final String aiLogic = sa.getParamOrDefault("AILogic", "");
final String aiLogic = sa.getParam("AILogic");
final String amountStr = sa.getParamOrDefault("CounterNum", "1");
final boolean divided = sa.isDividedAsYouChoose();
final int amount = AbilityUtils.calculateAmount(source, amountStr, sa);
@@ -765,14 +762,10 @@ public class CountersPutAi extends CountersAi {
}
if ("ChargeToBestCMC".equals(aiLogic)) {
AiAbilityDecision decision = doChargeToCMCLogic(ai, sa);
if (decision.willingToPlay()) {
return decision;
}
if (mandatory) {
return new AiAbilityDecision(50, AiPlayDecision.MandatoryPlay);
}
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
return doChargeToCMCLogic(ai, sa);
}
if (!sa.usesTargeting()) {
@@ -796,7 +789,6 @@ public class CountersPutAi extends CountersAi {
// things like Powder Keg, which are way too complex for the AI
}
} else if (sa.getTargetRestrictions().canOnlyTgtOpponent() && !sa.getTargetRestrictions().canTgtCreature()) {
// can only target opponent
PlayerCollection playerList = new PlayerCollection(IterableUtil.filter(
sa.getTargetRestrictions().getAllCandidates(sa, true, true), Player.class));
@@ -811,13 +803,12 @@ public class CountersPutAi extends CountersAi {
sa.getTargets().add(choice);
}
} else {
String logic = sa.getParam("AILogic");
if ("Fight".equals(logic) || "PowerDmg".equals(logic)) {
if ("Fight".equals(aiLogic) || "PowerDmg".equals(aiLogic)) {
int nPump = 0;
if (type.equals("P1P1")) {
nPump = amount;
}
AiAbilityDecision decision = FightAi.canFightAi(ai, sa, nPump, nPump);
AiAbilityDecision decision = FightAi.canFight(ai, sa, nPump, nPump);
if (decision.willingToPlay()) {
return decision;
}
@@ -838,7 +829,6 @@ public class CountersPutAi extends CountersAi {
while (sa.canAddMoreTarget()) {
if (mandatory) {
// When things are mandatory, gotta handle a little differently
if ((list.isEmpty() || !preferred) && sa.isTargetNumberValid()) {
return new AiAbilityDecision(0, AiPlayDecision.TargetingFailed);
}
@@ -863,7 +853,7 @@ public class CountersPutAi extends CountersAi {
return new AiAbilityDecision(sa.isTargetNumberValid() ? 100 : 0, sa.isTargetNumberValid() ? AiPlayDecision.WillPlay : AiPlayDecision.CantPlayAi);
}
Card choice = null;
Card choice;
// Choose targets here:
if (sa.isCurse()) {
@@ -889,10 +879,10 @@ public class CountersPutAi extends CountersAi {
choice = Aggregates.random(list);
}
if (choice != null && divided) {
int alloc = Math.max(amount / totalTargets, 1);
if (sa.getTargets().size() == Math.min(totalTargets, sa.getMaxTargets()) - 1) {
sa.addDividedAllocation(choice, left);
} else {
int alloc = Math.max(amount / totalTargets, 1);
sa.addDividedAllocation(choice, alloc);
left -= alloc;
}
@@ -982,9 +972,7 @@ public class CountersPutAi extends CountersAi {
final String amountStr = sa.getParamOrDefault("CounterNum", "1");
final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), amountStr, sa);
final boolean isCurse = sa.isCurse();
if (isCurse) {
if (sa.isCurse()) {
final CardCollection opponents = CardLists.filterControlledBy(options, ai.getOpponents());
if (!opponents.isEmpty()) {
@@ -1210,9 +1198,8 @@ public class CountersPutAi extends CountersAi {
}
if (numCtrs < optimalCMC) {
return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
} else {
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
}
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
}
private AiAbilityDecision doChargeToOppCtrlCMCLogic(Player ai, SpellAbility sa) {

View File

@@ -270,7 +270,7 @@ public class EffectAi extends SpellAbilityAi {
}
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
} else if (logic.equals("Fight")) {
return FightAi.canFightAi(ai, sa, 0,0);
return FightAi.canFight(ai, sa, 0,0);
} else if (logic.equals("Pump")) {
sa.resetTargets();
List<Card> options = CardUtil.getValidCardsToTarget(sa);

View File

@@ -177,7 +177,7 @@ public class FightAi extends SpellAbilityAi {
* @param power bonus to power
* @return true if fight effect should be played, false otherwise
*/
public static AiAbilityDecision canFightAi(final Player ai, final SpellAbility sa, int power, int toughness) {
public static AiAbilityDecision canFight(final Player ai, final SpellAbility sa, int power, int toughness) {
final Card source = sa.getHostCard();
final String sourceName = ComputerUtilAbility.getAbilitySourceName(sa);
AbilitySub tgtFight = sa.getSubAbility();

View File

@@ -453,7 +453,7 @@ public class PumpAi extends PumpAiBase {
}
if (isFight) {
return FightAi.canFightAi(ai, sa, attack, defense).willingToPlay();
return FightAi.canFight(ai, sa, attack, defense).willingToPlay();
}
}