mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
ChooseCardAi: updated AI for new SpellAbilityAi format
This commit is contained in:
@@ -1,6 +1,11 @@
|
|||||||
package forge.ai.ability;
|
package forge.ai.ability;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import forge.ai.ComputerUtilCard;
|
import forge.ai.ComputerUtilCard;
|
||||||
import forge.ai.ComputerUtilCombat;
|
import forge.ai.ComputerUtilCombat;
|
||||||
@@ -15,114 +20,123 @@ import forge.game.card.CounterType;
|
|||||||
import forge.game.combat.Combat;
|
import forge.game.combat.Combat;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
|
import forge.game.player.PlayerPredicates;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.TargetRestrictions;
|
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.Aggregates;
|
import forge.util.Aggregates;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
public class ChooseCardAi extends SpellAbilityAi {
|
public class ChooseCardAi extends SpellAbilityAi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rest of the logic not covered by the canPlayAI template is defined here
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean canPlayAI(final Player ai, SpellAbility sa) {
|
protected boolean checkApiLogic(final Player ai, final SpellAbility sa) {
|
||||||
|
if (sa.usesTargeting()) {
|
||||||
|
sa.resetTargets();
|
||||||
|
// search targetable Opponents
|
||||||
|
final List<Player> oppList = Lists.newArrayList(Iterables.filter(
|
||||||
|
ai.getOpponents(), PlayerPredicates.isTargetableBy(sa)));
|
||||||
|
|
||||||
|
if (oppList.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sa.getTargets().add(Iterables.getFirst(oppList, null));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the AI will play a SpellAbility with the specified AiLogic
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) {
|
||||||
final Card host = sa.getHostCard();
|
final Card host = sa.getHostCard();
|
||||||
final Game game = ai.getGame();
|
final Game game = ai.getGame();
|
||||||
|
ZoneType choiceZone = ZoneType.Battlefield;
|
||||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
if (sa.hasParam("ChoiceZone")) {
|
||||||
if (tgt != null) {
|
choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone"));
|
||||||
sa.resetTargets();
|
|
||||||
if (sa.canTarget(ai.getOpponent())) {
|
|
||||||
sa.getTargets().add(ai.getOpponent());
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (sa.hasParam("AILogic")) {
|
CardCollectionView choices = ai.getGame().getCardsIn(choiceZone);
|
||||||
ZoneType choiceZone = ZoneType.Battlefield;
|
if (sa.hasParam("Choices")) {
|
||||||
String logic = sa.getParam("AILogic");
|
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host);
|
||||||
if (sa.hasParam("ChoiceZone")) {
|
}
|
||||||
choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone"));
|
if (sa.hasParam("TargetControls")) {
|
||||||
}
|
choices = CardLists.filterControlledBy(choices, ai.getOpponents());
|
||||||
CardCollectionView choices = ai.getGame().getCardsIn(choiceZone);
|
}
|
||||||
if (sa.hasParam("Choices")) {
|
if (aiLogic.equals("AtLeast1") || aiLogic.equals("OppPreferred")) {
|
||||||
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host);
|
if (choices.isEmpty()) {
|
||||||
}
|
|
||||||
if (sa.hasParam("TargetControls")) {
|
|
||||||
choices = CardLists.filterControlledBy(choices, ai.getOpponent());
|
|
||||||
}
|
|
||||||
if (logic.equals("AtLeast1") || logic.equals("OppPreferred")) {
|
|
||||||
if (choices.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (logic.equals("AtLeast2") || logic.equals("BestBlocker")) {
|
|
||||||
if (choices.size() < 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (logic.equals("Clone") || logic.equals("Vesuva")) {
|
|
||||||
final String filter = logic.equals("Clone") ? "Permanent.YouDontCtrl,Permanent.nonLegendary" :
|
|
||||||
"Permanent.YouDontCtrl+notnamedVesuva,Permanent.nonLegendary+notnamedVesuva";
|
|
||||||
|
|
||||||
choices = CardLists.getValidCards(choices, filter, host.getController(), host);
|
|
||||||
if (choices.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (logic.equals("Never")) {
|
|
||||||
return false;
|
return false;
|
||||||
} else if (logic.equals("NeedsPrevention")) {
|
}
|
||||||
if (!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
|
} else if (aiLogic.equals("AtLeast2") || aiLogic.equals("BestBlocker")) {
|
||||||
return false;
|
if (choices.size() < 2) {
|
||||||
}
|
return false;
|
||||||
final Combat combat = game.getCombat();
|
}
|
||||||
choices = CardLists.filter(choices, new Predicate<Card>() {
|
} else if (aiLogic.equals("Clone") || aiLogic.equals("Vesuva")) {
|
||||||
@Override
|
final String filter = aiLogic.equals("Clone") ? "Permanent.YouDontCtrl,Permanent.nonLegendary"
|
||||||
public boolean apply(final Card c) {
|
: "Permanent.YouDontCtrl+notnamedVesuva,Permanent.nonLegendary+notnamedVesuva";
|
||||||
if (!combat.isAttacking(c, ai) || !combat.isUnblocked(c)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int ref = host.getName().equals("Forcefield") ? 1 : 0;
|
|
||||||
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (choices.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (logic.equals("Ashiok")) {
|
|
||||||
final int loyalty = host.getCounters(CounterType.LOYALTY) - 1;
|
|
||||||
for (int i = loyalty; i >= 0; i--) {
|
|
||||||
host.setSVar("ChosenX", "Number$" + i);
|
|
||||||
choices = ai.getGame().getCardsIn(choiceZone);
|
|
||||||
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host);
|
|
||||||
if (!choices.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (choices.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (logic.equals("RandomNonLand")) {
|
|
||||||
if (CardLists.getValidCards(choices, "Card.nonLand", host.getController(), host).isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (logic.equals("Duneblast")) {
|
|
||||||
CardCollection aiCreatures = ai.getCreaturesInPlay();
|
|
||||||
CardCollection oppCreatures = ai.getOpponent().getCreaturesInPlay();
|
|
||||||
aiCreatures = CardLists.getNotKeyword(aiCreatures, "Indestructible");
|
|
||||||
oppCreatures = CardLists.getNotKeyword(oppCreatures, "Indestructible");
|
|
||||||
|
|
||||||
// Use it as a wrath, when the human creatures threat the ai's life
|
|
||||||
if (aiCreatures.isEmpty() && ComputerUtilCombat.sumDamageIfUnblocked(oppCreatures, ai) >= ai.getLife()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Card chosen = ComputerUtilCard.getBestCreatureAI(aiCreatures);
|
choices = CardLists.getValidCards(choices, filter, host.getController(), host);
|
||||||
aiCreatures.remove(chosen);
|
if (choices.isEmpty()) {
|
||||||
int minGain = 200;
|
return false;
|
||||||
|
}
|
||||||
if ((ComputerUtilCard.evaluateCreatureList(aiCreatures) + minGain) >= ComputerUtilCard
|
} else if (aiLogic.equals("Never")) {
|
||||||
.evaluateCreatureList(oppCreatures)) {
|
return false;
|
||||||
return false;
|
} else if (aiLogic.equals("NeedsPrevention")) {
|
||||||
|
if (!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Combat combat = game.getCombat();
|
||||||
|
choices = CardLists.filter(choices, new Predicate<Card>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(final Card c) {
|
||||||
|
if (!combat.isAttacking(c, ai) || !combat.isUnblocked(c)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int ref = host.getName().equals("Forcefield") ? 1 : 0;
|
||||||
|
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
if (choices.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (aiLogic.equals("Ashiok")) {
|
||||||
|
final int loyalty = host.getCounters(CounterType.LOYALTY) - 1;
|
||||||
|
for (int i = loyalty; i >= 0; i--) {
|
||||||
|
host.setSVar("ChosenX", "Number$" + i);
|
||||||
|
choices = ai.getGame().getCardsIn(choiceZone);
|
||||||
|
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host);
|
||||||
|
if (!choices.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choices.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (aiLogic.equals("RandomNonLand")) {
|
||||||
|
if (CardLists.getValidCards(choices, "Card.nonLand", host.getController(), host).isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (aiLogic.equals("Duneblast")) {
|
||||||
|
CardCollection aiCreatures = ai.getCreaturesInPlay();
|
||||||
|
CardCollection oppCreatures = ai.getOpponent().getCreaturesInPlay();
|
||||||
|
aiCreatures = CardLists.getNotKeyword(aiCreatures, "Indestructible");
|
||||||
|
oppCreatures = CardLists.getNotKeyword(oppCreatures, "Indestructible");
|
||||||
|
|
||||||
|
// Use it as a wrath, when the human creatures threat the ai's life
|
||||||
|
if (aiCreatures.isEmpty() && ComputerUtilCombat.sumDamageIfUnblocked(oppCreatures, ai) >= ai.getLife()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Card chosen = ComputerUtilCard.getBestCreatureAI(aiCreatures);
|
||||||
|
aiCreatures.remove(chosen);
|
||||||
|
int minGain = 200;
|
||||||
|
|
||||||
|
if ((ComputerUtilCard.evaluateCreatureList(aiCreatures) + minGain) >= ComputerUtilCard
|
||||||
|
.evaluateCreatureList(oppCreatures)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -139,6 +153,7 @@ public class ChooseCardAi extends SpellAbilityAi {
|
|||||||
@Override
|
@Override
|
||||||
public Card chooseSingleCard(final Player ai, SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer) {
|
public Card chooseSingleCard(final Player ai, SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer) {
|
||||||
final Card host = sa.getHostCard();
|
final Card host = sa.getHostCard();
|
||||||
|
final Player ctrl = host.getController();
|
||||||
final String logic = sa.getParam("AILogic");
|
final String logic = sa.getParam("AILogic");
|
||||||
Card choice = null;
|
Card choice = null;
|
||||||
if (logic == null) {
|
if (logic == null) {
|
||||||
@@ -155,8 +170,9 @@ public class ChooseCardAi extends SpellAbilityAi {
|
|||||||
final String filter = logic.equals("Clone") ? "Permanent.YouDontCtrl,Permanent.nonLegendary" :
|
final String filter = logic.equals("Clone") ? "Permanent.YouDontCtrl,Permanent.nonLegendary" :
|
||||||
"Permanent.YouDontCtrl+notnamedVesuva,Permanent.nonLegendary+notnamedVesuva";
|
"Permanent.YouDontCtrl+notnamedVesuva,Permanent.nonLegendary+notnamedVesuva";
|
||||||
|
|
||||||
if (!CardLists.getValidCards(options, filter, host.getController(), host).isEmpty()) {
|
CardCollection newOptions = CardLists.getValidCards(options, filter.split(","), ctrl, host, sa);
|
||||||
options = CardLists.getValidCards(options, filter, host.getController(), host);
|
if (!newOptions.isEmpty()) {
|
||||||
|
options = newOptions;
|
||||||
}
|
}
|
||||||
choice = ComputerUtilCard.getBestAI(options);
|
choice = ComputerUtilCard.getBestAI(options);
|
||||||
if (logic.equals("Vesuva") && "Vesuva".equals(choice.getName())) {
|
if (logic.equals("Vesuva") && "Vesuva".equals(choice.getName())) {
|
||||||
@@ -166,8 +182,10 @@ public class ChooseCardAi extends SpellAbilityAi {
|
|||||||
options = CardLists.getValidCards(options, "Card.nonLand", host.getController(), host);
|
options = CardLists.getValidCards(options, "Card.nonLand", host.getController(), host);
|
||||||
choice = Aggregates.random(options);
|
choice = Aggregates.random(options);
|
||||||
} else if (logic.equals("Untap")) {
|
} else if (logic.equals("Untap")) {
|
||||||
if (!CardLists.getValidCards(options, "Permanent.YouCtrl,Permanent.tapped", host.getController(), host).isEmpty()) {
|
final String filter = "Permanent.YouCtrl,Permanent.tapped";
|
||||||
options = CardLists.getValidCards(options, "Permanent.YouCtrl,Permanent.tapped", host.getController(), host);
|
CardCollection newOptions = CardLists.getValidCards(options, filter.split(","), ctrl, host, sa);
|
||||||
|
if (!newOptions.isEmpty()) {
|
||||||
|
options = newOptions;
|
||||||
}
|
}
|
||||||
choice = ComputerUtilCard.getBestAI(options);
|
choice = ComputerUtilCard.getBestAI(options);
|
||||||
} else if (logic.equals("NeedsPrevention")) {
|
} else if (logic.equals("NeedsPrevention")) {
|
||||||
@@ -228,15 +246,15 @@ public class ChooseCardAi extends SpellAbilityAi {
|
|||||||
choice = ComputerUtilCard.getWorstPermanentAI(options, false, false, false, false);
|
choice = ComputerUtilCard.getWorstPermanentAI(options, false, false, false, false);
|
||||||
}
|
}
|
||||||
} else if (logic.equals("Duneblast")) {
|
} else if (logic.equals("Duneblast")) {
|
||||||
CardCollectionView aiCreatures = ai.getCreaturesInPlay();
|
CardCollectionView aiCreatures = ai.getCreaturesInPlay();
|
||||||
aiCreatures = CardLists.getNotKeyword(aiCreatures, "Indestructible");
|
aiCreatures = CardLists.getNotKeyword(aiCreatures, "Indestructible");
|
||||||
|
|
||||||
if (aiCreatures.isEmpty()) {
|
if (aiCreatures.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Card chosen = ComputerUtilCard.getBestCreatureAI(aiCreatures);
|
Card chosen = ComputerUtilCard.getBestCreatureAI(aiCreatures);
|
||||||
return chosen;
|
return chosen;
|
||||||
} else {
|
} else {
|
||||||
choice = ComputerUtilCard.getBestAI(options);
|
choice = ComputerUtilCard.getBestAI(options);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user