- Basic AI logic components for Raiding Party.

This commit is contained in:
Michael Kamensky
2020-12-08 10:51:39 +03:00
parent 37149d43e9
commit 63beb045f9
4 changed files with 31 additions and 3 deletions

View File

@@ -1802,6 +1802,9 @@ public class AiController {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
CardCollection result = new CardCollection(); CardCollection result = new CardCollection();
if (sa.hasParam("AIMaxAmount")) {
max = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("AIMaxAmount"), sa);
}
switch(sa.getApi()) { switch(sa.getApi()) {
case TwoPiles: case TwoPiles:
// TODO: improve AI // TODO: improve AI

View File

@@ -130,6 +130,12 @@ public class ChooseCardAi extends SpellAbilityAi {
return (ComputerUtilCard.evaluateCreatureList(aiCreatures) + minGain) < ComputerUtilCard return (ComputerUtilCard.evaluateCreatureList(aiCreatures) + minGain) < ComputerUtilCard
.evaluateCreatureList(oppCreatures); .evaluateCreatureList(oppCreatures);
} else if (aiLogic.equals("OwnCard")) {
CardCollectionView ownChoices = CardLists.filter(choices, CardPredicates.isController(ai));
if (ownChoices.isEmpty()) {
ownChoices = CardLists.filter(choices, CardPredicates.isControlledByAnyOf(ai.getAllies()));
}
return !ownChoices.isEmpty();
} }
return true; return true;
} }
@@ -156,6 +162,12 @@ public class ChooseCardAi extends SpellAbilityAi {
choice = ComputerUtilCard.getBestAI(options); choice = ComputerUtilCard.getBestAI(options);
} else if ("WorstCard".equals(logic)) { } else if ("WorstCard".equals(logic)) {
choice = ComputerUtilCard.getWorstAI(options); choice = ComputerUtilCard.getWorstAI(options);
} else if ("OwnCard".equals(logic)) {
CardCollectionView ownChoices = CardLists.filter(options, CardPredicates.isController(ai));
if (ownChoices.isEmpty()) {
ownChoices = CardLists.filter(options, CardPredicates.isControlledByAnyOf(ai.getAllies()));
}
choice = ComputerUtilCard.getBestAI(ownChoices);
} else if (logic.equals("BestBlocker")) { } else if (logic.equals("BestBlocker")) {
if (!CardLists.filter(options, Presets.UNTAPPED).isEmpty()) { if (!CardLists.filter(options, Presets.UNTAPPED).isEmpty()) {
options = CardLists.filter(options, Presets.UNTAPPED); options = CardLists.filter(options, Presets.UNTAPPED);

View File

@@ -2,10 +2,14 @@ package forge.ai.ability;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import forge.ai.*; import forge.ai.*;
import forge.card.MagicColor;
import forge.game.ability.AbilityUtils;
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.Cost;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
@@ -106,6 +110,14 @@ public class DestroyAllAi extends SpellAbilityAi {
} }
} }
// Special handling for Raiding Party
if (logic.equals("RaidingParty")) {
int numAiCanSave = Math.min(CardLists.filter(ai.getCreaturesInPlay(), Predicates.and(CardPredicates.isColor(MagicColor.WHITE), CardPredicates.Presets.UNTAPPED)).size() * 2, ailist.size());
int numOppsCanSave = Math.min(CardLists.filter(ai.getOpponents().getCreaturesInPlay(), Predicates.and(CardPredicates.isColor(MagicColor.WHITE), CardPredicates.Presets.UNTAPPED)).size() * 2, opplist.size());
return numOppsCanSave < opplist.size() && (ailist.size() - numAiCanSave < opplist.size() - numOppsCanSave);
}
// If effect is destroying creatures and AI is about to lose, activate effect anyway no matter what! // If effect is destroying creatures and AI is about to lose, activate effect anyway no matter what!
if ((!CardLists.getType(opplist, "Creature").isEmpty()) && (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) if ((!CardLists.getType(opplist, "Creature").isEmpty()) && (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS))
&& (ai.getGame().getCombat() != null && ComputerUtilCombat.lifeInSeriousDanger(ai, ai.getGame().getCombat()))) { && (ai.getGame().getCombat() != null && ComputerUtilCombat.lifeInSeriousDanger(ai, ai.getGame().getCombat()))) {

View File

@@ -3,14 +3,15 @@ ManaCost:2 R
Types:Enchantment Types:Enchantment
S:Mode$ CantTarget | ValidCard$ Card.Self | ValidSource$ Card.White | Description$ CARDNAME can't be the target of white spells or abilities from white sources. S:Mode$ CantTarget | ValidCard$ Card.Self | ValidSource$ Card.White | Description$ CARDNAME can't be the target of white spells or abilities from white sources.
A:AB$ RepeatEach | Cost$ Sac<1/Orc/Orc> | CostDesc$ Sacrifice an Orc: | RepeatPlayers$ Player | RepeatSubAbility$ ChooseCardsToTap | SubAbility$ DBDestroy | SpellDescription$ Each player may tap any number of untapped white creatures they control. For each creature tapped this way, that player chooses up to two Plains. Then destroy all Plains that werent chosen this way by any player. A:AB$ RepeatEach | Cost$ Sac<1/Orc/Orc> | CostDesc$ Sacrifice an Orc: | RepeatPlayers$ Player | RepeatSubAbility$ ChooseCardsToTap | SubAbility$ DBDestroy | SpellDescription$ Each player may tap any number of untapped white creatures they control. For each creature tapped this way, that player chooses up to two Plains. Then destroy all Plains that werent chosen this way by any player.
SVar:ChooseCardsToTap:DB$ ChooseCard | Defined$ Remembered | MinAmount$ 0 | Amount$ NumCreatures | References$ NumCreatures | Choices$ Creature.untapped+White+RememberedPlayerCtrl | ChoiceTitle$ Choose any number of untapped white creatures you control | ChoiceZone$ Battlefield | RememberChosen$ True | SubAbility$ DBTap SVar:ChooseCardsToTap:DB$ ChooseCard | Defined$ Remembered | MinAmount$ 0 | Amount$ NumCreatures | References$ NumCreatures,NumPlainsDiv2 | Choices$ Creature.untapped+White+RememberedPlayerCtrl | ChoiceTitle$ Choose any number of untapped white creatures you control | ChoiceZone$ Battlefield | RememberChosen$ True | AIMaxAmount$ NumPlainsDiv2 | SubAbility$ DBTap
SVar:DBTap:DB$ Tap | Defined$ Remembered | SubAbility$ ChoosePlainsToSave SVar:DBTap:DB$ Tap | Defined$ Remembered | SubAbility$ ChoosePlainsToSave
SVar:ChoosePlainsToSave:DB$ ChooseCard | Defined$ Remembered | MinAmount$ 0 | Amount$ TappedXTwo | References$ TappedXTwo | Choices$ Plains | ChoiceTitle$ Choose up to two Plains for each creature tapped | ChoiceZone$ Battlefield | ImprintChosen$ True | SubAbility$ DBCleanup SVar:ChoosePlainsToSave:DB$ ChooseCard | Defined$ Remembered | MinAmount$ 0 | Amount$ TappedXTwo | References$ TappedXTwo | Choices$ Plains | ChoiceTitle$ Choose up to two Plains for each creature tapped | ChoiceZone$ Battlefield | ImprintChosen$ True | AILogic$ OwnCard | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True
SVar:DBDestroy:DB$ DestroyAll | ValidCards$ Plains.IsNotImprinted | SubAbility$ DBCleanImp | StackDescription$ None SVar:DBDestroy:DB$ DestroyAll | ValidCards$ Plains.IsNotImprinted | SubAbility$ DBCleanImp | AILogic$ RaidingParty | StackDescription$ None
SVar:DBCleanImp:DB$ Cleanup | ClearImprinted$ True SVar:DBCleanImp:DB$ Cleanup | ClearImprinted$ True
SVar:NumCreatures:Count$Valid Creature.untapped+White+RememberedPlayerCtrl SVar:NumCreatures:Count$Valid Creature.untapped+White+RememberedPlayerCtrl
SVar:TappedXTwo:Count$Valid Creature.IsRemembered/Times.2 SVar:TappedXTwo:Count$Valid Creature.IsRemembered/Times.2
SVar:NumPlainsDiv2:Count$Valid Plains.YouCtrl/HalfUp
AI:RemoveDeck:Random AI:RemoveDeck:Random
SVar:NeedsToPlay:Plains.OppCtrl SVar:NeedsToPlay:Plains.OppCtrl
DeckNeeds:Type$Orc DeckNeeds:Type$Orc