From 496ab01599dd76676817d060b7e9b8327f997e25 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Fri, 27 May 2022 10:26:43 +0200 Subject: [PATCH] Fix Tap trigger decisions --- .../main/java/forge/ai/ability/DrawAi.java | 2 +- .../main/java/forge/ai/ability/TapAiBase.java | 20 +++++++++---------- .../main/java/forge/ai/ability/UntapAi.java | 16 +++++++-------- .../ability/effects/ControlGainEffect.java | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java index 630c6f71c64..f9c18915ca6 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java @@ -102,7 +102,7 @@ public class DrawAi extends SpellAbilityAi { return false; } - if (!ComputerUtilCost.checkDiscardCost(ai, cost, source,sa)) { + if (!ComputerUtilCost.checkDiscardCost(ai, cost, source, sa)) { AiCostDecision aiDecisions = new AiCostDecision(ai, sa, false); for (final CostPart part : cost.getCostParts()) { if (part instanceof CostDiscard) { diff --git a/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java b/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java index 69fc263cb3a..940c667ecf6 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java +++ b/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java @@ -106,10 +106,8 @@ public abstract class TapAiBase extends SpellAbilityAi { * @return a boolean. */ protected boolean tapPrefTargeting(final Player ai, final Card source, final SpellAbility sa, final boolean mandatory) { - final Player opp = AiAttackController.choosePreferredDefenderPlayer(ai); final Game game = ai.getGame(); - CardCollection tapList = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents()); - tapList = CardLists.getTargetableCards(tapList, sa); + CardCollection tapList = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa); tapList = CardLists.filter(tapList, Presets.UNTAPPED); tapList = CardLists.filter(tapList, new Predicate() { @Override @@ -129,8 +127,7 @@ public abstract class TapAiBase extends SpellAbilityAi { //use broader approach when the cost is a positive thing if (tapList.isEmpty() && ComputerUtil.activateForCost(sa, ai)) { - tapList = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents()); - tapList = CardLists.getTargetableCards(tapList, sa); + tapList = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa); tapList = CardLists.filter(tapList, new Predicate() { @Override public boolean apply(final Card c) { @@ -150,8 +147,10 @@ public abstract class TapAiBase extends SpellAbilityAi { //try to exclude things that will already be tapped due to something on stack or because something is //already targeted in a parent or sub SA - CardCollection toExclude = ComputerUtilAbility.getCardsTargetedWithApi(ai, tapList, sa, ApiType.Tap); - tapList.removeAll(toExclude); + if (!sa.isTrigger() || mandatory) { // but if just confirming trigger no need to look for other targets and might still help anyway + CardCollection toExclude = ComputerUtilAbility.getCardsTargetedWithApi(ai, tapList, sa, ApiType.Tap); + tapList.removeAll(toExclude); + } if (tapList.isEmpty()) { return false; @@ -176,6 +175,7 @@ public abstract class TapAiBase extends SpellAbilityAi { } PhaseHandler phase = game.getPhaseHandler(); + final Player opp = AiAttackController.choosePreferredDefenderPlayer(ai); Card primeTarget = ComputerUtil.getKilledByTargeting(sa, tapList); if (primeTarget != null) { choice = primeTarget; @@ -193,7 +193,7 @@ public abstract class TapAiBase extends SpellAbilityAi { return CombatUtil.canAttack(c, opp); } }); - attackers.remove(sa.getHostCard()); + attackers.remove(source); } Predicate findBlockers = CardPredicates.possibleBlockerForAtLeastOne(attackers); List creatureList = CardLists.filter(tapList, findBlockers); @@ -202,7 +202,7 @@ public abstract class TapAiBase extends SpellAbilityAi { if (!attackers.isEmpty() && !creatureList.isEmpty()) { choice = ComputerUtilCard.getBestCreatureAI(creatureList); - } else if (sa.getRootAbility().isTrigger() || ComputerUtil.castSpellInMain1(ai, sa)) { + } else if (sa.isTrigger() || ComputerUtil.castSpellInMain1(ai, sa)) { choice = ComputerUtilCard.getMostExpensivePermanentAI(tapList); } } else if (phase.isPlayerTurn(opp) @@ -272,7 +272,7 @@ public abstract class TapAiBase extends SpellAbilityAi { return true; } - // filter by enchantments and planeswalkers, their tapped state doesn't matter. + // filter by enchantments and planeswalkers, their tapped state (usually) doesn't matter. final String[] tappablePermanents = { "Enchantment", "Planeswalker" }; tapList = CardLists.getValidCards(list, tappablePermanents, source.getController(), source, sa); diff --git a/forge-ai/src/main/java/forge/ai/ability/UntapAi.java b/forge-ai/src/main/java/forge/ai/ability/UntapAi.java index 2f27d060eab..894f4ae8394 100644 --- a/forge-ai/src/main/java/forge/ai/ability/UntapAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/UntapAi.java @@ -53,7 +53,7 @@ public class UntapAi extends SpellAbilityAi { return false; } - return ComputerUtilCost.checkDiscardCost(ai, cost, sa.getHostCard(), sa); + return ComputerUtilCost.checkDiscardCost(ai, cost, source, sa); } @Override @@ -174,8 +174,10 @@ public class UntapAi extends SpellAbilityAi { //try to exclude things that will already be untapped due to something on stack or because something is //already targeted in a parent or sub SA - CardCollection toExclude = ComputerUtilAbility.getCardsTargetedWithApi(ai, untapList, sa, ApiType.Untap); - untapList.removeAll(toExclude); + if (!sa.isTrigger() || mandatory) { // but if just confirming trigger no need to look for other targets and might still help anyway + CardCollection toExclude = ComputerUtilAbility.getCardsTargetedWithApi(ai, untapList, sa, ApiType.Untap); + untapList.removeAll(toExclude); + } sa.resetTargets(); while (sa.canAddMoreTarget()) { @@ -199,7 +201,7 @@ public class UntapAi extends SpellAbilityAi { if (choice == null) { if (CardLists.getNotType(untapList, "Creature").isEmpty()) { choice = ComputerUtilCard.getBestCreatureAI(untapList); // if only creatures take the best - } else if (!sa.getPayCosts().hasManaCost() || sa.getRootAbility().isTrigger() + } else if (!sa.getPayCosts().hasManaCost() || sa.isTrigger() || "Always".equals(sa.getParam("AILogic"))) { choice = ComputerUtilCard.getMostExpensivePermanentAI(untapList); } @@ -290,7 +292,7 @@ public class UntapAi extends SpellAbilityAi { choice = ComputerUtilCard.getBestAI(tapList); if (choice == null) { // can't find anything left - if (sa.getTargets().size() < tgt.getMinTargets(sa.getHostCard(), sa) || sa.getTargets().size() == 0) { + if (sa.getTargets().size() < tgt.getMinTargets(source, sa) || sa.getTargets().size() == 0) { if (!mandatory) { sa.resetTargets(); } @@ -310,9 +312,7 @@ public class UntapAi extends SpellAbilityAi { @Override public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable list, boolean isOptional, Player targetedPlayer, Map params) { - PlayerCollection pl = new PlayerCollection(); - pl.add(ai); - pl.addAll(ai.getAllies()); + PlayerCollection pl = ai.getYourTeam(); return ComputerUtilCard.getBestAI(CardLists.filterControlledBy(list, pl)); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java index 7c175cf83b4..28881ebb355 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java @@ -132,7 +132,7 @@ public class ControlGainEffect extends SpellAbilityEffect { tgtCards = getDefinedCards(sa); } - if (tgtCards !=null & sa.hasParam("ControlledByTarget")) { + if (tgtCards != null & sa.hasParam("ControlledByTarget")) { tgtCards = CardLists.filterControlledBy(tgtCards, getTargetPlayers(sa)); }