- Implemented some rudimentary mana ritual AI.

- Marked Dark Ritual as AI-playable. Other similar cards can probably now also use AI ManaRitual for this purpose.
This commit is contained in:
Agetian
2017-01-23 11:41:51 +00:00
parent 8447c6cda6
commit e5acf1fa15
4 changed files with 57 additions and 2 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -218,6 +218,15 @@ public final class CardPredicates {
};
} // getColor()
public static final Predicate<Card> isColorless() {
return new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CardUtil.getColors(c).isColorless();
}
};
}
public static final Predicate<Card> isEquippedBy(final String name) {
return new Predicate<Card>() {
@Override
@@ -463,6 +472,24 @@ public final class CardPredicates {
return c.isLand();
}
};
/**
* a Predicate<Card> to get all permanents.
*/
public static final Predicate<Card> PERMANENTS = new Predicate<Card>() {
@Override
public boolean apply(Card c) {
return c.isPermanent();
}
};
/**
* a Predicate<Card> to get all nonland permanents.
*/
public static final Predicate<Card> NONLAND_PERMANENTS = new Predicate<Card>() {
@Override
public boolean apply(Card c) {
return c.isPermanent() && !c.isLand();
}
};
public static final Predicate<Card> hasFirstStrike = new Predicate<Card>() {
@Override

View File

@@ -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.