forked from External/mage
[TDM] fix Mistrise Village effect
* Add additional tests and fix effect to only work on next spell cast * closes #13891
This commit is contained in:
parent
ef270721a5
commit
05e304e621
2 changed files with 185 additions and 24 deletions
|
|
@ -1,10 +1,6 @@
|
|||
package mage.cards.m;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.CantBeCounteredSourceAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTappedUnlessAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.condition.common.YouControlPermanentCondition;
|
||||
|
|
@ -13,7 +9,6 @@ import mage.abilities.costs.mana.ManaCostsImpl;
|
|||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.AddContinuousEffectToGame;
|
||||
import mage.abilities.effects.common.continuous.NextSpellCastHasAbilityEffect;
|
||||
import mage.abilities.mana.BlueManaAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
|
@ -27,6 +22,10 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.watchers.common.SpellsCastWatcher;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -71,6 +70,8 @@ public final class MistriseVillage extends CardImpl {
|
|||
|
||||
class MistriseCantBeCounteredEffect extends ContinuousRuleModifyingEffectImpl {
|
||||
|
||||
private int spellsCastThisTurn;
|
||||
|
||||
public MistriseCantBeCounteredEffect() {
|
||||
super(Duration.OneUse, Outcome.Benefit, false, true);
|
||||
staticText = "the next spell you cast this turn can't be countered";
|
||||
|
|
@ -78,6 +79,7 @@ class MistriseCantBeCounteredEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
|
||||
protected MistriseCantBeCounteredEffect(final MistriseCantBeCounteredEffect effect) {
|
||||
super(effect);
|
||||
this.spellsCastThisTurn = effect.spellsCastThisTurn;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -90,6 +92,15 @@ class MistriseCantBeCounteredEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
return event.getType() == GameEvent.EventType.COUNTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class);
|
||||
if (watcher != null) {
|
||||
spellsCastThisTurn = watcher.getSpellsCastThisTurn(source.getControllerId()).size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
StackObject sourceObject = game.getStack().getStackObject(event.getSourceId());
|
||||
|
|
@ -103,10 +114,17 @@ class MistriseCantBeCounteredEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
boolean res = spell != null && spell.isControlledBy(source.getControllerId());
|
||||
if (res) {
|
||||
discard();
|
||||
SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class);
|
||||
if (spell == null || !spell.isControlledBy(source.getControllerId()) || watcher == null) {
|
||||
return false;
|
||||
}
|
||||
return res;
|
||||
List<Spell> spellsCast = watcher.getSpellsCastThisTurn(source.getControllerId());
|
||||
for (int i = 0; i < spellsCast.size(); i++) {
|
||||
if (i == spellsCastThisTurn && spellsCast.get(i).getId().equals(spell.getId())) {
|
||||
discard();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,41 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
|
||||
public class MistriseVillageTest extends CardTestPlayerBase {
|
||||
|
||||
/*
|
||||
Mistrise Village
|
||||
Land
|
||||
This land enters tapped unless you control a Mountain or a Forest.
|
||||
{T}: Add {U}.
|
||||
{U}, {T}: The next spell you cast this turn can’t be countered.
|
||||
*/
|
||||
private static final String MISTRISE = "Mistrise Village";
|
||||
private static final String COUNTER = "Counterspell";
|
||||
private static final String CUB = "Bear Cub";
|
||||
private static final String BEARS = "Balduvian Bears";
|
||||
private static final String COUNTERSPELL = "Counterspell";
|
||||
private static final String BEAR_CUB = "Bear Cub";
|
||||
private static final String BALDUVIAN_BEARS = "Balduvian Bears";
|
||||
/*
|
||||
Force of Negation
|
||||
{1}{U}{U}
|
||||
Instant
|
||||
If it’s not your turn, you may exile a blue card from your hand rather than pay this spell’s mana cost.
|
||||
Counter target noncreature spell. If that spell is countered this way, exile it instead of putting it into its owner’s graveyard.
|
||||
*/
|
||||
public static final String FORCE_OF_NEGATION = "Force of Negation";
|
||||
/*
|
||||
Narset, Parter of Veils
|
||||
{1}{U}{U}
|
||||
Legendary Planeswalker — Narset
|
||||
Each opponent can’t draw more than one card each turn.
|
||||
−2: Look at the top four cards of your library. You may reveal a noncreature, nonland card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
|
||||
*/
|
||||
public static final String NARSET_PARTER_OF_VEILS = "Narset, Parter of Veils";
|
||||
/*
|
||||
Aether Spellbomb
|
||||
{1}
|
||||
Artifact
|
||||
{U}, Sacrifice this artifact: Return target creature to its owner’s hand.
|
||||
{1}, Sacrifice this artifact: Draw a card.
|
||||
*/
|
||||
public static final String AETHER_SPELLBOMB = "Aether Spellbomb";
|
||||
|
||||
@Test
|
||||
public void testCounter() {
|
||||
|
|
@ -21,22 +52,134 @@ public class MistriseVillageTest extends CardTestPlayerBase {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "Island");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 4);
|
||||
addCard(Zone.HAND, playerB, COUNTER, 2);
|
||||
addCard(Zone.HAND, playerA, CUB);
|
||||
addCard(Zone.HAND, playerA, BEARS);
|
||||
addCard(Zone.HAND, playerB, COUNTERSPELL, 2);
|
||||
addCard(Zone.HAND, playerA, BEAR_CUB);
|
||||
addCard(Zone.HAND, playerA, BALDUVIAN_BEARS);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}, {T}");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}, {T}"); // Activate mistrise
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, CUB, true);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, COUNTER, CUB, CUB);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, BEARS, true);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, COUNTER, BEARS, BEARS);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, BEAR_CUB, true);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, COUNTERSPELL, BEAR_CUB, BEAR_CUB);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, BALDUVIAN_BEARS, true);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, COUNTERSPELL, BALDUVIAN_BEARS, BALDUVIAN_BEARS);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, CUB, 1);
|
||||
assertGraveyardCount(playerA, BEARS, 1);
|
||||
assertGraveyardCount(playerB, COUNTER, 2);
|
||||
assertPermanentCount(playerA, BEAR_CUB, 1);
|
||||
assertGraveyardCount(playerA, BALDUVIAN_BEARS, 1);
|
||||
assertGraveyardCount(playerB, COUNTERSPELL, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCastCounterAfterCastingSpell() {
|
||||
setStrictChooseMode(true);
|
||||
skipInitShuffling();
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, MISTRISE);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 8);
|
||||
addCard(Zone.HAND, playerA, NARSET_PARTER_OF_VEILS);
|
||||
addCard(Zone.HAND, playerA, AETHER_SPELLBOMB);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 3);
|
||||
addCard(Zone.HAND, playerB, FORCE_OF_NEGATION);
|
||||
addCard(Zone.LIBRARY, playerA, "Stock Up");
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}, {T}"); // Activate mistrise
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, NARSET_PARTER_OF_VEILS);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-2: "); // Narset ability
|
||||
setChoice(playerA, true);
|
||||
addTarget(playerA, "Stock Up");
|
||||
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Stock Up");
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, FORCE_OF_NEGATION, "Stock Up");
|
||||
|
||||
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN, playerA);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, AETHER_SPELLBOMB);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, NARSET_PARTER_OF_VEILS, 1);
|
||||
assertPermanentCount(playerA, AETHER_SPELLBOMB, 1);
|
||||
assertGraveyardCount(playerB, FORCE_OF_NEGATION, 1);
|
||||
assertExileCount(playerA, "Stock Up", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleMistrise() {
|
||||
setStrictChooseMode(true);
|
||||
skipInitShuffling();
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, MISTRISE,2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 8);
|
||||
addCard(Zone.HAND, playerA, NARSET_PARTER_OF_VEILS);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 6);
|
||||
addCard(Zone.HAND, playerB, FORCE_OF_NEGATION, 2);
|
||||
addCard(Zone.LIBRARY, playerA, AETHER_SPELLBOMB);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}, {T}"); // Activate mistrise
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}, {T}"); // Activate mistrise
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 2);
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, NARSET_PARTER_OF_VEILS);
|
||||
checkPlayableAbility("cast force", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cast Force", true);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, FORCE_OF_NEGATION, NARSET_PARTER_OF_VEILS); // Fail to counter
|
||||
setChoice(playerB, "Cast with no alternative cost");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-2: "); // Narset ability
|
||||
setChoice(playerA, true);
|
||||
addTarget(playerA, AETHER_SPELLBOMB);
|
||||
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, AETHER_SPELLBOMB);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, FORCE_OF_NEGATION, AETHER_SPELLBOMB); // Successful counter
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, NARSET_PARTER_OF_VEILS, 1);
|
||||
assertGraveyardCount(playerB, FORCE_OF_NEGATION, 2);
|
||||
assertExileCount(playerA, AETHER_SPELLBOMB, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleMistriseNotConsecutive() {
|
||||
setStrictChooseMode(true);
|
||||
skipInitShuffling();
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, MISTRISE,2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 8);
|
||||
addCard(Zone.HAND, playerA, NARSET_PARTER_OF_VEILS);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 6);
|
||||
addCard(Zone.HAND, playerB, FORCE_OF_NEGATION, 2);
|
||||
addCard(Zone.LIBRARY, playerA, AETHER_SPELLBOMB);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}, {T}"); // Activate mistrise
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 1);
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, NARSET_PARTER_OF_VEILS);
|
||||
checkPlayableAbility("cast force", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cast Force", true);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, FORCE_OF_NEGATION, NARSET_PARTER_OF_VEILS); // Fail to counter
|
||||
setChoice(playerB, "Cast with no alternative cost");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-2: "); // Narset ability
|
||||
setChoice(playerA, true);
|
||||
addTarget(playerA, AETHER_SPELLBOMB);
|
||||
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{U}, {T}"); // Activate mistrise
|
||||
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN, 1);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, AETHER_SPELLBOMB);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, FORCE_OF_NEGATION, AETHER_SPELLBOMB); // Successful counter
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, NARSET_PARTER_OF_VEILS, 1);
|
||||
assertGraveyardCount(playerB, FORCE_OF_NEGATION, 2);
|
||||
assertPermanentCount(playerA, AETHER_SPELLBOMB, 1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue