From 15834a0d67bcd5150c698f93e9ad3cd3813b85e0 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 26 Jan 2023 17:19:51 +0100 Subject: [PATCH 1/2] Fix inconsistent controller --- .../src/main/java/forge/ai/ComputerUtil.java | 39 ++++++++++--------- .../java/forge/ai/PlayerControllerAi.java | 8 ++-- .../java/forge/game/ability/AbilityUtils.java | 16 +++----- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index ec6b6636151..c5c5720241d 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -337,27 +337,30 @@ public class ComputerUtil { return true; } - public static final void playNoStack(final Player ai, SpellAbility sa, final Game game, final boolean effect) { + public static final boolean playNoStack(final Player ai, SpellAbility sa, final Game game, final boolean effect) { sa.setActivatingPlayer(ai, true); // TODO: We should really restrict what doesn't use the Stack - if (ComputerUtilCost.canPayCost(sa, ai, effect)) { - final Card source = sa.getHostCard(); - if (sa.isSpell() && !source.isCopiedSpell()) { - sa.setHostCard(game.getAction().moveToStack(source, sa)); - } - - sa = GameActionUtil.addExtraKeywordCost(sa); - - final Cost cost = sa.getPayCosts(); - if (cost == null) { - ComputerUtilMana.payManaCost(ai, sa, effect); - } else { - final CostPayment pay = new CostPayment(cost, sa); - pay.payComputerCosts(new AiCostDecision(ai, sa, effect)); - } - - AbilityUtils.resolve(sa); + if (!ComputerUtilCost.canPayCost(sa, ai, effect)) { + return false; } + + final Card source = sa.getHostCard(); + if (sa.isSpell() && !source.isCopiedSpell()) { + sa.setHostCard(game.getAction().moveToStack(source, sa)); + } + + sa = GameActionUtil.addExtraKeywordCost(sa); + + final Cost cost = sa.getPayCosts(); + if (cost == null) { + ComputerUtilMana.payManaCost(ai, sa, effect); + } else { + final CostPayment pay = new CostPayment(cost, sa); + pay.payComputerCosts(new AiCostDecision(ai, sa, effect)); + } + + AbilityUtils.resolve(sa); + return true; } public static Card getCardPreference(final Player ai, final Card activate, final String pref, final CardCollection typeList) { diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 74b6b1bc93c..f6929b142be 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -696,8 +696,7 @@ public class PlayerControllerAi extends PlayerController { ability.setActivatingPlayer(c.getController(), true); ability.setCardState(sa.getCardState()); - if (ComputerUtilCost.canPayCost(ability, c.getController(), true)) { - ComputerUtil.playNoStack(c.getController(), ability, getGame(), true); + if (ComputerUtil.playNoStack(c.getController(), ability, getGame(), true)) { // transfer this info for Balduvian Fallen sa.setPayingMana(ability.getPayingMana()); return true; @@ -1071,9 +1070,8 @@ public class PlayerControllerAi extends PlayerController { emptyAbility.setSVars(sa.getSVars()); emptyAbility.setCardState(sa.getCardState()); emptyAbility.setXManaCostPaid(sa.getRootAbility().getXManaCostPaid()); - if (ComputerUtilCost.willPayUnlessCost(sa, player, cost, alreadyPaid, allPayers) && ComputerUtilCost.canPayCost(emptyAbility, player, true)) { - ComputerUtil.playNoStack(player, emptyAbility, getGame(), true); // AI needs something to resolve to pay that cost - return true; + if (ComputerUtilCost.willPayUnlessCost(sa, player, cost, alreadyPaid, allPayers)) { + return ComputerUtil.playNoStack(player, emptyAbility, getGame(), true); // AI needs something to resolve to pay that cost } return false; } diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 9df276d0a21..8bac02f711b 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -421,8 +421,8 @@ public class AbilityUtils { // return empty strings and constants if (StringUtils.isBlank(amount)) { return 0; } if (card == null) { return 0; } - final Player player = card.getController(); - final Game game = player == null ? card.getGame() : player.getGame(); + final Player player = ability instanceof SpellAbility ? ((SpellAbility)ability).getActivatingPlayer() : card.getController(); + final Game game = card.getGame(); // Strip and save sign for calculations final boolean startsWithPlus = amount.charAt(0) == '+'; @@ -519,12 +519,7 @@ public class AbilityUtils { players.remove(game.getPhaseHandler().getPlayerTurn()); val = playerXCount(players, calcX[1], card, ability); } else if (hType.startsWith("PropertyYou")) { - if (ability instanceof SpellAbility) { - // Hollow One - players.add(((SpellAbility) ability).getActivatingPlayer()); - } else { - players.add(player); - } + players.add(player); val = playerXCount(players, calcX[1], card, ability); } else if (hType.startsWith("Property")) { String defined = hType.split("Property")[1]; @@ -3225,12 +3220,13 @@ public class AbilityUtils { * @return a int. */ public static int playerXCount(final List players, final String s, final Card source, CardTraitBase ctb) { - if (players.size() == 0) { + if (players.isEmpty()) { return 0; } final String[] l = s.split("/"); final String m = CardFactoryUtil.extractOperators(s); + final Player controller = ctb instanceof SpellAbility ? ((SpellAbility)ctb).getActivatingPlayer() : source.getController(); int n = 0; @@ -3311,7 +3307,7 @@ public class AbilityUtils { int totPlayer = 0; String property = sq[0].substring(11); for (Player p : players) { - if (p.hasProperty(property, source.getController(), source, ctb)) { + if (p.hasProperty(property, controller, source, ctb)) { totPlayer++; } } From 6d2d6dd11e5b995c4df18a17e40b2737f3bf4c5a Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 26 Jan 2023 18:17:44 +0100 Subject: [PATCH 2/2] Allow fallback if SA ever fails to deliver --- .../src/main/java/forge/game/ability/AbilityUtils.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 8bac02f711b..05486f1cd44 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -421,7 +421,15 @@ public class AbilityUtils { // return empty strings and constants if (StringUtils.isBlank(amount)) { return 0; } if (card == null) { return 0; } - final Player player = ability instanceof SpellAbility ? ((SpellAbility)ability).getActivatingPlayer() : card.getController(); + + Player player = null; + if (ability instanceof SpellAbility) { + player = ((SpellAbility)ability).getActivatingPlayer(); + } + if (player == null) { + player = card.getController(); + } + final Game game = card.getGame(); // Strip and save sign for calculations