From 19510914b4b5d8cad5a716f45cf60faf4d615792 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Wed, 26 Apr 2023 20:21:01 +0200 Subject: [PATCH] Fix ClassCastException when adding attacker --- .../src/main/java/forge/ai/ComputerUtilCombat.java | 11 ++++++++--- forge-ai/src/main/java/forge/ai/SpellAbilityAi.java | 12 ++++++------ .../src/main/java/forge/ai/ability/ChangeZoneAi.java | 4 ++-- .../main/java/forge/ai/ability/ChoosePlayerAi.java | 2 -- .../main/java/forge/ai/ability/CopyPermanentAi.java | 4 ++-- forge-ai/src/main/java/forge/ai/ability/DigAi.java | 4 ++-- forge-ai/src/main/java/forge/ai/ability/TokenAi.java | 4 ++-- .../src/main/java/forge/game/combat/Combat.java | 10 +++++----- 8 files changed, 27 insertions(+), 24 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java index a8008e8a5a5..60b7908160b 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java @@ -2478,10 +2478,15 @@ public class ComputerUtilCombat { public static GameEntity addAttackerToCombat(SpellAbility sa, Card attacker, Iterable defenders) { Combat combat = sa.getHostCard().getGame().getCombat(); if (combat != null) { - // 1. If the card that spawned the attacker was sent at a planeswalker, attack the same. Consider improving. GameEntity def = combat.getDefenderByAttacker(sa.getHostCard()); - if (def instanceof Card && ((Card)def).isPlaneswalker() && Iterables.contains(defenders, def)) { - return def; + // 1. If the card that spawned the attacker was sent at a card, attack the same. Consider improving. + if (def instanceof Card && Iterables.contains(defenders, def)) { + if (((Card)def).isPlaneswalker()) { + return def; + } + if (((Card)def).isBattle()) { + return def; + } } // 2. Otherwise, go through the list of options one by one, choose the first one that can't be blocked profitably. for (GameEntity p : defenders) { diff --git a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java index 671c9867b9b..285c07aca49 100644 --- a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java @@ -314,21 +314,21 @@ public abstract class SpellAbilityAi { public T chooseSingleEntity(Player ai, SpellAbility sa, Collection options, boolean isOptional, Player targetedPlayer, Map params) { boolean hasPlayer = false; boolean hasCard = false; - boolean hasPlaneswalker = false; + boolean hasAttackableCard = false; for (T ent : options) { if (ent instanceof Player) { hasPlayer = true; } else if (ent instanceof Card) { hasCard = true; - if (((Card)ent).isPlaneswalker()) { - hasPlaneswalker = true; + if (((Card)ent).isPlaneswalker() || ((Card)ent).isBattle()) { + hasAttackableCard = true; } } } - if (hasPlayer && hasPlaneswalker) { - return (T) chooseSinglePlayerOrPlaneswalker(ai, sa, (Collection) options, params); + if (hasPlayer && hasAttackableCard) { + return (T) chooseSingleAttackableEntity(ai, sa, (Collection) options, params); } else if (hasCard) { return (T) chooseSingleCard(ai, sa, (Collection) options, isOptional, targetedPlayer, params); } else if (hasPlayer) { @@ -353,7 +353,7 @@ public abstract class SpellAbilityAi { return Iterables.getFirst(options, null); } - protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options, Map params) { + protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable options, Map params) { System.err.println("Warning: default (ie. inherited from base class) implementation of chooseSinglePlayerOrPlaneswalker is used for " + this.getClass().getName() + ". Consider declaring an overloaded method"); return Iterables.getFirst(options, null); } diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java index bf263a06eed..d0a945d43a2 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java @@ -1760,12 +1760,12 @@ public class ChangeZoneAi extends SpellAbilityAi { } @Override - protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options, Map params) { + protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable options, Map params) { if (params != null && params.containsKey("Attacker")) { return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options); } // should not be reached - return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params); + return super.chooseSingleAttackableEntity(ai, sa, options, params); } private boolean doSacAndReturnFromGraveLogic(final Player ai, final SpellAbility sa) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ChoosePlayerAi.java b/forge-ai/src/main/java/forge/ai/ability/ChoosePlayerAi.java index d31fa1ab303..d2e1aed14a1 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChoosePlayerAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChoosePlayerAi.java @@ -1,13 +1,11 @@ package forge.ai.ability; -import java.util.Collections; import java.util.List; import java.util.Map; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import forge.ai.AiAttackController; import forge.ai.ComputerUtil; import forge.ai.SpellAbilityAi; import forge.game.player.Player; diff --git a/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java b/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java index 53fe0518bcf..e17c9926259 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java @@ -261,12 +261,12 @@ public class CopyPermanentAi extends SpellAbilityAi { } @Override - protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options, Map params) { + protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable options, Map params) { if (params != null && params.containsKey("Attacker")) { return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options); } // should not be reached - return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params); + return super.chooseSingleAttackableEntity(ai, sa, options, params); } } diff --git a/forge-ai/src/main/java/forge/ai/ability/DigAi.java b/forge-ai/src/main/java/forge/ai/ability/DigAi.java index cfd4214d834..c8e8e2b8c76 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DigAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DigAi.java @@ -196,12 +196,12 @@ public class DigAi extends SpellAbilityAi { } @Override - protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options, Map params) { + protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable options, Map params) { if (params != null && params.containsKey("Attacker")) { return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options); } // should not be reached - return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params); + return super.chooseSingleAttackableEntity(ai, sa, options, params); } /* (non-Javadoc) diff --git a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java index 023ad61cbf6..839d6fbbf00 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java @@ -326,12 +326,12 @@ public class TokenAi extends SpellAbilityAi { * @see forge.card.ability.SpellAbilityAi#chooseSinglePlayerOrPlaneswalker(forge.game.player.Player, forge.card.spellability.SpellAbility, Iterable options) */ @Override - protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options, Map params) { + protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable options, Map params) { if (params != null && params.containsKey("Attacker")) { return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options); } // should not be reached - return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params); + return super.chooseSingleAttackableEntity(ai, sa, options, params); } /** diff --git a/forge-game/src/main/java/forge/game/combat/Combat.java b/forge-game/src/main/java/forge/game/combat/Combat.java index 9f706fac6ec..851303f937d 100644 --- a/forge-game/src/main/java/forge/game/combat/Combat.java +++ b/forge-game/src/main/java/forge/game/combat/Combat.java @@ -625,17 +625,17 @@ public class Combat { } } - for (Card pw : getDefendingPlaneswalkers()) { - if (pw.equals(c)) { + for (Card battleOrPW : Iterables.filter(attackableEntries, Card.class)) { + if (battleOrPW.equals(c)) { Multimap attackerBuffer = ArrayListMultimap.create(); Collection bands = attackedByBands.get(c); - for (AttackingBand abPW : bands) { - unregisterDefender(c, abPW); + for (AttackingBand abDef : bands) { + unregisterDefender(c, abDef); // Rule 506.4c workaround to keep creatures in combat Card fake = new Card(-1, c.getGame()); fake.setName(""); fake.setController(c.getController(), 0); - attackerBuffer.put(fake, abPW); + attackerBuffer.put(fake, abDef); } bands.clear(); attackedByBands.putAll(attackerBuffer);