diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index 98f8608f8d3..00beb693357 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -925,7 +925,7 @@ public class AiController { // check if enough left (pass memory indirectly because we don't want to include those) Set tappedForMana = AiCardMemory.getMemorySet(player, MemorySet.PAYS_TAP_COST); - if (tappedForMana != null && tappedForMana.isEmpty() && + if (tappedForMana != null && !tappedForMana.isEmpty() && !ComputerUtilCost.checkTapTypeCost(player, sa.getPayCosts(), host, sa, new CardCollection(tappedForMana))) { return AiPlayDecision.CantAfford; } diff --git a/forge-ai/src/main/java/forge/ai/AiCostDecision.java b/forge-ai/src/main/java/forge/ai/AiCostDecision.java index 626e8898c67..65d59b3c534 100644 --- a/forge-ai/src/main/java/forge/ai/AiCostDecision.java +++ b/forge-ai/src/main/java/forge/ai/AiCostDecision.java @@ -29,12 +29,15 @@ public class AiCostDecision extends CostDecisionMakerBase { private final CardCollection tapped; public AiCostDecision(Player ai0, SpellAbility sa, final boolean effect) { + this(ai0, sa, effect, false); + } + public AiCostDecision(Player ai0, SpellAbility sa, final boolean effect, final boolean payMana) { super(ai0, effect, sa, sa.getHostCard()); discarded = new CardCollection(); tapped = new CardCollection(); Set tappedForMana = AiCardMemory.getMemorySet(ai0, MemorySet.PAYS_TAP_COST); - if (tappedForMana != null) { + if (!payMana && tappedForMana != null) { tapped.addAll(tappedForMana); } } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index 9518b852d63..dad9e7a2f4e 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -287,10 +287,6 @@ public class ComputerUtilMana { continue; } - if (!ComputerUtilCost.checkTapTypeCost(ai, ma.getPayCosts(), ma.getHostCard(), sa, AiCardMemory.getMemorySet(ai, MemorySet.PAYS_TAP_COST))) { - continue; - } - int amount = ma.hasParam("Amount") ? AbilityUtils.calculateAmount(ma.getHostCard(), ma.getParam("Amount"), ma) : 1; if (amount <= 0) { // wrong gamestate for variable amount @@ -357,9 +353,14 @@ public class ComputerUtilMana { continue; } + // these should come last since they reserve the paying cards + // (this means if a mana ability has both parts it doesn't currently undo reservations if the second part fails) if (!ComputerUtilCost.checkForManaSacrificeCost(ai, ma.getPayCosts(), ma, ma.isTrigger())) { continue; } + if (!ComputerUtilCost.checkTapTypeCost(ai, ma.getPayCosts(), ma.getHostCard(), sa, AiCardMemory.getMemorySet(ai, MemorySet.PAYS_TAP_COST))) { + continue; + } return paymentChoice; } @@ -819,7 +820,7 @@ public class ComputerUtilMana { sourcesForShards.values().removeIf(CardTraitPredicates.isHostCard(saPayment.getHostCard())); } else { final CostPayment pay = new CostPayment(saPayment.getPayCosts(), saPayment); - if (!pay.payComputerCosts(new AiCostDecision(ai, saPayment, effect))) { + if (!pay.payComputerCosts(new AiCostDecision(ai, saPayment, effect, true))) { saList.remove(saPayment); continue; } diff --git a/forge-gui/res/cardsfolder/k/karns_sylex.txt b/forge-gui/res/cardsfolder/k/karns_sylex.txt index 68580d91e56..a852ea06373 100644 --- a/forge-gui/res/cardsfolder/k/karns_sylex.txt +++ b/forge-gui/res/cardsfolder/k/karns_sylex.txt @@ -3,8 +3,7 @@ ManaCost:3 Types:Legendary Artifact R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplacementResult$ Updated | ReplaceWith$ ETBTapped | Description$ CARDNAME enters tapped. SVar:ETBTapped:DB$ Tap | Defined$ Self | ETB$ True -S:Mode$ CantPayLife | ValidPlayer$ Player | ValidCause$ Spell,Activated.nonManaAbility | ForCost$ True | Description$ Players can't pay life or sacrifice creatures to cast spells or activate abilities that aren't mana abilities. -S:Mode$ CantSacrifice | ValidCard$ Creature | ValidCause$ Spell,Activated.nonManaAbility | ForCost$ True | Secondary$ True | Description$ Players can't pay life or sacrifice creatures to cast spells or activate abilities that aren't mana abilities. +S:Mode$ CantPayLife | ValidPlayer$ Player | ValidCause$ Spell,Activated.nonManaAbility | ForCost$ True | Description$ Players can't pay life to cast spells or activate abilities that aren't mana abilities. A:AB$ DestroyAll | Cost$ X T Exile<1/CARDNAME> | ValidCards$ Permanent.nonLand+cmcLEX | SorcerySpeed$ True | SpellDescription$ Destroy each nonland permanent with mana value X or less. Activate only as a sorcery. SVar:X:Count$xPaid Oracle:Karn's Sylex enters tapped.\nPlayers can't pay life to cast spells or to activate abilities that aren't mana abilities.\n{X}, {T}, Exile Karn's Sylex: Destroy each nonland permanent with mana value X or less. Activate only as a sorcery. diff --git a/forge-gui/res/cardsfolder/s/spider_man_india.txt b/forge-gui/res/cardsfolder/s/spider_man_india.txt index 9066e790705..73dd5b52d25 100644 --- a/forge-gui/res/cardsfolder/s/spider_man_india.txt +++ b/forge-gui/res/cardsfolder/s/spider_man_india.txt @@ -1,7 +1,7 @@ Name:Spider-Man India ManaCost:3 G W Types:Legendary Creature Spider Human Hero -PT:4/3 +PT:4/4 K:Web-slinging:1 G W T:Mode$ SpellCast | ValidCard$ Card.Creature | ValidActivatingPlayer$ You | Execute$ TrigPutCounter | TriggerZones$ Battlefield | TriggerDescription$ Pavitr's Sevā — Whenever you cast a creature spell, put a +1/+1 counter on target creature you control. It gains flying until end of turn. SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBPump