mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 11:48:02 +00:00
- 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:
@@ -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
|
// Desecration Demon
|
||||||
public static class DesecrationDemon {
|
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
|
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
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package forge.ai.ability;
|
|||||||
|
|
||||||
|
|
||||||
import forge.ai.ComputerUtil;
|
import forge.ai.ComputerUtil;
|
||||||
|
import forge.ai.SpecialCardAi;
|
||||||
import forge.ai.SpellAbilityAi;
|
import forge.ai.SpellAbilityAi;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -11,6 +12,9 @@ public class ManaEffectAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canPlayAI(Player ai, SpellAbility sa) {
|
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)) {
|
if (ai.getGame().getPhaseHandler().is(PhaseType.MAIN2) && ComputerUtil.activateForCost(sa, ai)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,6 +218,15 @@ public final class CardPredicates {
|
|||||||
};
|
};
|
||||||
} // getColor()
|
} // 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) {
|
public static final Predicate<Card> isEquippedBy(final String name) {
|
||||||
return new Predicate<Card>() {
|
return new Predicate<Card>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -463,6 +472,24 @@ public final class CardPredicates {
|
|||||||
return c.isLand();
|
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>() {
|
public static final Predicate<Card> hasFirstStrike = new Predicate<Card>() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
Name:Dark Ritual
|
Name:Dark Ritual
|
||||||
ManaCost:B
|
ManaCost:B
|
||||||
Types:Instant
|
Types:Instant
|
||||||
A:SP$ Mana | Cost$ B | Produced$ B | Amount$ 3 | SpellDescription$ Add {B}{B}{B} to your mana pool.
|
A:SP$ Mana | Cost$ B | Produced$ B | Amount$ 3 | AILogic$ ManaRitual | SpellDescription$ Add {B}{B}{B} to your mana pool.
|
||||||
SVar:RemAIDeck:True
|
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/dark_ritual.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/dark_ritual.jpg
|
||||||
Oracle:Add {B}{B}{B} to your mana pool.
|
Oracle:Add {B}{B}{B} to your mana pool.
|
||||||
|
|||||||
Reference in New Issue
Block a user