mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
Fix ClassCastException when adding attacker
This commit is contained in:
@@ -2478,10 +2478,15 @@ public class ComputerUtilCombat {
|
|||||||
public static GameEntity addAttackerToCombat(SpellAbility sa, Card attacker, Iterable<? extends GameEntity> defenders) {
|
public static GameEntity addAttackerToCombat(SpellAbility sa, Card attacker, Iterable<? extends GameEntity> defenders) {
|
||||||
Combat combat = sa.getHostCard().getGame().getCombat();
|
Combat combat = sa.getHostCard().getGame().getCombat();
|
||||||
if (combat != null) {
|
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());
|
GameEntity def = combat.getDefenderByAttacker(sa.getHostCard());
|
||||||
if (def instanceof Card && ((Card)def).isPlaneswalker() && Iterables.contains(defenders, def)) {
|
// 1. If the card that spawned the attacker was sent at a card, attack the same. Consider improving.
|
||||||
return def;
|
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.
|
// 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) {
|
for (GameEntity p : defenders) {
|
||||||
|
|||||||
@@ -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) {
|
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 hasPlayer = false;
|
||||||
boolean hasCard = false;
|
boolean hasCard = false;
|
||||||
boolean hasPlaneswalker = false;
|
boolean hasAttackableCard = false;
|
||||||
|
|
||||||
for (T ent : options) {
|
for (T ent : options) {
|
||||||
if (ent instanceof Player) {
|
if (ent instanceof Player) {
|
||||||
hasPlayer = true;
|
hasPlayer = true;
|
||||||
} else if (ent instanceof Card) {
|
} else if (ent instanceof Card) {
|
||||||
hasCard = true;
|
hasCard = true;
|
||||||
if (((Card)ent).isPlaneswalker()) {
|
if (((Card)ent).isPlaneswalker() || ((Card)ent).isBattle()) {
|
||||||
hasPlaneswalker = true;
|
hasAttackableCard = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasPlayer && hasPlaneswalker) {
|
if (hasPlayer && hasAttackableCard) {
|
||||||
return (T) chooseSinglePlayerOrPlaneswalker(ai, sa, (Collection<GameEntity>) options, params);
|
return (T) chooseSingleAttackableEntity(ai, sa, (Collection<GameEntity>) options, params);
|
||||||
} else if (hasCard) {
|
} else if (hasCard) {
|
||||||
return (T) chooseSingleCard(ai, sa, (Collection<Card>) options, isOptional, targetedPlayer, params);
|
return (T) chooseSingleCard(ai, sa, (Collection<Card>) options, isOptional, targetedPlayer, params);
|
||||||
} else if (hasPlayer) {
|
} else if (hasPlayer) {
|
||||||
@@ -353,7 +353,7 @@ public abstract class SpellAbilityAi {
|
|||||||
return Iterables.getFirst(options, null);
|
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");
|
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);
|
return Iterables.getFirst(options, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1760,12 +1760,12 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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")) {
|
if (params != null && params.containsKey("Attacker")) {
|
||||||
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
|
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
|
||||||
}
|
}
|
||||||
// should not be reached
|
// 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) {
|
private boolean doSacAndReturnFromGraveLogic(final Player ai, final SpellAbility sa) {
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
package forge.ai.ability;
|
package forge.ai.ability;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import forge.ai.AiAttackController;
|
|
||||||
import forge.ai.ComputerUtil;
|
import forge.ai.ComputerUtil;
|
||||||
import forge.ai.SpellAbilityAi;
|
import forge.ai.SpellAbilityAi;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
|
|||||||
@@ -261,12 +261,12 @@ public class CopyPermanentAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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")) {
|
if (params != null && params.containsKey("Attacker")) {
|
||||||
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
|
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
|
||||||
}
|
}
|
||||||
// should not be reached
|
// should not be reached
|
||||||
return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params);
|
return super.chooseSingleAttackableEntity(ai, sa, options, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,12 +196,12 @@ public class DigAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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")) {
|
if (params != null && params.containsKey("Attacker")) {
|
||||||
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
|
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
|
||||||
}
|
}
|
||||||
// should not be reached
|
// should not be reached
|
||||||
return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params);
|
return super.chooseSingleAttackableEntity(ai, sa, options, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
|||||||
@@ -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)
|
* @see forge.card.ability.SpellAbilityAi#chooseSinglePlayerOrPlaneswalker(forge.game.player.Player, forge.card.spellability.SpellAbility, Iterable<forge.game.GameEntity> options)
|
||||||
*/
|
*/
|
||||||
@Override
|
@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")) {
|
if (params != null && params.containsKey("Attacker")) {
|
||||||
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
|
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
|
||||||
}
|
}
|
||||||
// should not be reached
|
// should not be reached
|
||||||
return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params);
|
return super.chooseSingleAttackableEntity(ai, sa, options, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -625,17 +625,17 @@ public class Combat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Card pw : getDefendingPlaneswalkers()) {
|
for (Card battleOrPW : Iterables.filter(attackableEntries, Card.class)) {
|
||||||
if (pw.equals(c)) {
|
if (battleOrPW.equals(c)) {
|
||||||
Multimap<GameEntity, AttackingBand> attackerBuffer = ArrayListMultimap.create();
|
Multimap<GameEntity, AttackingBand> attackerBuffer = ArrayListMultimap.create();
|
||||||
Collection<AttackingBand> bands = attackedByBands.get(c);
|
Collection<AttackingBand> bands = attackedByBands.get(c);
|
||||||
for (AttackingBand abPW : bands) {
|
for (AttackingBand abDef : bands) {
|
||||||
unregisterDefender(c, abPW);
|
unregisterDefender(c, abDef);
|
||||||
// Rule 506.4c workaround to keep creatures in combat
|
// Rule 506.4c workaround to keep creatures in combat
|
||||||
Card fake = new Card(-1, c.getGame());
|
Card fake = new Card(-1, c.getGame());
|
||||||
fake.setName("<Nothing>");
|
fake.setName("<Nothing>");
|
||||||
fake.setController(c.getController(), 0);
|
fake.setController(c.getController(), 0);
|
||||||
attackerBuffer.put(fake, abPW);
|
attackerBuffer.put(fake, abDef);
|
||||||
}
|
}
|
||||||
bands.clear();
|
bands.clear();
|
||||||
attackedByBands.putAll(attackerBuffer);
|
attackedByBands.putAll(attackerBuffer);
|
||||||
|
|||||||
Reference in New Issue
Block a user