Rework AsThough handling to allow choosing/affecting a specific alternate cast (#11114)

* Rework AsThoughEffect

* some cleanup of MageIdentifer

* refactor ActivationStatus

* fix bolas's citadel

* fix a couple of the Alternative Cost being applied too broadly.

* fix Risen Executioneer

* allow cancellation of AsThough choice.

* fix One with the Multiverse

* cleanup cards needing their own MageIdentifier

* last couple of fixes

* apply reviews for cleaner code.

* some more cleanup
This commit is contained in:
Susucre 2023-10-03 00:42:54 +02:00 committed by GitHub
parent ba135abc78
commit 7c454fb24c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 1176 additions and 395 deletions

View file

@ -0,0 +1,81 @@
package org.mage.test.cards.abilities.other;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Alex-Vasile, Susucr
*/
public class MultipleAsThoughEffects extends CardTestPlayerBase {
/**
* Reported bug: https://github.com/magefree/mage/issues/8584
*
* If there are multiple effects which allow a player to cast a spell,
* they should be able to choose which one they whish to use.
*/
@Test
public void ChoosingAlternateCastingMethod() {
setStrictChooseMode(true);
skipInitShuffling();
// You may cast creature spells from the top of your library.
addCard(Zone.HAND, playerA, "Vivien, Monsters' Advocate");
// You may play lands and cast spells from the top of your library.
// If you cast a spell this way, pay life equal to its mana value rather than pay its mana cost.
addCard(Zone.BATTLEFIELD, playerA, "Bolas's Citadel");
// Random creature card to play with mana value of 3
addCard(Zone.LIBRARY, playerA, "Abzan Beastmaster",2);
addCard(Zone.LIBRARY, playerA, "Grizzly Bears",1); // This one is drawn.
addCard(Zone.BATTLEFIELD, playerA, "Forest",5);
// For the "cast from the top" abilities to work, Vivien or Bolas's Citadel
// must be played and not be in battlefield as start. Or else the top of the library will
// not be able to be cast during the test.
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vivien, Monsters' Advocate");
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Abzan Beastmaster",true);
setChoice(playerA, "Vivien");
checkLife("Vivien not making pay life", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 20);
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Abzan Beastmaster");
setChoice(playerA, "Bolas's");
setStopAt(3, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Abzan Beastmaster", 2);
assertTappedCount("Forest", true, 3);
assertLife(playerA, 20 - 3); // 3 from casting Abzan Beastmaster with Bolas Citadel
}
/**
* Reported bug: https://github.com/magefree/mage/issues/2087
*
* If there are multiple effects which allow a player to cast a spell,
* they should be able to choose which one they whish to use, even if one is single-use.
*/
@Test
public void RisenExecutioner() {
setStrictChooseMode(true);
// You may cast Risen Executioner from your graveyard if you pay {1} more to cast it for each other creature card in your graveyard.
addCard(Zone.GRAVEYARD, playerA, "Risen Executioner", 2);
addCard(Zone.GRAVEYARD, playerA, "Grizzly Bears", 1);
// During each of your turns, you may cast a Zombie creature spell from your graveyard.
addCard(Zone.BATTLEFIELD, playerA, "Gisa and Geralf");
addCard(Zone.BATTLEFIELD, playerA, "Swamp",9); // Only enough mana to cast
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Risen Executioner", true); // Should cost {2}{B}{B} since cast with Gisa
setChoice(playerA, "Gisa");
checkPermanentTapped("Swamp tapped after cast with Gisa and Geralf", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swamp", true, 4);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Risen Executioner"); // Should cost {3}{B}{B} when cast with own ability, there is another creature in the graveyard
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Risen Executioner", 2);
assertTappedCount("Swamp", true, 4 + 5);
}
}

View file

@ -734,6 +734,7 @@ public class AdventureCardsTest extends CardTestPlayerBase {
checkExileCount("after exile 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Curious Pair", 1);
// play as adventure spell
castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Treats to Share");
setChoice(playerA, "Hostage Taker"); // Not sure why there is an alternative there. No issue with using either. TODO: investigate?
waitStackResolved(3, PhaseStep.POSTCOMBAT_MAIN);
checkPermanentCount("after play 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Food Token", 1);

View file

@ -96,11 +96,12 @@ public class KaradorGhostChieftainTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5);
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
//
// {1}{B}: Target attacking Zombie gains indestructible until end of turn.
addCard(Zone.LIBRARY, playerA, "Accursed Horde", 1); // Creature Zombie {3}{B}
addCard(Zone.LIBRARY, playerA, "Carrion Screecher", 1); // Creature Zombie {3}{B}
//
addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 5); // Creature {1}{W}
//
@ -119,15 +120,64 @@ public class KaradorGhostChieftainTest extends CardTestPlayerBase {
// you play any creatures due to two approve objects
checkPlayableAbility("before", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Silvercoat Lion", true);
checkPlayableAbility("before", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Accursed Horde", true);
checkPlayableAbility("before", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Carrion Screecher", true);
// cast zombie creature and approves by Karagar
// cast zombie creature and approves by Karador
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Accursed Horde");
setChoice(playerA, "Karador, Ghost Chieftain"); // choose the permitting object
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
waitStackResolved(3, PhaseStep.PRECOMBAT_MAIN);
// you can't cast lion due to approving object (Gisa needs zombie)
checkPlayableAbility("after", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Silvercoat Lion", false);
checkPlayableAbility("after", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Accursed Horde", false);
checkPlayableAbility("after", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Carrion Screecher", true);
setStrictChooseMode(true);
setStopAt(3, PhaseStep.BEGIN_COMBAT);
execute();
}
@Test
public void test_castFromGraveyardWithDifferentApproversOtherCast() {
skipInitShuffling();
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6);
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
//
// {1}{B}: Target attacking Zombie gains indestructible until end of turn.
addCard(Zone.LIBRARY, playerA, "Accursed Horde", 1); // Creature Zombie {3}{B}
addCard(Zone.LIBRARY, playerA, "Carrion Screecher", 1); // Creature Zombie {3}{B}
//
addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 5); // Creature {1}{W}
//
// Karador, Ghost Chieftain costs {1} less to cast for each creature card in your graveyard.
// During each of your turns, you may cast one creature card from your graveyard.
addCard(Zone.HAND, playerA, "Karador, Ghost Chieftain");// {5}{B}{G}{W}
//
// When Gisa and Geralf enters the battlefield, put the top four cards of your library into your graveyard.
// During each of your turns, you may cast a Zombie creature card from your graveyard.
addCard(Zone.HAND, playerA, "Gisa and Geralf"); // CREATURE {2}{U}{B} (4/4)
// prepare spels with same AsThough effects and puts creature to graveyard
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gisa and Geralf");
// you play any creatures due to two approve objects
checkPlayableAbility("before", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Silvercoat Lion", true);
checkPlayableAbility("before", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Accursed Horde", true);
checkPlayableAbility("before", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Carrion Screecher", true);
// cast zombie creature and approves by Gisa and Geralf
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Accursed Horde");
setChoice(playerA, "Gisa and Geralf"); // choose the permitting object
waitStackResolved(3, PhaseStep.PRECOMBAT_MAIN);
// you can't cast lion due to approving object (Gisa needs zombie)
checkPlayableAbility("after", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Silvercoat Lion", true);
checkPlayableAbility("after", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Accursed Horde", false);
checkPlayableAbility("after", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Carrion Screecher", true);
setStrictChooseMode(true);
setStopAt(3, PhaseStep.BEGIN_COMBAT);

View file

@ -0,0 +1,370 @@
package org.mage.test.cards.single.bro;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Susucr
*/
public class OneWithTheMultiverseTest extends CardTestPlayerBase {
/** One with the Multiverse
* {6}{U}{U}
* Enchantment
*
* You may look at the top card of your library any time.
* You may play lands and cast spells from the top of your library.
* Once during each of your turns, you may cast a spell from your hand or the top of your library without paying its mana cost.
*/
private final String owtm = "One with the Multiverse";
private final String ogre = "Gray Ogre"; // 2/2 {2}{R}
private final String piker = "Goblin Piker"; // 2/1 {1}{R}
@Test
public void castFromTopForFree() {
setStrictChooseMode(true);
skipInitShuffling();
// The "You may look at the top card of your library any time."
// is not set up properly if starting directly on the battlefield.
// So we do cast it in those tests.
addCard(Zone.HAND, playerA, owtm);
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 8);
addCard(Zone.LIBRARY, playerA, ogre, 3);
addCard(Zone.HAND, playerA, piker, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, owtm, true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ogre, true);
setChoice(playerA, "Without paying manacost");
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", false);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", false);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, ogre, 1);
assertPermanentCount(playerA, piker, 0);
assertLibraryCount(playerA, ogre, 2);
assertHandCount(playerA, piker, 2);
}
@Test
public void castFromHandForFree() {
setStrictChooseMode(true);
skipInitShuffling();
// The "You may look at the top card of your library any time."
// is not set up properly if starting directly on the battlefield.
// So we do cast it in those tests.
addCard(Zone.HAND, playerA, owtm);
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 8);
addCard(Zone.LIBRARY, playerA, ogre, 3);
addCard(Zone.HAND, playerA, piker, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, owtm, true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piker, true);
setChoice(playerA, "Without paying manacost");
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", false);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", false);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, ogre, 0);
assertPermanentCount(playerA, piker, 1);
assertLibraryCount(playerA, ogre, 3);
assertHandCount(playerA, piker, 1);
}
@Test
public void castFromTopForFreeThenNormalFromTop() {
setStrictChooseMode(true);
skipInitShuffling();
// The "You may look at the top card of your library any time."
// is not set up properly if starting directly on the battlefield.
// So we do cast it in those tests.
addCard(Zone.HAND, playerA, owtm);
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 11);
addCard(Zone.LIBRARY, playerA, ogre, 3);
addCard(Zone.HAND, playerA, piker, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, owtm, true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ogre, true);
setChoice(playerA, "Without paying manacost");
checkPlayableAbility("can cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ogre, true);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", false);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", false);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, ogre, 2);
assertPermanentCount(playerA, piker, 0);
assertLibraryCount(playerA, ogre, 1);
assertHandCount(playerA, piker, 2);
assertTappedCount("Volcanic Island", true, 8 + 3);
}
@Test
public void castFromTopForFreeThenNormalFromHand() {
setStrictChooseMode(true);
skipInitShuffling();
// The "You may look at the top card of your library any time."
// is not set up properly if starting directly on the battlefield.
// So we do cast it in those tests.
addCard(Zone.HAND, playerA, owtm);
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 11);
addCard(Zone.LIBRARY, playerA, ogre, 3);
addCard(Zone.HAND, playerA, piker, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, owtm, true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ogre, true);
setChoice(playerA, "Without paying manacost");
checkPlayableAbility("can cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piker, true);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", false);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", false);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, ogre, 1);
assertPermanentCount(playerA, piker, 1);
assertLibraryCount(playerA, ogre, 2);
assertHandCount(playerA, piker, 1);
assertTappedCount("Volcanic Island", true, 8 + 2);
}
@Test
public void castFromHandForFreeThenNormalFromHand() {
setStrictChooseMode(true);
skipInitShuffling();
// The "You may look at the top card of your library any time."
// is not set up properly if starting directly on the battlefield.
// So we do cast it in those tests.
addCard(Zone.HAND, playerA, owtm);
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 11);
addCard(Zone.LIBRARY, playerA, ogre, 3);
addCard(Zone.HAND, playerA, piker, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, owtm, true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piker, true);
setChoice(playerA, "Without paying manacost");
checkPlayableAbility("can cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piker, true);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", false);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", false);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, ogre, 0);
assertPermanentCount(playerA, piker, 2);
assertLibraryCount(playerA, ogre, 3);
assertHandCount(playerA, piker, 0);
assertTappedCount("Volcanic Island", true, 8 + 2);
}
@Test
public void castFromHandForFreeThenNormalFromTop() {
setStrictChooseMode(true);
skipInitShuffling();
// The "You may look at the top card of your library any time."
// is not set up properly if starting directly on the battlefield.
// So we do cast it in those tests.
addCard(Zone.HAND, playerA, owtm);
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 11);
addCard(Zone.LIBRARY, playerA, ogre, 3);
addCard(Zone.HAND, playerA, piker, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, owtm, true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piker, true);
setChoice(playerA, "Without paying manacost");
checkPlayableAbility("can cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ogre, true);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", false);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", false);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, ogre, 1);
assertPermanentCount(playerA, piker, 1);
assertLibraryCount(playerA, ogre, 2);
assertHandCount(playerA, piker, 1);
assertTappedCount("Volcanic Island", true, 8 + 3);
}
@Test
public void castNormalFromTopThenFreeFromHand() {
setStrictChooseMode(true);
skipInitShuffling();
// The "You may look at the top card of your library any time."
// is not set up properly if starting directly on the battlefield.
// So we do cast it in those tests.
addCard(Zone.HAND, playerA, owtm);
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 11);
addCard(Zone.LIBRARY, playerA, ogre, 3);
addCard(Zone.HAND, playerA, piker, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, owtm, true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ogre, true);
setChoice(playerA, owtm);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piker, true);
setChoice(playerA, "Without paying manacost");
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", false);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", false);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, ogre, 1);
assertPermanentCount(playerA, piker, 1);
assertLibraryCount(playerA, ogre, 2);
assertHandCount(playerA, piker, 1);
assertTappedCount("Volcanic Island", true, 8 + 3);
}
@Test
public void castNormalFromTopThenFreeFromTop() {
setStrictChooseMode(true);
skipInitShuffling();
// The "You may look at the top card of your library any time."
// is not set up properly if starting directly on the battlefield.
// So we do cast it in those tests.
addCard(Zone.HAND, playerA, owtm);
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 11);
addCard(Zone.LIBRARY, playerA, ogre, 3);
addCard(Zone.HAND, playerA, piker, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, owtm, true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ogre, true);
setChoice(playerA, owtm);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ogre, true);
setChoice(playerA, "Without paying manacost");
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", false);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", false);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, ogre, 2);
assertPermanentCount(playerA, piker, 0);
assertLibraryCount(playerA, ogre, 1);
assertHandCount(playerA, piker, 2);
assertTappedCount("Volcanic Island", true, 8 + 3);
}
@Test
public void castNormalFromHandThenFreeFromHand() {
setStrictChooseMode(true);
skipInitShuffling();
// The "You may look at the top card of your library any time."
// is not set up properly if starting directly on the battlefield.
// So we do cast it in those tests.
addCard(Zone.HAND, playerA, owtm);
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 11);
addCard(Zone.LIBRARY, playerA, ogre, 3);
addCard(Zone.HAND, playerA, piker, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, owtm, true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piker, true);
setChoice(playerA, piker);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piker, true);
setChoice(playerA, "Without paying manacost");
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", false);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", false);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, ogre, 0);
assertPermanentCount(playerA, piker, 2);
assertLibraryCount(playerA, ogre, 3);
assertHandCount(playerA, piker, 0);
assertTappedCount("Volcanic Island", true, 8 + 2);
}
@Test
public void castNormalFromHandThenFreeFromTop() {
setStrictChooseMode(true);
skipInitShuffling();
// The "You may look at the top card of your library any time."
// is not set up properly if starting directly on the battlefield.
// So we do cast it in those tests.
addCard(Zone.HAND, playerA, owtm);
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 11);
addCard(Zone.LIBRARY, playerA, ogre, 3);
addCard(Zone.HAND, playerA, piker, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, owtm, true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piker, true);
setChoice(playerA, piker);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", true);
checkPlayableAbility("can cast for free", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ogre, true);
setChoice(playerA, "Without paying manacost");
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Gray Ogre", false);
checkPlayableAbility("can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Piker", false);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, ogre, 1);
assertPermanentCount(playerA, piker, 1);
assertLibraryCount(playerA, ogre, 2);
assertHandCount(playerA, piker, 1);
assertTappedCount("Volcanic Island", true, 8 + 2);
}
}

