Fix ClassCastException when adding attacker

This commit is contained in:
tool4EvEr
2023-04-26 20:21:01 +02:00
parent 49bf19948e
commit 19510914b4
8 changed files with 27 additions and 24 deletions

View File

@@ -2478,10 +2478,15 @@ public class ComputerUtilCombat {
public static GameEntity addAttackerToCombat(SpellAbility sa, Card attacker, Iterable<? extends GameEntity> 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) {

View File

@@ -314,21 +314,21 @@ public abstract class SpellAbilityAi {
public <T extends GameEntity> T chooseSingleEntity(Player ai, SpellAbility sa, Collection<T> options, boolean isOptional, Player targetedPlayer, Map<String, Object> 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<GameEntity>) options, params);
if (hasPlayer && hasAttackableCard) {
return (T) chooseSingleAttackableEntity(ai, sa, (Collection<GameEntity>) options, params);
} else if (hasCard) {
return (T) chooseSingleCard(ai, sa, (Collection<Card>) 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<GameEntity> options, Map<String, Object> params) {
protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> 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);
}

View File

@@ -1760,12 +1760,12 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
@Override
protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> 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) {

View File

@@ -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;

View File

@@ -261,12 +261,12 @@ public class CopyPermanentAi extends SpellAbilityAi {
}
@Override
protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> 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);
}
}

View File

@@ -196,12 +196,12 @@ public class DigAi extends SpellAbilityAi {
}
@Override
protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> 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)

View File

@@ -326,12 +326,12 @@ public class TokenAi extends SpellAbilityAi {
* @see forge.card.ability.SpellAbilityAi#chooseSinglePlayerOrPlaneswalker(forge.game.player.Player, forge.card.spellability.SpellAbility, Iterable<forge.game.GameEntity> options)
*/
@Override
protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> 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);
}
/**

View File

@@ -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<GameEntity, AttackingBand> attackerBuffer = ArrayListMultimap.create();
Collection<AttackingBand> 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("<Nothing>");
fake.setController(c.getController(), 0);
attackerBuffer.put(fake, abPW);
attackerBuffer.put(fake, abDef);
}
bands.clear();
attackedByBands.putAll(attackerBuffer);