mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
- 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:
@@ -222,14 +222,29 @@ public abstract class SpellAbilityAi {
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T extends GameEntity> T chooseSingleEntity(Player ai, SpellAbility sa, Collection<T> options, boolean isOptional, Player targetedPlayer) {
|
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;
|
||||||
if (firstOption instanceof Card) {
|
boolean hasPlaneswalker = false;
|
||||||
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 (T) chooseSinglePlayer(ai, sa, (Collection<Player>) options);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,16 +254,20 @@ public abstract class SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer) {
|
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);
|
return Iterables.getFirst(options, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected GameEntity chooseSinglePlayer(Player ai, SpellAbility sa, Iterable<Player> options) {
|
protected Player 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");
|
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);
|
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) {
|
protected static boolean isUselessCreature(Player ai, Card c) {
|
||||||
if (c == null) {
|
if (c == null) {
|
||||||
|
|||||||
@@ -305,11 +305,30 @@ public class TokenAi extends SpellAbilityAi {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/*
|
||||||
* @see forge.card.ability.SpellAbilityAi#chooseSinglePlayer(forge.game.player.Player, forge.card.spellability.SpellAbility, Iterable<forge.game.player.Player> options)
|
* @see forge.card.ability.SpellAbilityAi#chooseSinglePlayer(forge.game.player.Player, forge.card.spellability.SpellAbility, Iterable<forge.game.player.Player> options)
|
||||||
*/
|
*/
|
||||||
@Override
|
@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
|
// TODO: AILogic
|
||||||
Combat combat = ai.getGame().getCombat();
|
Combat combat = ai.getGame().getCombat();
|
||||||
// TokenAttacking
|
// 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.
|
// 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);
|
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) {
|
for (GameEntity p : options) {
|
||||||
if (p instanceof Player && !ComputerUtilCard.canBeBlockedProfitably((Player)p, attacker)) {
|
if (p instanceof Player && !ComputerUtilCard.canBeBlockedProfitably((Player)p, attacker)) {
|
||||||
return p;
|
return p;
|
||||||
|
|||||||
Reference in New Issue
Block a user