* Cast an instant or sorcery spell this turn - fixed rollback error when you cast graveyard spell as first in turn (#7918);

This commit is contained in:
Oleg Agafonov 2021-06-23 05:05:51 +04:00
parent daf77b2ee8
commit 9a4489b47f
3 changed files with 105 additions and 12 deletions

View file

@ -0,0 +1,30 @@
package org.mage.test.cards.single.mh1;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author JayDi85
*/
public class LavaDartTest extends CardTestPlayerBase {
@Test
public void test_Play() {
// Lava Dart deals 1 damage to any target.
// Flashback-Sacrifice a Mountain.
addCard(Zone.GRAVEYARD, playerA, "Lava Dart"); // {R}
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flashback", playerB);
setChoice(playerA, "Mountain"); // sacrifice cost
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertLife(playerB, 20 - 1);
}
}

View file

@ -0,0 +1,73 @@
package org.mage.test.cards.single.stx;
import mage.abilities.keyword.VigilanceAbility;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.watchers.common.SpellsCastWatcher;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author JayDi85
*/
public class ShowOfConfidenceTest extends CardTestPlayerBase {
@Test
public void test_SpellsCastWatcher() {
// When you cast this spell, copy it for each other instant or sorcery spell you've cast this turn. You may choose new targets for the copies.
// Put a +1/+1 counter on target creature. It gains vigilance until end of turn.
addCard(Zone.HAND, playerA, "Show of Confidence"); // {1}{W}
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
//
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1);
addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
addCard(Zone.GRAVEYARD, playerA, "Lightning Bolt", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
//
// Each instant and sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost.
addCard(Zone.HAND, playerA, "Past in Flames", 1); // {3}{R}
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
// prepare NPE error for watcher
runCode("prepare watcher's NPE", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
// possible bug: NPE after wrong computeIfAbsent usage (lists desync)
SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class);
watcher.getSpellsCastThisTurn(player.getId());
});
// prepare flashback
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}", 4);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Past in Flames");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
// prepare spells count (1x from hand, 1x from grave)
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flashback {R}", playerB);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
// cast and copy 3x
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Show of Confidence", "Balduvian Bears");
setChoice(playerA, "No"); // no change target (copy 1)
setChoice(playerA, "No"); // no change target (copy 2)
setChoice(playerA, "No"); // no change target (copy 3)
// test watcher's copy
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
runCode("test watcher's copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class);
SpellsCastWatcher copiedWatcher = watcher.copy();
Assert.assertEquals("original watcher must see 4 spells", 4, watcher.getSpellsCastThisTurn(player.getId()).size());
Assert.assertEquals("copied watcher must see 4 spells", 4, copiedWatcher.getSpellsCastThisTurn(player.getId()).size());
});
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertCounterCount(playerA, "Balduvian Bears", CounterType.P1P1, 4);
assertAbility(playerA, "Balduvian Bears", VigilanceAbility.getInstance(), true);
}
}

View file

@ -36,18 +36,8 @@ public class SpellsCastWatcher extends Watcher {
}
}
if (spell != null) {
List<Spell> spells;
List<Spell> graveyardSpells;
if (!spellsCast.containsKey(spell.getControllerId())) {
spells = new ArrayList<>();
spellsCast.put(spell.getControllerId(), spells);
graveyardSpells = new ArrayList<>();
spellsCastFromGraveyard.put(spell.getControllerId(), graveyardSpells);
} else {
spells = spellsCast.get(spell.getControllerId());
graveyardSpells = spellsCastFromGraveyard.get(spell.getControllerId());
}
List<Spell> spells = spellsCast.computeIfAbsent(spell.getControllerId(), x -> new ArrayList<>());
List<Spell> graveyardSpells = spellsCastFromGraveyard.computeIfAbsent(spell.getControllerId(), x -> new ArrayList<>());
spells.add(spell.copy()); // copy needed because attributes like color could be changed later
if (event.getZone() == Zone.GRAVEYARD) {
graveyardSpells.add(spell.copy());