More target adding, reattach improves (#13807)

* Add Target to Provoke, Soulshift, remove from AttachableToRestrictedAbility

* Add Target to CurseOfInertia, FarrelsMantle, Incendiary, JubilantMascot, MantleOfTheAncients, MuseVessel, SoulSeizer. Fix DreamEater text.

* Fix CardImpl.cantBeAttachedBy to not early return with Protection abilities

* Improve tests
This commit is contained in:
ssk97 2025-07-01 22:08:27 -07:00 committed by GitHub
parent 8fda57401d
commit 7d7e517084
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 273 additions and 260 deletions

View file

@ -74,4 +74,70 @@ public class OneShotNonTargetTest extends CardTestPlayerBase {
assertPowerToughness(playerA, "Squire", 3, 4);
assertPowerToughness(playerA, "Soldier Token", 2, 2);
}
@Test
public void MuseVesselTest() {
String muse = "Muse Vessel";
addCard(Zone.HAND, playerA, muse);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 30);
addCard(Zone.BATTLEFIELD, playerA, "Vizier of Tumbling Sands", 2);
addCard(Zone.HAND, playerA, "Squire");
addCard(Zone.HAND, playerA, "Alpha Myr");
addCard(Zone.HAND, playerA, "Void Snare");
addCard(Zone.HAND, playerB, "Island");
addCard(Zone.HAND, playerB, "Corridor Monitor");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, muse, true);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Target player", playerB);
setChoice(playerB, "Island");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Untap", muse);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Target player", playerB);
setChoice(playerB, "Corridor Monitor");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Untap", muse);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Target player", playerA);
setChoice(playerA, "Squire");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}: Choose");
setChoice(playerA, "Island");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}: Choose");
setChoice(playerA, "Squire");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Squire", true);
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Island");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Void Snare", muse, true); // Bounce the vessel to hand, check exile ID correctly managed
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, muse, true);
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{1}: Choose"); // Should activate but no possible choices
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{3}, {T}: Target player", playerA);
setChoice(playerA, "Alpha Myr");
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{1}: Choose");
setChoice(playerA, "Alpha Myr");
checkPlayableAbility("Can cast on current turn", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Alpha Myr", true);
checkPlayableAbility("Can't cast on future turn", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Alpha Myr", false);
activateAbility(3, PhaseStep.BEGIN_COMBAT, playerA, "{1}: Choose");
setChoice(playerA, "Alpha Myr");
castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Alpha Myr");
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerA, 1); // Void Snare
assertGraveyardCount(playerB, 0);
assertExileCount(playerA, 0);
assertExileCount(playerB, 1); // Corridor Monitor remains in exile
assertPermanentCount(playerA, "Island", 1);
assertPermanentCount(playerA, "Squire", 1);
assertPermanentCount(playerA, "Alpha Myr", 1);
}
}

View file

@ -0,0 +1,70 @@
package org.mage.test.cards.single.afc;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.player.TestPlayer;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* {@link mage.cards.m.MantleOfTheAncients Mantle of the Ancients}
* {3}{W}{W}
* Enchantment Aura
* Enchant creature you control
* When this Aura enters, return any number of target Aura and/or Equipment cards from your graveyard to the battlefield attached to enchanted creature.
* Enchanted creature gets +1/+1 for each Aura and Equipment attached to it.
*
* @author notgreat
*/
public class MantleOfTheAncientsTest extends CardTestPlayerBase {
/**
* Ensure that cards that can't be attached are not returned, and that cards that can be are correctly attached
*/
@Test
public void testCardReturnsCorrectAttachments() {
String creature = "Skylasher";// Protection from Blue, 2/2 Creature and +1/+1 from first Mantle
addCard(Zone.HAND, playerA, "Mantle of the Ancients", 2);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 10);
addCard(Zone.BATTLEFIELD, playerA, creature);
addCard(Zone.BATTLEFIELD, playerA, "Grim Guardian"); // Counts number of enchantments entering
addCard(Zone.GRAVEYARD, playerA, "Konda's Banner"); // No attach, Not legendary, but is returned
addCard(Zone.GRAVEYARD, playerA, "O-Naginata"); // Yes attach, Pow >= 3
addCard(Zone.GRAVEYARD, playerA, "Aether Tunnel"); // No attach, Pro Blue, then Yes attach on 2nd try
addCard(Zone.GRAVEYARD, playerA, "Reprobation"); // Yes attach, Enchant Creature and removes Pro Blue ability
addCard(Zone.GRAVEYARD, playerA, "Indestructibility"); // Yes attach, Enchant Permanent
addCard(Zone.GRAVEYARD, playerA, "Abundant Growth"); // No attach, Enchant Land
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mantle of the Ancients", creature);
setChoice(playerA, "<i>Constellation"); //Stack trigger, Mantle + Grim
addTarget(playerA, "Konda's Banner^O-Naginata^Aether Tunnel^Reprobation^Indestructibility^Abundant Growth");
setChoice(playerA, "<i>Constellation"); //Stack trigger, Grim x2
checkPermanentCount("Gate Smasher not returned", 1, PhaseStep.BEGIN_COMBAT, playerA, "Gate Smasher",0);
checkPermanentCount("Aether Tunnel not returned", 1, PhaseStep.BEGIN_COMBAT, playerA, "Aether Tunnel",0);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Mantle of the Ancients", creature);
setChoice(playerA, "<i>Constellation</i>"); //Stack trigger, Mantle -> Grim
addTarget(playerA, "Gate Smasher^Aether Tunnel");
addTarget(playerA, TestPlayer.TARGET_SKIP);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAttachedTo(playerA, "Konda's Banner", creature, false);
assertPermanentCount(playerA, "Konda's Banner", 1);
assertAttachedTo(playerA, "O-Naginata", creature, true);
assertAttachedTo(playerA, "Aether Tunnel", creature, true);
assertAttachedTo(playerA, "Reprobation", creature, true);
assertAttachedTo(playerA, "Indestructibility", creature, true);
assertPermanentCount(playerA, "Abundant Growth", 0);
assertPermanentCount(playerA, "Mantle of the Ancients", 2);
assertPowerToughness(playerA, creature, 16, 13); // base 0/1, 6 attachments so +12/+12, O-Naginata plus Aether Tunnel +4/+0
assertLife(playerB, 15); // Mantle, Reprobation, Indestructibility + Mantle, Aether Tunnel
}
}

View file

@ -19,7 +19,11 @@ public class SoulSeizerTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerB, "Craw Wurm");
attack(1, playerA, "Soul Seizer");
addTarget(playerA, "Craw Wurm");
setChoice(playerA, true);
setStopAt(1, PhaseStep.END_COMBAT);
setStrictChooseMode(true);
execute();
assertLife(playerA, 20);
@ -38,8 +42,13 @@ public class SoulSeizerTest extends CardTestPlayerBase {
attack(1, playerA, "Soul Seizer");
addTarget(playerA, "Craw Wurm");
setChoice(playerA, true);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Clear", "Ghastly Haunting");
setStopAt(2, PhaseStep.BEGIN_COMBAT);
setStrictChooseMode(true);
execute();
assertLife(playerA, 20);
@ -59,7 +68,11 @@ public class SoulSeizerTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Battlegrowth", "Soul Seizer");
attack(1, playerA, "Soul Seizer");
addTarget(playerA, "Craw Wurm");
setChoice(playerA, true);
setStopAt(1, PhaseStep.END_COMBAT);
setStrictChooseMode(true);
execute();
assertLife(playerA, 20);

View file

@ -92,6 +92,7 @@ public class UnfinishedBusinessTest extends CardTestPlayerBase {
// EEB should never have been attached and therefore the White knight should be untapped
assertTapped(APOSTLE,false);
assertAttachedTo(playerA, EEB, APOSTLE,false);
assertPermanentCount(playerA, EEB, 1);
// Check that Ghoulflesh never entered the battlefield
assertLife(playerA, 20);