diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java index 04210b7d832..b49e6c5fb81 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java @@ -9,6 +9,7 @@ import forge.game.GameObject; import forge.game.ability.AbilityUtils; import forge.game.card.*; import forge.game.cost.Cost; +import forge.game.cost.CostRemoveCounter; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; @@ -357,17 +358,54 @@ public class DamageDealAi extends DamageAiBase { // Filter AI-specific targets if provided killables = ComputerUtil.filterAITgts(sa, ai, new CardCollection(killables), true); + // We can kill a planeswalker, so go for it if (pl.isOpponentOf(ai) && activator.equals(ai) && !killables.isEmpty()) { return ComputerUtilCard.getBestPlaneswalkerAI(killables); } + // We can hurt a planeswalker, so rank the one which is the best target if (!hPlay.isEmpty() && pl.isOpponentOf(ai) && activator.equals(ai)) { - return ComputerUtilCard.getBestPlaneswalkerAI(hPlay); + return getBestPlaneswalkerToDamage(hPlay); } return null; } + private Card getBestPlaneswalkerToDamage(final List pws) { + Card bestTgt = null; + + // As of right now, ranks planeswalkers by their Current Loyalty * 10 + Big buff if close to "Ultimate" + int bestScore = 0; + for (Card pw : pws) { + int curLoyalty = pw.getCounters(CounterType.LOYALTY); + int pwScore = curLoyalty * 10; + + for (SpellAbility sa : pw.getSpellAbilities()) { + if (sa.hasParam("Ultimate") && sa.getPayCosts() != null) { + int loyaltyCost = 0; + CostRemoveCounter remLoyalty = sa.getPayCosts().getCostPartByType(CostRemoveCounter.class); + if (remLoyalty != null) { + // if remLoyalty is null, generally there's an AddCounter<0/LOYALTY> cost, like for Gideon Jura. + loyaltyCost = remLoyalty.convertAmount(); + } + + if (loyaltyCost != 0 && loyaltyCost - curLoyalty <= 1) { + // Will ultimate soon + pwScore += 10000; + } + + if (pwScore > bestScore) { + bestScore = pwScore; + bestTgt = pw; + } + } + } + } + + return bestTgt; + } + + private List getTargetableCards(Player ai, SpellAbility sa, Player pl, TargetRestrictions tgt, Player activator, Card source, Game game) { List hPlay = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), activator, source, sa); diff --git a/forge-game/src/main/java/forge/game/cost/Cost.java b/forge-game/src/main/java/forge/game/cost/Cost.java index a6b3fc3a2a0..de26dd2f988 100644 --- a/forge-game/src/main/java/forge/game/cost/Cost.java +++ b/forge-game/src/main/java/forge/game/cost/Cost.java @@ -94,6 +94,15 @@ public class Cost implements Serializable { return true; } + public T getCostPartByType(Class costType) { + for (CostPart p : getCostParts()) { + if (costType.isInstance(p)) { + return (T)p; + } + } + return null; + } + /** * Gets the cost parts. *