|
| 1 | +package forge.ai.ability; |
| 2 | + |
| 3 | +import forge.ai.AITest; |
| 4 | +import forge.ai.SpellApiToAi; |
| 5 | +import forge.game.Game; |
| 6 | +import forge.game.ability.ApiType; |
| 7 | +import forge.game.card.Card; |
| 8 | +import forge.game.player.Player; |
| 9 | +import forge.game.spellability.SpellAbility; |
| 10 | +import forge.game.trigger.Trigger; |
| 11 | +import forge.game.zone.ZoneType; |
| 12 | +import org.testng.AssertJUnit; |
| 13 | +import org.testng.annotations.Test; |
| 14 | + |
| 15 | +/** |
| 16 | + * An optional trigger must respect the AI's life-cost safety, the way the activated path already |
| 17 | + * does (the gate lives in SpellAbilityAi.doTrigger). Exercised with Bringer of the Black Dawn's |
| 18 | + * "upkeep: you may pay 2 life, tutor" trigger, asserting both directions: it fires when the AI can |
| 19 | + * spare the life, and declines when paying would drop it below the safety threshold (the bug). |
| 20 | + */ |
| 21 | +public class TriggerLifeGateTest extends AITest { |
| 22 | + |
| 23 | + @Test |
| 24 | + public void optionalPayLifeTriggerRespectsLifeSafety() { |
| 25 | + AssertJUnit.assertTrue("should tutor when it can spare the life", |
| 26 | + tutors(bringerSetup(20))); |
| 27 | + AssertJUnit.assertFalse("should not pay 2 life down to 3 to tutor", |
| 28 | + tutors(bringerSetup(5))); // 5 - 2 = 3, below the threshold of 4 |
| 29 | + } |
| 30 | + |
| 31 | + private Player bringerSetup(int life) { |
| 32 | + Game game = initAndCreateGame(); |
| 33 | + Player ai = game.getPlayers().get(1); |
| 34 | + addCard("Bringer of the Black Dawn", ai); |
| 35 | + addCardToZone("Griselbrand", ai, ZoneType.Library); |
| 36 | + for (int i = 0; i < 6; i++) addCardToZone("Forest", ai, ZoneType.Library); |
| 37 | + ai.setLife(life, null); |
| 38 | + return ai; |
| 39 | + } |
| 40 | + |
| 41 | + private boolean tutors(Player ai) { |
| 42 | + Card bringer = null; |
| 43 | + for (Card c : ai.getCardsIn(ZoneType.Battlefield)) { |
| 44 | + if (c.getName().equals("Bringer of the Black Dawn")) { |
| 45 | + bringer = c; |
| 46 | + break; |
| 47 | + } |
| 48 | + } |
| 49 | + AssertJUnit.assertNotNull(bringer); |
| 50 | + SpellAbility sa = null; |
| 51 | + for (Trigger t : bringer.getTriggers()) { |
| 52 | + SpellAbility ability = t.ensureAbility(); |
| 53 | + if (ability != null && ability.getApi() == ApiType.ChangeZone) { |
| 54 | + sa = ability; |
| 55 | + break; |
| 56 | + } |
| 57 | + } |
| 58 | + AssertJUnit.assertNotNull("no tutor trigger on Bringer", sa); |
| 59 | + sa.setActivatingPlayer(ai); |
| 60 | + return SpellApiToAi.Converter.get(sa).doTrigger(ai, sa, false); |
| 61 | + } |
| 62 | +} |
0 commit comments