* Soulfire Grand Master - Fixed that a countered spell did wrongly return to hand if second ability was used.

This commit is contained in:
LevelX2 2015-04-18 11:53:51 +02:00
parent 2d3c98a7b4
commit 47b1753519
5 changed files with 102 additions and 37 deletions

View file

@ -89,27 +89,26 @@ class CurseOfInertiaTriggeredAbility extends TriggeredAbilityImpl {
public CurseOfInertiaTriggeredAbility() {
super(Zone.BATTLEFIELD, new CurseOfInertiaTapOrUntapTargetEffect(), false);
}
public CurseOfInertiaTriggeredAbility(Effect effect, boolean optional, String text) {
super(Zone.BATTLEFIELD, effect, optional);
}
public CurseOfInertiaTriggeredAbility(final CurseOfInertiaTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType().equals(EventType.DECLARED_ATTACKERS);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getType().equals(EventType.DECLARED_ATTACKERS)) {
Permanent enchantment = game.getPermanent(this.getSourceId());
if (enchantment != null
&& enchantment.getAttachedTo() != null
&& game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo())) {
for (Effect effect: this.getEffects()) {
effect.setTargetPointer(new FixedTarget(game.getCombat().getAttackerId()));
}
return true;
}
Permanent enchantment = game.getPermanent(this.getSourceId());
if (enchantment != null
&& enchantment.getAttachedTo() != null
&& game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo())) {
TargetPermanent target = new TargetPermanent();
target.setTargetController(game.getCombat().getAttackerId());
addTarget(target);
return true;
}
return false;
}
@ -138,24 +137,20 @@ class CurseOfInertiaTapOrUntapTargetEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source));
Player player = game.getPlayer(source.getTargets().get(0).getTargetController());
if (player != null) {
Target target = new TargetPermanent();
if (target.canChoose(source.getSourceId(), player.getId(), game)
&& player.choose(outcome, target, source.getSourceId(), game)) {
Permanent targetPermanent = game.getPermanent(target.getFirstTarget());
if (targetPermanent != null) {
if (targetPermanent.isTapped()) {
if (player.chooseUse(Outcome.Untap, "Untap that permanent?", game)) {
targetPermanent.untap(game);
}
} else {
if (player.chooseUse(Outcome.Tap, "Tap that permanent?", game)) {
targetPermanent.tap(game);
}
Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (targetPermanent != null) {
if (targetPermanent.isTapped()) {
if (player.chooseUse(Outcome.Untap, "Untap that permanent?", game)) {
targetPermanent.untap(game);
}
} else {
if (player.chooseUse(Outcome.Tap, "Tap that permanent?", game)) {
targetPermanent.tap(game);
}
return true;
}
return true;
}
}
return false;

View file

@ -48,14 +48,12 @@ import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.SubLayer;
import mage.constants.TargetController;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.FilterObject;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
@ -230,7 +228,10 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect
if (zEvent.getFromZone() == Zone.STACK &&
zEvent.getToZone() == Zone.GRAVEYARD &&
event.getTargetId().equals(spellId)) {
return true;
Spell spell = game.getStack().getSpell(spellId);
if (spell != null && !spell.isCountered()) {
return true;
}
}
}
return false;

View file

@ -30,7 +30,6 @@ package org.mage.test.cards.abilities.other;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
@ -42,7 +41,7 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase {
/**
* Soulfire Grand Master
* Creature â Human Monk 2/2, 1W (2)
* Creature - Human Monk 2/2, 1W (2)
* Lifelink
* Instant and sorcery spells you control have lifelink.
* {2}{U/R}{U/R}: The next time you cast an instant or sorcery spell from
@ -233,5 +232,67 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase {
assertLife(playerA, 20);
}
/**
* I activated the ability of Soulfire grand master, it resolved, then i cast Stoke the Flames
* on Whisperwood Elemental, my opponenet sacrificed the elemental, so stoke didnt resolve,
* but i still got the life from lifelink.
*/
@Test
public void testSoulfireStokeTheFlames() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8);
addCard(Zone.HAND, playerA, "Stoke the Flames");
addCard(Zone.BATTLEFIELD, playerA, "Soulfire Grand Master", 1);
addCard(Zone.BATTLEFIELD, playerB, "Whisperwood Elemental", 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{U/R}{U/R}:");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Stoke the Flames", "Whisperwood Elemental");
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Sacrifice {this}", null ,"{this} deals 4 damage");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerA, "Stoke the Flames", 1); // no legal target left so the spell is countered and goes to graveyard
assertGraveyardCount(playerB, "Whisperwood Elemental", 1);
assertLife(playerB, 20);
assertLife(playerA, 20);
}
/**
* Check if second ability resolved, the next spell that is counterer
* won't go to hand back because it did not resolve
*
*/
@Test
public void testSoulfireCounteredSpellDontGoesBack() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8);
addCard(Zone.HAND, playerA, "Stoke the Flames");
addCard(Zone.BATTLEFIELD, playerA, "Soulfire Grand Master", 1);
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
addCard(Zone.HAND, playerB, "Counterspell", 1);
addCard(Zone.BATTLEFIELD, playerB, "Whisperwood Elemental", 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{U/R}{U/R}:");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Stoke the Flames", "Whisperwood Elemental");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Counterspell", "Stoke the Flames");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerB, "Counterspell", 1);
assertGraveyardCount(playerA, "Stoke the Flames", 1); // no legal target left so the spell is countered and goes to graveyard
assertLife(playerB, 20);
assertLife(playerA, 20);
}
}

View file

@ -82,6 +82,7 @@ public class Spell implements StackObject, Card {
private UUID controllerId;
private boolean copiedSpell;
private boolean faceDown;
private boolean countered;
public Spell(Card card, SpellAbility ability, UUID controllerId, Zone fromZone) {
this.card = card;
@ -100,6 +101,7 @@ public class Spell implements StackObject, Card {
}
this.controllerId = controllerId;
this.fromZone = fromZone;
this.countered = false;
}
public Spell(final Spell spell) {
@ -521,6 +523,7 @@ public class Spell implements StackObject, Card {
@Override
public void counter(UUID sourceId, Game game) {
this.countered = true;
if (!isCopiedSpell()) {
card.moveToZone(Zone.GRAVEYARD, sourceId, game, false);
}
@ -1002,4 +1005,8 @@ public class Spell implements StackObject, Card {
throw new UnsupportedOperationException("Not supported.");
}
public boolean isCountered() {
return countered;
}
}

View file

@ -97,9 +97,10 @@ public class SpellStack extends ArrayDeque<StackObject> {
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, objectId, sourceId, stackObject.getControllerId()))) {
if ( stackObject instanceof Spell ) {
game.rememberLKI(objectId, Zone.STACK, (Spell)stackObject);
} else {
this.remove(stackObject);
}
this.remove(stackObject);
stackObject.counter(sourceId, game); // tries to move to graveyard
stackObject.counter(sourceId, game);
if (!game.isSimulation())
game.informPlayers(counteredObjectName + " is countered by " + sourceObject.getLogName());
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERED, objectId, sourceId, stackObject.getControllerId()));