From 2c395068794fabe8b8a1d3aed6774b550d9184b4 Mon Sep 17 00:00:00 2001 From: Agetian Date: Sun, 22 Jan 2017 05:56:30 +0000 Subject: [PATCH] - Some crash prevention in ChangeTargetsAi, the AI needs further improvement here if we're to teach it to retarget spells with multiple targets. - Generalized ChangeTargetsAi not to mention Spellskite by name (so other creatures can gain its ability and be correctly used by the AI) and also not to use AI Logic and detect the ability via DefinedMagnet instead. - Marking Muck Drubb as AI playable. --- .../forge/ai/ability/ChangeTargetsAi.java | 28 ++++++++++++------- .../res/cardsfolder/m/mizzium_meddler.txt | 2 +- forge-gui/res/cardsfolder/m/muck_drubb.txt | 1 - forge-gui/res/cardsfolder/s/spellskite.txt | 2 +- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeTargetsAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeTargetsAi.java index cdedc23132e..b2300a95fa9 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChangeTargetsAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChangeTargetsAi.java @@ -6,6 +6,7 @@ import forge.ai.ComputerUtilMana; import forge.ai.SpellAbilityAi; import forge.card.mana.ManaCost; import forge.card.mana.ManaCostParser; +import forge.card.mana.ManaCostShard; import forge.game.Game; import forge.game.mana.ManaCostBeingPaid; import forge.game.player.Player; @@ -26,10 +27,8 @@ public class ChangeTargetsAi extends SpellAbilityAi { final Game game = sa.getHostCard().getGame(); final SpellAbility topSa = game.getStack().isEmpty() ? null : ComputerUtilAbility.getTopSpellAbilityOnStack(game, sa); - if (sa.hasParam("AILogic")) { - if ("SpellMagnet".equals(sa.getParam("AILogic"))) { - return doSpellMagnet(sa, topSa, aiPlayer); - } + if ("Self".equals(sa.getParam("DefinedMagnet"))) { + return doSpellMagnet(sa, topSa, aiPlayer); } // The AI can't otherwise play this ability, but should at least not miss mandatory activations (e.g. triggers). @@ -41,10 +40,8 @@ public class ChangeTargetsAi extends SpellAbilityAi { final Game game = sa.getHostCard().getGame(); final SpellAbility topSa = game.getStack().isEmpty() ? null : ComputerUtilAbility.getTopSpellAbilityOnStack(game, sa); - if (sa.hasParam("AILogic")) { - if ("SpellMagnet".equals(sa.getParam("AILogic"))) { - return doSpellMagnet(sa, topSa, aiPlayer); - } + if ("Self".equals(sa.getParam("DefinedMagnet"))) { + return doSpellMagnet(sa, topSa, aiPlayer); } return true; @@ -64,8 +61,18 @@ public class ChangeTargetsAi extends SpellAbilityAi { if (!topSa.usesTargeting() || topSa.getTargets().getTargetCards().contains(sa.getHostCard())) { // if this does not target at all or already targets host, no need to redirect it again + + // TODO: currently the AI does not know how to change several targets to the same object (e.g. + // Cone Flame) and will stupidly keep retargeting the first available target unless stopped here. + // Needs investigation and improvement. return false; } + if (topSa.getTargets().getNumTargeted() > 1 && topSa.hasParam("DividedAsYouChoose")) { + // TODO: currently the AI will crash the game if it tries to change the target of a SA with a + // divided allocation map. May need improvement. + return false; + } + if (topSa.getHostCard() != null && !topSa.getHostCard().getController().isOpponentOf(aiPlayer)) { // make sure not to redirect our own abilities return false; @@ -74,8 +81,9 @@ public class ChangeTargetsAi extends SpellAbilityAi { // don't try targeting it if we can't legally target the host card with it in the first place return false; } - - if ("Spellskite".equals(sa.getHostCard().getName())) { + + if (sa.getPayCosts().getCostMana() != null && "{P/U}".equals(sa.getPayCosts().getCostMana().getMana().getShortString())) { + // e.g. Spellskite or a creature receiving its ability that requires Phyrexian mana P/U int potentialDmg = ComputerUtil.predictDamageFromSpell(topSa, aiPlayer); boolean canPayBlue = ComputerUtilMana.canPayManaCost(new ManaCostBeingPaid(new ManaCost(new ManaCostParser("U"))), sa, aiPlayer); if (potentialDmg != -1 && potentialDmg <= 2 && !canPayBlue && topSa.getTargets().getTargets().contains(aiPlayer)) { diff --git a/forge-gui/res/cardsfolder/m/mizzium_meddler.txt b/forge-gui/res/cardsfolder/m/mizzium_meddler.txt index cbd3383e9bc..1f57db6735d 100644 --- a/forge-gui/res/cardsfolder/m/mizzium_meddler.txt +++ b/forge-gui/res/cardsfolder/m/mizzium_meddler.txt @@ -4,6 +4,6 @@ Types:Creature Vedalken Wizard PT:1/4 K:Flash T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChange | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may change a target of target spell or ability to CARDNAME. -SVar:TrigChange:AB$ ChangeTargets | Cost$ 0 | TargetType$ Spell,Activated,Triggered | ValidTgts$ Card | DefinedMagnet$ Self | ChangeSingleTarget$ True | AILogic$ SpellMagnet +SVar:TrigChange:AB$ ChangeTargets | Cost$ 0 | TargetType$ Spell,Activated,Triggered | ValidTgts$ Card | DefinedMagnet$ Self | ChangeSingleTarget$ True SVar:Picture:http://www.wizards.com/global/images/magic/general/mizzium_meddler.jpg Oracle:Flash (You may cast this spell any time you could cast an instant.)\nWhen Mizzium Meddler enters the battlefield, you may change a target of target spell or ability to Mizzium Meddler. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/m/muck_drubb.txt b/forge-gui/res/cardsfolder/m/muck_drubb.txt index 7f073aa2624..9f7c109094a 100644 --- a/forge-gui/res/cardsfolder/m/muck_drubb.txt +++ b/forge-gui/res/cardsfolder/m/muck_drubb.txt @@ -6,6 +6,5 @@ K:Flash T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChange | TriggerDescription$ When CARDNAME enters the battlefield, change the target of target spell that targets only a single creature to Muck Drubb. SVar:TrigChange:AB$ ChangeTargets | Cost$ 0 | TargetType$ Spell | ValidTgts$ Card | DefinedMagnet$ Self | TargetsSingleTarget$ True | TargetValidTargeting$ Creature K:Madness:2 B -SVar:RemAIDeck:True SVar:Picture:http://www.wizards.com/global/images/magic/general/muck_drubb.jpg Oracle:Flash (You may cast this spell any time you could cast an instant.)\nWhen Muck Drubb enters the battlefield, change the target of target spell that targets only a single creature to Muck Drubb.\nMadness {2}{B} (If you discard this card, you may cast it for its madness cost instead of putting it into your graveyard.) diff --git a/forge-gui/res/cardsfolder/s/spellskite.txt b/forge-gui/res/cardsfolder/s/spellskite.txt index 9abb587325a..1738e528d97 100644 --- a/forge-gui/res/cardsfolder/s/spellskite.txt +++ b/forge-gui/res/cardsfolder/s/spellskite.txt @@ -2,6 +2,6 @@ Name:Spellskite ManaCost:2 Types:Artifact Creature Horror PT:0/4 -A:AB$ ChangeTargets | Cost$ PU | TargetType$ Spell,Activated,Triggered | ValidTgts$ Card | DefinedMagnet$ Self | ChangeSingleTarget$ True | AILogic$ SpellMagnet | SpellDescription$ Change a target of target spell or ability to CARDNAME. +A:AB$ ChangeTargets | Cost$ PU | TargetType$ Spell,Activated,Triggered | ValidTgts$ Card | DefinedMagnet$ Self | ChangeSingleTarget$ True | SpellDescription$ Change a target of target spell or ability to CARDNAME. SVar:Picture:http://www.wizards.com/global/images/magic/general/spellskite.jpg Oracle:{P/U}: Change a target of target spell or ability to Spellskite. ({P/U} can be paid with either {U} or 2 life.)