- A somewhat cleaner fix for Token AI that fully separates the logic for detecting and processing mixed player/planeswalker target lists.

This commit is contained in:
Agetian
2016-07-20 04:18:12 +00:00
parent 1acd48be9e
commit 7d89f5ee70
2 changed files with 48 additions and 12 deletions

View File

@@ -222,14 +222,29 @@ public abstract class SpellAbilityAi {
@SuppressWarnings("unchecked")
public <T extends GameEntity> T chooseSingleEntity(Player ai, SpellAbility sa, Collection<T> options, boolean isOptional, Player targetedPlayer) {
T firstOption = Iterables.getFirst(options, null);
boolean hasPlayer = false;
boolean hasCard = false;
boolean hasPlaneswalker = false;
if (firstOption instanceof Card) {
return (T) chooseSingleCard(ai, sa, (Collection<Card>) options, isOptional, targetedPlayer);
for (T ent : options) {
if (ent instanceof Player) {
hasPlayer = true;
} else if (ent instanceof Card) {
hasCard = true;
if (((Card)ent).isPlaneswalker()) {
hasPlaneswalker = true;
}
}
}
if (firstOption instanceof Player) {
if (hasPlayer && hasPlaneswalker) {
return (T) chooseSinglePlayerOrPlaneswalker(ai, sa, (Collection<GameEntity>) options);
} else if (hasCard) {
return (T) chooseSingleCard(ai, sa, (Collection<Card>) options, isOptional, targetedPlayer);
} else if (hasPlayer) {
return (T) chooseSinglePlayer(ai, sa, (Collection<Player>) options);
}
return null;
}
@@ -239,16 +254,20 @@ public abstract class SpellAbilityAi {
}
protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer) {
System.err.println("Warning: default (ie. inherited from base class) implementation of chooseSingleEntity is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
System.err.println("Warning: default (ie. inherited from base class) implementation of chooseSingleCard is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
return Iterables.getFirst(options, null);
}
protected GameEntity chooseSinglePlayer(Player ai, SpellAbility sa, Iterable<Player> options) {
System.err.println("Warning: default (ie. inherited from base class) implementation of chooseSingleEntity is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable<Player> options) {
System.err.println("Warning: default (ie. inherited from base class) implementation of chooseSinglePlayer is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
return Iterables.getFirst(options, null);
}
protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable<GameEntity> options) {
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);
}
protected static boolean isUselessCreature(Player ai, Card c) {
if (c == null) {

View File

@@ -305,11 +305,30 @@ public class TokenAi extends SpellAbilityAi {
return true;
}
/* (non-Javadoc)
/*
* @see forge.card.ability.SpellAbilityAi#chooseSinglePlayer(forge.game.player.Player, forge.card.spellability.SpellAbility, Iterable<forge.game.player.Player> options)
*/
@Override
protected GameEntity chooseSinglePlayer(Player ai, SpellAbility sa, Iterable<Player> options) {
protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable<Player> options) {
// TODO: AILogic
Combat combat = ai.getGame().getCombat();
// TokenAttacking
if (combat != null && sa.hasParam("TokenAttacking")) {
Card attacker = spawnToken(ai, sa);
for (Player p : options) {
if (!ComputerUtilCard.canBeBlockedProfitably(p, attacker)) {
return p;
}
}
}
return Iterables.getFirst(options, null);
}
/* (non-Javadoc)
* @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) {
// TODO: AILogic
Combat combat = ai.getGame().getCombat();
// TokenAttacking
@@ -323,8 +342,6 @@ public class TokenAi extends SpellAbilityAi {
}
// 2. Otherwise, go through the list of options one by one, choose the first one that can't be blocked profitably.
Card attacker = spawnToken(ai, sa);
// TODO: this list potentially includes planeswalkers represented as Card objects. This may need further improvement
// (SpellAbilityAi::chooseSingleGameEntity normally expects the list of options to be of the same type).
for (GameEntity p : options) {
if (p instanceof Player && !ComputerUtilCard.canBeBlockedProfitably((Player)p, attacker)) {
return p;