From ee870a8970758b52e2835b4a8c2564bf7716d354 Mon Sep 17 00:00:00 2001
From: BetaSteward <betasteward@gmail>
Date: Wed, 21 Sep 2011 14:01:00 -0400
Subject: [PATCH] changes to support tracking mana sources + some refactoring

---
 .../src/mage/sets/newphyrexia/CagedSun.java   |  10 +-
 .../newphyrexia/VorinclexVoiceOfHunger.java   |  12 +-
 Mage/src/mage/ConditionalMana.java            |  15 +
 Mage/src/mage/Constants.java                  |   4 +
 Mage/src/mage/Mana.java                       |  56 +-
 .../mage/abilities/costs/mana/ManaCost.java   |   3 +
 .../abilities/costs/mana/ManaCostImpl.java    | 115 +---
 .../abilities/costs/mana/ManaCostsImpl.java   |  13 +
 .../costs/mana/VariableManaCost.java          |   2 +-
 .../common/AddManaOfAnyColorEffect.java       |  10 +-
 .../effects/common/BasicManaEffect.java       |   2 +-
 .../effects/common/DynamicManaEffect.java     |   2 +-
 Mage/src/mage/players/ManaPool.java           | 542 +++++-------------
 Mage/src/mage/players/ManaPoolItem.java       | 206 +++++++
 Mage/src/mage/players/Players.java            |   5 +-
 15 files changed, 496 insertions(+), 501 deletions(-)
 create mode 100644 Mage/src/mage/players/ManaPoolItem.java

diff --git a/Mage.Sets/src/mage/sets/newphyrexia/CagedSun.java b/Mage.Sets/src/mage/sets/newphyrexia/CagedSun.java
index c4a8a12d57..fd6657b8c2 100644
--- a/Mage.Sets/src/mage/sets/newphyrexia/CagedSun.java
+++ b/Mage.Sets/src/mage/sets/newphyrexia/CagedSun.java
@@ -206,15 +206,15 @@ class CagedSunEffect extends ManaEffect<CagedSunEffect> {
         if (player != null) {
             ObjectColor color = (ObjectColor) game.getState().getValue(source.getSourceId() + "_color");
             if (color.isBlack())
-                player.getManaPool().changeMana(Mana.BlackMana, game, source);
+                player.getManaPool().addMana(Mana.BlackMana, game, source);
             else if (color.isBlue())
-                player.getManaPool().changeMana(Mana.BlueMana, game, source);
+                player.getManaPool().addMana(Mana.BlueMana, game, source);
             else if (color.isRed())
-                player.getManaPool().changeMana(Mana.RedMana, game, source);
+                player.getManaPool().addMana(Mana.RedMana, game, source);
             else if (color.isGreen())
-                player.getManaPool().changeMana(Mana.GreenMana, game, source);
+                player.getManaPool().addMana(Mana.GreenMana, game, source);
             else if (color.isWhite())
-                player.getManaPool().changeMana(Mana.WhiteMana, game, source);
+                player.getManaPool().addMana(Mana.WhiteMana, game, source);
         }
         return true;
     }
diff --git a/Mage.Sets/src/mage/sets/newphyrexia/VorinclexVoiceOfHunger.java b/Mage.Sets/src/mage/sets/newphyrexia/VorinclexVoiceOfHunger.java
index f80483cab8..0744bc3e1f 100644
--- a/Mage.Sets/src/mage/sets/newphyrexia/VorinclexVoiceOfHunger.java
+++ b/Mage.Sets/src/mage/sets/newphyrexia/VorinclexVoiceOfHunger.java
@@ -165,27 +165,27 @@ class VorinclexEffect extends ManaEffect<VorinclexEffect> {
             else
                 player.choose(outcome, choice, game);
             if (choice.getChoice().equals("Black")) {
-                player.getManaPool().changeMana(Mana.BlackMana, game, source);
+                player.getManaPool().addMana(Mana.BlackMana, game, source);
                 return true;
             }
             else if (choice.getChoice().equals("Blue")) {
-                player.getManaPool().changeMana(Mana.BlueMana, game, source);
+                player.getManaPool().addMana(Mana.BlueMana, game, source);
                 return true;
             }
             else if (choice.getChoice().equals("Red")) {
-                player.getManaPool().changeMana(Mana.RedMana, game, source);
+                player.getManaPool().addMana(Mana.RedMana, game, source);
                 return true;
             }
             else if (choice.getChoice().equals("Green")) {
-                player.getManaPool().changeMana(Mana.GreenMana, game, source);
+                player.getManaPool().addMana(Mana.GreenMana, game, source);
                 return true;
             }
             else if (choice.getChoice().equals("White")) {
-                player.getManaPool().changeMana(Mana.WhiteMana, game, source);
+                player.getManaPool().addMana(Mana.WhiteMana, game, source);
                 return true;
             }
             else if (choice.getChoice().equals("Colorless")) {
-                player.getManaPool().changeMana(Mana.ColorlessMana, game, source);
+                player.getManaPool().addMana(Mana.ColorlessMana, game, source);
                 return true;
             }
         }
diff --git a/Mage/src/mage/ConditionalMana.java b/Mage/src/mage/ConditionalMana.java
index a3d4509ef0..dc598f0bc8 100644
--- a/Mage/src/mage/ConditionalMana.java
+++ b/Mage/src/mage/ConditionalMana.java
@@ -27,9 +27,11 @@
 */
 package mage;
 
+import mage.Constants.ManaType;
 import mage.abilities.Ability;
 import mage.abilities.condition.Condition;
 import mage.filter.Filter;
+import mage.filter.FilterMana;
 import mage.game.Game;
 
 import java.io.Serializable;
