From 17a922ae5a0922783256496349b828c95ff71f1f Mon Sep 17 00:00:00 2001 From: Agetian Date: Wed, 5 Dec 2018 21:30:21 +0300 Subject: [PATCH 1/5] - Basic logic for fake counter move on Spikes from Tempest. --- .../java/forge/ai/ability/CountersPutAi.java | 35 ++++++++++++++++++- forge-gui/res/cardsfolder/s/spike_breeder.txt | 2 +- forge-gui/res/cardsfolder/s/spike_colony.txt | 2 +- forge-gui/res/cardsfolder/s/spike_drone.txt | 2 +- forge-gui/res/cardsfolder/s/spike_feeder.txt | 2 +- forge-gui/res/cardsfolder/s/spike_hatcher.txt | 2 +- forge-gui/res/cardsfolder/s/spike_rogue.txt | 2 +- forge-gui/res/cardsfolder/s/spike_soldier.txt | 2 +- forge-gui/res/cardsfolder/s/spike_tiller.txt | 2 +- forge-gui/res/cardsfolder/s/spike_weaver.txt | 2 +- forge-gui/res/cardsfolder/s/spike_worker.txt | 2 +- 11 files changed, 44 insertions(+), 11 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java index 920146771ff..e494dbb4179 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java @@ -11,6 +11,7 @@ import forge.game.GameEntity; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.card.*; +import forge.game.combat.Combat; import forge.game.combat.CombatUtil; import forge.game.cost.*; import forge.game.keyword.Keyword; @@ -43,6 +44,8 @@ public class CountersPutAi extends SpellAbilityAi { protected boolean willPayCosts(Player ai, SpellAbility sa, Cost cost, Card source) { final String type = sa.getParam("CounterType"); + final String aiLogic = sa.getParamOrDefault("AILogic", ""); + // TODO Auto-generated method stub if (!super.willPayCosts(ai, sa, cost, source)) { return false; @@ -53,7 +56,7 @@ public class CountersPutAi extends SpellAbilityAi { if (part instanceof CostRemoveCounter) { final CostRemoveCounter remCounter = (CostRemoveCounter) part; final CounterType counterType = remCounter.counter; - if (counterType.name().equals(type)) { + if (counterType.name().equals(type) && !aiLogic.startsWith("MoveCounter")) { return false; } if (!part.payCostFromSource()) { @@ -279,6 +282,36 @@ public class CountersPutAi extends SpellAbilityAi { if (!source.canTransform()) { return false; } + } else if (logic.equals("MoveCounterSpike")) { + // Spikes (Tempest) + + // Try not to do it unless at the end of opponent's turn or the creature is threatened + Combat combat = ai.getGame().getCombat(); + boolean threatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard()); + + if (!(threatened || (ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai))) { + return false; + } + + CardCollection targets = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa); + targets.remove(sa.getHostCard()); + + targets = CardLists.filter(targets, new Predicate() { + @Override + public boolean apply(Card card) { + // when threatened, any target is good to preserve the counter + return threatened || ComputerUtilCard.evaluateCreature(card, false, false) > ComputerUtilCard.evaluateCreature(sa.getHostCard(), false, false); + } + }); + + Card bestTgt = ComputerUtilCard.getBestCreatureAI(targets); + + if (bestTgt != null) { + sa.getTargets().add(bestTgt); + return true; + } + + return false; } if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) { diff --git a/forge-gui/res/cardsfolder/s/spike_breeder.txt b/forge-gui/res/cardsfolder/s/spike_breeder.txt index 68bc18a3bd2..ed8a550c3ff 100644 --- a/forge-gui/res/cardsfolder/s/spike_breeder.txt +++ b/forge-gui/res/cardsfolder/s/spike_breeder.txt @@ -3,7 +3,7 @@ ManaCost:3 G Types:Creature Spike PT:0/0 K:etbCounter:P1P1:3 -A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature. +A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | AILogic$ MoveCounterSpike | SpellDescription$ Put a +1/+1 counter on target creature. A:AB$ Token | Cost$ 2 SubCounter<1/P1P1> | TokenAmount$ 1 | TokenName$ Spike | TokenTypes$ Creature,Spike | TokenOwner$ You | TokenColors$ Green | TokenPower$ 1 | TokenToughness$ 1 | SpellDescription$ Create a 1/1 green Spike creature token. SVar:Picture:http://www.wizards.com/global/images/magic/general/spike_breeder.jpg Oracle:Spike Breeder enters the battlefield with three +1/+1 counters on it.\n{2}, Remove a +1/+1 counter from Spike Breeder: Put a +1/+1 counter on target creature.\n{2}, Remove a +1/+1 counter from Spike Breeder: Create a 1/1 green Spike creature token. diff --git a/forge-gui/res/cardsfolder/s/spike_colony.txt b/forge-gui/res/cardsfolder/s/spike_colony.txt index dfb1573e10f..afcd2b32c48 100644 --- a/forge-gui/res/cardsfolder/s/spike_colony.txt +++ b/forge-gui/res/cardsfolder/s/spike_colony.txt @@ -3,6 +3,6 @@ ManaCost:4 G Types:Creature Spike PT:0/0 K:etbCounter:P1P1:4 -A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature. +A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | AILogic$ MoveCounterSpike | SpellDescription$ Put a +1/+1 counter on target creature. SVar:Picture:http://www.wizards.com/global/images/magic/general/spike_colony.jpg Oracle:Spike Colony enters the battlefield with four +1/+1 counters on it.\n{2}, Remove a +1/+1 counter from Spike Colony: Put a +1/+1 counter on target creature. diff --git a/forge-gui/res/cardsfolder/s/spike_drone.txt b/forge-gui/res/cardsfolder/s/spike_drone.txt index 3e06e6ca6f4..511c6892116 100644 --- a/forge-gui/res/cardsfolder/s/spike_drone.txt +++ b/forge-gui/res/cardsfolder/s/spike_drone.txt @@ -3,6 +3,6 @@ ManaCost:G Types:Creature Spike Drone PT:0/0 K:etbCounter:P1P1:1 -A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature. +A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | AILogic$ MoveCounterSpike | SpellDescription$ Put a +1/+1 counter on target creature. SVar:Picture:http://www.wizards.com/global/images/magic/general/spike_drone.jpg Oracle:Spike Drone enters the battlefield with a +1/+1 counter on it.\n{2}, Remove a +1/+1 counter from Spike Drone: Put a +1/+1 counter on target creature. diff --git a/forge-gui/res/cardsfolder/s/spike_feeder.txt b/forge-gui/res/cardsfolder/s/spike_feeder.txt index 9eb9c25d30f..5cfd12ab571 100644 --- a/forge-gui/res/cardsfolder/s/spike_feeder.txt +++ b/forge-gui/res/cardsfolder/s/spike_feeder.txt @@ -3,7 +3,7 @@ ManaCost:1 G G Types:Creature Spike PT:0/0 K:etbCounter:P1P1:2 -A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature. +A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | AILogic$ MoveCounterSpike | SpellDescription$ Put a +1/+1 counter on target creature. A:AB$ GainLife | Cost$ SubCounter<1/P1P1> | LifeAmount$ 2 | SpellDescription$ You gain 2 life. SVar:Picture:http://www.wizards.com/global/images/magic/general/spike_feeder.jpg Oracle:Spike Feeder enters the battlefield with two +1/+1 counters on it.\n{2}, Remove a +1/+1 counter from Spike Feeder: Put a +1/+1 counter on target creature.\nRemove a +1/+1 counter from Spike Feeder: You gain 2 life. diff --git a/forge-gui/res/cardsfolder/s/spike_hatcher.txt b/forge-gui/res/cardsfolder/s/spike_hatcher.txt index 3c17a232f4e..a5ecaa56a45 100644 --- a/forge-gui/res/cardsfolder/s/spike_hatcher.txt +++ b/forge-gui/res/cardsfolder/s/spike_hatcher.txt @@ -3,7 +3,7 @@ ManaCost:6 G Types:Creature Spike PT:0/0 K:etbCounter:P1P1:6 -A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature. +A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | AILogic$ MoveCounterSpike | SpellDescription$ Put a +1/+1 counter on target creature. A:AB$ Regenerate | Cost$ 1 SubCounter<1/P1P1> | SpellDescription$ Regenerate Spike Hatcher. SVar:Picture:http://www.wizards.com/global/images/magic/general/spike_hatcher.jpg Oracle:Spike Hatcher enters the battlefield with six +1/+1 counters on it.\n{2}, Remove a +1/+1 counter from Spike Hatcher: Put a +1/+1 counter on target creature.\n{1}, Remove a +1/+1 counter from Spike Hatcher: Regenerate Spike Hatcher. diff --git a/forge-gui/res/cardsfolder/s/spike_rogue.txt b/forge-gui/res/cardsfolder/s/spike_rogue.txt index 26e18ab754b..2c79de74c9a 100644 --- a/forge-gui/res/cardsfolder/s/spike_rogue.txt +++ b/forge-gui/res/cardsfolder/s/spike_rogue.txt @@ -3,7 +3,7 @@ ManaCost:1 G G Types:Creature Spike PT:0/0 K:etbCounter:P1P1:2 -A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature. +A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | AILogic$ MoveCounterSpike | SpellDescription$ Put a +1/+1 counter on target creature. A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1/Creature.YouCtrl/Creature you Control> | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on CARDNAME. AI:RemoveDeck:All SVar:Picture:http://www.wizards.com/global/images/magic/general/spike_rogue.jpg diff --git a/forge-gui/res/cardsfolder/s/spike_soldier.txt b/forge-gui/res/cardsfolder/s/spike_soldier.txt index d57c54688eb..20454d45538 100644 --- a/forge-gui/res/cardsfolder/s/spike_soldier.txt +++ b/forge-gui/res/cardsfolder/s/spike_soldier.txt @@ -3,7 +3,7 @@ ManaCost:2 G G Types:Creature Spike Soldier PT:0/0 K:etbCounter:P1P1:3 -A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature. +A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | AILogic$ MoveCounterSpike | SpellDescription$ Put a +1/+1 counter on target creature. A:AB$ Pump | Cost$ SubCounter<1/P1P1> | Defined$ Self | NumAtt$ 2 | NumDef$ 2 | SpellDescription$ CARDNAME gets +2/+2 until end of turn. SVar:Picture:http://www.wizards.com/global/images/magic/general/spike_soldier.jpg Oracle:Spike Soldier enters the battlefield with three +1/+1 counters on it.\n{2}, Remove a +1/+1 counter from Spike Soldier: Put a +1/+1 counter on target creature.\nRemove a +1/+1 counter from Spike Soldier: Spike Soldier gets +2/+2 until end of turn. diff --git a/forge-gui/res/cardsfolder/s/spike_tiller.txt b/forge-gui/res/cardsfolder/s/spike_tiller.txt index d8544eb7173..eeecb2191da 100644 --- a/forge-gui/res/cardsfolder/s/spike_tiller.txt +++ b/forge-gui/res/cardsfolder/s/spike_tiller.txt @@ -3,7 +3,7 @@ ManaCost:3 G G Types:Creature Spike PT:0/0 K:etbCounter:P1P1:3 -A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature. +A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | AILogic$ MoveCounterSpike | SpellDescription$ Put a +1/+1 counter on target creature. A:AB$ Animate | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Land | TgtPrompt$ Choose target land. | Power$ 2 | Toughness$ 2 | Types$ Creature | Permanent$ True | SubAbility$ DBPutCounter | SpellDescription$ Target land becomes a 2/2 creature that's still a land. Put a +1/+1 counter on it. SVar:DBPutCounter:DB$PutCounter | Defined$ Targeted | CounterType$ P1P1 | CounterNum$ 1 SVar:Picture:http://www.wizards.com/global/images/magic/general/spike_tiller.jpg diff --git a/forge-gui/res/cardsfolder/s/spike_weaver.txt b/forge-gui/res/cardsfolder/s/spike_weaver.txt index 5937873b693..788f373bdc5 100644 --- a/forge-gui/res/cardsfolder/s/spike_weaver.txt +++ b/forge-gui/res/cardsfolder/s/spike_weaver.txt @@ -3,7 +3,7 @@ ManaCost:2 G G Types:Creature Spike PT:0/0 K:etbCounter:P1P1:3 -A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature. +A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | AILogic$ MoveCounterSpike | SpellDescription$ Put a +1/+1 counter on target creature. A:AB$ Fog | Cost$ 1 SubCounter<1/P1P1> | AILogic$ SeriousDamage | SpellDescription$ Prevent all combat damage that would be dealt this turn. SVar:Picture:http://www.wizards.com/global/images/magic/general/spike_weaver.jpg Oracle:Spike Weaver enters the battlefield with three +1/+1 counters on it.\n{2}, Remove a +1/+1 counter from Spike Weaver: Put a +1/+1 counter on target creature.\n{1}, Remove a +1/+1 counter from Spike Weaver: Prevent all combat damage that would be dealt this turn. diff --git a/forge-gui/res/cardsfolder/s/spike_worker.txt b/forge-gui/res/cardsfolder/s/spike_worker.txt index 70223734d96..1fba05ca944 100644 --- a/forge-gui/res/cardsfolder/s/spike_worker.txt +++ b/forge-gui/res/cardsfolder/s/spike_worker.txt @@ -3,6 +3,6 @@ ManaCost:2 G Types:Creature Spike PT:0/0 K:etbCounter:P1P1:2 -A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature. +A:AB$ PutCounter | Cost$ 2 SubCounter<1/P1P1> | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ 1 | AILogic$ MoveCounterSpike | SpellDescription$ Put a +1/+1 counter on target creature. SVar:Picture:http://www.wizards.com/global/images/magic/general/spike_worker.jpg Oracle:Spike Worker enters the battlefield with two +1/+1 counters on it.\n{2}, Remove a +1/+1 counter from Spike Worker: Put a +1/+1 counter on target creature. From f588038ac990f62123914c8f1ea59a2e7403e59d Mon Sep 17 00:00:00 2001 From: Agetian Date: Wed, 5 Dec 2018 21:39:43 +0300 Subject: [PATCH 2/5] - Predict lethal combat. --- forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java index e494dbb4179..b6429340df7 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java @@ -287,7 +287,8 @@ public class CountersPutAi extends SpellAbilityAi { // Try not to do it unless at the end of opponent's turn or the creature is threatened Combat combat = ai.getGame().getCombat(); - boolean threatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard()); + boolean threatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard()) + || (combat != null && combat.isBlocked(sa.getHostCard()) && ComputerUtilCombat.attackerWouldBeDestroyed(ai, sa.getHostCard(), combat)); if (!(threatened || (ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai))) { return false; From 8e7a9d46cd052f27c132134fc644f4394c46a6ce Mon Sep 17 00:00:00 2001 From: Agetian Date: Wed, 5 Dec 2018 21:53:49 +0300 Subject: [PATCH 3/5] - Account for tapped diff in evaluation. --- forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java index b6429340df7..817e1fe568a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java @@ -301,7 +301,7 @@ public class CountersPutAi extends SpellAbilityAi { @Override public boolean apply(Card card) { // when threatened, any target is good to preserve the counter - return threatened || ComputerUtilCard.evaluateCreature(card, false, false) > ComputerUtilCard.evaluateCreature(sa.getHostCard(), false, false); + return threatened || ComputerUtilCard.evaluateCreature(card, false, false) > ComputerUtilCard.evaluateCreature(sa.getHostCard(), false, false) + 1; } }); From 498237a65ec9f1406e2ef189a7e2aaa82f973cf5 Mon Sep 17 00:00:00 2001 From: Agetian Date: Wed, 5 Dec 2018 21:55:27 +0300 Subject: [PATCH 4/5] - Comment fix --- forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java index 817e1fe568a..459c7564fa3 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java @@ -51,7 +51,7 @@ public class CountersPutAi extends SpellAbilityAi { return false; } - // disable moving counters + // disable moving counters (unless a specialized AI logic supports it) for (final CostPart part : cost.getCostParts()) { if (part instanceof CostRemoveCounter) { final CostRemoveCounter remCounter = (CostRemoveCounter) part; From 3719812889919a1aabd7eae815b0608499164c3f Mon Sep 17 00:00:00 2001 From: Agetian Date: Wed, 5 Dec 2018 21:57:17 +0300 Subject: [PATCH 5/5] - Refactor the method for the logic. --- .../java/forge/ai/ability/CountersPutAi.java | 65 ++++++++++--------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java index 459c7564fa3..7a38e503055 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java @@ -283,36 +283,7 @@ public class CountersPutAi extends SpellAbilityAi { return false; } } else if (logic.equals("MoveCounterSpike")) { - // Spikes (Tempest) - - // Try not to do it unless at the end of opponent's turn or the creature is threatened - Combat combat = ai.getGame().getCombat(); - boolean threatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard()) - || (combat != null && combat.isBlocked(sa.getHostCard()) && ComputerUtilCombat.attackerWouldBeDestroyed(ai, sa.getHostCard(), combat)); - - if (!(threatened || (ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai))) { - return false; - } - - CardCollection targets = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa); - targets.remove(sa.getHostCard()); - - targets = CardLists.filter(targets, new Predicate() { - @Override - public boolean apply(Card card) { - // when threatened, any target is good to preserve the counter - return threatened || ComputerUtilCard.evaluateCreature(card, false, false) > ComputerUtilCard.evaluateCreature(sa.getHostCard(), false, false) + 1; - } - }); - - Card bestTgt = ComputerUtilCard.getBestCreatureAI(targets); - - if (bestTgt != null) { - sa.getTargets().add(bestTgt); - return true; - } - - return false; + return doMoveCounterSpikeLogic(ai, sa, ph); } if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) { @@ -1033,4 +1004,38 @@ public class CountersPutAi extends SpellAbilityAi { } return Iterables.getFirst(options, null); } + + private boolean doMoveCounterSpikeLogic(Player ai, SpellAbility sa, PhaseHandler ph) { + // Spikes (Tempest) + + // Try not to do it unless at the end of opponent's turn or the creature is threatened + Combat combat = ai.getGame().getCombat(); + boolean threatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard()) + || (combat != null && combat.isBlocked(sa.getHostCard()) && ComputerUtilCombat.attackerWouldBeDestroyed(ai, sa.getHostCard(), combat)); + + if (!(threatened || (ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai))) { + return false; + } + + CardCollection targets = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa); + targets.remove(sa.getHostCard()); + + targets = CardLists.filter(targets, new Predicate() { + @Override + public boolean apply(Card card) { + // when threatened, any target is good to preserve the counter + return threatened || ComputerUtilCard.evaluateCreature(card, false, false) > ComputerUtilCard.evaluateCreature(sa.getHostCard(), false, false) + 1; + } + }); + + Card bestTgt = ComputerUtilCard.getBestCreatureAI(targets); + + if (bestTgt != null) { + sa.getTargets().add(bestTgt); + return true; + } + + return false; + } + }