From e5df3b9cb306759b86fe21c7849030bf0d4b6e4f Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Fri, 21 May 2021 08:43:36 +0200 Subject: [PATCH] Fix workaround --- .../java/forge/ai/AiAttackController.java | 16 ++----- .../main/java/forge/ai/AiBlockController.java | 12 ----- .../src/main/java/forge/ai/AiController.java | 13 ++--- .../src/main/java/forge/ai/ComputerUtil.java | 4 +- .../java/forge/ai/ComputerUtilCombat.java | 47 +++---------------- .../java/forge/game/combat/CombatUtil.java | 18 ++----- 6 files changed, 22 insertions(+), 88 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/AiAttackController.java b/forge-ai/src/main/java/forge/ai/AiAttackController.java index 7014baef64e..9f78b5b3336 100644 --- a/forge-ai/src/main/java/forge/ai/AiAttackController.java +++ b/forge-ai/src/main/java/forge/ai/AiAttackController.java @@ -54,7 +54,6 @@ import forge.util.TextUtil; import forge.util.collect.FCollectionView; -//doesHumanAttackAndWin() uses the global variable AllZone.getComputerPlayer() /** *

* ComputerUtil_Attack2 class. @@ -412,12 +411,10 @@ public class AiAttackController { final Player opp = this.defendingOpponent; - // Increase the total number of blockers needed by 1 if Finest Hour in - // play + // Increase the total number of blockers needed by 1 if Finest Hour in play // (human will get an extra first attack with a creature that untaps) // In addition, if the computer guesses it needs no blockers, make sure - // that - // it won't be surprised by Exalted + // that it won't be surprised by Exalted final int humanExaltedBonus = opp.countExaltedBonus(); if (humanExaltedBonus > 0) { @@ -448,7 +445,6 @@ public class AiAttackController { return notNeededAsBlockers; } - // this uses a global variable, which isn't perfect public final boolean doesHumanAttackAndWin(final Player ai, final int nBlockingCreatures) { int totalAttack = 0; int totalPoison = 0; @@ -715,7 +711,7 @@ public class AiAttackController { int attackMax = restrict.getMax(); if (attackMax == -1) { // check with the local limitations vs. the chosen defender - attackMax = ComputerUtilCombat.getMaxAttackersFor(defender); + attackMax = restrict.getDefenderMax().get(defender) == null ? -1 : restrict.getDefenderMax().get(defender); } if (attackMax == 0) { @@ -775,7 +771,6 @@ public class AiAttackController { return; } - if (bAssault) { if (LOG_AI_ATTACKS) System.out.println("Assault"); @@ -849,7 +844,6 @@ public class AiAttackController { // no more creatures to attack return; } - // ******************* // Evaluate the creature forces @@ -1291,8 +1285,8 @@ public class AiAttackController { } if (numberOfPossibleBlockers > 2 - || (numberOfPossibleBlockers >= 1 && CombatUtil.canAttackerBeBlockedWithAmount(attacker, 1, combat)) - || (numberOfPossibleBlockers == 2 && CombatUtil.canAttackerBeBlockedWithAmount(attacker, 2, combat))) { + || (numberOfPossibleBlockers >= 1 && CombatUtil.canAttackerBeBlockedWithAmount(attacker, 1, this.defendingOpponent)) + || (numberOfPossibleBlockers == 2 && CombatUtil.canAttackerBeBlockedWithAmount(attacker, 2, this.defendingOpponent))) { canBeBlocked = true; } // decide if the creature should attack based on the prevailing strategy choice in aiAggression diff --git a/forge-ai/src/main/java/forge/ai/AiBlockController.java b/forge-ai/src/main/java/forge/ai/AiBlockController.java index 7abaff5aa4d..a6b16cb648d 100644 --- a/forge-ai/src/main/java/forge/ai/AiBlockController.java +++ b/forge-ai/src/main/java/forge/ai/AiBlockController.java @@ -180,11 +180,9 @@ public class AiBlockController { // Good Blocks means a good trade or no trade private void makeGoodBlocks(final Combat combat) { - List currentAttackers = new ArrayList<>(attackersLeft); for (final Card attacker : attackersLeft) { - if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT") || attacker.hasKeyword("CARDNAME can't be blocked unless all creatures defending player controls block it.") || attacker.hasKeyword(Keyword.MENACE)) { @@ -192,7 +190,6 @@ public class AiBlockController { } Card blocker = null; - final List blockers = getPossibleBlockers(combat, attacker, blockersLeft, true); final List safeBlockers = getSafeBlockers(combat, attacker, blockers); @@ -305,7 +302,6 @@ public class AiBlockController { } Card blocker = null; - final List blockers = getPossibleBlockers(combat, attacker, blockersLeft, true); for (Card b : blockers) { @@ -584,12 +580,10 @@ public class AiBlockController { * @param combat a {@link forge.game.combat.Combat} object. */ private void makeTradeBlocks(final Combat combat) { - List currentAttackers = new ArrayList<>(attackersLeft); List killingBlockers; for (final Card attacker : attackersLeft) { - if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT") || attacker.hasKeyword(Keyword.MENACE) || attacker.hasKeyword("CARDNAME can't be blocked unless all creatures defending player controls block it.")) { @@ -625,7 +619,6 @@ public class AiBlockController { // Chump Blocks (should only be made if life is in danger) private void makeChumpBlocks(final Combat combat) { - List currentAttackers = new ArrayList<>(attackersLeft); makeChumpBlocks(combat, currentAttackers); @@ -636,7 +629,6 @@ public class AiBlockController { } private void makeChumpBlocks(final Combat combat, List attackers) { - if (attackers.isEmpty() || !ComputerUtilCombat.lifeInDanger(ai, combat)) { return; } @@ -691,11 +683,9 @@ public class AiBlockController { // Block creatures with "can't be blocked except by two or more creatures" private void makeMultiChumpBlocks(final Combat combat) { - List currentAttackers = new ArrayList<>(attackersLeft); for (final Card attacker : currentAttackers) { - if (!attacker.hasStartOfKeyword("CantBeBlockedByAmount LT") && !attacker.hasKeyword(Keyword.MENACE) && !attacker.hasKeyword("CARDNAME can't be blocked unless all creatures defending player controls block it.")) { @@ -727,7 +717,6 @@ public class AiBlockController { /** Reinforce blockers blocking attackers with trample (should only be made if life is in danger) */ private void reinforceBlockersAgainstTrample(final Combat combat) { - List chumpBlockers; List tramplingAttackers = CardLists.getKeyword(attackers, Keyword.TRAMPLE); @@ -760,7 +749,6 @@ public class AiBlockController { /** Support blockers not destroying the attacker with more blockers to try to kill the attacker */ private void reinforceBlockersToKill(final Combat combat) { - List safeBlockers; List blockers; List targetAttackers = CardLists.filter(blockedButUnkilled, Predicates.not(rampagesOrNeedsManyToBlock)); diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index 786e0638a09..f439130a65d 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -613,8 +613,7 @@ public class AiController { SpellAbility currentSA = sa; sa.setActivatingPlayer(player); // check everything necessary - - + AiPlayDecision opinion = canPlayAndPayFor(currentSA); //PhaseHandler ph = game.getPhaseHandler(); // System.out.printf("Ai thinks '%s' of %s @ %s %s >>> \n", opinion, sa, Lang.getPossesive(ph.getPlayerTurn().getName()), ph.getPhase()); @@ -1726,10 +1725,8 @@ public class AiController { for (int i = 0; i < numToExile; i++) { Card chosen = null; for (final Card c : grave) { // Exile noncreatures first in - // case we can revive. Might - // wanna do some additional - // checking here for Flashback - // and the like. + // case we can revive. Might wanna do some additional + // checking here for Flashback and the like. if (!c.isCreature()) { chosen = c; break; @@ -1998,7 +1995,6 @@ public class AiController { return result; } - // this is where the computer cheats // changes AllZone.getComputerPlayer().getZone(Zone.Library) @@ -2278,8 +2274,7 @@ public class AiController { } } - // AI logic for choosing which replacement effect to apply - // happens here. + // AI logic for choosing which replacement effect to apply happens here. return Iterables.getFirst(list, null); } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index 4898f2cf777..99f2234841e 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -2432,8 +2432,7 @@ public class ComputerUtil { if (!source.canReceiveCounters(p1p1Type)) { return opponent ? "Feather" : "Quill"; } - // if source is not on the battlefield anymore, choose +1/+1 - // ones + // if source is not on the battlefield anymore, choose +1/+1 ones if (!game.getCardState(source).isInZone(ZoneType.Battlefield)) { return opponent ? "Feather" : "Quill"; } @@ -2850,7 +2849,6 @@ public class ComputerUtil { } public static boolean lifegainNegative(final Player player, final Card source, final int n) { - if (!player.canGainLife()) { return false; } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java index ef6277c173a..32c004785fd 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java @@ -334,7 +334,7 @@ public class ComputerUtilCombat { */ public static int resultingPoison(final Player ai, final Combat combat) { - // ai can't get poision counters, so the value can't change + // ai can't get poison counters, so the value can't change if (!ai.canReceiveCounters(CounterEnumType.POISON)) { return ai.getPoisonCounters(); } @@ -491,8 +491,7 @@ public class ComputerUtilCombat { } public static boolean lifeInSeriousDanger(final Player ai, final Combat combat, final int payment) { - // life in danger only cares about the player's life. Not about a - // Planeswalkers life + // life in danger only cares about the player's life. Not about a Planeswalkers life if (ai.cantLose() || combat == null) { return false; } @@ -567,8 +566,7 @@ public class ComputerUtilCombat { return damage; } - // This calculates the amount of damage a blocker in a blockgang can deal to - // the attacker + // This calculates the amount of damage a blocker in a blockgang can deal to the attacker /** *

* dealsDamageAsBlocker. @@ -581,7 +579,6 @@ public class ComputerUtilCombat { * @return a int. */ public static int dealsDamageAsBlocker(final Card attacker, final Card defender) { - int defenderDamage = predictDamageByBlockerWithoutDoubleStrike(attacker, defender); if (defender.hasKeyword(Keyword.DOUBLE_STRIKE)) { @@ -646,7 +643,6 @@ public class ComputerUtilCombat { * @return a int. */ public static int totalShieldDamage(final Card attacker, final List defenders) { - int defenderDefense = 0; for (final Card defender : defenders) { @@ -670,7 +666,6 @@ public class ComputerUtilCombat { * @return a int. */ public static int shieldDamage(final Card attacker, final Card blocker) { - if (ComputerUtilCombat.canDestroyBlockerBeforeFirstStrike(blocker, attacker, false)) { return 0; } @@ -931,8 +926,7 @@ public class ComputerUtilCombat { } final Game game = attacker.getGame(); - // look out for continuous static abilities that only care for blocking - // creatures + // look out for continuous static abilities that only care for blocking creatures final CardCollectionView cardList = CardCollection.combine(game.getCardsIn(ZoneType.Battlefield), game.getCardsIn(ZoneType.Command)); for (final Card card : cardList) { for (final StaticAbility stAb : card.getStaticAbilities()) { @@ -1232,8 +1226,7 @@ public class ComputerUtilCombat { theTriggers.addAll(blocker.getTriggers()); } - // look out for continuous static abilities that only care for attacking - // creatures + // look out for continuous static abilities that only care for attacking creatures if (!withoutCombatStaticAbilities) { final CardCollectionView cardList = CardCollection.combine(game.getCardsIn(ZoneType.Battlefield), game.getCardsIn(ZoneType.Command)); for (final Card card : cardList) { @@ -1420,8 +1413,7 @@ public class ComputerUtilCombat { theTriggers.addAll(blocker.getTriggers()); } - // look out for continuous static abilities that only care for attacking - // creatures + // look out for continuous static abilities that only care for attacking creatures if (!withoutCombatStaticAbilities) { final CardCollectionView cardList = game.getCardsIn(ZoneType.Battlefield); for (final Card card : cardList) { @@ -2256,7 +2248,6 @@ public class ComputerUtilCombat { */ public final static int predictDamageTo(final Player target, final int damage, final Card source, final boolean isCombat) { - final Game game = target.getGame(); int restDamage = damage; @@ -2317,13 +2308,7 @@ public class ComputerUtilCombat { // This function helps the AI calculate the actual amount of damage an // effect would deal public final static int predictDamageTo(final Card target, final int damage, final Card source, final boolean isCombat) { - - int restDamage = damage; - - restDamage = target.staticReplaceDamage(restDamage, source, isCombat); - restDamage = target.staticDamagePrevention(restDamage, 0, source, isCombat); - - return restDamage; + return predictDamageTo(target, damage, 0, source, isCombat); } @@ -2345,7 +2330,6 @@ public class ComputerUtilCombat { * @return a int. */ public final static int predictDamageTo(final Card target, final int damage, final int possiblePrevention, final Card source, final boolean isCombat) { - int restDamage = damage; restDamage = target.staticReplaceDamage(restDamage, source, isCombat); @@ -2355,7 +2339,6 @@ public class ComputerUtilCombat { } public final static boolean dealsFirstStrikeDamage(final Card combatant, final boolean withoutAbilities, final Combat combat) { - if (combatant.hasKeyword(Keyword.DOUBLE_STRIKE) || combatant.hasKeyword(Keyword.FIRST_STRIKE)) { return true; } @@ -2479,20 +2462,6 @@ public class ComputerUtilCombat { return afflictDmg > attacker.getNetPower() || afflictDmg >= aiDefender.getLife(); } - public static int getMaxAttackersFor(final GameEntity defender) { - if (defender instanceof Player) { - for (final Card card : ((Player) defender).getCardsIn(ZoneType.Battlefield)) { - if (card.hasKeyword("No more than one creature can attack you each combat.")) { - return 1; - } else if (card.hasKeyword("No more than two creatures can attack you each combat.")) { - return 2; - } - } - } - - return -1; - } - public static List categorizeAttackersByEvasion(List attackers) { List categorizedAttackers = Lists.newArrayList(); @@ -2582,5 +2551,3 @@ public class ComputerUtilCombat { return false; } } - - diff --git a/forge-game/src/main/java/forge/game/combat/CombatUtil.java b/forge-game/src/main/java/forge/game/combat/CombatUtil.java index b0d6a8694f9..898443abe87 100644 --- a/forge-game/src/main/java/forge/game/combat/CombatUtil.java +++ b/forge-game/src/main/java/forge/game/combat/CombatUtil.java @@ -1079,7 +1079,10 @@ public class CombatUtil { } // canBlock() public static boolean canAttackerBeBlockedWithAmount(Card attacker, int amount, Combat combat) { - if( amount == 0 ) + return canAttackerBeBlockedWithAmount(attacker, amount, combat != null ? combat.getDefenderPlayerByAttacker(attacker) : null); + } + public static boolean canAttackerBeBlockedWithAmount(Card attacker, int amount, Player defender) { + if(amount == 0 ) return false; // no block List restrictions = Lists.newArrayList(); @@ -1098,18 +1101,7 @@ public class CombatUtil { if (Expressions.compare(amount, operator, operand) ) return false; } - if (combat != null && attacker.hasKeyword("CARDNAME can't be blocked " + - "unless all creatures defending player controls block it.")) { - Player defender = combat.getDefenderPlayerByAttacker(attacker); - if (defender == null) { - // TODO: a better fix is needed here (to prevent a hard NPE, e.g. when the AI attacks with Tromokratis). - System.out.println("Warning: defender was 'null' in CombatUtil::canAttackerBeBlockedWithAmount for the card " + attacker + ", attempting to deduce defender."); - defender = combat.getDefendingPlayers().getFirst(); - if (defender == null) { - System.out.println("Warning: it was impossible to deduce the defending player in CombatUtil#canAttackerBeBlockedWithAmount, returning 'true' (safest default)."); - return true; - } - } + if (defender != null && attacker.hasKeyword("CARDNAME can't be blocked unless all creatures defending player controls block it.")) { return amount >= defender.getCreaturesInPlay().size(); }