- AI: Avoid infinitely activating AF Untap on another permanent that will then be used to untap the first one (e.g. 2x Kiora's Follower)

This commit is contained in:
Agetian
2017-08-08 04:44:05 +00:00
parent 431d5ef8a8
commit 4fb1c866da
2 changed files with 30 additions and 0 deletions

View File

@@ -13,6 +13,8 @@ import forge.game.card.CardCollection;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets; import forge.game.card.CardPredicates.Presets;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.cost.CostTap;
import forge.game.cost.CostTapType;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerCollection; import forge.game.player.PlayerCollection;
@@ -148,6 +150,25 @@ public class UntapAi extends SpellAbilityAi {
final String[] tappablePermanents = {"Creature", "Land", "Artifact"}; final String[] tappablePermanents = {"Creature", "Land", "Artifact"};
untapList = CardLists.getValidCards(untapList, tappablePermanents, source.getController(), source, sa); untapList = CardLists.getValidCards(untapList, tappablePermanents, source.getController(), source, sa);
// Try to avoid potential infinite recursion,
// e.g. Kiora's Follower untapping another Kiora's Follower and repeating infinitely
if (sa.getPayCosts() != null && sa.getPayCosts().hasOnlySpecificCostType(CostTap.class)) {
CardCollection toRemove = new CardCollection();
for (Card c : untapList) {
for (SpellAbility ab : c.getAllSpellAbilities()) {
if (ab.getApi() == ApiType.Untap
&& ab.getPayCosts() != null
&& ab.getPayCosts().hasOnlySpecificCostType(CostTap.class)
&& ab.canTarget(source)) {
System.out.println("Found a recursive untap target: " + c);
toRemove.add(c);
break;
}
}
}
untapList.removeAll(toRemove);
}
sa.resetTargets(); sa.resetTargets();
while (sa.getTargets().getNumTargeted() < tgt.getMaxTargets(sa.getHostCard(), sa)) { while (sa.getTargets().getNumTargeted() < tgt.getMaxTargets(sa.getHostCard(), sa)) {
Card choice = null; Card choice = null;

View File

@@ -73,6 +73,15 @@ public class Cost {
return false; return false;
} }
public final boolean hasOnlySpecificCostType(Class<? extends CostPart> costType) {
for (CostPart p : getCostParts()) {
if (!costType.isInstance(p)) {
return false;
}
}
return true;
}
/** /**
* Gets the cost parts. * Gets the cost parts.
* *