diff --git a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java index 43fc4fe3f36..dbf89788c62 100644 --- a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java +++ b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java @@ -180,6 +180,31 @@ public class SpecialCardAi { } } + // Dark Ritual and other similar instants/sorceries that add mana to mana pool + public static class DarkRitualOrSimilar { + public static boolean consider(Player ai, SpellAbility sa) { + PhaseHandler ph = ai.getGame().getPhaseHandler(); + + if (!(ph.getPlayerTurn().equals(ai) && ph.is(PhaseType.MAIN2))) { + return false; + } + + CardCollection manaSources = ComputerUtilMana.getAvailableMana(ai, true); + int numManaSrcs = manaSources.size(); + int manaReceived = Integer.parseInt(sa.getParam("Amount")); + int selfCost = sa.getPayCosts().getCostMana() != null ? sa.getPayCosts().getCostMana().getMana().getCMC() : 0; + byte producedColor = MagicColor.fromName(sa.getParam("Produced")); + + // try to determine the number of permanents we can cast with this + int numPerms = CardLists.filter(ai.getCardsIn(ZoneType.Hand), + Predicates.and(CardPredicates.Presets.NONLAND_PERMANENTS, CardPredicates.lessCMC(numManaSrcs - selfCost + manaReceived), + Predicates.or(CardPredicates.isColorless(), CardPredicates.isColor(producedColor)))).size(); + + // TODO: this will probably still waste the card from time to time. Somehow improve detection of castable material. + return numPerms > 0; + } + } + // Desecration Demon public static class DesecrationDemon { private static final int demonSacThreshold = Integer.MAX_VALUE; // if we're in dire conditions, sac everything from worst to best hoping to find an answer diff --git a/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java b/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java index f18fe588744..cea148946dd 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java @@ -2,6 +2,7 @@ package forge.ai.ability; import forge.ai.ComputerUtil; +import forge.ai.SpecialCardAi; import forge.ai.SpellAbilityAi; import forge.game.phase.PhaseType; import forge.game.player.Player; @@ -11,6 +12,9 @@ public class ManaEffectAi extends SpellAbilityAi { @Override protected boolean canPlayAI(Player ai, SpellAbility sa) { + if ("ManaRitual".equals(sa.getParam("AILogic"))) { + return SpecialCardAi.DarkRitualOrSimilar.consider(ai, sa); + } if (ai.getGame().getPhaseHandler().is(PhaseType.MAIN2) && ComputerUtil.activateForCost(sa, ai)) { return true; } diff --git a/forge-game/src/main/java/forge/game/card/CardPredicates.java b/forge-game/src/main/java/forge/game/card/CardPredicates.java index 920f25a9bed..d3d0e83406f 100644 --- a/forge-game/src/main/java/forge/game/card/CardPredicates.java +++ b/forge-game/src/main/java/forge/game/card/CardPredicates.java @@ -218,6 +218,15 @@ public final class CardPredicates { }; } // getColor() + public static final Predicate isColorless() { + return new Predicate() { + @Override + public boolean apply(final Card c) { + return CardUtil.getColors(c).isColorless(); + } + }; + } + public static final Predicate isEquippedBy(final String name) { return new Predicate() { @Override @@ -463,6 +472,24 @@ public final class CardPredicates { return c.isLand(); } }; + /** + * a Predicate to get all permanents. + */ + public static final Predicate PERMANENTS = new Predicate() { + @Override + public boolean apply(Card c) { + return c.isPermanent(); + } + }; + /** + * a Predicate to get all nonland permanents. + */ + public static final Predicate NONLAND_PERMANENTS = new Predicate() { + @Override + public boolean apply(Card c) { + return c.isPermanent() && !c.isLand(); + } + }; public static final Predicate hasFirstStrike = new Predicate() { @Override diff --git a/forge-gui/res/cardsfolder/d/dark_ritual.txt b/forge-gui/res/cardsfolder/d/dark_ritual.txt index 4f03d5ffa76..d6b13c145e7 100644 --- a/forge-gui/res/cardsfolder/d/dark_ritual.txt +++ b/forge-gui/res/cardsfolder/d/dark_ritual.txt @@ -1,7 +1,6 @@ Name:Dark Ritual ManaCost:B Types:Instant -A:SP$ Mana | Cost$ B | Produced$ B | Amount$ 3 | SpellDescription$ Add {B}{B}{B} to your mana pool. -SVar:RemAIDeck:True +A:SP$ Mana | Cost$ B | Produced$ B | Amount$ 3 | AILogic$ ManaRitual | SpellDescription$ Add {B}{B}{B} to your mana pool. SVar:Picture:http://www.wizards.com/global/images/magic/general/dark_ritual.jpg Oracle:Add {B}{B}{B} to your mana pool.