mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
@@ -24,6 +24,7 @@ public enum SpellApiToAi {
|
|||||||
.put(ApiType.AddPhase, AddPhaseAi.class)
|
.put(ApiType.AddPhase, AddPhaseAi.class)
|
||||||
.put(ApiType.AddTurn, AddTurnAi.class)
|
.put(ApiType.AddTurn, AddTurnAi.class)
|
||||||
.put(ApiType.AdvanceCrank, AdvanceCrankAi.class)
|
.put(ApiType.AdvanceCrank, AdvanceCrankAi.class)
|
||||||
|
.put(ApiType.Airbend, AirbendAi.class)
|
||||||
.put(ApiType.AlterAttribute, AlterAttributeAi.class)
|
.put(ApiType.AlterAttribute, AlterAttributeAi.class)
|
||||||
.put(ApiType.Amass, AmassAi.class)
|
.put(ApiType.Amass, AmassAi.class)
|
||||||
.put(ApiType.Animate, AnimateAi.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;
|
package forge.ai.ability;
|
||||||
|
|
||||||
import forge.ai.AiAbilityDecision;
|
import forge.ai.*;
|
||||||
import forge.ai.AiPlayDecision;
|
|
||||||
import forge.ai.ComputerUtilCard;
|
|
||||||
import forge.ai.SpellAbilityAi;
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardLists;
|
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.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
|
||||||
public class EarthbendAi extends SpellAbilityAi {
|
public class EarthbendAi extends SpellAbilityAi {
|
||||||
@Override
|
@Override
|
||||||
protected AiAbilityDecision canPlay(Player aiPlayer, SpellAbility sa) {
|
protected AiAbilityDecision canPlay(Player aiPlayer, SpellAbility sa) {
|
||||||
CardCollection nonAnimatedLands = CardLists.filter(aiPlayer.getLandsInPlay(), CardPredicates.NON_CREATURES);
|
CardCollection lands = aiPlayer.getLandsInPlay();
|
||||||
|
if (lands.isEmpty()) {
|
||||||
if (nonAnimatedLands.isEmpty()) {
|
|
||||||
return new AiAbilityDecision(0, AiPlayDecision.AnotherTime);
|
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);
|
Card tgtLand = null;
|
||||||
sa.getTargets().add(bestToAnimate);
|
|
||||||
|
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);
|
return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user