@@ -109,4 +111,17 @@ public class ConditionalMana extends Mana implements Serializable {
 	public String getDescription() {
 		return staticText;
 	}
+
+    public void removeAll(FilterMana filter) {
+		if (filter == null) {
+			return;
+		}
+		if (filter.isBlack()) black = 0;
+		if (filter.isBlue()) blue = 0;
+		if (filter.isWhite()) white = 0;
+		if (filter.isGreen()) green = 0;
+		if (filter.isRed()) red = 0;
+		if (filter.isColorless()) colorless = 0;
+    }
+
 }
diff --git a/Mage/src/mage/Constants.java b/Mage/src/mage/Constants.java
index f3bc032a42..375c9de0e1 100644
--- a/Mage/src/mage/Constants.java
+++ b/Mage/src/mage/Constants.java
@@ -65,6 +65,10 @@ public final class Constants {
 
 	}
 
+    public enum ManaType {
+        BLACK, BLUE, GREEN, RED, WHITE, COLORLESS
+    }
+    
 	public enum CardType {
 		ARTIFACT ("Artifact"),
 		CREATURE ("Creature"),
diff --git a/Mage/src/mage/Mana.java b/Mage/src/mage/Mana.java
index 7cb8c5fedf..142f1d701d 100644
--- a/Mage/src/mage/Mana.java
+++ b/Mage/src/mage/Mana.java
@@ -31,6 +31,7 @@ package mage;
 import java.io.Serializable;
 
 import mage.Constants.ColoredManaSymbol;
+import mage.Constants.ManaType;
 import mage.filter.FilterMana;
 import mage.util.Copyable;
 
@@ -40,13 +41,13 @@ import mage.util.Copyable;
  */
 public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
 
-	private int red;
-	private int green;
-	private int blue;
-	private int white;
-	private int black;
-	private int colorless;
-	private int any;
+	protected int red;
+	protected int green;
+	protected int blue;
+	protected int white;
+	protected int black;
+	protected int colorless;
+	protected int any;
 
 	public static final Mana RedMana = RedMana(1);
 	public static final Mana GreenMana = GreenMana(1);
@@ -418,4 +419,45 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
 		return 0;
 	}
 
+    public int get(ManaType manaType) {
+        switch(manaType) {
+            case BLACK:
+                return black;
+            case BLUE:
+                return blue;
+            case GREEN:
+                return green;
+            case RED:
+                return red;
+            case WHITE:
+                return white;
+            case COLORLESS:
+                return colorless;
+        }
+        return 0;
+    }
+
+    public void set(ManaType manaType, int amount) {
+        switch(manaType) {
+            case BLACK:
+                black = amount;
+                break;
+            case BLUE:
+                blue = amount;
+                break;
+            case GREEN:
+                green = amount;
+                break;
+            case RED:
+                red = amount;
+                break;
+            case WHITE:
+                white = amount;
+                break;
+            case COLORLESS:
+                colorless = amount;
+                break;
+        }
+    }
+
 }
diff --git a/Mage/src/mage/abilities/costs/mana/ManaCost.java b/Mage/src/mage/abilities/costs/mana/ManaCost.java
index a1b888e956..c9c0fc526b 100644
--- a/Mage/src/mage/abilities/costs/mana/ManaCost.java
+++ b/Mage/src/mage/abilities/costs/mana/ManaCost.java
@@ -32,6 +32,7 @@ import mage.abilities.Ability;
 import mage.abilities.costs.*;
 import mage.Mana;
 import mage.abilities.mana.ManaOptions;
+import mage.filter.Filter;
 import mage.game.Game;
 import mage.players.ManaPool;
 
@@ -47,6 +48,8 @@ public interface ManaCost extends Cost {
 	public ManaCost getUnpaid();
 	public ManaOptions getOptions();
 	public boolean testPay(Mana testMana);
+    public Filter getSourceFilter();
+    public void setSourceFilter(Filter filter);
 
 	@Override
 	public ManaCost copy();
diff --git a/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java b/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java
index 71e002caf4..1383f27097 100644
--- a/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java
+++ b/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java
@@ -31,10 +31,12 @@ package mage.abilities.costs.mana;
 import java.util.UUID;
 
 import mage.Constants.ColoredManaSymbol;
+import mage.Constants.ManaType;
 import mage.Mana;
 import mage.abilities.Ability;
 import mage.abilities.costs.CostImpl;
 import mage.abilities.mana.ManaOptions;
+import mage.filter.Filter;
 import mage.game.Game;
 import mage.players.ManaPool;
 import mage.players.Player;
@@ -44,6 +46,7 @@ public abstract class ManaCostImpl<T extends ManaCostImpl<T>> extends CostImpl<T
     protected Mana payment;
     protected Mana cost;
     protected ManaOptions options;
+    protected Filter sourceFilter;
 
     @Override
     public abstract T copy();
@@ -58,6 +61,8 @@ public abstract class ManaCostImpl<T extends ManaCostImpl<T>> extends CostImpl<T
         this.payment = manaCost.payment.copy();
         this.cost = manaCost.cost.copy();
         this.options = manaCost.options.copy();
+        if (manaCost.sourceFilter != null)
+            this.sourceFilter = manaCost.sourceFilter.copy();
     }
 
     @Override
@@ -81,46 +86,45 @@ public abstract class ManaCostImpl<T extends ManaCostImpl<T>> extends CostImpl<T
         super.clearPaid();
     }
 
+    @Override
+    public Filter getSourceFilter() {
+        return this.sourceFilter;
+    }
+    
+    @Override
+    public void setSourceFilter(Filter filter) {
+        this.sourceFilter = filter;
+    }
+    
     protected boolean assignColored(Ability ability, Game game, ManaPool pool, ColoredManaSymbol mana) {
         // first check special mana
         switch (mana) {
             case B:
-                if (payConditionalBlack(ability, game, pool)) return true;
-                if (pool.getBlack() > 0) {
+                if (pool.pay(ManaType.BLACK, ability, sourceFilter, game)) {
                     this.payment.addBlack();
-                    pool.removeBlack();
                     return true;
                 }
                 break;
             case U:
-                if (payConditionalBlue(ability, game, pool)) return true;
-                if (pool.getBlue() > 0) {
+                if (pool.pay(ManaType.BLUE, ability, sourceFilter, game)) {
                     this.payment.addBlue();
-                    pool.removeBlue();
                     return true;
                 }
                 break;
             case W:
-                if (payConditionalWhite(ability, game, pool)) return true;
-                if (pool.getWhite() > 0) {
+                if (pool.pay(ManaType.WHITE, ability, sourceFilter, game)) {
                     this.payment.addWhite();
-                    pool.removeWhite();
                     return true;
                 }
-                break;
             case G:
-                if (payConditionalGreen(ability, game, pool)) return true;
-                if (pool.getGreen() > 0) {
+                if (pool.pay(ManaType.GREEN, ability, sourceFilter, game)) {
                     this.payment.addGreen();
-                    pool.removeGreen();
                     return true;
                 }
                 break;
             case R:
-                if (payConditionalRed(ability, game, pool)) return true;
-                if (pool.getRed() > 0) {
+                if (pool.pay(ManaType.RED, ability, sourceFilter, game)) {
                     this.payment.addRed();
-                    pool.removeRed();
                     return true;
                 }
                 break;
@@ -128,98 +132,31 @@ public abstract class ManaCostImpl<T extends ManaCostImpl<T>> extends CostImpl<T
         return false;
     }
 
-    private boolean payConditionalRed(Ability ability, Game game, ManaPool pool) {
-        if (pool.getConditionalRed(ability, game) > 0) {
-            this.payment.addRed();
-            pool.removeConditionalRed(ability, game);
-            return true;
-        }
-        return false;
-    }
-
-    private boolean payConditionalGreen(Ability ability, Game game, ManaPool pool) {
-        if (pool.getConditionalGreen(ability, game) > 0) {
-            this.payment.addGreen();
-            pool.removeConditionalGreen(ability, game);
-            return true;
-        }
-        return false;
-    }
-
-    private boolean payConditionalWhite(Ability ability, Game game, ManaPool pool) {
-        if (pool.getConditionalWhite(ability, game) > 0) {
-            this.payment.addWhite();
-            pool.removeConditionalWhite(ability, game);
-            return true;
-        }
-        return false;
-    }
-
-    private boolean payConditionalBlue(Ability ability, Game game, ManaPool pool) {
-        if (pool.getConditionalBlue(ability, game) > 0) {
-            this.payment.addBlue();
-            pool.removeConditionalBlue(ability, game);
-            return true;
-        }
-        return false;
-    }
-
-    private boolean payConditionalBlack(Ability ability, Game game, ManaPool pool) {
-        if (pool.getConditionalBlack(ability, game) > 0) {
-            this.payment.addBlack();
-            pool.removeConditionalBlack(ability, game);
-            return true;
-        }
-        return false;
-    }
-
-    private boolean payConditionalColorless(Ability ability, Game game, ManaPool pool) {
-        if (pool.getConditionalColorless(ability, game) > 0) {
-            this.payment.addColorless();
-            pool.removeConditionalColorless(ability, game);
-            return true;
-        }
-        return false;
-    }
-
     protected boolean assignColorless(Ability ability, Game game, ManaPool pool, int mana) {
         int conditionalCount = pool.getConditionalCount(ability, game, null);
         while (mana > payment.count() && (pool.count() > 0 || conditionalCount > 0)) {
-            if (payConditionalColorless(ability, game, pool)) continue;
-            if (payConditionalBlack(ability, game, pool)) continue;
-            if (payConditionalBlue(ability, game, pool)) continue;
-            if (payConditionalWhite(ability, game, pool)) continue;
-            if (payConditionalGreen(ability, game, pool)) continue;
-            if (payConditionalRed(ability, game, pool)) continue;
-
-            if (pool.getColorless() > 0) {
+            if (pool.pay(ManaType.COLORLESS, ability, sourceFilter, game)) {
                 this.payment.addColorless();
-                pool.removeColorless();
                 continue;
             }
-            if (pool.getBlack() > 0) {
+            if (pool.pay(ManaType.BLACK, ability, sourceFilter, game)) {
                 this.payment.addBlack();
-                pool.removeBlack();
                 continue;
             }
-            if (pool.getBlue() > 0) {
+            if (pool.pay(ManaType.BLUE, ability, sourceFilter, game)) {
                 this.payment.addBlue();
-                pool.removeBlue();
                 continue;
             }
-            if (pool.getWhite() > 0) {
+            if (pool.pay(ManaType.WHITE, ability, sourceFilter, game)) {
                 this.payment.addWhite();
-                pool.removeWhite();
                 continue;
             }
-            if (pool.getGreen() > 0) {
+            if (pool.pay(ManaType.GREEN, ability, sourceFilter, game)) {
                 this.payment.addGreen();
-                pool.removeGreen();
                 continue;
             }
-            if (pool.getRed() > 0) {
+            if (pool.pay(ManaType.RED, ability, sourceFilter, game)) {
                 this.payment.addRed();
-                pool.removeRed();
                 continue;
             }
             break;
diff --git a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java
index d2edd98b11..ada7a96506 100644
--- a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java
+++ b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java
@@ -33,6 +33,7 @@ import mage.Mana;
 import mage.abilities.Ability;
 import mage.abilities.costs.VariableCost;
 import mage.abilities.mana.ManaOptions;
+import mage.filter.Filter;
 import mage.game.Game;
 import mage.players.ManaPool;
 import mage.players.Player;
@@ -352,4 +353,16 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
         return new ManaCostsImpl(this);
     }
 
+    @Override
+    public Filter getSourceFilter() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void setSourceFilter(Filter filter) {
+        for (T cost : this) {
+            cost.setSourceFilter(filter);
+        }
+    }
+
 }
diff --git a/Mage/src/mage/abilities/costs/mana/VariableManaCost.java b/Mage/src/mage/abilities/costs/mana/VariableManaCost.java
index df352c618b..873b46f0bc 100644
--- a/Mage/src/mage/abilities/costs/mana/VariableManaCost.java
+++ b/Mage/src/mage/abilities/costs/mana/VariableManaCost.java
@@ -69,7 +69,7 @@ public class VariableManaCost extends ManaCostImpl<VariableManaCost> implements
 	public void assignPayment(Game game, Ability ability, ManaPool pool) {
 		payment.add(pool.getMana(filter));
 		payment.add(pool.getAllConditionalMana(ability, game, filter));
-		pool.emptyPoolConditional(ability, game, filter);
+		pool.payX(ability, game, filter);
 	}
 
 	@Override
diff --git a/Mage/src/mage/abilities/effects/common/AddManaOfAnyColorEffect.java b/Mage/src/mage/abilities/effects/common/AddManaOfAnyColorEffect.java
index 441ddb5421..6e88fda0cd 100644
--- a/Mage/src/mage/abilities/effects/common/AddManaOfAnyColorEffect.java
+++ b/Mage/src/mage/abilities/effects/common/AddManaOfAnyColorEffect.java
@@ -59,23 +59,23 @@ public class AddManaOfAnyColorEffect extends ManaEffect<AddManaOfAnyColorEffect>
 		ChoiceColor choice = (ChoiceColor) source.getChoices().get(0);
 		Player player = game.getPlayer(source.getControllerId());
 		if (choice.getColor().isBlack()) {
-			player.getManaPool().changeMana(Mana.BlackMana, game, source);
+			player.getManaPool().addMana(Mana.BlackMana, game, source);
 			return true;
 		}
 		else if (choice.getColor().isBlue()) {
-			player.getManaPool().changeMana(Mana.BlueMana, game, source);
+			player.getManaPool().addMana(Mana.BlueMana, game, source);
 			return true;
 		}
 		else if (choice.getColor().isRed()) {
-			player.getManaPool().changeMana(Mana.RedMana, game, source);
+			player.getManaPool().addMana(Mana.RedMana, game, source);
 			return true;
 		}
 		else if (choice.getColor().isGreen()) {
-			player.getManaPool().changeMana(Mana.GreenMana, game, source);
+			player.getManaPool().addMana(Mana.GreenMana, game, source);
 			return true;
 		}
 		else if (choice.getColor().isWhite()) {
-			player.getManaPool().changeMana(Mana.WhiteMana, game, source);
+			player.getManaPool().addMana(Mana.WhiteMana, game, source);
 			return true;
 		}
 		return false;
diff --git a/Mage/src/mage/abilities/effects/common/BasicManaEffect.java b/Mage/src/mage/abilities/effects/common/BasicManaEffect.java
index 4e977af95e..d8374f132c 100644
--- a/Mage/src/mage/abilities/effects/common/BasicManaEffect.java
+++ b/Mage/src/mage/abilities/effects/common/BasicManaEffect.java
@@ -33,7 +33,7 @@ public class BasicManaEffect extends ManaEffect<BasicManaEffect> {
 
     @Override
 	public boolean apply(Game game, Ability source) {
-		game.getPlayer(source.getControllerId()).getManaPool().changeMana(mana, game, source);
+		game.getPlayer(source.getControllerId()).getManaPool().addMana(mana, game, source);
 		return true;
 	}
 
diff --git a/Mage/src/mage/abilities/effects/common/DynamicManaEffect.java b/Mage/src/mage/abilities/effects/common/DynamicManaEffect.java
index 96ffaa0ddf..0a9139a985 100644
--- a/Mage/src/mage/abilities/effects/common/DynamicManaEffect.java
+++ b/Mage/src/mage/abilities/effects/common/DynamicManaEffect.java
@@ -63,7 +63,7 @@ public class DynamicManaEffect extends BasicManaEffect {
     @Override
     public boolean apply(Game game, Ability source) {
         computeMana(game, source);
-        game.getPlayer(source.getControllerId()).getManaPool().changeMana(computedMana, game, source);
+        game.getPlayer(source.getControllerId()).getManaPool().addMana(computedMana, game, source);
         return true;
     }
 
diff --git a/Mage/src/mage/players/ManaPool.java b/Mage/src/mage/players/ManaPool.java
index e777d9c649..efc6bd0e2b 100644
--- a/Mage/src/mage/players/ManaPool.java
+++ b/Mage/src/mage/players/ManaPool.java
@@ -34,6 +34,7 @@ import java.util.Iterator;
 import java.util.List;
 
 import mage.ConditionalMana;
+import mage.Constants.ManaType;
 import mage.Mana;
 import mage.abilities.Ability;
 import mage.filter.Filter;
@@ -47,236 +48,75 @@ import mage.game.events.GameEvent;
  */
 public class ManaPool implements Serializable {
 
-	private int red = 0;
-	private int green = 0;
-	private int blue = 0;
-	private int white = 0;
-	private int black = 0;
-	private int colorless = 0;
-
-	private List<ConditionalMana> conditionalMana = new ArrayList<ConditionalMana>();
+    private List<ManaPoolItem> manaItems = new ArrayList<ManaPoolItem>();
 
 	public ManaPool() {}
 
 	public ManaPool(final ManaPool pool) {
-		this.red = pool.red;
-		this.green = pool.green;
-		this.blue = pool.blue;
-		this.white = pool.white;
-		this.black = pool.black;
-		this.colorless = pool.colorless;
-		for (ConditionalMana mana : pool.conditionalMana) {
-			conditionalMana.add(mana.copy());
-		}
+        for (ManaPoolItem item: pool.manaItems) {
+            manaItems.add(item.copy());
+        }
 	}
-
-	public void setRed(int red) {
-		this.red = red;
-	}
-
-	public void removeRed() {
-		red--;
-	}
-
-	public void addRed() {
-		red++;
-	}
-
+    
 	public int getRed() {
-		return red;
-	}
-
-	public int getConditionalRed(Ability ability, Game game) {
-		if (ability == null || conditionalMana.size() == 0) {
-			return 0;
-		}
-		boolean hasRed = false;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getRed() > 0) {
-				hasRed = true;
-				break;
-			}
-		}
-		if (!hasRed) return 0;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getRed() > 0 && mana.apply(ability, game)) {
-				return mana.getRed();
-			}
-		}
-		return 0;
-	}
-
-	public void setGreen(int green) {
-		this.green = green;
-	}
-
-	public void removeGreen() {
-		green--;
-	}
-
-	public void addGreen() {
-		green++;
+		return get(ManaType.RED);
 	}
 
 	public int getGreen() {
-		return green;
+		return get(ManaType.GREEN);
 	}
 
-	public int getConditionalGreen(Ability ability, Game game) {
-		if (ability == null || conditionalMana.size() == 0) {
+    public int getBlue() {
+		return get(ManaType.BLUE);
+	}
+
+    public int getWhite() {
+		return get(ManaType.WHITE);
+	}
+
+    public int getBlack() {
+		return get(ManaType.BLACK);
+	}
+
+    public boolean pay(ManaType manaType, Ability ability, Filter filter, Game game) {
+        if (getConditional(manaType, ability, filter, game) > 0) {
+            removeConditional(manaType, ability, game);
+            return true;
+        }
+        for (ManaPoolItem mana : manaItems) {
+            if (filter == null || filter.match(game.getObject(mana.getSourceId()))) {
+                if (mana.get(manaType) > 0) {
+                    mana.remove(manaType);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+	public int get(ManaType manaType) {
+		return getMana().get(manaType);
+	}
+    
+	private int getConditional(ManaType manaType, Ability ability, Filter filter, Game game) {
+		if (ability == null || getConditionalMana().isEmpty()) {
 			return 0;
 		}
-		boolean hasGreen = false;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getGreen() > 0) {
-				hasGreen = true;
-				break;
-			}
-		}
-		if (!hasGreen) return 0;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getGreen() > 0 && mana.apply(ability, game)) {
-				return mana.getGreen();
+		for (ManaPoolItem mana : manaItems) {
+			if (mana.isConditional() && mana.getConditionalMana().get(manaType) > 0 && mana.getConditionalMana().apply(ability, game)) {
+                if (filter == null || filter.match(game.getObject(mana.getSourceId())))
+                    return mana.getConditionalMana().get(manaType);
 			}
 		}
 		return 0;
 	}
 
-	public void setBlue(int blue) {
-		this.blue = blue;
-}
-
-	public void removeBlue() {
-		blue--;
-	}
-
-	public void addBlue() {
-		blue++;
-	}
-
-	public int getBlue() {
-		return blue;
-	}
-
-	public int getConditionalBlue(Ability ability, Game game) {
-		if (ability == null || conditionalMana.size() == 0) {
-			return 0;
-		}
-		boolean hasBlue = false;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getBlue() > 0) {
-				hasBlue = true;
-				break;
-			}
-		}
-		if (!hasBlue) return 0;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getBlue() > 0 && mana.apply(ability, game)) {
-				return mana.getBlue();
-			}
-		}
-		return 0;
-	}
-
-	public void setWhite(int white) {
-		this.white = white;
-	}
-
-	public void removeWhite() {
-		white--;
-	}
-
-	public void addWhite() {
-		white++;
-	}
-
-	public int getWhite() {
-		return white;
-	}
-
-	public int getConditionalWhite(Ability ability, Game game) {
-		if (ability == null || conditionalMana.size() == 0) {
-			return 0;
-		}
-		boolean hasWhite = false;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getWhite() > 0) {
-				hasWhite = true;
-				break;
-			}
-		}
-		if (!hasWhite) return 0;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getWhite() > 0 && mana.apply(ability, game)) {
-				return mana.getWhite();
-			}
-		}
-		return 0;
-	}
-
-	public void setBlack(int black) {
-		this.black = black;
-	}
-
-	public void removeBlack() {
-		black--;
-	}
-
-	public void addBlack() {
-		black++;
-	}
-
-	public int getBlack() {
-		return black;
-	}
-
-	public int getConditionalBlack(Ability ability, Game game) {
-		if (ability == null || conditionalMana.size() == 0) {
-			return 0;
-		}
-		boolean hasBlack = false;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getBlack() > 0) {
-				hasBlack = true;
-				break;
-			}
-		}
-		if (!hasBlack) return 0;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getBlack() > 0 && mana.apply(ability, game)) {
-				return mana.getBlack();
-			}
-		}
-		return 0;
-	}
-
-	public int getConditionalColorless(Ability ability, Game game) {
-		if (ability == null || conditionalMana.size() == 0) {
-			return 0;
-		}
-		boolean hasColorless = false;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getColorless() > 0) {
-				hasColorless = true;
-				break;
-			}
-		}
-		if (!hasColorless) return 0;
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getColorless() > 0 && mana.apply(ability, game)) {
-				return mana.getColorless();
-			}
-		}
-		return 0;
-	}
-
-
 	public int getConditionalCount(Ability ability, Game game, FilterMana filter) {
-		if (ability == null || conditionalMana.size() == 0) {
+		if (ability == null || getConditionalMana().isEmpty()) {
 			return 0;
 		}
 		int count = 0;
-		for (ConditionalMana mana : conditionalMana) {
+		for (ConditionalMana mana : getConditionalMana()) {
 			if (mana.apply(ability, game)) {
 				count += mana.count(filter);
 			}
@@ -284,126 +124,128 @@ public class ManaPool implements Serializable {
 		return count;
 	}
 
-	public void setColorless(int colorless) {
-		this.colorless = colorless;
-	}
-
-	public void removeColorless() {
-		colorless--;
-	}
-
-	public void addColorless() {
-		colorless++;
-	}
-
-	public int getColorless() {
-		return colorless;
+    public int getColorless() {
+		return get(ManaType.COLORLESS);
 	}
 
 	public int emptyPool() {
 		int total = count();
-		black = 0;
-		blue = 0;
-		white = 0;
-		red = 0;
-		green = 0;
-		colorless = 0;
-		conditionalMana.clear();
+        manaItems.clear();
 		return total;
 	}
 
-	public int emptyPoolConditional(Ability ability, Game game) {
-		int total = count();
-		black = 0;
-		blue = 0;
-		white = 0;
-		red = 0;
-		green = 0;
-		colorless = 0;
-		// remove only those mana that can be spent for ability
-		Iterator<ConditionalMana> it = conditionalMana.iterator();
-		while (it.hasNext()) {
-			ConditionalMana mana = it.next();
-			if (mana.apply(ability, game)) {
-				total += mana.count();
-				it.remove();
-			}
-		}
-		return total;
+	private int payX(Ability ability, Game game) {
+        int total = 0;
+        Iterator<ManaPoolItem> it = manaItems.iterator();
+        while (it.hasNext()) {
+            ManaPoolItem item = it.next();
+            if (item.isConditional()) {
+                if (item.getConditionalMana().apply(ability, game)) {
+                    total += item.count();
+                    it.remove();
+                }
+            }
+            else {
+                total += item.count();
+                it.remove();
+            }
+        }
+        return total;
 	}
 
-	public int emptyPoolConditional(Ability ability, Game game, FilterMana filter) {
+    /**
+     * remove all mana from pool that applies and that matches filter
+     * @param ability
+     * @param game
+     * @param filter
+     * @return 
+     */
+	public int payX(Ability ability, Game game, FilterMana filter) {
 		if (filter == null) {
-			return emptyPoolConditional(ability, game);
+			return payX(ability, game);
 		}
-		int total = count(filter);
-		if (filter.isBlack()) black = 0;
-		if (filter.isBlue()) blue = 0;
-		if (filter.isWhite()) white = 0;
-		if (filter.isRed()) red = 0;
-		if (filter.isGreen()) green = 0;
-		if (filter.isColorless()) colorless = 0;
-		// remove only those mana that can be spent for ability
-		Iterator<ConditionalMana> it = conditionalMana.iterator();
-		while (it.hasNext()) {
-			ConditionalMana mana = it.next();
-			if (mana.apply(ability, game)) {
-				if (mana.count(filter) > 0) {
-					total += mana.count();
-					it.remove();
-				}
-			}
-		}
-		return total;
+        int total = 0;
+        Iterator<ManaPoolItem> it = manaItems.iterator();
+        while (it.hasNext()) {
+            ManaPoolItem item = it.next();
+            if (item.isConditional()) {
+                ConditionalMana c = item.getConditionalMana();
+                if (c.apply(ability, game)) {
+                    int count = c.count(filter);
+                    if (count > 0) {
+                        total += count;
+                        c.removeAll(filter);
+                        if (c.count() == 0)
+                            it.remove();
+                    }
+                }
+            }
+            else {
+                if (filter.isBlack()) {
+                    total += item.getBlack();
+                    item.removeBlack();
+                }
+                if (filter.isBlue()) {
+                    total += item.getBlue();
+                    item.removeBlue();
+                }
+                if (filter.isWhite()) {
+                    total += item.getWhite();
+                    item.removeWhite();
+                }
+                if (filter.isRed()) {
+                    total += item.getRed();
+                    item.removeRed();
+                }
+                if (filter.isGreen()) {
+                    total += item.getGreen();
+                    item.removeGreen();
+                }
+                if (filter.isColorless()) {
+                    total += item.getColorless();
+                    item.removeColorless();
+                }
+                if (item.count() == 0)
+                    it.remove();
+            }
+        }
+        return total;
 	}
 
 	public Mana getMana() {
-		Mana mana = new Mana();
-		mana.setBlack(black);
-		mana.setBlue(blue);
-		mana.setColorless(colorless);
-		mana.setGreen(green);
-		mana.setRed(red);
-		mana.setWhite(white);
-		return mana;
+		Mana m = new Mana();
+        for (ManaPoolItem item: manaItems) {
+            m.add(item.getMana());
+        }
+		return m;
 	}
 
 	public Mana getMana(FilterMana filter) {
 		if (filter == null) {
 			return getMana();
 		}
-		Mana mana = new Mana();
-		if (filter.isBlack()) mana.setBlack(black);
-		if (filter.isBlue()) mana.setBlue(blue);
-		if (filter.isColorless()) mana.setColorless(colorless);
-		if (filter.isGreen()) mana.setGreen(green);
-		if (filter.isRed()) mana.setRed(red);
-		if (filter.isWhite()) mana.setWhite(white);
-		return mana;
-	}
-
-	public Mana getAllConditionalMana(Ability ability, Game game) {
-		Mana mana = new Mana();
-		mana.setColorless(getConditionalCount(ability, game, null));
-		return mana;
+		Mana test = getMana();
+        Mana m = new Mana();
+		if (filter.isBlack()) m.setBlack(test.getBlack());
+		if (filter.isBlue()) m.setBlue(test.getBlue());
+		if (filter.isColorless()) m.setColorless(test.getColorless());
+		if (filter.isGreen()) m.setGreen(test.getGreen());
+		if (filter.isRed()) m.setRed(test.getRed());
+		if (filter.isWhite()) m.setWhite(test.getWhite());
+		return m;
 	}
 
 	public Mana getAllConditionalMana(Ability ability, Game game, FilterMana filter) {
-		Mana mana = new Mana();
-		mana.setColorless(getConditionalCount(ability, game, filter));
-		return mana;
+		Mana m = new Mana();
+		m.setColorless(getConditionalCount(ability, game, filter));
+		return m;
 	}
 
-	public void changeMana(Mana mana, Game game, Ability source) {
+	public void addMana(Mana mana, Game game, Ability source) {
 		if (mana instanceof ConditionalMana) {
-			this.conditionalMana.add((ConditionalMana)mana);
+            this.manaItems.add(new ManaPoolItem((ConditionalMana)mana, source.getSourceId()));
 		} else {
-			this.black += mana.getBlack();
-			this.blue += mana.getBlue();
-			this.white += mana.getWhite();
-			this.red += mana.getRed();
-			this.green += mana.getGreen();
-			this.colorless += mana.getColorless();
+            this.manaItems.add(new ManaPoolItem(mana.getRed(), mana.getGreen(), mana.getBlue(), mana.getWhite(), mana.getBlack(), mana.getColorless(), source.getSourceId()));
             GameEvent event = GameEvent.getEvent(GameEvent.EventType.MANA_ADDED, source.getSourceId(), source.getId(), source.getControllerId());
             event.setData(mana.toString());
             game.fireEvent(event);
@@ -411,101 +253,33 @@ public class ManaPool implements Serializable {
 	}
 
 	public List<ConditionalMana> getConditionalMana() {
+        List<ConditionalMana> conditionalMana = new ArrayList<ConditionalMana>();
+        for (ManaPoolItem item: manaItems) {
+            if (item.isConditional()) {
+                conditionalMana.add(item.getConditionalMana());
+            }
+        }
 		return conditionalMana;
 	}
 
-	public boolean checkMana(Mana mana) {
-		if (this.black < mana.getBlack())
-			return false;
-		if (this.blue < mana.getBlue())
-			return false;
-		if (this.white < mana.getWhite())
-			return false;
-		if (this.red < mana.getRed())
-			return false;
-		if (this.green < mana.getGreen())
-			return false;
-		if (this.colorless < mana.getColorless())
-			return false;
-
-		return true;
-
-	}
-
 	public int count() {
-		return red + green + blue + white + black + colorless;
-	}
-
-	public int count(FilterMana filter) {
-		if (filter == null) {
-			return count();
-		}
-		int count = 0;
-		if (filter.isBlack()) count += black;
-		if (filter.isBlue()) count += blue;
-		if (filter.isWhite()) count += white;
-		if (filter.isGreen()) count += green;
-		if (filter.isRed()) count += red;
-		if (filter.isColorless()) count += colorless;
-		return count;
+        int x = 0;
+        for (ManaPoolItem item: manaItems) {
+            x += item.count();
+        }
+        return x;
 	}
 
 	public ManaPool copy() {
 		return new ManaPool(this);
 	}
 
-	public void removeConditionalBlack(Ability ability, Game game) {
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getBlack() > 0 && mana.apply(ability, game)) {
-				mana.setBlack(mana.getBlack() - 1);
+	private void removeConditional(ManaType manaType, Ability ability, Game game) {
+		for (ConditionalMana mana : getConditionalMana()) {
+			if (mana.get(manaType) > 0 && mana.apply(ability, game)) {
+				mana.set(manaType, mana.get(manaType) - 1);
 				break;
 			}
 		}
 	}
-
-	public void removeConditionalBlue(Ability ability, Game game) {
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getBlue() > 0 && mana.apply(ability, game)) {
-				mana.setBlue(mana.getBlue() - 1);
-				break;
-			}
-		}
-	}
-
-	public void removeConditionalWhite(Ability ability, Game game) {
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getWhite() > 0 && mana.apply(ability, game)) {
-				mana.setWhite(mana.getWhite() - 1);
-				break;
-			}
-		}
-	}
-
-	public void removeConditionalGreen(Ability ability, Game game) {
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getGreen() > 0 && mana.apply(ability, game)) {
-				mana.setGreen(mana.getGreen() - 1);
-				break;
-			}
-		}
-	}
-
-	public void removeConditionalRed(Ability ability, Game game) {
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getRed() > 0 && mana.apply(ability, game)) {
-				mana.setRed(mana.getRed() - 1);
-				break;
-			}
-		}
-	}
-
-	public void removeConditionalColorless(Ability ability, Game game) {
-		for (ConditionalMana mana : conditionalMana) {
-			if (mana.getColorless() > 0 && mana.apply(ability, game)) {
-				mana.setColorless(mana.getColorless() - 1);
-				break;
-			}
-		}
-	}
-
 }
diff --git a/Mage/src/mage/players/ManaPoolItem.java b/Mage/src/mage/players/ManaPoolItem.java
new file mode 100644
index 0000000000..fcd6757754
--- /dev/null
+++ b/Mage/src/mage/players/ManaPoolItem.java
@@ -0,0 +1,206 @@
+/*
+* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without modification, are
+* permitted provided that the following conditions are met:
+*
+*    1. Redistributions of source code must retain the above copyright notice, this list of
+*       conditions and the following disclaimer.
+*
+*    2. Redistributions in binary form must reproduce the above copyright notice, this list
+*       of conditions and the following disclaimer in the documentation and/or other materials
+*       provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+* The views and conclusions contained in the software and documentation are those of the
+* authors and should not be interpreted as representing official policies, either expressed
+* or implied, of BetaSteward_at_googlemail.com.
+*/
+package mage.players;
+
+import java.io.Serializable;
+import java.util.UUID;
+import mage.ConditionalMana;
+import mage.Constants.ManaType;
+import mage.Mana;
+
+/**
+ *
+ * @author BetaSteward_at_googlemail.com
+ */
+public class ManaPoolItem implements Serializable {
+    
+	private int red = 0;
+	private int green = 0;
+	private int blue = 0;
+	private int white = 0;
+	private int black = 0;
+	private int colorless = 0;
+    private ConditionalMana conditionalMana;
+    private UUID sourceId;
+    
+    public ManaPoolItem() {}
+    
+    public ManaPoolItem(int red, int green, int blue, int white, int black, int colorless, UUID sourceId) {
+        this.red = red;
+        this.green = green;
+        this.blue = blue;
+        this.white = white;
+        this.black = black;
+        this.colorless = colorless;
+        this.sourceId = sourceId;
+    }
+    
+    public ManaPoolItem(ConditionalMana conditionalMana, UUID sourceId) {
+        this.conditionalMana = conditionalMana;
+        this.sourceId = sourceId;
+    }
+    
+    public ManaPoolItem(final ManaPoolItem item) {
+		this.red = item.red;
+		this.green = item.green;
+		this.blue = item.blue;
+		this.white = item.white;
+		this.black = item.black;
+		this.colorless = item.colorless;
+        if (item.conditionalMana != null)
+            this.conditionalMana = item.conditionalMana.copy();
+        this.sourceId = item.sourceId;
+    }
+    
+    public ManaPoolItem copy() {
+        return new ManaPoolItem(this);
+    }
+    
+    public UUID getSourceId() {
+        return sourceId;
+    }
+    
+    public int getRed() {
+        return red;
+    }
+
+    public void removeRed() {
+        if (red > 0)
+            red--;
+    }
+
+    public int getGreen() {
+        return green;
+    }
+
+    public void removeGreen() {
+        if (green > 0)
+            green--;
+    }
+
+    public int getBlue() {
+        return blue;
+    }
+
+    public void removeBlue() {
+        if (blue > 0)
+            blue--;
+    }
+
+    public int getBlack() {
+        return black;
+    }
+
+    public void removeBlack() {
+        if (black > 0)
+            black--;
+    }
+
+    public int getWhite() {
+        return white;
+    }
+
+    public void removeWhite() {
+        if (white > 0)
+            white--;
+    }
+
+    public int getColorless() {
+        return colorless;
+    }
+
+    public void removeColorless() {
+        if (colorless > 0)
+            colorless--;
+    }
+
+    public boolean isConditional() {
+        return conditionalMana != null;
+    }
+    
+    public ConditionalMana getConditionalMana() {
+        return conditionalMana;
+    }
+
+    public Mana getMana() {
+        return new Mana(red, green, blue, white, black, colorless, 0);
+    }
+
+    public int count() {
+        if (conditionalMana == null)
+            return red + green + blue + white + black + colorless;
+        return conditionalMana.count();
+    }
+
+    public int get(ManaType manaType) {
+        switch(manaType) {
+            case BLACK:
+                return black;
+            case BLUE:
+                return blue;
+            case GREEN:
+                return green;
+            case RED:
+                return red;
+            case WHITE:
+                return white;
+            case COLORLESS:
+                return colorless;
+        }
+        return 0;
+    }
+
+    public void remove(ManaType manaType) {
+        switch(manaType) {
+            case BLACK:
+                if (black > 0)
+                    black--;
+                break;
+            case BLUE:
+                if (blue > 0)
+                    blue--;
+                break;
+            case GREEN:
+                if (green > 0)
+                    green--;
+                break;
+            case RED:
+                if (red > 0)
+                    red--;
+                break;
+            case WHITE:
+                if (white > 0)
+                    white--;
+                break;
+            case COLORLESS:
+                if (colorless > 0)
+                    colorless--;
+                break;
+        }
+    }
+}
diff --git a/Mage/src/mage/players/Players.java b/Mage/src/mage/players/Players.java
index 2ca5cf7170..6394e1ad39 100644
--- a/Mage/src/mage/players/Players.java
+++ b/Mage/src/mage/players/Players.java
@@ -30,6 +30,7 @@ package mage.players;
 
 import java.util.LinkedHashMap;
 import java.util.UUID;
+import java.util.Map.Entry;
 
 /**
  *
@@ -40,8 +41,8 @@ public class Players extends LinkedHashMap<UUID, Player> {
 	public Players() {}
 
 	public Players(final Players players) {
-		for (UUID id: players.keySet()) {
-			this.put(id, players.get(id).copy());
+		for (Entry<UUID, Player> entry: players.entrySet()) {
+			this.put(entry.getKey(), entry.getValue().copy());
 		}
 	}