- RemAIDeck update: next iteration (Last Rites, mostly for Reanimator).

This commit is contained in:
Agetian
2017-10-08 14:16:41 +00:00
parent faa8ca0b34
commit 9ee58451b5
3 changed files with 64 additions and 3 deletions

View File

@@ -865,6 +865,36 @@ public class AiController {
} else if ("VolrathsShapeshifter".equals(sa.getParam("AILogic"))) { } else if ("VolrathsShapeshifter".equals(sa.getParam("AILogic"))) {
return SpecialCardAi.VolrathsShapeshifter.targetBestCreature(player, sa); return SpecialCardAi.VolrathsShapeshifter.targetBestCreature(player, sa);
} }
if (sa.hasParam("AnyNumber")) {
if ("DiscardUncastableAndExcess".equals(sa.getParam("AILogic"))) {
// Note that at this point, there is no guarantee that the AI will discard specific cards found here,
// but since the AI generally discards things it doesn't need / can't immediately use, it's a relatively
// safe assumption that the follow-up discard action will be in line with what is considered here.
CardCollection discards = new CardCollection();
final CardCollectionView inHand = player.getCardsIn(ZoneType.Hand);
final int numLandsOTB = CardLists.filter(player.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS).size();
int numOppInHand = 0;
for (Player p : player.getGame().getPlayers()) {
if (p.getCardsIn(ZoneType.Hand).size() > numOppInHand) {
numOppInHand = p.getCardsIn(ZoneType.Hand).size();
}
}
for (Card c : inHand) {
if (c.hasSVar("DoNotDiscardIfAble") || c.hasSVar("IsReanimatorCard")) { continue; }
if (c.isCreature() && !ComputerUtilMana.hasEnoughManaSourcesToCast(c.getSpellPermanent(), player)) {
discards.add(c);
}
if ((c.isLand() && numLandsOTB >= 5) || (c.getFirstSpellAbility() != null && !ComputerUtilMana.hasEnoughManaSourcesToCast(c.getFirstSpellAbility(), player))) {
if (discards.size() + 1 <= numOppInHand) {
discards.add(c);
}
}
}
return discards;
}
}
} }
// look for good discards // look for good discards

View File

@@ -3,6 +3,9 @@ package forge.ai.ability;
import forge.ai.*; import forge.ai.*;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
@@ -98,7 +101,35 @@ public class DiscardAi extends SpellAbilityAi {
} }
} }
// TODO: Implement support for Discard AI for cards with AnyNumber set to true. // TODO: Improve support for Discard AI for cards with AnyNumber set to true.
if (sa.hasParam("AnyNumber")) {
if ("DiscardUncastableAndExcess".equals(aiLogic)) {
final CardCollectionView inHand = ai.getCardsIn(ZoneType.Hand);
final int numLandsOTB = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS).size();
int numDiscard = 0;
int numOppInHand = 0;
for (Player p : ai.getGame().getPlayers()) {
if (p.getCardsIn(ZoneType.Hand).size() > numOppInHand) {
numOppInHand = p.getCardsIn(ZoneType.Hand).size();
}
}
for (Card c : inHand) {
if (c.equals(sa.getHostCard())) { continue; }
if (c.hasSVar("DoNotDiscardIfAble") || c.hasSVar("IsReanimatorCard")) { continue; }
if (c.isCreature() && !ComputerUtilMana.hasEnoughManaSourcesToCast(c.getSpellPermanent(), ai)) {
numDiscard++;
}
if ((c.isLand() && numLandsOTB >= 5) || (c.getFirstSpellAbility() != null && !ComputerUtilMana.hasEnoughManaSourcesToCast(c.getFirstSpellAbility(), ai))) {
if (numDiscard + 1 <= numOppInHand) {
numDiscard++;
}
}
}
if (numDiscard == 0) {
return false;
}
}
}
// Don't use draw abilities before main 2 if possible // Don't use draw abilities before main 2 if possible
if (ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) if (ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)

View File

@@ -1,10 +1,10 @@
Name:Last Rites Name:Last Rites
ManaCost:2 B ManaCost:2 B
Types:Sorcery Types:Sorcery
A:SP$ Discard | Cost$ 2 B | AnyNumber$ True | Optional$ True | Mode$ TgtChoose | RememberDiscarded$ True | SubAbility$ DBLastRitesDiscard | SpellDescription$ Discard any number of cards. Target player reveals his or her hand, then you choose a nonland card from it for each card discarded this way. That player discards those cards. A:SP$ Discard | Cost$ 2 B | AnyNumber$ True | Optional$ True | Mode$ TgtChoose | RememberDiscarded$ True | SubAbility$ DBLastRitesDiscard | AILogic$ DiscardUncastableAndExcess | SpellDescription$ Discard any number of cards. Target player reveals his or her hand, then you choose a nonland card from it for each card discarded this way. That player discards those cards.
SVar:DBLastRitesDiscard:DB$ Discard | Mode$ RevealYouChoose | NumCards$ X | DiscardValid$ Card.nonLand | ValidTgts$ Opponent | References$ X SVar:DBLastRitesDiscard:DB$ Discard | Mode$ RevealYouChoose | NumCards$ X | DiscardValid$ Card.nonLand | ValidTgts$ Opponent | References$ X
SVar:DBLastRitesCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBLastRitesCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Remembered$Amount SVar:X:Remembered$Amount
SVar:RemAIDeck:True SVar:RemRandomDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/last_rites.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/last_rites.jpg
Oracle:Discard any number of cards. Target player reveals his or her hand, then you choose a nonland card from it for each card discarded this way. That player discards those cards. Oracle:Discard any number of cards. Target player reveals his or her hand, then you choose a nonland card from it for each card discarded this way. That player discards those cards.