mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
chooseSingleCardForEffect - moved implementations to SpellAbilityAi descendants, closer to the rest of AI code regarding each ability
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
package forge.card.ability;
|
package forge.card.ability;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import forge.Card;
|
||||||
import forge.card.spellability.AbilitySub;
|
import forge.card.spellability.AbilitySub;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
import forge.game.ai.ComputerUtilCost;
|
import forge.game.ai.ComputerUtilCost;
|
||||||
@@ -109,4 +112,14 @@ public abstract class SpellAbilityAi {
|
|||||||
System.err.println("Warning: default (ie. inherited from base class) implementation of confirmAction is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
|
System.err.println("Warning: default (ie. inherited from base class) implementation of confirmAction is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Card chooseSingleCard(Player ai, SpellAbility sa, List<Card> options, boolean isOptional) {
|
||||||
|
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 options.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player chooseSinglePlayer(Player ai, SpellAbility sa, List<Player> options, boolean isOptional) {
|
||||||
|
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 options.get(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,12 @@
|
|||||||
*/
|
*/
|
||||||
package forge.card.ability.ai;
|
package forge.card.ability.ai;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import forge.Card;
|
||||||
import forge.card.ability.SpellAbilityAi;
|
import forge.card.ability.SpellAbilityAi;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
|
import forge.game.ai.ComputerUtilCard;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,4 +49,10 @@ public final class BondAi extends SpellAbilityAi {
|
|||||||
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
|
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
|
||||||
return true;
|
return true;
|
||||||
} // end bondCanPlayAI()
|
} // end bondCanPlayAI()
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Card chooseSingleCard(Player ai, SpellAbility sa, List<Card> options, boolean isOptional) {
|
||||||
|
return ComputerUtilCard.getBestCreatureAI(options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1382,4 +1382,11 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Card chooseSingleCard(Player ai, SpellAbility sa, List<Card> options, boolean isOptional) {
|
||||||
|
// Called when looking for creature to attach aura or equipment
|
||||||
|
return ComputerUtilCard.getBestAI(options);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ import com.google.common.base.Predicate;
|
|||||||
|
|
||||||
import forge.Card;
|
import forge.Card;
|
||||||
import forge.CardLists;
|
import forge.CardLists;
|
||||||
|
import forge.CardPredicates.Presets;
|
||||||
import forge.card.ability.SpellAbilityAi;
|
import forge.card.ability.SpellAbilityAi;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
import forge.card.spellability.Target;
|
import forge.card.spellability.Target;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
|
import forge.game.ai.ComputerUtilCard;
|
||||||
import forge.game.ai.ComputerUtilCombat;
|
import forge.game.ai.ComputerUtilCombat;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -90,4 +92,57 @@ public class ChooseCardAi extends SpellAbilityAi {
|
|||||||
public boolean chkAIDrawback(SpellAbility sa, Player ai) {
|
public boolean chkAIDrawback(SpellAbility sa, Player ai) {
|
||||||
return canPlayAI(ai, sa);
|
return canPlayAI(ai, sa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see forge.card.ability.SpellAbilityAi#chooseSingleCard(forge.card.spellability.SpellAbility, java.util.List, boolean)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Card chooseSingleCard(final Player ai, SpellAbility sa, List<Card> options, boolean isOptional) {
|
||||||
|
final Card host = sa.getSourceCard();
|
||||||
|
final String logic = sa.getParam("AILogic");
|
||||||
|
Card choice = null;
|
||||||
|
if (logic == null) {
|
||||||
|
// Base Logic is choose "best"
|
||||||
|
choice = ComputerUtilCard.getBestAI(options);
|
||||||
|
} else if ("WorstCard".equals(logic)) {
|
||||||
|
choice = ComputerUtilCard.getWorstAI(options);
|
||||||
|
} else if (logic.equals("BestBlocker")) {
|
||||||
|
if (!CardLists.filter(options, Presets.UNTAPPED).isEmpty()) {
|
||||||
|
options = CardLists.filter(options, Presets.UNTAPPED);
|
||||||
|
}
|
||||||
|
choice = ComputerUtilCard.getBestCreatureAI(options);
|
||||||
|
} else if (logic.equals("Clone")) {
|
||||||
|
if (!CardLists.getValidCards(options, "Permanent.YouDontCtrl,Permanent.nonLegendary", host.getController(), host).isEmpty()) {
|
||||||
|
options = CardLists.getValidCards(options, "Permanent.YouDontCtrl,Permanent.nonLegendary", host.getController(), host);
|
||||||
|
}
|
||||||
|
choice = ComputerUtilCard.getBestAI(options);
|
||||||
|
} else if (logic.equals("Untap")) {
|
||||||
|
if (!CardLists.getValidCards(options, "Permanent.YouCtrl,Permanent.tapped", host.getController(), host).isEmpty()) {
|
||||||
|
options = CardLists.getValidCards(options, "Permanent.YouCtrl,Permanent.tapped", host.getController(), host);
|
||||||
|
}
|
||||||
|
choice = ComputerUtilCard.getBestAI(options);
|
||||||
|
} else if (logic.equals("NeedsPrevention")) {
|
||||||
|
List<Card> better = CardLists.filter(options, new Predicate<Card>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(final Card c) {
|
||||||
|
final Game game = ai.getGame();
|
||||||
|
if (!c.isAttacking(ai) || !game.getCombat().isUnblocked(c)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (host.getName().equals("Forcefield")) {
|
||||||
|
return ComputerUtilCombat.damageIfUnblocked(c, ai, game.getCombat()) > 1;
|
||||||
|
}
|
||||||
|
return ComputerUtilCombat.damageIfUnblocked(c, ai, game.getCombat()) > 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!better.isEmpty()) {
|
||||||
|
choice = ComputerUtilCard.getBestAI(better);
|
||||||
|
} else {
|
||||||
|
choice = ComputerUtilCard.getBestAI(options);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
choice = ComputerUtilCard.getBestAI(options);
|
||||||
|
}
|
||||||
|
return choice;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,16 @@
|
|||||||
*/
|
*/
|
||||||
package forge.card.ability.ai;
|
package forge.card.ability.ai;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
|
||||||
|
import forge.Card;
|
||||||
|
import forge.CardLists;
|
||||||
import forge.card.ability.SpellAbilityAi;
|
import forge.card.ability.SpellAbilityAi;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
|
import forge.game.ai.ComputerUtilCard;
|
||||||
|
import forge.game.phase.CombatUtil;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.player.PlayerActionConfirmMode;
|
import forge.game.player.PlayerActionConfirmMode;
|
||||||
|
|
||||||
@@ -58,4 +66,35 @@ public final class EncodeAi extends SpellAbilityAi {
|
|||||||
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see forge.card.ability.SpellAbilityAi#chooseSingleCard(forge.game.player.Player, forge.card.spellability.SpellAbility, java.util.List, boolean)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Card chooseSingleCard(Player ai, SpellAbility sa, List<Card> options, boolean isOptional) {
|
||||||
|
Card choice = null;
|
||||||
|
final String logic = sa.getParam("AILogic");
|
||||||
|
if (logic == null) {
|
||||||
|
final List<Card> attackers = CardLists.filter(options, new Predicate<Card>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(final Card c) {
|
||||||
|
return CombatUtil.canAttackNextTurn(c);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
final List<Card> unblockables = CardLists.filter(attackers, new Predicate<Card>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(final Card c) {
|
||||||
|
return !CombatUtil.canBeBlocked(c);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!unblockables.isEmpty()) {
|
||||||
|
choice = ComputerUtilCard.getBestAI(unblockables);
|
||||||
|
} else if (!attackers.isEmpty()) {
|
||||||
|
choice = ComputerUtilCard.getBestAI(attackers);
|
||||||
|
} else {
|
||||||
|
choice = ComputerUtilCard.getBestAI(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return choice;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -611,98 +611,6 @@ public class AiController {
|
|||||||
return discardList;
|
return discardList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These methods might be moved into matching SpellAbilityAi classes just without all these switches here
|
|
||||||
public Card chooseSingleCardForEffect(List<Card> options, SpellAbility sa, String title, boolean isOptional) {
|
|
||||||
ApiType api = sa.getApi();
|
|
||||||
if ( null == api ) {
|
|
||||||
throw new InvalidParameterException("SA is not api-based, this is not supported yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
Card choice = null;
|
|
||||||
final Card host = sa.getSourceCard();
|
|
||||||
final String logic = sa.getParam("AILogic");
|
|
||||||
|
|
||||||
switch(api) {
|
|
||||||
case Bond:
|
|
||||||
return ComputerUtilCard.getBestCreatureAI(options);
|
|
||||||
|
|
||||||
case ChooseCard:
|
|
||||||
if (logic == null) {
|
|
||||||
// Base Logic is choose "best"
|
|
||||||
choice = ComputerUtilCard.getBestAI(options);
|
|
||||||
} else if ("WorstCard".equals(logic)) {
|
|
||||||
choice = ComputerUtilCard.getWorstAI(options);
|
|
||||||
} else if (logic.equals("BestBlocker")) {
|
|
||||||
if (!CardLists.filter(options, Presets.UNTAPPED).isEmpty()) {
|
|
||||||
options = CardLists.filter(options, Presets.UNTAPPED);
|
|
||||||
}
|
|
||||||
choice = ComputerUtilCard.getBestCreatureAI(options);
|
|
||||||
} else if (logic.equals("Clone")) {
|
|
||||||
if (!CardLists.getValidCards(options, "Permanent.YouDontCtrl,Permanent.nonLegendary", host.getController(), host).isEmpty()) {
|
|
||||||
options = CardLists.getValidCards(options, "Permanent.YouDontCtrl,Permanent.nonLegendary", host.getController(), host);
|
|
||||||
}
|
|
||||||
choice = ComputerUtilCard.getBestAI(options);
|
|
||||||
} else if (logic.equals("Untap")) {
|
|
||||||
if (!CardLists.getValidCards(options, "Permanent.YouCtrl,Permanent.tapped", host.getController(), host).isEmpty()) {
|
|
||||||
options = CardLists.getValidCards(options, "Permanent.YouCtrl,Permanent.tapped", host.getController(), host);
|
|
||||||
}
|
|
||||||
choice = ComputerUtilCard.getBestAI(options);
|
|
||||||
} else if (logic.equals("NeedsPrevention")) {
|
|
||||||
final Player ai = this.getPlayer();
|
|
||||||
List<Card> better = CardLists.filter(options, new Predicate<Card>() {
|
|
||||||
@Override
|
|
||||||
public boolean apply(final Card c) {
|
|
||||||
if (!c.isAttacking(ai) || !game.getCombat().isUnblocked(c)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (host.getName().equals("Forcefield")) {
|
|
||||||
return ComputerUtilCombat.damageIfUnblocked(c, ai, game.getCombat()) > 1;
|
|
||||||
}
|
|
||||||
return ComputerUtilCombat.damageIfUnblocked(c, ai, game.getCombat()) > 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!better.isEmpty()) {
|
|
||||||
choice = ComputerUtilCard.getBestAI(better);
|
|
||||||
} else {
|
|
||||||
choice = ComputerUtilCard.getBestAI(options);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
choice = ComputerUtilCard.getBestAI(options);
|
|
||||||
}
|
|
||||||
return choice;
|
|
||||||
|
|
||||||
case Encode:
|
|
||||||
if (logic == null) {
|
|
||||||
final List<Card> attackers = CardLists.filter(options, new Predicate<Card>() {
|
|
||||||
@Override
|
|
||||||
public boolean apply(final Card c) {
|
|
||||||
return CombatUtil.canAttackNextTurn(c);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
final List<Card> unblockables = CardLists.filter(attackers, new Predicate<Card>() {
|
|
||||||
@Override
|
|
||||||
public boolean apply(final Card c) {
|
|
||||||
return !CombatUtil.canBeBlocked(c);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!unblockables.isEmpty()) {
|
|
||||||
choice = ComputerUtilCard.getBestAI(unblockables);
|
|
||||||
} else if (!attackers.isEmpty()) {
|
|
||||||
choice = ComputerUtilCard.getBestAI(attackers);
|
|
||||||
} else {
|
|
||||||
choice = ComputerUtilCard.getBestAI(options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return choice;
|
|
||||||
|
|
||||||
case ChangeZone: // called when permanent ETB 'AttachedTo' something
|
|
||||||
return ComputerUtilCard.getBestAI(options);
|
|
||||||
|
|
||||||
default: throw new InvalidParameterException("AI chooseSingleCard does not know how to choose card for " + api);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("incomplete-switch")
|
@SuppressWarnings("incomplete-switch")
|
||||||
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
ApiType api = sa.getApi();
|
ApiType api = sa.getApi();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package forge.game.player;
|
package forge.game.player;
|
||||||
|
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -14,6 +15,7 @@ import forge.Card;
|
|||||||
import forge.CardLists;
|
import forge.CardLists;
|
||||||
import forge.CardPredicates;
|
import forge.CardPredicates;
|
||||||
import forge.GameEntity;
|
import forge.GameEntity;
|
||||||
|
import forge.card.ability.ApiType;
|
||||||
import forge.card.cost.Cost;
|
import forge.card.cost.Cost;
|
||||||
import forge.card.mana.Mana;
|
import forge.card.mana.Mana;
|
||||||
import forge.card.replacement.ReplacementEffect;
|
import forge.card.replacement.ReplacementEffect;
|
||||||
@@ -134,7 +136,12 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Card chooseSingleCardForEffect(List<Card> options, SpellAbility sa, String title, boolean isOptional) {
|
public Card chooseSingleCardForEffect(List<Card> options, SpellAbility sa, String title, boolean isOptional) {
|
||||||
return getAi().chooseSingleCardForEffect(options, sa, title, isOptional);
|
ApiType api = sa.getApi();
|
||||||
|
if ( null == api ) {
|
||||||
|
throw new InvalidParameterException("SA is not api-based, this is not supported yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.getAi().chooseSingleCard(player, sa, options, isOptional);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user