Fix Stack Overflow (#2228)

* Fix cards

* Fix Stack Overflow

* Performance fix

Co-authored-by: tool4EvEr <tool4EvEr@192.168.0.59>
Co-authored-by: TRT <>
This commit is contained in:
tool4ever
2023-01-11 12:06:12 +01:00
committed by GitHub
parent 11a893e64a
commit 876668c370
9 changed files with 53 additions and 41 deletions

View File

@@ -33,6 +33,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import forge.ai.AiCardMemory.MemorySet;
import forge.ai.ability.ChooseGenericEffectAi;
import forge.ai.ability.ProtectAi;
import forge.ai.ability.TokenAi;
@@ -449,14 +450,27 @@ public class ComputerUtil {
}
// try everything when about to die
if (game.getPhaseHandler().getPhase().equals(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& ComputerUtilCombat.lifeInSeriousDanger(ai, game.getCombat())) {
final CardCollection nonCreatures = CardLists.getNotType(typeList, "Creature");
if (!nonCreatures.isEmpty()) {
return ComputerUtilCard.getWorstAI(nonCreatures);
} else if (!typeList.isEmpty()) {
// TODO make sure survival is possible in case the creature blocks a trampler
return ComputerUtilCard.getWorstAI(typeList);
if (game.getPhaseHandler().getPhase().equals(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
// in some rare situations the call to lifeInDanger could lead us back here, this will prevent an overflow
boolean preventReturn = sa != null && sa.isManaAbility();
if (preventReturn) {
AiCardMemory.rememberCard(ai, sa.getHostCard(), MemorySet.HELD_MANA_SOURCES_FOR_NEXT_SPELL);
}
boolean danger = ComputerUtilCombat.lifeInSeriousDanger(ai, game.getCombat());
if (preventReturn) {
AiCardMemory.forgetCard(ai, sa.getHostCard(), MemorySet.HELD_MANA_SOURCES_FOR_NEXT_SPELL);
}
if (danger) {
final CardCollection nonCreatures = CardLists.getNotType(typeList, "Creature");
if (!nonCreatures.isEmpty()) {
return ComputerUtilCard.getWorstAI(nonCreatures);
} else if (!typeList.isEmpty()) {
// TODO make sure survival is possible in case the creature blocks a trampler
return ComputerUtilCard.getWorstAI(typeList);
}
}
}
}
@@ -609,7 +623,7 @@ public class ComputerUtil {
int count = 0;
while (count < amount) {
Card prefCard = getCardPreference(ai, source, "SacCost", typeList);
Card prefCard = getCardPreference(ai, source, "SacCost", typeList, ability);
if (prefCard == null) {
prefCard = ComputerUtilCard.getWorstAI(typeList);
}

View File

@@ -328,10 +328,10 @@ public class ComputerUtilCombat {
if (blockers.size() == 0
|| StaticAbilityAssignCombatDamageAsUnblocked.assignCombatDamageAsUnblocked(attacker)) {
unblocked.add(attacker);
} else if (attacker.hasKeyword(Keyword.TRAMPLE)
&& getAttack(attacker) > totalShieldDamage(attacker, blockers)) {
if (!attacker.hasKeyword(Keyword.INFECT)) {
damage += getAttack(attacker) - totalShieldDamage(attacker, blockers);
} else if (attacker.hasKeyword(Keyword.TRAMPLE) && !attacker.hasKeyword(Keyword.INFECT)) {
int dmgAfterShielding = getAttack(attacker) - totalShieldDamage(attacker, blockers);
if (dmgAfterShielding > 0) {
damage += dmgAfterShielding;
}
}
}
@@ -369,13 +369,14 @@ public class ComputerUtilCombat {
if (blockers.size() == 0
|| StaticAbilityAssignCombatDamageAsUnblocked.assignCombatDamageAsUnblocked(attacker)) {
unblocked.add(attacker);
} else if (attacker.hasKeyword(Keyword.TRAMPLE)
&& getAttack(attacker) > totalShieldDamage(attacker, blockers)) {
} else if (attacker.hasKeyword(Keyword.TRAMPLE)) {
int trampleDamage = getAttack(attacker) - totalShieldDamage(attacker, blockers);
if (attacker.hasKeyword(Keyword.INFECT)) {
poison += trampleDamage;
if (trampleDamage > 0) {
if (attacker.hasKeyword(Keyword.INFECT)) {
poison += trampleDamage;
}
poison += predictPoisonFromTriggers(attacker, ai, trampleDamage);
}
poison += predictPoisonFromTriggers(attacker, ai, trampleDamage);
}
}
@@ -686,7 +687,7 @@ public class ComputerUtilCombat {
final int defenderDefense = blocker.getLethalDamage() - flankingMagnitude + defBushidoMagnitude;
return defenderDefense;
} // shieldDamage
}
// For AI safety measures like Regeneration
/**

View File

@@ -234,7 +234,7 @@ public class ComputerUtilCost {
return true;
}
public static boolean checkForManaSacrificeCost(final Player ai, final Cost cost, final Card source, final SpellAbility sourceAbility, final boolean effect) {
public static boolean checkForManaSacrificeCost(final Player ai, final Cost cost, final SpellAbility sourceAbility, final boolean effect) {
// TODO cheating via autopay can still happen, need to get the real ai player from controlledBy
if (cost == null || !ai.isAI()) {
return true;
@@ -247,18 +247,17 @@ public class ComputerUtilCost {
exclude.addAll(AiCardMemory.getMemorySet(ai, MemorySet.PAYS_SAC_COST));
}
if (part.payCostFromSource()) {
list.add(source);
list.add(sourceAbility.getHostCard());
} else if (part.getType().equals("OriginalHost")) {
list.add(sourceAbility.getOriginalHost());
} else if (part.getAmount().equals("All")) {
// Does the AI want to use Sacrifice All?
return false;
} else {
final String amount = part.getAmount();
Integer c = part.convertAmount();
if (c == null) {
c = AbilityUtils.calculateAmount(source, amount, sourceAbility);
c = part.getAbilityAmount(sourceAbility);
}
final AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
CardCollectionView choices = aic.chooseSacrificeType(part.getType(), sourceAbility, effect, c, exclude);
@@ -636,7 +635,7 @@ public class ComputerUtilCost {
return ComputerUtilMana.canPayManaCost(sa, player, extraManaNeeded, effect)
&& CostPayment.canPayAdditionalCosts(sa.getPayCosts(), sa);
} // canPayCost()
}
public static boolean willPayUnlessCost(SpellAbility sa, Player payer, Cost cost, boolean alreadyPaid, FCollectionView<Player> payers) {
final Card source = sa.getHostCard();

View File

@@ -316,10 +316,6 @@ public class ComputerUtilMana {
continue;
}
if (!ComputerUtilCost.checkForManaSacrificeCost(ai, ma.getPayCosts(), ma.getHostCard(), ma, ma.isTrigger())) {
continue;
}
if (sa.getApi() == ApiType.Animate) {
// For abilities like Genju of the Cedars, make sure that we're not activating the aura ability by tapping the enchanted card for mana
if (saHost.isAura() && "Enchanted".equals(sa.getParam("Defined"))
@@ -381,9 +377,15 @@ public class ComputerUtilMana {
continue;
}
if (canPayShardWithSpellAbility(toPay, ai, paymentChoice, sa, checkCosts, cost.getXManaCostPaidByColor())) {
return paymentChoice;
if (!canPayShardWithSpellAbility(toPay, ai, paymentChoice, sa, checkCosts, cost.getXManaCostPaidByColor())) {
continue;
}
if (!ComputerUtilCost.checkForManaSacrificeCost(ai, ma.getPayCosts(), ma, ma.isTrigger())) {
continue;
}
return paymentChoice;
}
return null;
}