mirror of
https://github.com/correl/mage.git
synced 2024-12-26 03:00:11 +00:00
Fixed a bug that fizzling spell copies let also wrongly fizzle the original spell on the stack the copy was made from.
This commit is contained in:
parent
2d20045b61
commit
c042d50ec7
5 changed files with 106 additions and 28 deletions
|
@ -64,7 +64,7 @@ public class AtraxaPraetorsVoice extends CardImpl {
|
|||
// Lifelink
|
||||
this.addAbility(LifelinkAbility.getInstance());
|
||||
|
||||
// At the beginning of your end step, proliferate.
|
||||
// At the beginning of your end step, proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.)
|
||||
this.addAbility(new BeginningOfEndStepTriggeredAbility(new ProliferateEffect(), TargetController.YOU, false));
|
||||
}
|
||||
|
||||
|
|
|
@ -90,8 +90,9 @@ public class CopySpellTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Reported bug: "Silverfur Partisan and fellow wolves did not trigger off of copies of Strength of Arms made by Zada, Hedron Grinder.
|
||||
* Not sure about other spells, but I imagine similar results."
|
||||
* Reported bug: "Silverfur Partisan and fellow wolves did not trigger off
|
||||
* of copies of Strength of Arms made by Zada, Hedron Grinder. Not sure
|
||||
* about other spells, but I imagine similar results."
|
||||
*/
|
||||
@Test
|
||||
public void ZadaHedronSilverfurPartisan() {
|
||||
|
@ -206,12 +207,13 @@ public class CopySpellTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* {4}{U} Enchantment (Enchant Player)
|
||||
* Whenever enchanted player casts an instant or sorcery spell, each other player may copy that spell
|
||||
* and may choose new targets for the copy he or she controls.
|
||||
* {4}{U} Enchantment (Enchant Player) Whenever enchanted player casts an
|
||||
* instant or sorcery spell, each other player may copy that spell and may
|
||||
* choose new targets for the copy he or she controls.
|
||||
*
|
||||
* Reported bug: "A player with Curse of Echoes attached to them played Bribery and the player who controlled the curse had control
|
||||
* of all 3 copies. This seems to be the case for all spells."
|
||||
* Reported bug: "A player with Curse of Echoes attached to them played
|
||||
* Bribery and the player who controlled the curse had control of all 3
|
||||
* copies. This seems to be the case for all spells."
|
||||
*/
|
||||
@Test
|
||||
public void testCurseOfEchoes() {
|
||||
|
@ -236,4 +238,56 @@ public class CopySpellTest extends CardTestPlayerBase {
|
|||
assertLife(playerB, 17); // copy redirected
|
||||
}
|
||||
|
||||
/**
|
||||
* What happened was my opponent had an Atraxa, Praetors' Voice and a
|
||||
* Walking Ballista with 2 counters in play. On my turn, I cast Flame Slash
|
||||
* targeting Atraxa and holding priority, then I cast Dualcaster Mage. I
|
||||
* change the target of the Flame Slash copy to Walking Ballista. My
|
||||
* opponent removes the counters from Ballista to kill a 2/2 creature of
|
||||
* mine. Game log says both Flame Slashes fizzle, and Atraxa ends up still
|
||||
* being in play at the end of it all. Only the Flame Slash targeting
|
||||
* Walking Ballista should have fizzled.
|
||||
*/
|
||||
@Test
|
||||
public void testOnlyCopyFizzles() {
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||
// Flying, vigilance, deathtouch, lifelink
|
||||
// At the beginning of your end step, proliferate.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Atraxa, Praetors' Voice", 4);
|
||||
// Walking Ballista enters the battlefield with X +1/+1 counters on it.
|
||||
// {4}: Put a +1/+1 counter on Walking Ballista.
|
||||
// Remove a +1/+1 counter from Walking Ballista: It deals 1 damage to target creature or player.
|
||||
addCard(Zone.HAND, playerA, "Walking Ballista"); // {X}{X}
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
|
||||
// Flame Slash deals 4 damage to target creature.
|
||||
addCard(Zone.HAND, playerB, "Flame Slash"); // Sorcery {R}
|
||||
// Flash
|
||||
// When Dualcaster Mage enters the battlefield, copy target instant or sorcery spell. You may choose new targets for the copy.
|
||||
addCard(Zone.HAND, playerB, "Dualcaster Mage"); // Creature {1}{R}{R}
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 4);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Walking Ballista");
|
||||
setChoice(playerA, "X=1");
|
||||
setChoice(playerA, "Walking Ballista"); // for proliferate
|
||||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Flame Slash", "Atraxa, Praetors' Voice");
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Dualcaster Mage");
|
||||
addTarget(playerB, "Flame Slash"); // original target
|
||||
setChoice(playerB, "Yes");
|
||||
addTarget(playerB, "Walking Ballista");
|
||||
|
||||
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Remove a", "Silvercoat Lion", "Flame Slash", StackClause.WHILE_COPY_ON_STACK);
|
||||
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Remove a", "Silvercoat Lion", "Flame Slash", StackClause.WHILE_COPY_ON_STACK);
|
||||
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
|
||||
assertPermanentCount(playerB, "Dualcaster Mage", 1);
|
||||
assertPermanentCount(playerA, "Atraxa, Praetors' Voice", 0);
|
||||
assertPermanentCount(playerA, "Walking Ballista", 0);
|
||||
assertGraveyardCount(playerB, "Flame Slash", 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,6 +190,16 @@ public class TestPlayer implements Player {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
} else if (groups[2].startsWith("spellCopyOnStack=")) {
|
||||
String spellOnStack = groups[2].substring(17);
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
if (stackObject.getStackAbility().toString().contains(spellOnStack)) {
|
||||
if (stackObject.isCopy()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (groups[2].startsWith("!spellOnStack=")) {
|
||||
String spellNotOnStack = groups[2].substring(14);
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
|
@ -223,7 +233,7 @@ public class TestPlayer implements Player {
|
|||
boolean result = true;
|
||||
for (int i = 1; i < groupsForTargetHandling.length; i++) {
|
||||
String group = groupsForTargetHandling[i];
|
||||
if (group.startsWith("spellOnStack") || group.startsWith("spellOnTopOfStack") || group.startsWith("!spellOnStack") || group.startsWith("target=null") || group.startsWith("manaInPool=")) {
|
||||
if (group.startsWith("spell") || group.startsWith("!spell") || group.startsWith("target=null") || group.startsWith("manaInPool=")) {
|
||||
break;
|
||||
}
|
||||
if (ability instanceof SpellAbility && ((SpellAbility) ability).getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) {
|
||||
|
|
|
@ -1022,6 +1022,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
public enum StackClause {
|
||||
|
||||
WHILE_ON_STACK,
|
||||
WHILE_COPY_ON_STACK,
|
||||
WHILE_NOT_ON_STACK
|
||||
}
|
||||
|
||||
|
@ -1105,6 +1106,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
* @param targetName if not target has to be defined use the constant
|
||||
* NO_TARGET
|
||||
* @param spellOnStack
|
||||
* @param clause
|
||||
*/
|
||||
public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack, StackClause clause) {
|
||||
StringBuilder sb = new StringBuilder("activate:").append(ability);
|
||||
|
@ -1112,7 +1114,19 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
sb.append("$target=").append(targetName);
|
||||
}
|
||||
if (spellOnStack != null && !spellOnStack.isEmpty()) {
|
||||
sb.append('$').append(StackClause.WHILE_ON_STACK.equals(clause) ? "" : "!").append("spellOnStack=").append(spellOnStack);
|
||||
sb.append('$');
|
||||
switch (clause) {
|
||||
case WHILE_ON_STACK:
|
||||
sb.append("spellOnStack=");
|
||||
break;
|
||||
case WHILE_NOT_ON_STACK:
|
||||
sb.append("!spellOnStack=");
|
||||
break;
|
||||
case WHILE_COPY_ON_STACK:
|
||||
sb.append("spellCopyOnStack=");
|
||||
break;
|
||||
}
|
||||
sb.append(spellOnStack);
|
||||
}
|
||||
player.addAction(turnNum, step, sb.toString());
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
*/
|
||||
package mage.game.stack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
|
@ -63,11 +67,6 @@ import mage.game.permanent.PermanentCard;
|
|||
import mage.players.Player;
|
||||
import mage.util.GameLog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -394,7 +393,8 @@ public class Spell extends StackObjImpl implements Card {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
card.removeFromZone(game, Zone.STACK, sourceId);
|
||||
// Copied spell, only remove from stack
|
||||
game.getStack().remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue