diff --git a/forge-ai/src/main/java/forge/ai/AiAttackController.java b/forge-ai/src/main/java/forge/ai/AiAttackController.java index de0d1bc489d..95b72d502d5 100644 --- a/forge-ai/src/main/java/forge/ai/AiAttackController.java +++ b/forge-ai/src/main/java/forge/ai/AiAttackController.java @@ -544,7 +544,13 @@ public class AiAttackController { return; } + boolean playAggro = false; + if (ai.getController().isAI()) { + playAggro = ((PlayerControllerAi) ai.getController()).getAi().getProperty(AiProps.PLAY_AGGRO).equals("true"); + } final boolean bAssault = this.doAssault(ai); + final boolean lightmineField = ComputerUtilCard.isPresentOnBattlefield(ai.getGame(), "Lightmine Field"); + // Determine who will be attacked GameEntity defender = this.chooseDefender(combat, bAssault); List attackersLeft = new ArrayList(this.attackers); @@ -590,6 +596,38 @@ public class AiAttackController { if (attackersLeft.isEmpty()) { return; } + + // Lightmine Field: make sure the AI doesn't wipe out its own creatures + if (lightmineField) { + CardCollection attSorted = new CardCollection(attackersLeft); + CardCollection attUnsafe = new CardCollection(); + CardLists.sortByToughnessDesc(attSorted); + + int i = 0; + int refPowerValue = 0; // Aggro profiles do not account for the possible blockers' power, conservative profiles do. + + if (!playAggro && this.blockers.size() > 0) { + // Conservative play: check to ensure that the card can't be killed off while damaged + // TODO: currently sorting a copy of this.blockers, but it looks safe to operate on this.blockers directly? + // Also, this should ideally somehow account for double blocks, unblockability, etc. Difficult to do without + // running simulations. + CardCollection blkSorted = new CardCollection(this.blockers); + CardLists.sortByPowerDesc(blkSorted); + refPowerValue = blkSorted.get(0).getCurrentPower(); + } + + for (Card cre : attSorted) { + i++; + if (i + refPowerValue >= cre.getCurrentToughness()) { + attUnsafe.add(cre); + } else { + continue; + } + } + + attackersLeft.removeAll(attUnsafe); + } + if (bAssault) { if (LOG_AI_ATTACKS) System.out.println("Assault"); @@ -824,15 +862,11 @@ public class AiAttackController { // end see how long until unblockable attackers will be fatal // ***************** + // decide on attack aggression based on a comparison of forces, life // totals and other considerations // some bad "magic numbers" here, TODO replace with nice descriptive // variable names - boolean playAggro = false; - if (ai.getController().isAI()) { - playAggro = ((PlayerControllerAi) ai.getController()).getAi().getProperty(AiProps.PLAY_AGGRO).equals("true"); - } - if (ratioDiff > 0 && doAttritionalAttack) { this.aiAggression = 5; // attack at all costs } else if ((ratioDiff >= 1 && this.attackers.size() > 1 && (humanLifeToDamageRatio < 2 || outNumber > 0)) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index a705e81babe..4182811bf11 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -1584,4 +1584,7 @@ public class ComputerUtilCard { return false; } + public static boolean isPresentOnBattlefield(final Game game, final String cardName) { + return !CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals(cardName)).isEmpty(); + } } diff --git a/forge-game/src/main/java/forge/game/card/CardLists.java b/forge-game/src/main/java/forge/game/card/CardLists.java index 134bb8864f3..9e6c9470bb7 100644 --- a/forge-game/src/main/java/forge/game/card/CardLists.java +++ b/forge-game/src/main/java/forge/game/card/CardLists.java @@ -73,6 +73,12 @@ public class CardLists { return a.getNetToughness() - b.getNetToughness(); } }; + public static final Comparator ToughnessComparatorInv = new Comparator() { + @Override + public int compare(final Card a, final Card b) { + return b.getNetToughness() - a.getNetToughness(); + } + }; public static final Comparator PowerComparator = new Comparator() { @Override public int compare(final Card a, final Card b) { @@ -104,18 +110,29 @@ public class CardLists { */ public static void sortByCmcDesc(final List list) { Collections.sort(list, CmcComparatorInv); - } // sortCMC + } // sortByCmcDesc /** *

- * sortAttackLowFirst. + * sortByToughnessAsc *

* * @param list */ public static void sortByToughnessAsc(final List list) { Collections.sort(list, ToughnessComparator); - } // sortAttackLowFirst() + } // sortByToughnessAsc() + + /** + *

+ * sortByToughnessDesc + *

+ * + * @param list + */ + public static void sortByToughnessDesc(final List list) { + Collections.sort(list, ToughnessComparatorInv); + } // sortByToughnessDesc() /** *