mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
@@ -24,6 +24,7 @@ public enum SpellApiToAi {
|
||||
.put(ApiType.AddPhase, AddPhaseAi.class)
|
||||
.put(ApiType.AddTurn, AddTurnAi.class)
|
||||
.put(ApiType.AdvanceCrank, AdvanceCrankAi.class)
|
||||
.put(ApiType.Airbend, AirbendAi.class)
|
||||
.put(ApiType.AlterAttribute, AlterAttributeAi.class)
|
||||
.put(ApiType.Amass, AmassAi.class)
|
||||
.put(ApiType.Animate, AnimateAi.class)
|
||||
|
||||
53
forge-ai/src/main/java/forge/ai/ability/AirbendAi.java
Normal file
53
forge-ai/src/main/java/forge/ai/ability/AirbendAi.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import forge.ai.*;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
public class AirbendAi extends SpellAbilityAi {
|
||||
@Override
|
||||
protected AiAbilityDecision canPlay(Player aiPlayer, SpellAbility sa) {
|
||||
// Check own cards that need saving, non-token, above CMC 2 so that it's hopefully worth saving this one
|
||||
final Combat combat = aiPlayer.getGame().getCombat();
|
||||
final CardCollection threatenedTgts = CardLists.filter(aiPlayer.getCreaturesInPlay(),
|
||||
card -> !card.isToken() && card.getCMC() > 2 &&
|
||||
(ComputerUtil.predictThreatenedObjects(aiPlayer, null, true).contains(card)
|
||||
|| (combat.isAttacking(card) && combat.isBlocked(card) && ComputerUtilCombat.combatantWouldBeDestroyed(aiPlayer, card, combat))));
|
||||
if (!threatenedTgts.isEmpty()) {
|
||||
Card bestSaved = ComputerUtilCard.getBestAI(threatenedTgts);
|
||||
sa.getTargets().add(bestSaved);
|
||||
return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
|
||||
}
|
||||
|
||||
// Check opponent's cards that need bouncing (only in the AI's own turn, main phase 1, or at the end of opponent's
|
||||
// turn, to get rid of potential blockers)
|
||||
PhaseHandler ph = aiPlayer.getGame().getPhaseHandler();
|
||||
if (ph.is(PhaseType.MAIN1, aiPlayer) || (ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == aiPlayer)) {
|
||||
final CardCollection opposingThreats = aiPlayer.getOpponents().getCreaturesInPlay();
|
||||
if (!opposingThreats.isEmpty()) {
|
||||
sa.getTargets().add(ComputerUtilCard.getBestAI(opposingThreats));
|
||||
return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add logic to use it to remove threatening spells when the ability allows to target spells?
|
||||
|
||||
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AiAbilityDecision doTriggerNoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) {
|
||||
AiAbilityDecision decision = canPlay(aiPlayer, sa);
|
||||
if (decision.willingToPlay() || mandatory) {
|
||||
return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
|
||||
}
|
||||
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +1,50 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import forge.ai.AiAbilityDecision;
|
||||
import forge.ai.AiPlayDecision;
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import forge.ai.*;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.cost.Cost;
|
||||
import forge.game.cost.CostPart;
|
||||
import forge.game.cost.CostSacrifice;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
public class EarthbendAi extends SpellAbilityAi {
|
||||
@Override
|
||||
protected AiAbilityDecision canPlay(Player aiPlayer, SpellAbility sa) {
|
||||
CardCollection nonAnimatedLands = CardLists.filter(aiPlayer.getLandsInPlay(), CardPredicates.NON_CREATURES);
|
||||
|
||||
if (nonAnimatedLands.isEmpty()) {
|
||||
CardCollection lands = aiPlayer.getLandsInPlay();
|
||||
if (lands.isEmpty()) {
|
||||
return new AiAbilityDecision(0, AiPlayDecision.AnotherTime);
|
||||
}
|
||||
CardCollection fetchLands = CardLists.filter(lands, c -> {
|
||||
for (final SpellAbility ability : c.getAllSpellAbilities()) {
|
||||
if (ability.isActivatedAbility()) {
|
||||
final Cost cost = ability.getPayCosts();
|
||||
for (final CostPart part : cost.getCostParts()) {
|
||||
if (!(part instanceof CostSacrifice)) {
|
||||
continue;
|
||||
}
|
||||
CostSacrifice sacCost = (CostSacrifice) part;
|
||||
if (sacCost.payCostFromSource() && ComputerUtilCost.canPayCost(ability, c.getController(), false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
Card bestToAnimate = ComputerUtilCard.getBestLandToAnimate(nonAnimatedLands);
|
||||
sa.getTargets().add(bestToAnimate);
|
||||
Card tgtLand = null;
|
||||
|
||||
if (!fetchLands.isEmpty()) {
|
||||
// Prioritize fetchlands as they can be reused later
|
||||
tgtLand = ComputerUtilCard.getBestLandToAnimate(fetchLands);
|
||||
} else {
|
||||
tgtLand = ComputerUtilCard.getBestLandToAnimate(lands);
|
||||
}
|
||||
|
||||
sa.getTargets().add(tgtLand);
|
||||
|
||||
return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user