diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index 2dabc751d06..b54c6344cbb 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -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 diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java index f8a48d2ec25..461e6b2e60c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java @@ -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); diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java index 9a837bc1601..4a7c80ccdd8 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java @@ -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()))) { diff --git a/forge-gui/res/cardsfolder/r/raiding_party.txt b/forge-gui/res/cardsfolder/r/raiding_party.txt index 7c1a88b1095..66bf60c1755 100644 --- a/forge-gui/res/cardsfolder/r/raiding_party.txt +++ b/forge-gui/res/cardsfolder/r/raiding_party.txt @@ -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 weren’t 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