AbilityUtils: don't crash when CardTrait is null

This commit is contained in:
Hans Mackowiak
2021-03-18 13:37:05 +01:00
parent fc5557a137
commit 0d81961325
19 changed files with 57 additions and 133 deletions

View File

@@ -214,7 +214,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
return null; return null;
} }
else { else {
CardCollectionView chosen = ComputerUtil.chooseExileFrom(player, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c); CardCollectionView chosen = ComputerUtil.chooseExileFrom(player, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c, ability);
return null == chosen ? null : PaymentDecision.card(chosen); return null == chosen ? null : PaymentDecision.card(chosen);
} }
} }
@@ -421,7 +421,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
chosen = chosen.subList(0, c); chosen = chosen.subList(0, c);
} }
else { else {
chosen = ComputerUtil.choosePutToLibraryFrom(player, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c); chosen = ComputerUtil.choosePutToLibraryFrom(player, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c, ability);
} }
return chosen.isEmpty() ? null : PaymentDecision.card(chosen); return chosen.isEmpty() ? null : PaymentDecision.card(chosen);
} }
@@ -493,7 +493,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
type = TextUtil.fastReplace(type, "+withTotalPowerGE", ""); type = TextUtil.fastReplace(type, "+withTotalPowerGE", "");
totap = ComputerUtil.chooseTapTypeAccumulatePower(player, type, ability, !cost.canTapSource, Integer.parseInt(totalP), exclude); totap = ComputerUtil.chooseTapTypeAccumulatePower(player, type, ability, !cost.canTapSource, Integer.parseInt(totalP), exclude);
} else { } else {
totap = ComputerUtil.chooseTapType(player, type, source, !cost.canTapSource, c, exclude); totap = ComputerUtil.chooseTapType(player, type, source, !cost.canTapSource, c, exclude, ability);
} }
if (totap == null) { if (totap == null) {
@@ -536,7 +536,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability);
} }
CardCollectionView res = ComputerUtil.chooseReturnType(player, cost.getType(), source, ability.getTargetCard(), c); CardCollectionView res = ComputerUtil.chooseReturnType(player, cost.getType(), source, ability.getTargetCard(), c, ability);
return res.isEmpty() ? null : PaymentDecision.card(res); return res.isEmpty() ? null : PaymentDecision.card(res);
} }
@@ -854,7 +854,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }
CardCollectionView list = ComputerUtil.chooseUntapType(player, cost.getType(), source, cost.canUntapSource, c); CardCollectionView list = ComputerUtil.chooseUntapType(player, cost.getType(), source, cost.canUntapSource, c, ability);
if (list == null) { if (list == null) {
System.out.println("Couldn't find a valid card to untap for: " + source.getName()); System.out.println("Couldn't find a valid card to untap for: " + source.getName());

View File

@@ -539,7 +539,7 @@ public class ComputerUtil {
public static CardCollection chooseSacrificeType(final Player ai, final String type, final SpellAbility ability, final Card target, final int amount) { public static CardCollection chooseSacrificeType(final Player ai, final String type, final SpellAbility ability, final Card target, final int amount) {
final Card source = ability.getHostCard(); final Card source = ability.getHostCard();
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, null); CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, ability);
typeList = CardLists.filter(typeList, CardPredicates.canBeSacrificedBy(ability)); typeList = CardLists.filter(typeList, CardPredicates.canBeSacrificedBy(ability));
@@ -570,8 +570,8 @@ public class ComputerUtil {
} }
public static CardCollection chooseExileFrom(final Player ai, final ZoneType zone, final String type, final Card activate, public static CardCollection chooseExileFrom(final Player ai, final ZoneType zone, final String type, final Card activate,
final Card target, final int amount) { final Card target, final int amount, SpellAbility sa) {
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, null); CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, sa);
if ((target != null) && target.getController() == ai) { if ((target != null) && target.getController() == ai) {
typeList.remove(target); // don't exile the card we're pumping typeList.remove(target); // don't exile the card we're pumping
@@ -591,8 +591,8 @@ public class ComputerUtil {
} }
public static CardCollection choosePutToLibraryFrom(final Player ai, final ZoneType zone, final String type, final Card activate, public static CardCollection choosePutToLibraryFrom(final Player ai, final ZoneType zone, final String type, final Card activate,
final Card target, final int amount) { final Card target, final int amount, SpellAbility sa) {
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, null); CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, sa);
if ((target != null) && target.getController() == ai) { if ((target != null) && target.getController() == ai) {
typeList.remove(target); // don't move the card we're pumping typeList.remove(target); // don't move the card we're pumping
@@ -615,14 +615,11 @@ public class ComputerUtil {
return list; return list;
} }
public static CardCollection chooseTapType(final Player ai, final String type, final Card activate, final boolean tap, final int amount) { public static CardCollection chooseTapType(final Player ai, final String type, final Card activate, final boolean tap, final int amount, final CardCollectionView exclude, SpellAbility sa) {
return chooseTapType(ai, type, activate, tap, amount, CardCollection.EMPTY);
}
public static CardCollection chooseTapType(final Player ai, final String type, final Card activate, final boolean tap, final int amount, final CardCollectionView exclude) {
CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield)); CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield));
all.removeAll(exclude); all.removeAll(exclude);
CardCollection typeList = CardCollection typeList =
CardLists.getValidCards(all, type.split(";"), activate.getController(), activate, null); CardLists.getValidCards(all, type.split(";"), activate.getController(), activate, sa);
// is this needed? // is this needed?
typeList = CardLists.filter(typeList, Presets.UNTAPPED); typeList = CardLists.filter(typeList, Presets.UNTAPPED);
@@ -695,9 +692,9 @@ public class ComputerUtil {
return tapList; return tapList;
} }
public static CardCollection chooseUntapType(final Player ai, final String type, final Card activate, final boolean untap, final int amount) { public static CardCollection chooseUntapType(final Player ai, final String type, final Card activate, final boolean untap, final int amount, SpellAbility sa) {
CardCollection typeList = CardCollection typeList =
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, null); CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa);
// is this needed? // is this needed?
typeList = CardLists.filter(typeList, Presets.TAPPED); typeList = CardLists.filter(typeList, Presets.TAPPED);
@@ -720,9 +717,9 @@ public class ComputerUtil {
return untapList; return untapList;
} }
public static CardCollection chooseReturnType(final Player ai, final String type, final Card activate, final Card target, final int amount) { public static CardCollection chooseReturnType(final Player ai, final String type, final Card activate, final Card target, final int amount, SpellAbility sa) {
final CardCollection typeList = final CardCollection typeList =
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, null); CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa);
if ((target != null) && target.getController() == ai) { if ((target != null) && target.getController() == ai) {
// don't bounce the card we're pumping // don't bounce the card we're pumping
typeList.remove(target); typeList.remove(target);
@@ -970,7 +967,7 @@ public class ComputerUtil {
} }
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
if (tgt != null) { if (tgt != null) {
if (CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), controller, sa.getHostCard(), null).contains(card)) { if (CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), controller, sa.getHostCard(), sa).contains(card)) {
prevented += AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("Amount"), sa); prevented += AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("Amount"), sa);
} }
@@ -1586,9 +1583,8 @@ public class ComputerUtil {
if (threatApi == null) { if (threatApi == null) {
return threatened; return threatened;
} }
final TargetRestrictions tgt = topStack.getTargetRestrictions();
if (tgt == null) { if (!topStack.usesTargeting()) {
if (topStack.hasParam("Defined")) { if (topStack.hasParam("Defined")) {
objects = AbilityUtils.getDefinedObjects(source, topStack.getParam("Defined"), topStack); objects = AbilityUtils.getDefinedObjects(source, topStack.getParam("Defined"), topStack);
} else if (topStack.hasParam("ValidCards")) { } else if (topStack.hasParam("ValidCards")) {
@@ -1685,7 +1681,7 @@ public class ComputerUtil {
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) { if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) {
boolean canSave = ComputerUtilCombat.predictDamageTo(c, dmg - toughness, source, false) < ComputerUtilCombat.getDamageToKill(c); boolean canSave = ComputerUtilCombat.predictDamageTo(c, dmg - toughness, source, false) < ComputerUtilCombat.getDamageToKill(c);
if ((tgt == null && !grantIndestructible && !canSave) if ((!topStack.usesTargeting() && !grantIndestructible && !canSave)
|| (!grantIndestructible && !grantShroud && !canSave)) { || (!grantIndestructible && !grantShroud && !canSave)) {
continue; continue;
} }
@@ -1745,7 +1741,7 @@ public class ComputerUtil {
final boolean cantSave = c.getNetToughness() + toughness <= dmg final boolean cantSave = c.getNetToughness() + toughness <= dmg
|| (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && c.getShieldCount() == 0 && !grantIndestructible || (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && c.getShieldCount() == 0 && !grantIndestructible
&& (dmg >= toughness + ComputerUtilCombat.getDamageToKill(c))); && (dmg >= toughness + ComputerUtilCombat.getDamageToKill(c)));
if (cantSave && (tgt == null || !grantShroud)) { if (cantSave && (!topStack.usesTargeting() || !grantShroud)) {
continue; continue;
} }
} }
@@ -1758,7 +1754,7 @@ public class ComputerUtil {
} }
if (saviourApi == ApiType.Protection) { if (saviourApi == ApiType.Protection) {
if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) { if (!topStack.usesTargeting() || (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue; continue;
} }
} }
@@ -1795,13 +1791,13 @@ public class ComputerUtil {
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll
|| saviorWithSubsApi == ApiType.Pump || saviorWithSubsApi == ApiType.Pump
|| saviorWithSubsApi == ApiType.PumpAll) { || saviorWithSubsApi == ApiType.PumpAll) {
if ((tgt == null && !grantIndestructible) if ((!topStack.usesTargeting() && !grantIndestructible)
|| (!grantShroud && !grantIndestructible)) { || (!grantShroud && !grantIndestructible)) {
continue; continue;
} }
} }
if (saviourApi == ApiType.Protection) { if (saviourApi == ApiType.Protection) {
if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) { if (!topStack.usesTargeting() || (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue; continue;
} }
} }
@@ -1830,11 +1826,11 @@ public class ComputerUtil {
if (o instanceof Card) { if (o instanceof Card) {
final Card c = (Card) o; final Card c = (Card) o;
// give Shroud to targeted creatures // give Shroud to targeted creatures
if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) && (tgt == null || !grantShroud)) { if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) && (!topStack.usesTargeting() || !grantShroud)) {
continue; continue;
} }
if (saviourApi == ApiType.Protection) { if (saviourApi == ApiType.Protection) {
if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) { if (!topStack.usesTargeting() || (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue; continue;
} }
} }
@@ -1858,11 +1854,11 @@ public class ComputerUtil {
if (o instanceof Card) { if (o instanceof Card) {
final Card c = (Card) o; final Card c = (Card) o;
// give Shroud to targeted creatures // give Shroud to targeted creatures
if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll && tgt == null) && !grantShroud) { if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll && !topStack.usesTargeting()) && !grantShroud) {
continue; continue;
} }
if (saviourApi == ApiType.Protection) { if (saviourApi == ApiType.Protection) {
if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) { if (!topStack.usesTargeting() || (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue; continue;
} }
} }
@@ -1879,11 +1875,11 @@ public class ComputerUtil {
if (o instanceof Card) { if (o instanceof Card) {
final Card c = (Card) o; final Card c = (Card) o;
// give Shroud to targeted creatures // give Shroud to targeted creatures
if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll && tgt == null) && !grantShroud) { if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll && !topStack.usesTargeting()) && !grantShroud) {
continue; continue;
} }
if (saviourApi == ApiType.Protection) { if (saviourApi == ApiType.Protection) {
if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) { if (!topStack.usesTargeting() || (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue; continue;
} }
} }

