mirror of
https://github.com/magefree/mage.git
synced 2025-12-22 11:32:00 -08:00
Introduce new batch event for life lost for a specific player (#13071)
* Introduce new batch event for life lost for a specific player closes #12202, fix #10805 * implement [DSC] Valgavoth, Harrower of Souls * text fixes
This commit is contained in:
parent
95e986dee7
commit
d6cf207a8b
28 changed files with 693 additions and 707 deletions
|
|
@ -1,4 +1,4 @@
|
|||
package org.mage.test.cards.watchers;
|
||||
package org.mage.test.cards.single.aer;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
|
|
@ -7,7 +7,6 @@ import org.junit.Test;
|
|||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author escplan9
|
||||
*/
|
||||
public class GontisMachinationsTest extends CardTestPlayerBase {
|
||||
|
|
@ -19,57 +18,59 @@ Whenever you lose life for the first time each turn, you get {E}. (You get an en
|
|||
Pay {E}{E}, Sacrifice Gonti's Machinations: Each opponent loses 3 life. You gain life equal to the life lost this way.
|
||||
*/
|
||||
private final String gMachinations = "Gonti's Machinations";
|
||||
|
||||
|
||||
/*
|
||||
* Reported bug: [[Gonti's Machinations]] currently triggers and gain 1 energy whenever you lose life instead of only the first life loss of each turn.
|
||||
* See issue #3499 (test is currently failing due to bug in code)
|
||||
*/
|
||||
* See issue #3499 for context
|
||||
*/
|
||||
@Test
|
||||
public void machinations_ThreeCreaturesCombatDamage_OneTrigger() {
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
||||
String memnite = "Memnite"; // {0} 1/1
|
||||
String gBears = "Grizzly Bears"; // {1}{G} 2/2
|
||||
String hGiant = "Hill Giant"; // {2}{R} 3/3
|
||||
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, gMachinations);
|
||||
addCard(Zone.BATTLEFIELD, playerA, memnite);
|
||||
addCard(Zone.BATTLEFIELD, playerA, gBears);
|
||||
addCard(Zone.BATTLEFIELD, playerA, hGiant);
|
||||
|
||||
|
||||
attack(3, playerA, memnite);
|
||||
attack(3, playerA, gBears);
|
||||
attack(3, playerA, hGiant);
|
||||
|
||||
|
||||
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
|
||||
assertTapped(memnite, true);
|
||||
assertTapped(gBears, true);
|
||||
assertTapped(hGiant, true);
|
||||
assertLife(playerB, 14); // 1 + 2 + 3 damage
|
||||
assertCounterCount(playerB, CounterType.ENERGY, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reported bug: [[Gonti's Machinations]] currently triggers and gain 1 energy whenever you lose life instead of only the first life loss of each turn.
|
||||
* See issue #3499 (test is currently failing due to bug in code)
|
||||
*/
|
||||
* See issue #3499 for context
|
||||
*/
|
||||
@Test
|
||||
public void machinations_NonCombatDamageThreeTimes_OneTrigger() {
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
||||
String bolt = "Lightning Bolt"; // {R} deal 3
|
||||
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, gMachinations);
|
||||
addCard(Zone.HAND, playerA, bolt, 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, playerB);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, playerB);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, playerB);
|
||||
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
|
||||
assertTappedCount("Mountain", true, 3);
|
||||
assertGraveyardCount(playerA, bolt, 3);
|
||||
assertLife(playerB, 11); // 3 x 3 damage
|
||||
|
|
@ -7,13 +7,14 @@ import org.junit.Test;
|
|||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class ExquisiteBloodTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void BasicCardTest() {
|
||||
public void basicCardTest() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
|
||||
|
|
@ -45,10 +46,12 @@ public class ExquisiteBloodTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Ajani, Inspiring leader does not trigger Exquisite Blood + Defiant Bloodlord #6464
|
||||
* Ajani, Inspiring leader does not trigger Exquisite Blood + Defiant Bloodlord #6464
|
||||
*/
|
||||
@Test
|
||||
public void triggerCascadeTest() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
// +2: You gain 2 life. Put two +1/+1 counters on up to one target creature.
|
||||
// −3: Exile target creature. Its controller gains 2 life.
|
||||
// −10: Creatures you control gain flying and double strike until end of turn.
|
||||
|
|
@ -57,14 +60,12 @@ public class ExquisiteBloodTest extends CardTestPlayerBase {
|
|||
// Flying
|
||||
// Whenever you gain life, target opponent loses that much life.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Defiant Bloodlord", 1); // Creature 4/5 {5}{B}{B}
|
||||
|
||||
|
||||
// Whenever an opponent loses life, you gain that much life.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Exquisite Blood", 1); // Enchantment {4}{B}
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+2:", "Defiant Bloodlord");
|
||||
addTarget(playerA, playerB); // Target opponent of Defiant Bloodlord triggered ability (looping until opponent is dead)
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
|
|
@ -72,7 +73,9 @@ public class ExquisiteBloodTest extends CardTestPlayerBase {
|
|||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
|
@ -82,15 +85,17 @@ public class ExquisiteBloodTest extends CardTestPlayerBase {
|
|||
|
||||
assertLife(playerB, 0); // Player B is dead, game ends
|
||||
assertLife(playerA, 40);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajani, Inspiring leader does not trigger Exquisite Blood + Defiant Bloodlord #6464
|
||||
* Ajani, Inspiring leader does not trigger Exquisite Blood + Defiant Bloodlord #6464
|
||||
*/
|
||||
@Test
|
||||
public void triggerCascadeAjaniSecondAbilityTest() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
// +2: You gain 2 life. Put two +1/+1 counters on up to one target creature.
|
||||
// −3: Exile target creature. Its controller gains 2 life.
|
||||
// −10: Creatures you control gain flying and double strike until end of turn.
|
||||
|
|
@ -100,14 +105,12 @@ public class ExquisiteBloodTest extends CardTestPlayerBase {
|
|||
// Flying
|
||||
// Whenever you gain life, target opponent loses that much life.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Defiant Bloodlord", 1); // Creature 4/5 {5}{B}{B}
|
||||
|
||||
|
||||
// Whenever an opponent loses life, you gain that much life.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Exquisite Blood", 1); // Enchantment {4}{B}
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-3:", "Silvercoat Lion");
|
||||
addTarget(playerA, playerB); // Target opponent of Defiant Bloodlord triggered ability (looping until opponent is dead)
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
|
|
@ -115,7 +118,9 @@ public class ExquisiteBloodTest extends CardTestPlayerBase {
|
|||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
addTarget(playerA, playerB);
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
|
@ -126,7 +131,28 @@ public class ExquisiteBloodTest extends CardTestPlayerBase {
|
|||
|
||||
assertLife(playerB, 0); // Player B is dead, game ends
|
||||
assertLife(playerA, 40);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void attackWithTwoCreatures() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
// Whenever an opponent loses life, you gain that much life.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Exquisite Blood", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Memnite");
|
||||
|
||||
attack(1, playerA, "Elite Vanguard", playerB);
|
||||
attack(1, playerA, "Memnite", playerB);
|
||||
|
||||
// no trigger stacking, only 1 trigger
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 20 - 2 - 1);
|
||||
assertLife(playerA, 20 + 3);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
package org.mage.test.cards.single.ice;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class OathOfLimDulTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* {@link mage.cards.o.OathOfLimDul Oath of Lim-Dûl} {3}{B}
|
||||
* Enchantment
|
||||
* Whenever you lose life, for each 1 life you lost, sacrifice a permanent other than Oath of Lim-Dûl unless you discard a card. (Damage dealt to you causes you to lose life.)
|
||||
* {B}{B}: Draw a card.
|
||||
*/
|
||||
private static final String oath = "Oath of Lim-Dul";
|
||||
|
||||
@Test
|
||||
public void test_3Sacrifice() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, oath, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||
addCard(Zone.HAND, playerA, "Swamp", 5);
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerA);
|
||||
setChoice(playerA, false); // No to discard on first instance.
|
||||
setChoice(playerA, "Mountain"); // sacrifice Mountain
|
||||
setChoice(playerA, false); // No to discard on second instance.
|
||||
setChoice(playerA, "Mountain"); // sacrifice Mountain
|
||||
setChoice(playerA, false); // No to discard on third instance.
|
||||
setChoice(playerA, "Mountain"); // sacrifice Mountain
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20 - 3);
|
||||
assertGraveyardCount(playerA, "Mountain", 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_3Discard() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, oath, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||
addCard(Zone.HAND, playerA, "Swamp", 5);
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerA);
|
||||
setChoice(playerA, true); // Yes to discard on first instance.
|
||||
setChoice(playerA, "Swamp"); // sacrifice Swamp
|
||||
setChoice(playerA, true); // Yes to discard on second instance.
|
||||
setChoice(playerA, "Swamp"); // sacrifice Swamp
|
||||
setChoice(playerA, true); // Yes to discard on third instance.
|
||||
setChoice(playerA, "Swamp"); // sacrifice Swamp
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20 - 3);
|
||||
assertGraveyardCount(playerA, "Swamp", 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_1Sacrifice1Discard_NoOther() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, oath, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
addCard(Zone.HAND, playerA, "Swamp", 1);
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerA);
|
||||
setChoice(playerA, true); // Yes to discard on first instance.
|
||||
setChoice(playerA, "Swamp"); // discard Swamp
|
||||
// No more possibility to Discard
|
||||
setChoice(playerA, "Mountain"); // sacrifice Mountain
|
||||
// No more things to Sacrifice
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20 - 3);
|
||||
assertGraveyardCount(playerA, "Mountain", 1);
|
||||
assertGraveyardCount(playerA, "Swamp", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AllSacrificeNoDiscard_KeepCardInHand() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, oath, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
addCard(Zone.HAND, playerA, "Swamp", 1);
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerA);
|
||||
setChoice(playerA, false); // No to discard on first instance.
|
||||
setChoice(playerA, "Mountain"); // sacrifice Mountain
|
||||
setChoice(playerA, false); // No to discard on second instance.
|
||||
setChoice(playerA, false); // No to discard on third instance.
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20 - 3);
|
||||
assertPermanentCount(playerA, oath, 1);
|
||||
assertGraveyardCount(playerA, "Mountain", 1);
|
||||
assertHandCount(playerA, "Swamp", 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package org.mage.test.cards.single.snc;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class VampireScrivenerTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* {@link mage.cards.v.VampireScrivener Vampire Scrivener} {4}{B}
|
||||
* Creature — Vampire Warlock
|
||||
* Flying
|
||||
* Whenever you gain life during your turn, put a +1/+1 counter on Vampire Scrivener.
|
||||
* Whenever you lose life during your turn, put a +1/+1 counter on Vampire Scrivener.
|
||||
* 2/2
|
||||
*/
|
||||
private static final String scrivener = "Vampire Scrivener";
|
||||
|
||||
@Test
|
||||
public void test_LoseLife_Twice() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, scrivener, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Battlefield Forge"); // painland
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); // cause 1 trigger
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerA); // cause 1 trigger
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20 - 3 - 1);
|
||||
assertCounterCount(playerA, scrivener, CounterType.P1P1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_RakdosCharm() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, scrivener, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Kobolds of Kher Keep", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Badlands", 2);
|
||||
addCard(Zone.HAND, playerA, "Rakdos Charm");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rakdos Charm");
|
||||
setModeChoice(playerA, "3"); // Choose third mode
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20 - 4);
|
||||
assertCounterCount(playerA, scrivener, CounterType.P1P1, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_RakdosCharm_NotYourTurn() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, scrivener, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Kobolds of Kher Keep", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Badlands", 2);
|
||||
addCard(Zone.HAND, playerA, "Rakdos Charm");
|
||||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Rakdos Charm");
|
||||
setModeChoice(playerA, "3"); // Choose third mode
|
||||
|
||||
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20 - 4);
|
||||
assertCounterCount(playerA, scrivener, CounterType.P1P1, 0); // No trigger, as not your turn.
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue