Merge branch 'master' into 'master'

Basic AI logic components for Raiding Party.

See merge request core-developers/forge!3500
This commit is contained in:
Michael Kamensky
2020-12-08 07:53:24 +00:00
4 changed files with 31 additions and 3 deletions

View File

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

View File

@@ -130,6 +130,12 @@ public class ChooseCardAi extends SpellAbilityAi {
return (ComputerUtilCard.evaluateCreatureList(aiCreatures) + minGain) < ComputerUtilCard
.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;
}
@@ -156,6 +162,12 @@ public class ChooseCardAi extends SpellAbilityAi {
choice = ComputerUtilCard.getBestAI(options);
} else if ("WorstCard".equals(logic)) {
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")) {
if (!CardLists.filter(options, Presets.UNTAPPED).isEmpty()) {
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.Predicates;
import forge.ai.*;
import forge.card.MagicColor;
import forge.game.ability.AbilityUtils;
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.keyword.Keyword;
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 ((!CardLists.getType(opplist, "Creature").isEmpty()) && (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS))
&& (ai.getGame().getCombat() != null && ComputerUtilCombat.lifeInSeriousDanger(ai, ai.getGame().getCombat()))) {

View File

@@ -3,14 +3,15 @@ ManaCost:2 R
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.
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: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: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:NumCreatures:Count$Valid Creature.untapped+White+RememberedPlayerCtrl
SVar:TappedXTwo:Count$Valid Creature.IsRemembered/Times.2
SVar:NumPlainsDiv2:Count$Valid Plains.YouCtrl/HalfUp
AI:RemoveDeck:Random
SVar:NeedsToPlay:Plains.OppCtrl
DeckNeeds:Type$Orc