fix split cards interaction with Feather, the Redeemed and the like

Fixes #12353
Fixes #13665
This commit is contained in:
Susucre 2025-05-25 16:06:44 +02:00
parent 4f3635ee17
commit a4f22f21cf
5 changed files with 244 additions and 42 deletions

View file

@ -115,4 +115,47 @@ public class FeatherTheRedeemedTest extends CardTestPlayerBase {
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
}
@Test
public void test_SplitCard() {
// cast fire, put to exile, return to hand
addCard(Zone.BATTLEFIELD, playerA, "Feather, the Redeemed");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.HAND, playerA, "Fire // Ice", 1);
// cast and put to exile
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fire");
addTargetAmount(playerA, "Feather, the Redeemed", 2);
checkExileCount("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Fire // Ice", 1);
checkHandCardCount("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Fire // Ice", 0);
// return to hand at the next end step
checkExileCount("turn 1 after", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Fire // Ice", 0);
checkHandCardCount("turn 1 after", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Fire // Ice", 1);
setStrictChooseMode(true);
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
}
@Test
public void test_Adventure() {
// cast stomp, put to exile, no return to hand
addCard(Zone.BATTLEFIELD, playerA, "Feather, the Redeemed");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.HAND, playerA, "Bonecrusher Giant", 1);
// cast and put to exile
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Stomp", "Feather, the Redeemed");
checkExileCount("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Bonecrusher Giant", 1);
checkHandCardCount("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Bonecrusher Giant", 0);
// no return to hand, as it does not go to graveyard on resolve
checkExileCount("turn 1 after", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Bonecrusher Giant", 1);
checkHandCardCount("turn 1 after", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Bonecrusher Giant", 0);
setStrictChooseMode(true);
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
}
}

View file

@ -0,0 +1,161 @@
package org.mage.test.cards.single.ltc;
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 GandalfOfTheSecretFireTest extends CardTestPlayerBase {
/**
* {@link mage.cards.g.GandalfOfTheSecretFire Gandalf of the Secret Fire} {1}{U}{R}{W}
* Legendary Creature Avatar Wizard
* Whenever you cast an instant or sorcery spell from your hand during an opponents turn, exile that card with three time counters on it instead of putting it into your graveyard as it resolves. Then if the exiled card doesnt have suspend, it gains suspend. (At the beginning of your upkeep, remove a time counter. When the last is removed, you may play it without paying its mana cost.)
* 3/4
*/
private static final String gandalf = "Gandalf of the Secret Fire";
@Test
public void test_yourturn() {
addCard(Zone.BATTLEFIELD, playerA, gandalf, 1);
addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerB, 20 - 3);
assertGraveyardCount(playerA, "Lightning Bolt", 1);
}
@Test
public void test_oppturn_suspend() {
addCard(Zone.BATTLEFIELD, playerA, gandalf, 1);
addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
checkExileCount("1: bolt in exile", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", 1);
checkCardCounters("1: bolt has 3 time counters", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", CounterType.TIME, 3);
// turn 3: from 3 to 2 time counter
checkCardCounters("2: bolt has 2 time counters", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", CounterType.TIME, 2);
// turn 5: from 2 to 1 time counter
checkCardCounters("3: bolt has 1 time counters", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", CounterType.TIME, 1);
setChoice(playerA, true); // yes to cast from suspend removing last counter
addTarget(playerA, playerB);
setStrictChooseMode(true);
setStopAt(7, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerB, 20 - 6);
assertGraveyardCount(playerA, "Lightning Bolt", 1);
}
@Test
public void test_split_suspend() {
addCard(Zone.BATTLEFIELD, playerA, gandalf, 1);
addCard(Zone.HAND, playerA, "Fire // Ice", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Fire", playerB);
addTargetAmount(playerA, playerB, 2);
checkExileCount("1: fire//ice in exile", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Fire // Ice", 1);
checkCardCounters("1: fire//ice has 3 time counters", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Fire // Ice", CounterType.TIME, 3);
// turn 3: from 3 to 2 time counter
checkCardCounters("2: fire//ice has 2 time counters", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Fire // Ice", CounterType.TIME, 2);
// turn 5: from 2 to 1 time counter
checkCardCounters("3: fire//ice has 1 time counters", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Fire // Ice", CounterType.TIME, 1);
setChoice(playerA, true); // yes to cast from suspend removing last counter
setChoice(playerA, "Cast Fire"); // choose to cast Fire side
addTargetAmount(playerA, playerB, 2);
setStrictChooseMode(true);
setStopAt(7, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerB, 20 - 4);
assertGraveyardCount(playerA, "Fire // Ice", 1);
}
@Test
public void test_oppturn_counterspell_suspend() {
addCard(Zone.BATTLEFIELD, playerA, gandalf, 1);
addCard(Zone.HAND, playerA, "Counterspell", 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
addCard(Zone.HAND, playerB, "Lightning Bolt", 1);
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerB);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Counterspell", "Lightning Bolt");
setStrictChooseMode(true);
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerB, 20);
assertExileCount(playerA, "Counterspell", 1);
assertGraveyardCount(playerB, "Lightning Bolt", 1);
}
@Test
public void test_oppturn_countered_nosuspend() {
addCard(Zone.BATTLEFIELD, playerB, gandalf, 1);
addCard(Zone.HAND, playerA, "Counterspell", 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
addCard(Zone.HAND, playerB, "Lightning Bolt", 1);
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerB);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Counterspell", "Lightning Bolt", "Lightning Bolt");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerB, 20);
assertGraveyardCount(playerA, "Counterspell", 1);
assertGraveyardCount(playerB, "Lightning Bolt", 1);
}
@Test
public void test_adventure_nosuspend() {
addCard(Zone.BATTLEFIELD, playerA, gandalf, 1);
addCard(Zone.HAND, playerA, "Bonecrusher Giant", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Stomp", playerB);
setStrictChooseMode(true);
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerB, 20 - 2);
assertExileCount(playerA, "Bonecrusher Giant", 1);
// since an Adventure card is not going to the graveyard on resolve, Gandalf's trigger does not suspend it.
assertCounterOnExiledCardCount("Bonecrusher Giant", CounterType.TIME, 0);
}
}