From 1d22d59c42326d7d90653a0ef27521e6ed279a8a Mon Sep 17 00:00:00 2001
From: magenoxx <magenoxx@gmail>
Date: Fri, 8 Jun 2012 17:55:44 +0400
Subject: [PATCH] Added zoneChangeCounter to fix spell fizzle on flicker bug.
 All tests passed.

---
 Mage/src/mage/cards/Card.java        |  2 ++
 Mage/src/mage/cards/CardImpl.java    | 14 ++++++++++++++
 Mage/src/mage/game/stack/Spell.java  |  7 ++++++-
 Mage/src/mage/target/TargetImpl.java | 27 +++++++++++++++++++++++++--
 4 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/Mage/src/mage/cards/Card.java b/Mage/src/mage/cards/Card.java
index 918c52fb6f..45988f0135 100644
--- a/Mage/src/mage/cards/Card.java
+++ b/Mage/src/mage/cards/Card.java
@@ -67,6 +67,8 @@ public interface Card extends MageObject {
 
 	public void assignNewId();
 
+    public int getZoneChangeCounter();
+
     /**
      * Moves the card to the specified zone
      * @param zone
diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java
index f9e099c066..1fc0102aad 100644
--- a/Mage/src/mage/cards/CardImpl.java
+++ b/Mage/src/mage/cards/CardImpl.java
@@ -66,6 +66,7 @@ public abstract class CardImpl<T extends CardImpl<T>> extends MageObjectImpl<T>
     protected boolean nightCard;
     protected SpellAbility spellAbility;
     protected boolean flipCard;
+    protected int zoneChangeCounter = 1;
 
     public CardImpl(UUID ownerId, int cardNumber, String name, Rarity rarity, CardType[] cardTypes, String costs) {
         this(ownerId, name);
@@ -277,6 +278,7 @@ public abstract class CardImpl<T extends CardImpl<T>> extends MageObjectImpl<T>
                     return false;
             }
             setControllerId(ownerId);
+            updateZoneChangeCounter();
             game.setZone(objectId, event.getToZone());
             game.fireEvent(event);
             return game.getState().getZone(objectId) == toZone;
@@ -342,6 +344,7 @@ public abstract class CardImpl<T extends CardImpl<T>> extends MageObjectImpl<T>
             } else {
                 game.getExile().createZone(exileId, name).add(this);
             }
+            updateZoneChangeCounter();
             game.setZone(objectId, event.getToZone());
             game.fireEvent(event);
             return true;
@@ -373,6 +376,7 @@ public abstract class CardImpl<T extends CardImpl<T>> extends MageObjectImpl<T>
                     logger.warn("Couldn't find card in fromZone, card=" + getName() + ", fromZone=" + fromZone);
                 }
             }
+            updateZoneChangeCounter();
             PermanentCard permanent = new PermanentCard(this, controllerId);
             game.getBattlefield().addPermanent(permanent);
             game.setZone(objectId, Zone.BATTLEFIELD);
@@ -420,7 +424,17 @@ public abstract class CardImpl<T extends CardImpl<T>> extends MageObjectImpl<T>
         return this.nightCard;
     }
 
+    @Override
     public boolean isFlipCard() {
         return flipCard;
     }
+
+    @Override
+    public int getZoneChangeCounter() {
+        return zoneChangeCounter;
+    }
+
+    private void updateZoneChangeCounter() {
+        zoneChangeCounter++;
+    }
 }
diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java
index 1aa98f664f..e8b29c6327 100644
--- a/Mage/src/mage/game/stack/Spell.java
+++ b/Mage/src/mage/game/stack/Spell.java
@@ -436,7 +436,12 @@ public class Spell<T extends Spell<T>> implements StackObject, Card {
 		throw new UnsupportedOperationException("Unsupported operation");
 	}
 
-	public void setCopiedSpell(boolean isCopied) {
+    @Override
+    public int getZoneChangeCounter() {
+        return card.getZoneChangeCounter();
+    }
+
+    public void setCopiedSpell(boolean isCopied) {
 		this.copiedSpell = isCopied;
 	}
 	
diff --git a/Mage/src/mage/target/TargetImpl.java b/Mage/src/mage/target/TargetImpl.java
index cabb4d3381..b86b59d97a 100644
--- a/Mage/src/mage/target/TargetImpl.java
+++ b/Mage/src/mage/target/TargetImpl.java
@@ -31,6 +31,7 @@ package mage.target;
 import mage.Constants.Outcome;
 import mage.Constants.Zone;
 import mage.abilities.Ability;
+import mage.cards.Card;
 import mage.game.Game;
 import mage.game.events.GameEvent;
 import mage.game.events.GameEvent.EventType;
@@ -45,7 +46,8 @@ import java.util.*;
 public abstract class TargetImpl<T extends TargetImpl<T>> implements Target {
 
 	protected Map<UUID, Integer> targets = new LinkedHashMap<UUID, Integer>();
-
+    protected Map<UUID, Integer> zoneChangeCounters = new HashMap<UUID, Integer>();
+    
 	protected String targetName;
 	protected Zone zone;
 	protected int maxNumberOfTargets;
@@ -73,6 +75,7 @@ public abstract class TargetImpl<T extends TargetImpl<T>> implements Target {
 		this.required = target.required;
 		this.chosen = target.chosen;
         this.targets.putAll(target.targets);
+        this.zoneChangeCounters.putAll(target.zoneChangeCounters);
 	}
 
 	@Override
@@ -152,6 +155,7 @@ public abstract class TargetImpl<T extends TargetImpl<T>> implements Target {
 	@Override
 	public void clearChosen() {
 		targets.clear();
+        zoneChangeCounters.clear();
 		chosen = false;
 	}
 
@@ -160,14 +164,17 @@ public abstract class TargetImpl<T extends TargetImpl<T>> implements Target {
 		if (maxNumberOfTargets == 0 || targets.size() < maxNumberOfTargets) {
 			if (!targets.containsKey(id)) {
 				targets.put(id, 0);
+                rememberZoneChangeCounter(id, game);
 			}
 		}
 	}
     
     @Override
     public void remove(UUID id) {
-        if (targets.containsKey(id))
+        if (targets.containsKey(id)) {
             targets.remove(id);
+            zoneChangeCounters.remove(id);
+        }
     }
 
 	@Override
@@ -183,6 +190,7 @@ public abstract class TargetImpl<T extends TargetImpl<T>> implements Target {
 				if (source != null) {
 					if (!game.replaceEvent(GameEvent.getEvent(EventType.TARGET, id, source.getId(), source.getControllerId()))) {
 						targets.put(id, 0);
+                        rememberZoneChangeCounter(id, game);
 						chosen = targets.size() >= minNumberOfTargets;
                         if (!skipEvent)
                             game.fireEvent(GameEvent.getEvent(EventType.TARGETED, id, source.getId(), source.getControllerId()));
@@ -195,6 +203,13 @@ public abstract class TargetImpl<T extends TargetImpl<T>> implements Target {
 		}
 	}
 
+    private void rememberZoneChangeCounter(UUID id, Game game) {
+        Card card = game.getCard(id);
+        if (card != null) {
+            zoneChangeCounters.put(id, card.getZoneChangeCounter());
+        }
+    }
+
     @Override
 	public void addTarget(UUID id, int amount, Ability source, Game game) {
         addTarget(id, amount, source, game, false);
@@ -208,6 +223,7 @@ public abstract class TargetImpl<T extends TargetImpl<T>> implements Target {
 		if (source != null) {
 			if (!game.replaceEvent(GameEvent.getEvent(EventType.TARGET, id, source.getId(), source.getControllerId()))) {
 				targets.put(id, amount);
+                rememberZoneChangeCounter(id, game);
 				chosen = targets.size() >= minNumberOfTargets;
                 if (!skipEvent)
                     game.fireEvent(GameEvent.getEvent(EventType.TARGETED, id, source.getId(), source.getControllerId()));
@@ -215,6 +231,7 @@ public abstract class TargetImpl<T extends TargetImpl<T>> implements Target {
 		}
 		else {
 			targets.put(id, amount);
+            rememberZoneChangeCounter(id, game);
 		}
 	}
     
@@ -248,6 +265,12 @@ public abstract class TargetImpl<T extends TargetImpl<T>> implements Target {
 	public boolean isLegal(Ability source, Game game) {
 		//20101001 - 608.2b
         for (UUID targetId: targets.keySet()) {
+            Card card = game.getCard(targetId);
+            if (card != null) {
+                if (zoneChangeCounters.containsKey(targetId) && zoneChangeCounters.get(targetId) != card.getZoneChangeCounter()) {
+                    continue; // it's not legal so continue to have a look at other targeted cards
+                }
+            }
 			if (game.replaceEvent(GameEvent.getEvent(EventType.TARGET, targetId, source.getId(), source.getControllerId())))
 				continue;
 			if (canTarget(targetId, source, game))