View File

@@ -1913,7 +1913,7 @@ public class ComputerUtilCard {
CardCollectionView list = game.getCardsIn(ZoneType.Battlefield); CardCollectionView list = game.getCardsIn(ZoneType.Battlefield);
list = CardLists.getValidCards(list, needsToPlay.split(","), card.getController(), card, null); list = CardLists.getValidCards(list, needsToPlay.split(","), card.getController(), card, sa);
if (list.isEmpty()) { if (list.isEmpty()) {
return AiPlayDecision.MissingNeededCards; return AiPlayDecision.MissingNeededCards;
} }

View File

@@ -137,7 +137,7 @@ public class ComputerUtilCost {
* the source * the source
* @return true, if successful * @return true, if successful
*/ */
public static boolean checkDiscardCost(final Player ai, final Cost cost, final Card source) { public static boolean checkDiscardCost(final Player ai, final Cost cost, final Card source, SpellAbility sa) {
if (cost == null) { if (cost == null) {
return true; return true;
} }
@@ -152,7 +152,7 @@ public class ComputerUtilCost {
if (type.equals("CARDNAME") && source.getAbilityText().contains("Bloodrush")) { if (type.equals("CARDNAME") && source.getAbilityText().contains("Bloodrush")) {
continue; continue;
} }
final CardCollection typeList = CardLists.getValidCards(hand, type.split(","), source.getController(), source, null); final CardCollection typeList = CardLists.getValidCards(hand, type.split(","), source.getController(), source, sa);
if (typeList.size() > ai.getMaxHandSize()) { if (typeList.size() > ai.getMaxHandSize()) {
continue; continue;
} }
@@ -270,7 +270,7 @@ public class ComputerUtilCost {
} }
final CardCollection sacList = new CardCollection(); final CardCollection sacList = new CardCollection();
final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, null); final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, sourceAbility);
int count = 0; int count = 0;
while (count < amount) { while (count < amount) {
@@ -320,7 +320,7 @@ public class ComputerUtilCost {
} }
final CardCollection sacList = new CardCollection(); final CardCollection sacList = new CardCollection();
final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, null); final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, sourceAbility);
int count = 0; int count = 0;
while (count < amount) { while (count < amount) {
@@ -641,7 +641,7 @@ public class ComputerUtilCost {
return checkLifeCost(payer, cost, source, 4, sa) return checkLifeCost(payer, cost, source, 4, sa)
&& checkDamageCost(payer, cost, source, 4) && checkDamageCost(payer, cost, source, 4)
&& (isMine || checkSacrificeCost(payer, cost, source, sa)) && (isMine || checkSacrificeCost(payer, cost, source, sa))
&& (isMine || checkDiscardCost(payer, cost, source)) && (isMine || checkDiscardCost(payer, cost, source, sa))
&& (!source.getName().equals("Tyrannize") || payer.getCardsIn(ZoneType.Hand).size() > 2) && (!source.getName().equals("Tyrannize") || payer.getCardsIn(ZoneType.Hand).size() > 2)
&& (!source.getName().equals("Perplex") || payer.getCardsIn(ZoneType.Hand).size() < 2) && (!source.getName().equals("Perplex") || payer.getCardsIn(ZoneType.Hand).size() < 2)
&& (!source.getName().equals("Breaking Point") || payer.getCreaturesInPlay().size() > 1) && (!source.getName().equals("Breaking Point") || payer.getCreaturesInPlay().size() > 1)
@@ -722,7 +722,7 @@ public class ComputerUtilCost {
continue; continue;
} }
final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), part.getType().split(";"), source.getController(), source, null); final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), part.getType().split(";"), source.getController(), source, sa);
int count = 0; int count = 0;
while (count < val) { while (count < val) {

View File

@@ -127,7 +127,7 @@ public abstract class SpellAbilityAi {
if (!ComputerUtilCost.checkLifeCost(ai, cost, source, 4, sa)) { if (!ComputerUtilCost.checkLifeCost(ai, cost, source, 4, sa)) {
return false; return false;
} }
if (!ComputerUtilCost.checkDiscardCost(ai, cost, source)) { if (!ComputerUtilCost.checkDiscardCost(ai, cost, source, sa)) {
return false; return false;
} }
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, source, sa)) { if (!ComputerUtilCost.checkSacrificeCost(ai, cost, source, sa)) {

View File

@@ -288,7 +288,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
return false; return false;
} }
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) { if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source, sa)) {
for (final CostPart part : abCost.getCostParts()) { for (final CostPart part : abCost.getCostParts()) {
if (part instanceof CostDiscard) { if (part instanceof CostDiscard) {
CostDiscard cd = (CostDiscard) part; CostDiscard cd = (CostDiscard) part;

View File

@@ -51,7 +51,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
return false; return false;
} }
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) { if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source, sa)) {
boolean aiLogicAllowsDiscard = sa.hasParam("AILogic") && sa.getParam("AILogic").startsWith("DiscardAll"); boolean aiLogicAllowsDiscard = sa.hasParam("AILogic") && sa.getParam("AILogic").startsWith("DiscardAll");
if (!aiLogicAllowsDiscard) { if (!aiLogicAllowsDiscard) {

View File

@@ -10,7 +10,6 @@ import com.google.common.collect.Lists;
import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat; import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.Game; import forge.game.Game;
import forge.game.GameObject; import forge.game.GameObject;
@@ -47,20 +46,7 @@ public class ChooseSourceAi extends SpellAbilityAi {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs if (!willPayCosts(ai, sa, abCost, source)) {
if (!ComputerUtilCost.checkLifeCost(ai, abCost, source, 4, sa)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) {
return false;
}
if (!ComputerUtilCost.checkSacrificeCost(ai, abCost, source, sa)) {
return false;
}
if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source, sa)) {
return false; return false;
} }
} }

View File

@@ -52,7 +52,7 @@ public class CountersPutAllAi extends SpellAbilityAi {
return false; return false;
} }
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) { if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source, sa)) {
return false; return false;
} }

