Merge pull request #5212 from magefree/5189-recast-spells-keep-their-previous-targets

Fix that cards that are cast using alternative cost effects keep their previous targets
This commit is contained in:
quercitron 2018-08-11 02:48:07 +03:00 committed by GitHub
commit db2db4c27a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 120 additions and 1 deletions

View file

@ -0,0 +1,115 @@
package org.mage.test.cards.cost.alternate;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Quercitron
*/
public class CastFromLibraryWithoutPayingManaCostTest extends CardTestPlayerBase {
/**
* Test for issue https://github.com/magefree/mage/issues/5189
*
* I've cast Utter End via Sunforger, then later on I've shuffled Utter End from my GY back into my library
* via Elixir of Immortality. I cast Utter End again via Sunforger, but this time I don't get prompted to select
* a target - it keeps the old target, a permanent that's already in exile, and thus the recast Utter End fizzles.
*/
@Test
public void testCastCardFromLibraryTwice() {
addCard(Zone.BATTLEFIELD, playerA, "Storm Crow");
// {R}{W}, Unattach Sunforger: Search your library for a red or white instant card with
// converted mana cost 4 or less and cast that card without paying its mana cost. Then shuffle your library.
// Equip {3}
addCard(Zone.BATTLEFIELD, playerA, "Sunforger");
// {2}, {T}: You gain 5 life. Shuffle Elixir of Immortality and your graveyard into their owner's library.
addCard(Zone.BATTLEFIELD, playerA, "Elixir of Immortality");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 10);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10);
// Exile target nonland permanent.
addCard(Zone.LIBRARY, playerA, "Utter End");
addCard(Zone.BATTLEFIELD, playerB, "Gray Ogre");
addCard(Zone.BATTLEFIELD, playerB, "Hill Giant");
// Equip Sunforger to Storm Crow.
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", "Storm Crow");
// Unattach Sunforger to cast Utter End from library targeting Gray Ogre.
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}{W}, Unattach");
addTarget(playerA, "Utter End");
addTarget(playerA, "Gray Ogre");
// Sacrifice Elixir of Immortality to shuffle Utter End from graveyard to library.
activateAbility(1, PhaseStep.BEGIN_COMBAT, playerA, "{2}, {T}: You gain 5 life");
// Equip Sunforger to Storm Crow again.
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Equip", "Storm Crow");
// Unattach Sunforger to cast Utter End from library targeting Hill Giant.
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{R}{W}, Unattach");
addTarget(playerA, "Utter End");
addTarget(playerA, "Hill Giant");
setStopAt(1, PhaseStep.END_TURN);
execute();
// Check that Elixir of Immortality was sacrificed.
assertPermanentCount(playerA, "Elixir of Immortality", 0);
// Check that Gray Ogre was exiled.
assertPermanentCount(playerB, "Gray Ogre", 0);
// Check that Hill Giant was exiled.
assertPermanentCount(playerB, "Hill Giant", 0);
// Check that Utter End is in the graveyard.
assertGraveyardCount(playerA, "Utter End", 1);
}
@Test
public void testCastCardFromHandAndThenFromLibrary() {
addCard(Zone.BATTLEFIELD, playerA, "Storm Crow");
// {R}{W}, Unattach Sunforger: Search your library for a red or white instant card with
// converted mana cost 4 or less and cast that card without paying its mana cost. Then shuffle your library.
// Equip {3}
addCard(Zone.BATTLEFIELD, playerA, "Sunforger");
addCard(Zone.BATTLEFIELD, playerA, "Elixir of Immortality");
// {2}, {T}: You gain 5 life. Shuffle Elixir of Immortality and your graveyard into their owner's library.
addCard(Zone.BATTLEFIELD, playerA, "Plains", 10);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 10);
// Exile target nonland permanent.
addCard(Zone.HAND, playerA, "Utter End");
addCard(Zone.BATTLEFIELD, playerB, "Gray Ogre");
addCard(Zone.BATTLEFIELD, playerB, "Hill Giant");
// Cast Utter End from hand targeting Gray Ogre.
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Utter End", "Gray Ogre");
// Sacrifice Elixir of Immortality to shuffle Utter End from graveyard to library.
activateAbility(1, PhaseStep.BEGIN_COMBAT, playerA, "{2}, {T}: You gain 5 life");
// Equip Sunforger to Storm Crow.
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Equip", "Storm Crow");
// Unattach Sunforger to cast Utter End from library targeting Hill Giant.
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{R}{W}, Unattach");
addTarget(playerA, "Utter End");
addTarget(playerA, "Hill Giant");
setStopAt(1, PhaseStep.END_TURN);
execute();
// Check that Elixir of Immortality was sacrificed.
assertPermanentCount(playerA, "Elixir of Immortality", 0);
// Check that Gray Ogre was exiled.
assertPermanentCount(playerB, "Gray Ogre", 0);
// Check that Hill Giant was exiled.
assertPermanentCount(playerB, "Hill Giant", 0);
// Check that Utter End is in the graveyard.
assertGraveyardCount(playerA, "Utter End", 1);
}
}

View file

@ -1045,6 +1045,10 @@ public abstract class PlayerImpl implements Player, Serializable {
if (game == null || ability == null) {
return false;
}
// Use ability copy to avoid problems with targets and costs on recast (issue https://github.com/magefree/mage/issues/5189).
ability = ability.copy();
ability.setControllerId(getId());
if (ability.getSpellAbilityType() != SpellAbilityType.BASE) {
ability = chooseSpellAbilityForCast(ability, game, noMana);
@ -1267,7 +1271,7 @@ public abstract class PlayerImpl implements Player, Serializable {
result = playManaAbility((ActivatedManaAbilityImpl) ability.copy(), game);
break;
case SPELL:
result = cast((SpellAbility) ability.copy(), game, false, activationStatus.getPermittingObject());
result = cast((SpellAbility) ability, game, false, activationStatus.getPermittingObject());
break;
default:
result = playAbility(ability.copy(), game);