View file

@ -46,6 +46,7 @@ public class ValkiGodOfLiesTest extends CardTestPlayerBase {
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+2: Exile the top card of each player's library.");
playLand(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Plains");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Ephemerate", "Grizzly Bears");
setChoice(playerA, "Emblem Tibalt");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);

View file

@ -3161,22 +3161,22 @@ public class TestPlayer implements Player {
}
@Override
public void setCastSourceIdWithAlternateMana(UUID sourceId, ManaCosts manaCosts, Costs costs) {
computerPlayer.setCastSourceIdWithAlternateMana(sourceId, manaCosts, costs);
public void setCastSourceIdWithAlternateMana(UUID sourceId, ManaCosts manaCosts, Costs costs, MageIdentifier identifier) {
computerPlayer.setCastSourceIdWithAlternateMana(sourceId, manaCosts, costs, identifier);
}
@Override
public Set<UUID> getCastSourceIdWithAlternateMana() {
public Map<UUID, Set<MageIdentifier>> getCastSourceIdWithAlternateMana() {
return computerPlayer.getCastSourceIdWithAlternateMana();
}
@Override
public Map<UUID, ManaCosts<ManaCost>> getCastSourceIdManaCosts() {
public Map<UUID, Map<MageIdentifier,ManaCosts<ManaCost>>> getCastSourceIdManaCosts() {
return computerPlayer.getCastSourceIdManaCosts();
}
@Override
public Map<UUID, Costs<Cost>> getCastSourceIdCosts() {
public Map<UUID, Map<MageIdentifier,Costs<Cost>>> getCastSourceIdCosts() {
return computerPlayer.getCastSourceIdCosts();
}

View file

@ -1,6 +1,7 @@
package org.mage.test.stub;
import mage.ApprovingObject;
import mage.MageIdentifier;
import mage.MageObject;
import mage.Mana;
import mage.abilities.*;
@ -1270,22 +1271,22 @@ public class PlayerStub implements Player {
}
@Override
public Set<UUID> getCastSourceIdWithAlternateMana() {
public Map<UUID, Set<MageIdentifier>> getCastSourceIdWithAlternateMana() {
return null;
}
@Override
public void setCastSourceIdWithAlternateMana(UUID sourceId, ManaCosts<ManaCost> manaCosts, Costs<Cost> costs) {
public void setCastSourceIdWithAlternateMana(UUID sourceId, ManaCosts<ManaCost> manaCosts, Costs<Cost> costs, MageIdentifier identifier) {
}
@Override
public Map<UUID, Costs<Cost>> getCastSourceIdCosts() {
public Map<UUID, Map<MageIdentifier,Costs<Cost>>> getCastSourceIdCosts() {
return null;
}
@Override
public Map<UUID, ManaCosts<ManaCost>> getCastSourceIdManaCosts() {
public Map<UUID, Map<MageIdentifier, ManaCosts<ManaCost>>> getCastSourceIdManaCosts() {
return null;
}