diff --git a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java index 9324711e278..94da02c1d91 100644 --- a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java +++ b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java @@ -296,8 +296,6 @@ public class SpecialCardAi { public static class PithingNeedle { public static String chooseCard(final Player ai, final SpellAbility sa) { // TODO Remove names of cards already named by other Pithing Needles - Card best = null; - CardCollection oppPerms = CardLists.getValidCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), "Card.OppCtrl+hasNonmanaAbilities", ai, sa.getHostCard(), sa); if (!oppPerms.isEmpty()) { return chooseCardFromList(oppPerms).getName(); diff --git a/forge-ai/src/main/java/forge/ai/simulation/SpellAbilityPicker.java b/forge-ai/src/main/java/forge/ai/simulation/SpellAbilityPicker.java index 814704cf181..ffce0adcf6a 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/SpellAbilityPicker.java +++ b/forge-ai/src/main/java/forge/ai/simulation/SpellAbilityPicker.java @@ -331,6 +331,13 @@ public class SpellAbilityPicker { } private AiPlayDecision canPlayAndPayForSim(final SpellAbility sa) { + if (!sa.isLegalAfterStack()) { + return AiPlayDecision.CantPlaySa; + } + if (!sa.checkRestrictions(sa.getHostCard(), player)) { + return AiPlayDecision.CantPlaySa; + } + if (sa instanceof LandAbility) { return AiPlayDecision.WillPlay; } diff --git a/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java b/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java index 99a9b65cc33..033ce11b235 100644 --- a/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java +++ b/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java @@ -7,6 +7,7 @@ import java.util.List; import forge.item.PaperCard; import forge.model.FModel; +import java.util.function.Predicate; import org.testng.AssertJUnit; import org.testng.annotations.Test; @@ -860,4 +861,37 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest { AssertJUnit.assertTrue(targets.toString().contains("Forest Bear")); AssertJUnit.assertTrue(targets.toString().contains("Flying Men")); } + + @Test + public void testPithingNeedlePreventsAbilitiesFromBeingChosen() { + Game game = initAndCreateGame(); + Player p = game.getPlayers().get(1); + Player opponent = game.getPlayers().get(0); + opponent.setLife(1, null); + Card goblinBombardment = addCard("Goblin Bombardment", p); + addCard("Flying Men", p); + game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p); + + final SpellAbilityPicker picker = new SpellAbilityPicker(game, p); + Runnable assertPickIsGoblinBombardmenTargetingOpponent = () -> { + game.getAction().checkStateEffects(true); + SpellAbility sa = picker.chooseSpellAbilityToPlay(null); + AssertJUnit.assertNotNull(sa); + AssertJUnit.assertEquals(goblinBombardment, sa.getHostCard()); + MultiTargetSelector.Targets targets = picker.getPlan().getSelectedDecision().targets; + AssertJUnit.assertEquals(1, targets.size()); + AssertJUnit.assertTrue(targets.toString().contains(opponent.getName())); + }; + assertPickIsGoblinBombardmenTargetingOpponent.run(); + + // If we have a Pithing Needle, but it's naming something else, that's still fine. + Card pithingNeedle = addCard("Pithing Needle", opponent); + pithingNeedle.setNamedCard("Flooded Strand"); + assertPickIsGoblinBombardmenTargetingOpponent.run(); + + // But if it's naming Gobling Bombardment, then we can't choose that SA. + pithingNeedle.setNamedCard("Goblin Bombardment"); + game.getAction().checkStateEffects(true); + AssertJUnit.assertNull(picker.chooseSpellAbilityToPlay(null)); + } }