View File

@@ -245,7 +245,7 @@ public class DamageDealAi extends DamageAiBase {
return false; return false;
} }
if ("DiscardLands".equals(sa.getParam("AILogic")) && !ComputerUtilCost.checkDiscardCost(ai, abCost, source)) { if ("DiscardLands".equals(sa.getParam("AILogic")) && !ComputerUtilCost.checkDiscardCost(ai, abCost, source, sa)) {
return false; return false;
} }

View File

@@ -6,7 +6,6 @@ import java.util.List;
import forge.ai.ComputerUtil; import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat; import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.Game; import forge.game.Game;
import forge.game.GameObject; import forge.game.GameObject;
@@ -37,20 +36,7 @@ public class DamagePreventAi extends SpellAbilityAi {
final Cost cost = sa.getPayCosts(); final Cost cost = sa.getPayCosts();
// temporarily disabled until better AI if (!willPayCosts(ai, sa, cost, hostCard)) {
if (!ComputerUtilCost.checkLifeCost(ai, cost, hostCard, 4, sa)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, cost, hostCard)) {
return false;
}
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, hostCard, sa)) {
return false;
}
if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard, sa)) {
return false; return false;
} }

View File

@@ -1,7 +1,5 @@
package forge.ai.ability; package forge.ai.ability;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.cost.Cost; import forge.game.cost.Cost;
@@ -22,19 +20,7 @@ public class DamagePreventAllAi extends SpellAbilityAi {
final Cost cost = sa.getPayCosts(); final Cost cost = sa.getPayCosts();
// temporarily disabled until better AI // temporarily disabled until better AI
if (!ComputerUtilCost.checkLifeCost(ai, cost, hostCard, 4, sa)) { if (!willPayCosts(ai, sa, cost, hostCard)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, cost, hostCard)) {
return false;
}
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, hostCard, sa)) {
return false;
}
if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard, sa)) {
return false; return false;
} }

View File

@@ -32,26 +32,11 @@ public class DiscardAi extends SpellAbilityAi {
final Cost abCost = sa.getPayCosts(); final Cost abCost = sa.getPayCosts();
final String aiLogic = sa.getParamOrDefault("AILogic", ""); final String aiLogic = sa.getParamOrDefault("AILogic", "");
if (abCost != null) { // temporarily disabled until better AI
// AI currently disabled for these costs if (!willPayCosts(ai, sa, abCost, source)) {
if (!ComputerUtilCost.checkSacrificeCost(ai, abCost, source, sa)) {
return false; return false;
} }
if (!ComputerUtilCost.checkLifeCost(ai, abCost, source, 4, sa)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) {
return false;
}
if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source, sa)) {
return false;
}
}
if ("Chandra, Flamecaller".equals(sourceName)) { if ("Chandra, Flamecaller".equals(sourceName)) {
final int hand = ai.getCardsIn(ZoneType.Hand).size(); final int hand = ai.getCardsIn(ZoneType.Hand).size();
return MyRandom.getRandom().nextFloat() < (1.0 / (1 + hand)); return MyRandom.getRandom().nextFloat() < (1.0 / (1 + hand));

View File

@@ -100,7 +100,7 @@ public class DrawAi extends SpellAbilityAi {
return false; return false;
} }
if (!ComputerUtilCost.checkDiscardCost(ai, cost, source)) { if (!ComputerUtilCost.checkDiscardCost(ai, cost, source,sa)) {
AiCostDecision aiDecisions = new AiCostDecision(ai, sa); AiCostDecision aiDecisions = new AiCostDecision(ai, sa);
for (final CostPart part : cost.getCostParts()) { for (final CostPart part : cost.getCostParts()) {
if (part instanceof CostDiscard) { if (part instanceof CostDiscard) {

View File

@@ -43,14 +43,14 @@ public class LifeGainAi extends SpellAbilityAi {
if (!lifeCritical) { if (!lifeCritical) {
// return super.willPayCosts(ai, sa, cost, source); // return super.willPayCosts(ai, sa, cost, source);
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, source, sa,false)) { if (!ComputerUtilCost.checkSacrificeCost(ai, cost, source, sa, false)) {
return false; return false;
} }
if (!ComputerUtilCost.checkLifeCost(ai, cost, source, 4, sa)) { if (!ComputerUtilCost.checkLifeCost(ai, cost, source, 4, sa)) {
return false; return false;
} }
if (!ComputerUtilCost.checkDiscardCost(ai, cost, source)) { if (!ComputerUtilCost.checkDiscardCost(ai, cost, source, sa)) {
return false; return false;
} }

View File

@@ -1,7 +1,5 @@
package forge.ai.ability; package forge.ai.ability;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.cost.Cost; import forge.game.cost.Cost;
@@ -21,19 +19,7 @@ public class ProtectAllAi extends SpellAbilityAi {
final Cost cost = sa.getPayCosts(); final Cost cost = sa.getPayCosts();
// temporarily disabled until better AI // temporarily disabled until better AI
if (!ComputerUtilCost.checkLifeCost(ai, cost, hostCard, 4, sa)) { if (!willPayCosts(ai, sa, cost, hostCard)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, cost, hostCard)) {
return false;
}
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, hostCard, sa)) {
return false;
}
if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard, sa)) {
return false; return false;
} }

View File

@@ -48,11 +48,10 @@ public class TapAi extends TapAiBase {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
final Cost abCost = sa.getPayCosts(); final Cost abCost = sa.getPayCosts();
if (abCost != null) {
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) { if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source, sa)) {
return false; return false;
} }
}
if (!sa.usesTargeting()) { if (!sa.usesTargeting()) {
boolean bFlag = false; boolean bFlag = false;

View File

@@ -52,7 +52,7 @@ public class UntapAi extends SpellAbilityAi {
return false; return false;
} }
return ComputerUtilCost.checkDiscardCost(ai, cost, sa.getHostCard()); return ComputerUtilCost.checkDiscardCost(ai, cost, sa.getHostCard(), sa);
} }
@Override @Override

View File

@@ -1606,7 +1606,7 @@ public class AbilityUtils {
final String s2 = AbilityUtils.applyAbilityTextChangeEffects(s, ctb); final String s2 = AbilityUtils.applyAbilityTextChangeEffects(s, ctb);
final String[] l = s2.split("/"); final String[] l = s2.split("/");
final String expr = CardFactoryUtil.extractOperators(s2); final String expr = CardFactoryUtil.extractOperators(s2);
final Player player = ctb instanceof SpellAbility ? ((SpellAbility)ctb).getActivatingPlayer() : ctb.getHostCard().getController(); final Player player = ctb == null ? null : ctb instanceof SpellAbility ? ((SpellAbility)ctb).getActivatingPlayer() : ctb.getHostCard().getController();
final String[] sq; final String[] sq;
sq = l[0].split("\\."); sq = l[0].split("\\.");