* Flashback - Fixed that exile effect was not removed after applied.

This commit is contained in:
LevelX2 2016-03-10 00:09:50 +01:00
parent c2b68a9b6f
commit 3184252d54
4 changed files with 53 additions and 12 deletions

View file

@ -214,4 +214,35 @@ public class FlashbackTest extends CardTestPlayerBase {
assertHandCount(playerA, 0);
}
/**
* I cast Runic Repetition targeting a Silent Departure in exile, and
* afterwards I cast the Silent Departure from my hand. When it resolves, it
* goes back to exile instead of ending up in my graveyard. Looks like a
* problem with Runic Repetition?
*/
@Test
public void testFlashbackReturnToHandAndCastAgain() {
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 2);
addCard(Zone.BATTLEFIELD, playerA, "Island", 9);
// Return target creature to its owner's hand.
// Flashback {4}{U}
addCard(Zone.GRAVEYARD, playerA, "Silent Departure", 1); // {U}
addCard(Zone.HAND, playerA, "Runic Repetition", 1);// {2}{U}
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flashback");
addTarget(playerA, "Silvercoat Lion");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Runic Repetition");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silent Departure", "Silvercoat Lion");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertHandCount(playerA, "Silvercoat Lion", 2);
assertExileCount("Silent Departure", 0);
assertGraveyardCount(playerA, "Silent Departure", 1);
assertGraveyardCount(playerA, "Runic Repetition", 1);
}
}

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.common;
import mage.abilities.TriggeredAbilityImpl;
@ -41,7 +40,6 @@ import mage.target.targetpointer.FixedTarget;
*
* @author Loki
*/
public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl {
private TargetController targetController;
@ -90,7 +88,7 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl {
case YOU:
boolean yours = event.getPlayerId().equals(this.controllerId);
if (yours && setTargetPointer) {
if (getTargets().size() == 0) {
if (getTargets().isEmpty()) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getPlayerId()));
}
@ -99,7 +97,7 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl {
return yours;
case OPPONENT:
if (game.getPlayer(this.controllerId).hasOpponent(event.getPlayerId(), game)) {
if (setTargetPointer && getTargets().size() == 0) {
if (setTargetPointer && getTargets().isEmpty()) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getPlayerId()));
}
@ -108,7 +106,7 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl {
}
break;
case ANY:
if (setTargetPointer && getTargets().size() == 0) {
if (setTargetPointer && getTargets().isEmpty()) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getPlayerId()));
}
@ -119,7 +117,7 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl {
if (attachment != null && attachment.getAttachedTo() != null) {
Permanent attachedTo = game.getPermanent(attachment.getAttachedTo());
if (attachedTo != null && attachedTo.getControllerId().equals(event.getPlayerId())) {
if (setTargetPointer && getTargets().size() == 0) {
if (setTargetPointer && getTargets().isEmpty()) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getPlayerId()));
}
@ -143,9 +141,9 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl {
switch (targetController) {
case YOU:
if (this.optional) {
if (sb.substring(0, 6).toLowerCase().equals("target")){
if (sb.substring(0, 6).toLowerCase().equals("target")) {
sb.insert(0, "you may have ");
} else if (!sb.substring(0, 4).toLowerCase().equals("you ")){
} else if (!sb.substring(0, 4).toLowerCase().equals("you ")) {
sb.insert(0, "you may ");
}
}

View file

@ -32,6 +32,7 @@ import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.VariableCost;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.Card;
@ -45,6 +46,7 @@ import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
/**
* 702.32. Flashback
@ -206,7 +208,9 @@ class FlashbackEffect extends OneShotEffect {
}
spellAbility.setCostModificationActive(false); // prevents to apply cost modification twice for flashbacked spells
if (controller.cast(spellAbility, game, false)) {
game.addEffect(new FlashbackReplacementEffect(), source);
ContinuousEffect effect = new FlashbackReplacementEffect();
effect.setTargetPointer(new FixedTarget(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId())));
game.addEffect(effect, source);
return true;
}
return false;
@ -256,8 +260,16 @@ class FlashbackReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return event.getTargetId().equals(source.getSourceId())
if (event.getTargetId().equals(source.getSourceId())
&& ((ZoneChangeEvent) event).getFromZone() == Zone.STACK
&& ((ZoneChangeEvent) event).getToZone() != Zone.EXILED;
&& ((ZoneChangeEvent) event).getToZone() != Zone.EXILED) {
discard();
int zcc = game.getState().getZoneChangeCounter(source.getSourceId());
if (((FixedTarget) getTargetPointer()).getZoneChangeCounter() == zcc) {
return true;
}
}
return false;
}
}

View file

@ -625,7 +625,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
this.removeFromCombat(game);
this.controlledFromStartOfControllerTurn = false;
this.abilities.setControllerId(controllerId);
this.getAbilities(game).setControllerId(controllerId);
game.getContinuousEffects().setController(objectId, controllerId);
// the controller of triggered abilites is always set/checked before the abilities triggers so not needed here
game.fireEvent(new GameEvent(EventType.LOST_CONTROL, objectId, objectId, beforeResetControllerId));