From 82ce5daf05c3b814c4adf0dd511f83ae78db489f Mon Sep 17 00:00:00 2001 From: TRT <> Date: Fri, 26 Nov 2021 16:52:00 +0100 Subject: [PATCH 1/2] CharmEffect: fix choosing illegal mode --- .../main/java/forge/ai/ability/CharmAi.java | 19 +++++++++++++++++++ .../java/forge/ai/ability/GameLossAi.java | 7 +++---- .../game/ability/effects/CharmEffect.java | 17 +++++++++-------- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/CharmAi.java b/forge-ai/src/main/java/forge/ai/ability/CharmAi.java index 36fee21c07d..c71bb90204a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CharmAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CharmAi.java @@ -251,4 +251,23 @@ public class CharmAi extends SpellAbilityAi { public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable opponents, Map params) { return Aggregates.random(opponents); } + + @Override + protected boolean doTriggerAINoCost(final Player aiPlayer, final SpellAbility sa, final boolean mandatory) { + // already done by chooseOrderOfSimultaneousStackEntry + if (sa.getChosenList() != null) { + return true; + } + return super.doTriggerAINoCost(aiPlayer, sa, mandatory); + } + + @Override + public boolean chkDrawbackWithSubs(Player aiPlayer, AbilitySub ab) { + // choices were already targeted + if (ab.getRootAbility().getChosenList() != null) { + return true; + } + return super.chkDrawbackWithSubs(aiPlayer, ab); + } + } diff --git a/forge-ai/src/main/java/forge/ai/ability/GameLossAi.java b/forge-ai/src/main/java/forge/ai/ability/GameLossAi.java index 762db5c2189..7dafdfe4b64 100644 --- a/forge-ai/src/main/java/forge/ai/ability/GameLossAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/GameLossAi.java @@ -17,11 +17,10 @@ public class GameLossAi extends SpellAbilityAi { if (sa.usesTargeting()) { sa.resetTargets(); sa.getTargets().add(opp); + return true; } - // In general, don't return true. - // But this card wins the game, I can make an exception for that - return true; + return false; } @Override @@ -35,7 +34,7 @@ public class GameLossAi extends SpellAbilityAi { loser = ai.getGame().getCombat().getDefenderPlayerByAttacker(sa.getHostCard()); } - if (!mandatory && loser.cantLose()) { + if (!mandatory && (loser == ai || loser.cantLose())) { return false; } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java index ec348aebae2..988e313275a 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java @@ -33,17 +33,18 @@ public class CharmEffect extends SpellAbilityEffect { } } - int indx = 0; List choices = Lists.newArrayList(sa.getAdditionalAbilityList("Choices")); - if (restriction != null) { - List toRemove = Lists.newArrayList(); - for (AbilitySub ch : choices) { - if (restriction.contains(ch.getDescription())) { - toRemove.add(ch); - } + List toRemove = Lists.newArrayList(); + for (AbilitySub ch : choices) { + // 603.3c If one of the modes would be illegal, that mode can't be chosen. + if ((ch.usesTargeting() && ch.isTrigger() && ch.getTargetRestrictions().getNumCandidates(ch, true) == 0) || + (restriction != null && restriction.contains(ch.getDescription()))) { + toRemove.add(ch); } - choices.removeAll(toRemove); } + choices.removeAll(toRemove); + + int indx = 0; // set CharmOrder for (AbilitySub sub : choices) { sub.setSVar("CharmOrder", Integer.toString(indx)); From 2d871db8ea61b11be0636afbb57411d545745262 Mon Sep 17 00:00:00 2001 From: TRT <> Date: Fri, 26 Nov 2021 17:44:18 +0100 Subject: [PATCH 2/2] Fix Orcus --- forge-ai/src/main/java/forge/ai/ability/CharmAi.java | 3 +++ forge-ai/src/main/java/forge/ai/ability/LifeLoseAi.java | 2 +- .../main/java/forge/game/ability/effects/PumpAllEffect.java | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/CharmAi.java b/forge-ai/src/main/java/forge/ai/ability/CharmAi.java index c71bb90204a..f0cf10e2205 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CharmAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CharmAi.java @@ -69,6 +69,9 @@ public class CharmAi extends SpellAbilityAi { if (timingRight) { // Set minimum choices for triggers where chooseMultipleOptionsAi() returns null chosenList = chooseOptionsAi(choices, ai, true, num, min, sa.hasParam("CanRepeatModes")); + if (chosenList.isEmpty() && min != 0) { + return false; + } } else { return false; } diff --git a/forge-ai/src/main/java/forge/ai/ability/LifeLoseAi.java b/forge-ai/src/main/java/forge/ai/ability/LifeLoseAi.java index 29b295018a8..41e62d105fb 100644 --- a/forge-ai/src/main/java/forge/ai/ability/LifeLoseAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/LifeLoseAi.java @@ -38,7 +38,7 @@ public class LifeLoseAi extends SpellAbilityAi { SpellAbility root = sa.getRootAbility(); if (root.getXManaCostPaid() != null) { amount = root.getXManaCostPaid(); - } else { + } else if (root.getPayCosts() != null && root.getPayCosts().hasXInAnyCostPart()) { // Set PayX here to maximum value. final int xPay = ComputerUtilCost.getMaxXValue(sa, ai); root.setXManaCostPaid(xPay); diff --git a/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java index 44d33726de5..d37674c4139 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java @@ -20,6 +20,7 @@ import forge.game.zone.ZoneType; import forge.util.TextUtil; public class PumpAllEffect extends SpellAbilityEffect { + private static void applyPumpAll(final SpellAbility sa, final Iterable list, final int a, final int d, final List keywords, final List affectedZones) {