mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
- Refactored AI logic for cards like Goblin Dark-Dwellers and Snapcaster Mage.
- Rewired AI logic for Goblin Dark-Dwellers to work with the new card implementation.
This commit is contained in:
@@ -2636,4 +2636,34 @@ public class ComputerUtil {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean targetPlayableSpellCard(final Player ai, CardCollection options, final SpellAbility sa, final boolean withoutPayingManaCost) {
|
||||
// determine and target a card with a SA that the AI can afford and will play
|
||||
AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
|
||||
Card targetSpellCard = null;
|
||||
for (Card c : options) {
|
||||
for (SpellAbility ab : c.getSpellAbilities()) {
|
||||
if (ab.getApi() == null) {
|
||||
// only API-based SAs are supported, other things may lead to a NPE (e.g. Ancestral Vision Suspend SA)
|
||||
continue;
|
||||
}
|
||||
SpellAbility abTest = withoutPayingManaCost ? ab.copyWithNoManaCost() : ab.copy();
|
||||
// at this point, we're assuming that card will be castable from whichever zone it's in by the AI player.
|
||||
abTest.setActivatingPlayer(ai);
|
||||
abTest.getRestrictions().setZone(c.getZone().getZoneType());
|
||||
final boolean play = AiPlayDecision.WillPlay == aic.canPlaySa(abTest);
|
||||
final boolean pay = ComputerUtilCost.canPayCost(abTest, ai);
|
||||
if (play && pay) {
|
||||
targetSpellCard = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetSpellCard == null) {
|
||||
return false;
|
||||
} else {
|
||||
sa.getTargets().add(targetSpellCard);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ package forge.ai.ability;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.ai.AiController;
|
||||
|
||||
import forge.ai.AiPlayDecision;
|
||||
import forge.ai.ComputerUtil;
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.ComputerUtilCost;
|
||||
import forge.ai.PlayerControllerAi;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import forge.game.Game;
|
||||
@@ -68,7 +70,34 @@ public class PlayAi extends SpellAbilityAi {
|
||||
*/
|
||||
@Override
|
||||
protected boolean doTriggerAINoCost(final Player ai, final SpellAbility sa, final boolean mandatory) {
|
||||
final Card source = sa.getHostCard();
|
||||
final Game game = ai.getGame();
|
||||
|
||||
// general logic (no AILogic specified)
|
||||
if (sa.usesTargeting()) {
|
||||
if (!sa.hasParam("AILogic")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CardCollection cards = null;
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
if (tgt != null) {
|
||||
ZoneType zone = tgt.getZone().get(0);
|
||||
cards = CardLists.getValidCards(game.getCardsIn(zone), tgt.getValidTgts(), ai, source, sa);
|
||||
if (cards.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
} else if (!sa.hasParam("Valid")) {
|
||||
cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa);
|
||||
if (cards.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ("PlayWithNoManaCost".equals(sa.getParam("AILogic"))) {
|
||||
return ComputerUtil.targetPlayableSpellCard(ai, cards, sa, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -478,11 +478,7 @@ public class PumpAi extends PumpAiBase {
|
||||
}
|
||||
|
||||
if ("Snapcaster".equals(sa.getParam("AILogic"))) {
|
||||
if (!doTargetSpellToPlayLogic(ai, list, sa, false)) {
|
||||
return false;
|
||||
}
|
||||
} else if ("PlaySpellForFree".equals(sa.getParam("AILogic"))) {
|
||||
if (!doTargetSpellToPlayLogic(ai, list, sa, true)) {
|
||||
if (!ComputerUtil.targetPlayableSpellCard(ai, list, sa, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -520,36 +516,6 @@ public class PumpAi extends PumpAiBase {
|
||||
return true;
|
||||
} // pumpTgtAI()
|
||||
|
||||
private boolean doTargetSpellToPlayLogic(final Player ai, CardCollection options, final SpellAbility sa, final boolean withoutPayingManaCost) {
|
||||
// determine and target a card with a SA that the AI can afford and will play
|
||||
AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
|
||||
Card targetSpellCard = null;
|
||||
for (Card c : options) {
|
||||
for (SpellAbility ab : c.getSpellAbilities()) {
|
||||
if (ab.getApi() == null) {
|
||||
// only API-based SAs are supported, other things may lead to a NPE (e.g. Ancestral Vision Suspend SA)
|
||||
continue;
|
||||
}
|
||||
SpellAbility abTest = withoutPayingManaCost ? ab.copyWithNoManaCost() : ab.copy();
|
||||
// at this point, we're assuming that card will be castable from whichever zone it's in by the AI player.
|
||||
abTest.setActivatingPlayer(ai);
|
||||
abTest.getRestrictions().setZone(c.getZone().getZoneType());
|
||||
final boolean play = AiPlayDecision.WillPlay == aic.canPlaySa(abTest);
|
||||
final boolean pay = ComputerUtilCost.canPayCost(abTest, ai);
|
||||
if (play && pay) {
|
||||
targetSpellCard = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetSpellCard == null) {
|
||||
return false;
|
||||
} else {
|
||||
sa.getTargets().add(targetSpellCard);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean pumpMandatoryTarget(final Player ai, final SpellAbility sa) {
|
||||
final Game game = ai.getGame();
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
|
||||
@@ -4,6 +4,6 @@ Types:Creature Goblin
|
||||
PT:4/4
|
||||
K:Menace
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPlay | TriggerDescription$ When CARDNAME enters the battlefield, you may cast target instant or sorcery card with converted mana cost 3 or less from your graveyard without paying its mana cost. If that card would be put into your graveyard this turn, exile it instead.
|
||||
SVar:TrigPlay:DB$ Play | TgtZone$ Graveyard | ValidTgts$ Instant.YouCtrl+cmcLE3,Sorcery.YouCtrl+cmcLE3 | TgtPrompt$ Choose target instant or sorcery card with converted mana cost 3 or less from your graveyard | WithoutManaCost$ True | Optional$ True | ReplaceGraveyard$ Exile
|
||||
SVar:TrigPlay:DB$ Play | TgtZone$ Graveyard | ValidTgts$ Instant.YouCtrl+cmcLE3,Sorcery.YouCtrl+cmcLE3 | TgtPrompt$ Choose target instant or sorcery card with converted mana cost 3 or less from your graveyard | WithoutManaCost$ True | Optional$ True | ReplaceGraveyard$ Exile | AILogic$ PlayWithNoManaCost
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/goblin_dark_dwellers.jpg
|
||||
Oracle:Menace\nWhen Goblin Dark-Dwellers enters the battlefield, you may cast target instant or sorcery card with converted mana cost 3 or less from your graveyard without paying its mana cost. If that card would be put into your graveyard this turn, exile it instead.
|
||||
|
||||
Reference in New Issue
Block a user