From a168875f3773e2e7cdd329aba3cf48a103f6c063 Mon Sep 17 00:00:00 2001 From: Agetian Date: Thu, 5 Jan 2017 16:16:42 +0000 Subject: [PATCH] - Added Chain of Smog with basic AI support when the player casts it targeting AI, it will only continue the chain if it ends up having no cards in hand. The AI itself currently does not know when/how to time it properly when casting it from hand (will always cast it), --- .gitattributes | 2 + .../src/main/java/forge/ai/SpellApiToAi.java | 2 +- .../forge/ai/ability/CopySpellAbilityAi.java | 55 +++++++++++++++++++ forge-gui/res/cardsfolder/c/chain_of_smog.txt | 9 +++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 forge-ai/src/main/java/forge/ai/ability/CopySpellAbilityAi.java create mode 100644 forge-gui/res/cardsfolder/c/chain_of_smog.txt diff --git a/.gitattributes b/.gitattributes index e1c4e0616d5..6aabcb7ea76 100644 --- a/.gitattributes +++ b/.gitattributes @@ -65,6 +65,7 @@ forge-ai/src/main/java/forge/ai/ability/CloneAi.java -text forge-ai/src/main/java/forge/ai/ability/ControlExchangeAi.java -text forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java -text forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java -text +forge-ai/src/main/java/forge/ai/ability/CopySpellAbilityAi.java -text forge-ai/src/main/java/forge/ai/ability/CounterAi.java -text forge-ai/src/main/java/forge/ai/ability/CountersAi.java svneol=native#text/plain forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java -text @@ -3565,6 +3566,7 @@ forge-gui/res/cardsfolder/c/ceta_sanctuary.txt svneol=native#text/plain forge-gui/res/cardsfolder/c/cetavolver.txt -text forge-gui/res/cardsfolder/c/chain_lightning.txt -text forge-gui/res/cardsfolder/c/chain_of_plasma.txt -text +forge-gui/res/cardsfolder/c/chain_of_smog.txt -text forge-gui/res/cardsfolder/c/chain_of_vapor.txt -text forge-gui/res/cardsfolder/c/chain_reaction.txt svneol=native#text/plain forge-gui/res/cardsfolder/c/chain_stasis.txt -text diff --git a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java index f223935686e..5a38913f3ab 100644 --- a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java @@ -45,7 +45,7 @@ public enum SpellApiToAi { .put(ApiType.Cleanup, AlwaysPlayAi.class) .put(ApiType.Clone, CloneAi.class) .put(ApiType.CopyPermanent, CopyPermanentAi.class) - .put(ApiType.CopySpellAbility, CanPlayAsDrawbackAi.class) + .put(ApiType.CopySpellAbility, CopySpellAbilityAi.class) .put(ApiType.ControlPlayer, CannotPlayAi.class) .put(ApiType.ControlSpell, CannotPlayAi.class) .put(ApiType.Counter, CounterAi.class) diff --git a/forge-ai/src/main/java/forge/ai/ability/CopySpellAbilityAi.java b/forge-ai/src/main/java/forge/ai/ability/CopySpellAbilityAi.java new file mode 100644 index 00000000000..7a7f74935fa --- /dev/null +++ b/forge-ai/src/main/java/forge/ai/ability/CopySpellAbilityAi.java @@ -0,0 +1,55 @@ +package forge.ai.ability; + +import forge.ai.SpellAbilityAi; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; +import forge.game.zone.ZoneType; + +import java.util.List; + +public class CopySpellAbilityAi extends SpellAbilityAi { + + @Override + protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) { + return false; + } + + @Override + protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) { + return false; + } + + @Override + public boolean chkAIDrawback(final SpellAbility sa, final Player aiPlayer) { + // NOTE: Other SAs that use CopySpellAbilityAi (e.g. Chain Lightning) are currently routed through + // generic method SpellAbilityAi#chkDrawbackWithSubs and are handled there. + + if ("ChainOfSmog".equals(sa.getParam("AILogic"))) { + if (aiPlayer.getCardsIn(ZoneType.Hand).size() == 0) { + // avoid failure to add to stack by providing a legal target + // TODO: this makes the AI target opponents with 0 cards in hand, but bailing from here causes a + // "failed to add to stack" error, needs investigation and improvement. + Player targOpp = aiPlayer.getOpponent(); + + for (Player opp : aiPlayer.getOpponents()) { + if (opp.getCardsIn(ZoneType.Hand).size() > 0) { + targOpp = opp; + break; + } + } + + sa.getParent().resetTargets(); + sa.getParent().getTargets().add(targOpp); + return true; + } + } + + return super.chkAIDrawback(sa, aiPlayer); + } + + @Override + public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells) { + return spells.get(0); + } +} + diff --git a/forge-gui/res/cardsfolder/c/chain_of_smog.txt b/forge-gui/res/cardsfolder/c/chain_of_smog.txt new file mode 100644 index 00000000000..ad0ca8a35c1 --- /dev/null +++ b/forge-gui/res/cardsfolder/c/chain_of_smog.txt @@ -0,0 +1,9 @@ +Name:Chain of Smog +ManaCost:1 B +Types:Sorcery +A:SP$ Discard | Cost$ 1 B | ValidTgts$ Player | NumCards$ 2 | Mode$ TgtChoose | SubAbility$ DBCopy | SpellDescription$ Target player discards two cards. That player may copy this spell and may choose a new target for that copy. +SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedPlayer | AILogic$ ChainOfSmog | StackDescription$ None +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/chain_of_smog.jpg +Oracle:Target player discards two cards. That player may copy this spell and may choose a new target for that copy. +