diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index fbd5f8b6c96..a2edc9086e4 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -733,20 +733,6 @@ public class AiController { AiPlayDecision canPlay = canPlaySa(sa); // this is the "heaviest" check, which also sets up targets, defines X, etc. - // Account for possible Ward after the spell is fully targeted - // TODO: ideally, this should be done while targeting, so that a different target can be preferred if the best - // one is warded and can't be paid for. - if (sa.usesTargeting()) { - for (Card tgt : sa.getTargets().getTargetCards()) { - if (tgt.hasKeyword(Keyword.WARD)) { - int amount = tgt.getKeywordMagnitude(Keyword.WARD); - if (amount > 0 && !ComputerUtilCost.canPayCost(sa, player)) { - return AiPlayDecision.CantAfford; - } - } - } - } - if (sa.getCardState() != null && !sa.getHostCard().isInPlay() && sa.getCardState().getStateName() == CardStateName.Modal) { sa.getHostCard().setState(CardStateName.Original, false); } @@ -755,6 +741,20 @@ public class AiController { return canPlay; } + // Account for possible Ward after the spell is fully targeted + // TODO: ideally, this should be done while targeting, so that a different target can be preferred if the best + // one is warded and can't be paid for. + if (sa.usesTargeting()) { + for (Card tgt : sa.getTargets().getTargetCards()) { + if (tgt.hasKeyword(Keyword.WARD) && tgt.getController().isOpponentOf(sa.getHostCard().getController())) { + int amount = tgt.getKeywordMagnitude(Keyword.WARD); + if (amount > 0 && !ComputerUtilCost.canPayCost(sa, player)) { + return AiPlayDecision.CantAfford; + } + } + } + } + // check if some target raised cost if (oldCMC > -1) { int finalCMC = CostAdjustment.adjust(sa.getPayCosts(), sa).getTotalMana().getCMC(); diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index 049aea47f54..a69292585c1 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -289,7 +289,7 @@ public class ComputerUtil { final Card source = newSA.getHostCard(); if (newSA.isSpell() && !source.isCopiedSpell()) { - newSA.setHostCard(game.getAction().moveToStack(source, sa)); + newSA.setHostCard(game.getAction().moveToStack(source, newSA)); if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) { if (!CharmEffect.makeChoices(newSA)) { diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java index cb37f9c4f10..605f3bb389b 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java @@ -592,7 +592,7 @@ public class ComputerUtilCost { // Ward - will be accounted for when rechecking a targeted ability if (sa.usesTargeting()) { for (Card tgt : sa.getTargets().getTargetCards()) { - if (tgt.hasKeyword(Keyword.WARD)) { + if (tgt.hasKeyword(Keyword.WARD) && tgt.getController().isOpponentOf(sa.getHostCard().getController())) { extraManaNeeded += tgt.getKeywordMagnitude(Keyword.WARD); } } diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java index bb33b00f10e..a43320c7922 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java @@ -492,4 +492,10 @@ public class CountersMoveAi extends SpellAbilityAi { // like keeping the last counter on a 0/0 creature return max; } + + @Override + public CounterType chooseCounterType(List options, SpellAbility sa, Map params) { + // TODO + return super.chooseCounterType(options, sa, params); + } } diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java index 698f9a83cca..7ab8c24fbc0 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java @@ -144,7 +144,6 @@ public class CountersRemoveAi extends SpellAbilityAi { sa.getTargets().add(ComputerUtilCard.getBestPlaneswalkerAI(planeswalkerList)); return true; } - } else if (type.matches("Any")) { // variable amount for Hex Parasite int amount; @@ -264,7 +263,6 @@ public class CountersRemoveAi extends SpellAbilityAi { sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(aiList)); return true; } - } else if (type.equals("P1P1")) { // no special amount for that one yet int amount = AbilityUtils.calculateAmount(source, amountStr, sa); @@ -298,7 +296,6 @@ public class CountersRemoveAi extends SpellAbilityAi { return true; } } - } else if (type.equals("TIME")) { int amount; boolean xPay = false; diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java index 8a1195e9443..2e356e1ad39 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java @@ -94,7 +94,7 @@ public class PumpAi extends PumpAiBase { return true; } - return ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN); + return SpellAbilityAi.isSorcerySpeed(sa) || (ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN)); } else if (logic.equals("Aristocrat")) { final boolean isThreatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard()); if (!ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && !isThreatened) { diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java index 1951861fb44..b2eeedb3877 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -105,6 +105,7 @@ public final class GameActionUtil { lkicheck = true; } + // 601.3e if (lkicheck) { // double freeze tracker, so it doesn't update view game.getTracker().freeze(); @@ -377,6 +378,7 @@ public final class GameActionUtil { lkicheck = true; } + // 601.3e if (lkicheck) { // double freeze tracker, so it doesn't update view game.getTracker().freeze(); diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerTokenCreated.java b/forge-game/src/main/java/forge/game/trigger/TriggerTokenCreated.java index 0493537026a..d745fcaaec9 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerTokenCreated.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerTokenCreated.java @@ -60,8 +60,7 @@ public class TriggerTokenCreated extends Trigger { /** {@inheritDoc} */ @Override public final void setTriggeringObjects(final SpellAbility sa, Map runParams) { - sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player); - sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card); + sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player, AbilityKey.Card); } /** {@inheritDoc} diff --git a/forge-gui/res/cardsfolder/d/daghatar_the_adamant.txt b/forge-gui/res/cardsfolder/d/daghatar_the_adamant.txt index d1b1cc4b7a3..65907063992 100644 --- a/forge-gui/res/cardsfolder/d/daghatar_the_adamant.txt +++ b/forge-gui/res/cardsfolder/d/daghatar_the_adamant.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Human Warrior PT:0/0 K:Vigilance K:etbCounter:P1P1:4 -A:AB$ Pump | Cost$ 1 BG BG | ValidTgts$ Creature | TgtPrompt$ Select target creature to remove a +1/+1 counter from | SubAbility$ DBMove | StackDescription$ None | SpellDescription$ Move a +1/+1 counter from target creature onto a second target creature. +A:AB$ Pump | Cost$ 1 BG BG | ValidTgts$ Creature | TgtPrompt$ Select target creature to remove a +1/+1 counter from | AILogic$ MoveCounter | SubAbility$ DBMove | StackDescription$ None | SpellDescription$ Move a +1/+1 counter from target creature onto a second target creature. SVar:DBMove:DB$ MoveCounter | Source$ ParentTarget | ValidTgts$ Creature | TgtPrompt$ Select target creature to move a +1/+1 counter to | TargetUnique$ True | CounterType$ P1P1 | CounterNum$ 1 AI:RemoveDeck:All SVar:Picture:http://www.wizards.com/global/images/magic/general/daghatar_the_adamant.jpg diff --git a/forge-gui/res/cardsfolder/n/nesting_grounds.txt b/forge-gui/res/cardsfolder/n/nesting_grounds.txt index f887f4a4547..d076622d588 100755 --- a/forge-gui/res/cardsfolder/n/nesting_grounds.txt +++ b/forge-gui/res/cardsfolder/n/nesting_grounds.txt @@ -4,4 +4,5 @@ Types:Land A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. A:AB$ Pump | Cost$ 1 T | ValidTgts$ Permanent.YouCtrl | TgtPrompt$ Select target permanent you control | SubAbility$ DBMove | SorcerySpeed$ True | StackDescription$ SpellDescription | SpellDescription$ Move a counter from target permanent you control onto another target permanent. Activate only as a sorcery. SVar:DBMove:DB$ MoveCounter | Source$ ParentTarget | ValidTgts$ Permanent | TgtPrompt$ Select target permanent to move counter to | TargetUnique$ True | CounterType$ Any | CounterNum$ 1 | StackDescription$ None +AI:RemoveDeck:All Oracle:{T}: Add {C}.\n{1}, {T}: Move a counter from target permanent you control onto another target permanent. Activate only as a sorcery. diff --git a/forge-gui/res/cardsfolder/o/outland_liberator_frenzied_trapbreaker.txt b/forge-gui/res/cardsfolder/o/outland_liberator_frenzied_trapbreaker.txt index b55430505d1..8789ec4a30b 100644 --- a/forge-gui/res/cardsfolder/o/outland_liberator_frenzied_trapbreaker.txt +++ b/forge-gui/res/cardsfolder/o/outland_liberator_frenzied_trapbreaker.txt @@ -19,5 +19,4 @@ T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescripti SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer,Enchantment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target artifact or enchantment defending player controls K:Nightbound SVar:HasAttackEffect:TRUE -Oracle:{1}, Sacrifice Frenzied Trapbreaker: Destroy target artifact or enchantment. -Whenever Frenzied Trapbreaker attacks, destroy target artifact or enchantment defending player controls.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.) +Oracle:{1}, Sacrifice Frenzied Trapbreaker: Destroy target artifact or enchantment.\nWhenever Frenzied Trapbreaker attacks, destroy target artifact or enchantment defending player controls.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)