Fix SimAI not respecting Pithing Needle effects.

Before this change, Sim AI would just choose effects that should be blocked by Pithing Needle (and similar cards). Adds a test.
This commit is contained in:
asvitkine
2023-10-04 15:15:10 -04:00
parent 23ec143892
commit 685cd2583f
3 changed files with 41 additions and 2 deletions

View File

@@ -296,8 +296,6 @@ public class SpecialCardAi {
public static class PithingNeedle { public static class PithingNeedle {
public static String chooseCard(final Player ai, final SpellAbility sa) { public static String chooseCard(final Player ai, final SpellAbility sa) {
// TODO Remove names of cards already named by other Pithing Needles // 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); CardCollection oppPerms = CardLists.getValidCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), "Card.OppCtrl+hasNonmanaAbilities", ai, sa.getHostCard(), sa);
if (!oppPerms.isEmpty()) { if (!oppPerms.isEmpty()) {
return chooseCardFromList(oppPerms).getName(); return chooseCardFromList(oppPerms).getName();

View File

@@ -331,6 +331,13 @@ public class SpellAbilityPicker {
} }
private AiPlayDecision canPlayAndPayForSim(final SpellAbility sa) { 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) { if (sa instanceof LandAbility) {
return AiPlayDecision.WillPlay; return AiPlayDecision.WillPlay;
} }

View File

@@ -7,6 +7,7 @@ import java.util.List;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.model.FModel; import forge.model.FModel;
import java.util.function.Predicate;
import org.testng.AssertJUnit; import org.testng.AssertJUnit;
import org.testng.annotations.Test; 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("Forest Bear"));
AssertJUnit.assertTrue(targets.toString().contains("Flying Men")); 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));
}
} }