diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form
index 8a9d385eae9..6f93568ea09 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form
+++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form
@@ -59,6 +59,10 @@
+
+
+
+
@@ -133,6 +137,8 @@
+
+
@@ -389,5 +395,12 @@
+
+
+
+
+
+
+
diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java
index 2e41a985139..95158581c34 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java
@@ -79,6 +79,7 @@ public class NewTableDialog extends MageDialog {
this.spnNumWins.setModel(new SpinnerNumberModel(1, 1, 5, 1));
this.spnFreeMulligans.setModel(new SpinnerNumberModel(0, 0, 5, 1));
this.spnQuitRatio.setModel(new SpinnerNumberModel(100, 0, 100, 5));
+ this.spnEdhPowerLevel.setModel(new SpinnerNumberModel(100, 0, 100, 5));
MageFrame.getUI().addButton(MageComponents.NEW_TABLE_OK_BUTTON, btnOK);
}
@@ -125,7 +126,9 @@ public class NewTableDialog extends MageDialog {
btnOK = new javax.swing.JButton();
btnCancel = new javax.swing.JButton();
lblQuitRatio = new javax.swing.JLabel();
+ lblEdhPowerLevel = new javax.swing.JLabel();
spnQuitRatio = new javax.swing.JSpinner();
+ spnEdhPowerLevel = new javax.swing.JSpinner();
setTitle("New Table");
@@ -214,8 +217,10 @@ public class NewTableDialog extends MageDialog {
});
lblQuitRatio.setText("Allowed quit %");
+ lblEdhPowerLevel.setText("EDH power level");
spnQuitRatio.setToolTipText("Players with quit % more than this value can't join this table");
+ spnEdhPowerLevel.setToolTipText("Players with decks with a higher power level can't join this table");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
@@ -256,7 +261,10 @@ public class NewTableDialog extends MageDialog {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(lblQuitRatio)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE))))
+ .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(lblEdhPowerLevel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
@@ -314,7 +322,10 @@ public class NewTableDialog extends MageDialog {
.addComponent(lbDeckType)
.addComponent(lblQuitRatio)
.addComponent(chkRated)
- .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(lblEdhPowerLevel)
+ .addComponent(chkRated)
+ .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
@@ -395,6 +406,7 @@ public class NewTableDialog extends MageDialog {
options.setFreeMulligans((Integer) this.spnFreeMulligans.getValue());
options.setPassword(this.txtPassword.getText());
options.setQuitRatio((Integer) this.spnQuitRatio.getValue());
+ options.setEdhPowerLevel((Integer) this.spnEdhPowerLevel.getValue());
if (!checkMatchOptions(options)) {
return;
}
@@ -658,6 +670,7 @@ public class NewTableDialog extends MageDialog {
}
this.spnQuitRatio.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_QUIT_RATIO, "100")));
+ this.spnEdhPowerLevel.setValue(0);
}
/**
@@ -721,6 +734,7 @@ public class NewTableDialog extends MageDialog {
private javax.swing.JLabel lblNumWins;
private javax.swing.JLabel lblPassword;
private javax.swing.JLabel lblQuitRatio;
+ private javax.swing.JLabel lblEdhPowerLevel;
private javax.swing.JLabel lblRange;
private javax.swing.JLabel lblSkillLevel;
private mage.client.table.NewPlayerPanel player1Panel;
@@ -729,6 +743,7 @@ public class NewTableDialog extends MageDialog {
private javax.swing.JSpinner spnNumPlayers;
private javax.swing.JSpinner spnNumWins;
private javax.swing.JSpinner spnQuitRatio;
+ private javax.swing.JSpinner spnEdhPowerLevel;
private javax.swing.JTextField txtName;
private javax.swing.JTextField txtPassword;
// End of variables declaration//GEN-END:variables
diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagidexImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagidexImageSource.java
new file mode 100644
index 00000000000..7a39d6768a7
--- /dev/null
+++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagidexImageSource.java
@@ -0,0 +1,104 @@
+/*
+* Copyright 2010 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 org.mage.plugins.card.dl.sources;
+
+import org.mage.plugins.card.images.CardDownloadData;
+import java.net.URI;
+
+/**
+ *
+ * @author Pete Rossi
+ */
+
+public class MagidexImageSource implements CardImageSource {
+ private static CardImageSource instance = new MagidexImageSource();
+
+ public static CardImageSource getInstance() {
+ if (instance == null) {
+ instance = new MagidexImageSource();
+ }
+ return instance;
+ }
+ @Override
+ public String getSourceName() {
+ return "magidex.com";
+ }
+
+ @Override
+ public String getNextHttpImageUrl() {
+ return null;
+ }
+
+ @Override
+ public String getFileForHttpImage(String httpImageUrl) {
+ return null;
+ }
+
+ @Override
+ public String generateURL(CardDownloadData card) throws Exception {
+ String cardDownloadName = card.getDownloadName().toLowerCase();
+ String cardSet = card.getSet();
+
+ if (cardDownloadName == null || cardSet == null) {
+ throw new Exception("Wrong parameters for image: cardDownloadName: " + cardDownloadName + ",card set: " + cardSet);
+ }
+
+ if (card.isSplitCard()) {
+ cardDownloadName = cardDownloadName.replaceAll(" // ", "");
+ }
+
+ // This will properly escape the url
+ URI uri = new URI("http", "magidex.com", "/extstatic/card/" + cardSet + "/" + cardDownloadName + ".jpg", null, null);
+ return uri.toASCIIString();
+ }
+
+ @Override
+ public String generateTokenUrl(CardDownloadData card) {
+ return null;
+ }
+
+ @Override
+ public Float getAverageSize() {
+ return 62.0f;
+ }
+
+ @Override
+ public Integer getTotalImages() {
+ return -1;
+ }
+
+ @Override
+ public Boolean isTokenSource() {
+ return false;
+ }
+
+ @Override
+ public void doPause(String httpImageUrl) {
+ }
+}
diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java
index 92b0a9f5a35..efb627fefc7 100644
--- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java
+++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java
@@ -64,6 +64,7 @@ import org.mage.plugins.card.dl.sources.MtgOnlTokensImageSource;
import org.mage.plugins.card.dl.sources.MythicspoilerComSource;
import org.mage.plugins.card.dl.sources.TokensMtgImageSource;
import org.mage.plugins.card.dl.sources.WizardCardsImageSource;
+import org.mage.plugins.card.dl.sources.MagidexImageSource;
import org.mage.plugins.card.properties.SettingsManager;
import org.mage.plugins.card.utils.CardImageUtils;
@@ -149,7 +150,8 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
"tokens.mtg.onl", //"mtgimage.com (HQ)",
"mtg.onl",
"alternative.mtg.onl",
- "GrabBag"
+ "GrabBag",
+ "magidex.com"
//"mtgathering.ru HQ",
//"mtgathering.ru MQ",
//"mtgathering.ru LQ",
@@ -186,6 +188,9 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
case 6:
cardImageSource = GrabbagImageSource.getInstance();
break;
+ case 7:
+ cardImageSource = MagidexImageSource.getInstance();
+ break;
}
updateCardsToDownload();
}
diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java
index 6fef4d52ed3..db6f671d22a 100644
--- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java
+++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java
@@ -204,4 +204,358 @@ public class Commander extends Constructed {
|| cardColor.isWhite() && !commander.isWhite());
}
+ @Override
+ public int getEdhPowerLevel(Deck deck) {
+ if (deck == null) {
+ return 0;
+ }
+
+ int edhPowerLevel = 0;
+ for (Card card : deck.getCards()) {
+
+ int thisMaxPower = 0;
+
+ // Examine rules to work out most egregious functions in edh
+ boolean anyNumberOfTarget = false;
+ boolean buyback = false;
+ boolean cascade = false;
+ boolean copy = false;
+ boolean exile = false;
+ boolean exileAll = false;
+ boolean counter = false;
+ boolean destroy = false;
+ boolean destroyAll = false;
+ boolean each = false;
+ boolean exalted = false;
+ boolean drawCards = false;
+ boolean extraTurns = false;
+ boolean gainControl = false;
+ boolean infect = false;
+ boolean mayCastForFree = false;
+ boolean miracle = false;
+ boolean overload = false;
+ boolean persist = false;
+ boolean proliferate = false;
+ boolean retrace = false;
+ boolean sacrifice = false;
+ boolean skip = false;
+ boolean sliver = false;
+ boolean tutor = false;
+ boolean undying = false;
+ boolean wheneverEnters = false;
+ boolean youControlTarget = false;
+
+ for (String str : card.getRules()) {
+ String s = str.toLowerCase();
+ anyNumberOfTarget |= s.contains("any number");
+ buyback |= s.contains("buyback");
+ cascade |= s.contains("cascade");
+ copy |= s.contains("copy");
+ counter |= s.contains("counter") && s.contains("target");
+ destroy |= s.contains("destroy");
+ destroyAll |= s.contains("destroy all");
+ drawCards |= s.contains("draw cards");
+ each |= s.contains("each");
+ exalted |= s.contains("exalted");
+ exile |= s.contains("exile");
+ exileAll |= s.contains("exile") && s.contains(" all ");
+ extraTurns |= s.contains("extra turn");
+ gainControl |= s.contains("gain control");
+ infect |= s.contains("infect");
+ mayCastForFree |= s.contains("may cast") && s.contains("without paying");
+ miracle |= s.contains("miracle");
+ overload |= s.contains("overload");
+ persist |= s.contains("persist");
+ proliferate |= s.contains("proliferate");
+ retrace |= s.contains("retrace");
+ sacrifice |= s.contains("sacrifice");
+ skip |= s.contains("skip") && s.contains("each");
+ sliver |= s.contains("sliver");
+ tutor |= s.contains("search your library");
+ undying |= s.contains("undying");
+ wheneverEnters |= s.contains("when") && s.contains("another") && s.contains("enters");
+ youControlTarget |= s.contains("you control target");
+ }
+
+ if (extraTurns) {
+ thisMaxPower = Math.max(thisMaxPower, 7);
+ }
+ if (buyback) {
+ thisMaxPower = Math.max(thisMaxPower, 6);
+ }
+ if (tutor) {
+ thisMaxPower = Math.max(thisMaxPower, 6);
+ }
+ if (infect) {
+ thisMaxPower = Math.max(thisMaxPower, 5);
+ }
+ if (overload) {
+ thisMaxPower = Math.max(thisMaxPower, 5);
+ }
+ if (cascade) {
+ thisMaxPower = Math.max(thisMaxPower, 4);
+ }
+ if (each) {
+ thisMaxPower = Math.max(thisMaxPower, 4);
+ }
+ if (exileAll) {
+ thisMaxPower = Math.max(thisMaxPower, 4);
+ }
+ if (gainControl) {
+ thisMaxPower = Math.max(thisMaxPower, 4);
+ }
+ if (mayCastForFree) {
+ thisMaxPower = Math.max(thisMaxPower, 4);
+ }
+ if (proliferate) {
+ thisMaxPower = Math.max(thisMaxPower, 4);
+ }
+ if (skip) {
+ thisMaxPower = Math.max(thisMaxPower, 4);
+ }
+ if (wheneverEnters) {
+ thisMaxPower = Math.max(thisMaxPower, 4);
+ }
+ if (youControlTarget) {
+ thisMaxPower = Math.max(thisMaxPower, 4);
+ }
+ if (anyNumberOfTarget) {
+ thisMaxPower = Math.max(thisMaxPower, 3);
+ }
+ if (destroyAll) {
+ thisMaxPower = Math.max(thisMaxPower, 3);
+ }
+ if (undying) {
+ thisMaxPower = Math.max(thisMaxPower, 3);
+ }
+ if (persist) {
+ thisMaxPower = Math.max(thisMaxPower, 3);
+ }
+ if (exile) {
+ thisMaxPower = Math.max(thisMaxPower, 2);
+ }
+ if (miracle) {
+ thisMaxPower = Math.max(thisMaxPower, 2);
+ }
+ if (sliver) {
+ thisMaxPower = Math.max(thisMaxPower, 2);
+ }
+ if (sacrifice) {
+ thisMaxPower = Math.max(thisMaxPower, 2);
+ }
+ if (copy) {
+ thisMaxPower = Math.max(thisMaxPower, 1);
+ }
+ if (counter) {
+ thisMaxPower = Math.max(thisMaxPower, 1);
+ }
+ if (destroy) {
+ thisMaxPower = Math.max(thisMaxPower, 1);
+ }
+ if (drawCards) {
+ thisMaxPower = Math.max(thisMaxPower, 1);
+ }
+ if (exalted) {
+ thisMaxPower = Math.max(thisMaxPower, 1);
+ }
+ if (retrace) {
+ thisMaxPower = Math.max(thisMaxPower, 1);
+ }
+
+ // Planeswalkers
+ if (card.getCardType().contains(CardType.PLANESWALKER)) {
+ if (card.getName().toLowerCase().equals("jace, the mind sculptor")) {
+ thisMaxPower = Math.max(thisMaxPower, 5);
+ }
+ thisMaxPower = Math.max(thisMaxPower, 3);
+ }
+
+ if (card.getCardType().contains(CardType.LAND)) {
+ thisMaxPower = 0;
+ }
+
+ // Banned in french or unfair cards
+ String cn = card.getName().toLowerCase();
+ if (cn.equals("ancient tomb")
+ || cn.equals("anafenza, the foremost")
+ || cn.equals("arcum dagsson")
+ || cn.equals("armageddon")
+ || cn.equals("aura shards")
+ || cn.equals("azami, lady of scrolls")
+ || cn.equals("azusa, lost but seeking")
+ || cn.equals("back to basics")
+ || cn.equals("bane of progress")
+ || cn.equals("basalt monolith")
+ || cn.equals("blightsteel collossus")
+ || cn.equals("braids, cabal minion")
+ || cn.equals("cabal coffers")
+ || cn.equals("captain sisay")
+ || cn.equals("celestial dawn")
+ || cn.equals("child of alara")
+ || cn.equals("coalition relic")
+ || cn.equals("craterhoof behemoth")
+ || cn.equals("deepglow skate")
+ || cn.equals("derevi, empyrial tactician")
+ || cn.equals("dig through time")
+ || cn.equals("edric, spymaster of trest")
+ || cn.equals("elesh norn, grand cenobite")
+ || cn.equals("entomb")
+ || cn.equals("food chain")
+ || cn.equals("gaddock teeg")
+ || cn.equals("gaea's cradle")
+ || cn.equals("grand arbiter augustin iv")
+ || cn.equals("grim monolith")
+ || cn.equals("hermit druid")
+ || cn.equals("hokori, dust drinker")
+ || cn.equals("humility")
+ || cn.equals("imperial seal")
+ || cn.equals("iona, shield of emeria")
+ || cn.equals("jin-gitaxias, core augur")
+ || cn.equals("karador, ghost chieftain")
+ || cn.equals("karakas")
+ || cn.equals("kataki, war's wage")
+ || cn.equals("knowledge pool")
+ || cn.equals("linvala, keeper of silence")
+ || cn.equals("living death")
+ || cn.equals("llawan, cephalid empress")
+ || cn.equals("loyal retainers")
+ || cn.equals("maelstrom wanderer")
+ || cn.equals("malfegor")
+ || cn.equals("mana crypt")
+ || cn.equals("mana drain")
+ || cn.equals("mana vault")
+ || cn.equals("michiko konda, truth seeker")
+ || cn.equals("nath of the gilt-leaf")
+ || cn.equals("natural order")
+ || cn.equals("necrotic ooze")
+ || cn.equals("nicol bolas")
+ || cn.equals("numot, the devastator")
+ || cn.equals("oath of druids")
+ || cn.equals("pattern of rebirth")
+ || cn.equals("protean hulk")
+ || cn.equals("purphoros, god of the forge")
+ || cn.equals("ravages of war")
+ || cn.equals("reclamation sage")
+ || cn.equals("sen triplets")
+ || cn.equals("serra's sanctum")
+ || cn.equals("sheoldred, whispering one")
+ || cn.equals("sol ring")
+ || cn.equals("spore frog")
+ || cn.equals("stasis")
+ || cn.equals("strip mine")
+ || cn.equals("the tabernacle at pendrell vale")
+ || cn.equals("tinker")
+ || cn.equals("tolarian academy")
+ || cn.equals("treasure cruise")
+ || cn.equals("urabrask the hidden")
+ || cn.equals("vorinclex, voice of hunger")
+ || cn.equals("winter orb")
+ || cn.equals("zur the enchanter")) {
+ thisMaxPower = Math.max(thisMaxPower, 4);
+ }
+
+ // Parts of infinite combos
+ if (cn.equals("animate artifact") || cn.equals("archaeomancer")
+ || cn.equals("ashnod's altar") || cn.equals("azami, lady of scrolls")
+ || cn.equals("basalt monolith") || cn.equals("brago, king eternal")
+ || cn.equals("candelabra of tawnos") || cn.equals("cephalid aristocrat")
+ || cn.equals("cephalid illusionist") || cn.equals("changeling berserker")
+ || cn.equals("cinderhaze wretch") || cn.equals("cryptic gateway")
+ || cn.equals("deadeye navigator") || cn.equals("derevi, empyrial tactician")
+ || cn.equals("doubling season") || cn.equals("dross scorpion")
+ || cn.equals("earthcraft") || cn.equals("erratic portal")
+ || cn.equals("enter the infinite") || cn.equals("omniscience")
+ || cn.equals("exquisite blood") || cn.equals("future sight")
+ || cn.equals("grave titan") || cn.equals("great whale")
+ || cn.equals("grim monolith") || cn.equals("gush")
+ || cn.equals("hellkite charger") || cn.equals("intruder alarm")
+ || cn.equals("iona, shield of emeria")
+ || cn.equals("karn, silver golem") || cn.equals("kiki-jiki, mirror breaker")
+ || cn.equals("krark-clan ironworks") || cn.equals("krenko, mob boss")
+ || cn.equals("krosan restorer") || cn.equals("laboratory maniac")
+ || cn.equals("leovold, emissary of trest")
+ || cn.equals("leonin relic-warder") || cn.equals("leyline of the void")
+ || cn.equals("memnarch") || cn.equals("memnarch")
+ || cn.equals("meren of clan nel toth") || cn.equals("mikaeus, the unhallowed")
+ || cn.equals("mindcrank") || cn.equals("mindslaver")
+ || cn.equals("minion reflector") || cn.equals("mycosynth lattice")
+ || cn.equals("myr turbine") || cn.equals("narset, enlightened master")
+ || cn.equals("nekusar, the mindrazer") || cn.equals("norin the wary")
+ || cn.equals("opalescence") || cn.equals("ornithopter")
+ || cn.equals("planar portal") || cn.equals("power artifact")
+ || cn.equals("rings of brighthearth") || cn.equals("rite of replication")
+ || cn.equals("sanguine bond") || cn.equals("sensei's divining top")
+ || cn.equals("splinter twin") || cn.equals("stony silence")
+ || cn.equals("storm cauldron") || cn.equals("teferi's puzzle box")
+ || cn.equals("teferi, mage of zhalfir") || cn.equals("teferi, mage of zhalfir")
+ || cn.equals("tezzeret the seeker") || cn.equals("time stretch")
+ || cn.equals("time warp") || cn.equals("training grounds")
+ || cn.equals("triskelavus") || cn.equals("triskelion")
+ || cn.equals("turnabout") || cn.equals("umbral mantle")
+ || cn.equals("uyo, silent prophet") || cn.equals("voltaic key")
+ || cn.equals("workhorse") || cn.equals("worldgorger dragon")
+ || cn.equals("worthy cause") || cn.equals("yawgmoth's will")
+ || cn.equals("zealous conscripts")) {
+ thisMaxPower = Math.max(thisMaxPower, 6);
+ }
+ edhPowerLevel += thisMaxPower;
+ }
+
+ for (Card commander : deck.getSideboard()) {
+ int thisMaxPower = 0;
+ String cn = commander.getName().toLowerCase();
+
+ // Least fun commanders
+ if (cn.equals("azami, lady of scrolls")
+ || cn.equals("braids, cabal minion")
+ || cn.equals("child of alara")
+ || cn.equals("derevi, empyrial tactician")
+ || cn.equals("edric, spymaster of trest")
+ || cn.equals("gaddock teeg")
+ || cn.equals("grand arbiter augustin iv")
+ || cn.equals("hokori, dust drinker")
+ || cn.equals("iona, shield of emeria")
+ || cn.equals("jin-gitaxias, core augur")
+ || cn.equals("karador, ghost chieftain")
+ || cn.equals("linvala, keeper of silence")
+ || cn.equals("llawan, cephalid empress")
+ || cn.equals("memnarch")
+ || cn.equals("meren of clan nel toth")
+ || cn.equals("michiko konda, truth seeker")
+ || cn.equals("narset, enlightened master")
+ || cn.equals("nekusar, the mindrazer")
+ || cn.equals("norin the wary")
+ || cn.equals("numot, the devastator")
+ || cn.equals("sheoldred, whispering one")
+ || cn.equals("teferi, mage of zhalfir")
+ || cn.equals("zur the enchanter")) {
+ thisMaxPower = Math.max(thisMaxPower, 15);
+ }
+
+ // Next least fun commanders
+ if (cn.equals("anafenza, the foremost")
+ || cn.equals("arcum dagsson")
+ || cn.equals("azusa, lost but seeking")
+ || cn.equals("brago, king eternal")
+ || cn.equals("captain sisay")
+ || cn.equals("elesh norn, grand cenobite")
+ || cn.equals("malfegor")
+ || cn.equals("maelstrom wanderer")
+ || cn.equals("mikaeus the unhallowed")
+ || cn.equals("nath of the gilt-leaf")
+ || cn.equals("purphoros, god of the forge")
+ || cn.equals("sen triplets")
+ || cn.equals("urabrask the hidden")
+ || cn.equals("vorinclex, voice of hunger")) {
+ thisMaxPower = Math.max(thisMaxPower, 10);
+ }
+ edhPowerLevel += thisMaxPower;
+ }
+
+ edhPowerLevel = (int) Math.round(edhPowerLevel / 2.5);
+ if (edhPowerLevel > 100) {
+ edhPowerLevel = 100;
+ }
+ return edhPowerLevel;
+ }
}
diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java
index 2162af3c6bc..6b1704182fc 100644
--- a/Mage.Server/src/main/java/mage/server/TableController.java
+++ b/Mage.Server/src/main/java/mage/server/TableController.java
@@ -297,6 +297,19 @@ public class TableController {
user.showUserMessage("Join Table", message);
return false;
}
+
+ // Check power level for table (currently only used for EDH/Commander table)
+ int edhPowerLevel = table.getMatch().getOptions().getEdhPowerLevel();
+ if (edhPowerLevel > 0 && table.getValidator().getName().toLowerCase().equals("commander")) {
+ int deckEdhPowerLevel = table.getValidator().getEdhPowerLevel(deck);
+ if (deckEdhPowerLevel > edhPowerLevel) {
+ String message = new StringBuilder("Your deck appears to be too powerful for this table.\n\nReduce the number of extra turn cards, infect, counters, fogs, reconsider your commander. ")
+ .append("\nThe table requirement has a maximum power level of ").append(edhPowerLevel).append (" whilst your deck has a calculated power level of ")
+ .append(deckEdhPowerLevel).toString();
+ user.showUserMessage("Join Table", message);
+ return false;
+ }
+ }
Player player = createPlayer(name, seat.getPlayerType(), skill);
if (player == null) {
diff --git a/Mage.Sets/src/mage/cards/c/CollectiveRestraint.java b/Mage.Sets/src/mage/cards/c/CollectiveRestraint.java
index e51144f6a8a..d0cf351fc69 100644
--- a/Mage.Sets/src/mage/cards/c/CollectiveRestraint.java
+++ b/Mage.Sets/src/mage/cards/c/CollectiveRestraint.java
@@ -28,7 +28,6 @@
package mage.cards.c;
import java.util.UUID;
-
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCosts;
@@ -49,7 +48,7 @@ import mage.game.events.GameEvent;
public class CollectiveRestraint extends CardImpl {
public CollectiveRestraint(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}");
+ super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}");
// Domain - Creatures can't attack you unless their controller pays {X} for each creature he or she controls that's attacking you, where X is the number of basic land types you control.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CollectiveRestraintPayManaToAttackAllEffect()));
@@ -69,7 +68,7 @@ public class CollectiveRestraint extends CardImpl {
class CollectiveRestraintPayManaToAttackAllEffect extends CantAttackYouUnlessPayManaAllEffect {
CollectiveRestraintPayManaToAttackAllEffect() {
- super(null, true);
+ super(null, false);
staticText = "Creatures can't attack you unless their controller pays {X} for each creature he or she controls that's attacking you, where X is the number of basic land types you control.";
}
diff --git a/Mage.Sets/src/mage/cards/d/DemonspineWhip.java b/Mage.Sets/src/mage/cards/d/DemonspineWhip.java
index cb54ac98940..a10e00bf475 100644
--- a/Mage.Sets/src/mage/cards/d/DemonspineWhip.java
+++ b/Mage.Sets/src/mage/cards/d/DemonspineWhip.java
@@ -27,6 +27,7 @@
*/
package mage.cards.d;
+import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.GenericManaCost;
@@ -41,8 +42,6 @@ import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
-import java.util.UUID;
-
/**
*
* @author jeffwadsworth
@@ -50,12 +49,9 @@ import java.util.UUID;
public class DemonspineWhip extends CardImpl {
public DemonspineWhip(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{B}{R}");
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{B}{R}");
this.subtype.add("Equipment");
-
-
-
// {X}: Equipped creature gets +X/+0 until end of turn.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(new XPaid(), new StaticValue(0), Duration.EndOfTurn), new ManaCostsImpl("{X}")));
@@ -88,7 +84,7 @@ class XPaid implements DynamicValue {
@Override
public String getMessage() {
- return "X paid";
+ return "";
}
@Override
diff --git a/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java b/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java
index e2a9e3cd950..73ec30086c0 100644
--- a/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java
+++ b/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java
@@ -50,8 +50,8 @@ import mage.target.common.TargetControlledCreaturePermanent;
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
*/
public class GravespawnSovereign extends CardImpl {
-
- private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Vampires you control");
+
+ private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Zombies you control");
static {
filter.add(new SubtypePredicate("Zombie"));
@@ -59,7 +59,7 @@ public class GravespawnSovereign extends CardImpl {
}
public GravespawnSovereign(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}");
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}");
this.subtype.add("Zombie");
this.power = new MageInt(3);
this.toughness = new MageInt(3);
@@ -68,7 +68,7 @@ public class GravespawnSovereign extends CardImpl {
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(5, 5, filter, true)));
ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard")));
this.addAbility(ability);
-
+
}
public GravespawnSovereign(final GravespawnSovereign card) {
diff --git a/Mage.Sets/src/mage/cards/n/NaturesWay.java b/Mage.Sets/src/mage/cards/n/NaturesWay.java
index 92fecc32150..4a8212e2901 100644
--- a/Mage.Sets/src/mage/cards/n/NaturesWay.java
+++ b/Mage.Sets/src/mage/cards/n/NaturesWay.java
@@ -61,7 +61,7 @@ public class NaturesWay extends CardImpl {
}
public NaturesWay(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{G}");
+ super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}");
// Target creature you control gains vigilance and trample until end of turn. It deals damage equal to its power to target creature you don't control.
Effect effect = new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn);
@@ -69,6 +69,7 @@ public class NaturesWay extends CardImpl {
this.getSpellAbility().addEffect(effect);
effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn);
effect.setText("and trample until end of turn");
+ this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addEffect(new NaturesWayEffect());
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
diff --git a/Mage.Sets/src/mage/cards/o/ObscuringAether.java b/Mage.Sets/src/mage/cards/o/ObscuringAether.java
index 8e514390f4e..5cbc3d93ee0 100644
--- a/Mage.Sets/src/mage/cards/o/ObscuringAether.java
+++ b/Mage.Sets/src/mage/cards/o/ObscuringAether.java
@@ -55,14 +55,14 @@ public class ObscuringAether extends CardImpl {
}
public ObscuringAether(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}");
+ super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}");
// Face-down creature spells you cast cost {1} less to cast.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(filter, 1)));
// {1}{G}: Turn Obscuring Aether face down.
Effect effect = new BecomesFaceDownCreatureEffect(Duration.Custom, BecomesFaceDownCreatureEffect.FaceDownType.MANUAL);
- effect.setText("Turn Obscuring Aether face down. (It becomes a 2/2 creature.)");
+ effect.setText("Turn {this} face down. (It becomes a 2/2 creature.)");
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{G}")));
}
diff --git a/Mage.Sets/src/mage/cards/s/SanguinePraetor.java b/Mage.Sets/src/mage/cards/s/SanguinePraetor.java
index e0176430828..b30de0ca5a1 100644
--- a/Mage.Sets/src/mage/cards/s/SanguinePraetor.java
+++ b/Mage.Sets/src/mage/cards/s/SanguinePraetor.java
@@ -81,7 +81,7 @@ class SanguinePraetorEffect extends OneShotEffect {
public SanguinePraetorEffect() {
super(Outcome.Damage);
- staticText = "Destroy each creature with the same converted mana cost as the sacrificed creature.";
+ staticText = "Destroy each creature with the same converted mana cost as the sacrificed creature";
}
public SanguinePraetorEffect(final SanguinePraetorEffect effect) {
@@ -98,7 +98,7 @@ class SanguinePraetorEffect extends OneShotEffect {
}
}
- for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) {
+ for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) {
if (permanent.getConvertedManaCost() == cmc) {
permanent.destroy(source.getSourceId(), game, false);
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java
index cb724e8731d..4d9ad428692 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java
@@ -30,6 +30,7 @@ package org.mage.test.cards.abilities.keywords;
import mage.cards.Card;
import mage.constants.PhaseStep;
import mage.constants.Zone;
+import mage.game.permanent.Permanent;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
@@ -214,7 +215,6 @@ public class ManifestTest extends CardTestPlayerBase {
/*
I casted a Silence the Believers on a manifested card. It moved to the exile zone face-down.
*/
-
@Test
public void testCardGetsExiledFaceUp() {
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
@@ -326,6 +326,8 @@ public class ManifestTest extends CardTestPlayerBase {
assertPermanentCount(playerB, "", 0);
assertPermanentCount(playerB, "Aerie Bowmasters", 1);
assertPowerToughness(playerB, "Aerie Bowmasters", 4, 5); // 3/4 and the +1/+1 counter from Megamorph
+ Permanent aerie = getPermanent("Aerie Bowmasters", playerB);
+ Assert.assertTrue("Aerie Bowmasters has to be green", aerie != null && aerie.getColor(currentGame).isGreen());
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MegamorphTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MegamorphTest.java
new file mode 100644
index 00000000000..c70a5954613
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MegamorphTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010 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 org.mage.test.cards.abilities.keywords;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import mage.game.permanent.Permanent;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class MegamorphTest extends CardTestPlayerBase {
+
+ @Test
+ public void testManifestMegamorph() {
+ // Reach (This creature can block creatures with flying.)
+ // Megamorph {5}{G}
+ addCard(Zone.HAND, playerA, "Aerie Bowmasters", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Forest", 6);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aerie Bowmasters");
+ setChoice(playerA, "Yes"); // cast it face down as 2/2 creature
+
+ activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{5}{G}: Turn");
+
+ setStopAt(3, PhaseStep.BEGIN_COMBAT);
+ execute();
+
+ assertPermanentCount(playerA, "Aerie Bowmasters", 1);
+ assertPowerToughness(playerA, "Aerie Bowmasters", 4, 5); // 3/4 and the +1/+1 counter from Megamorph
+
+ Permanent aerie = getPermanent("Aerie Bowmasters", playerA);
+ Assert.assertTrue("Aerie Bowmasters has to be green", aerie != null && aerie.getColor(currentGame).isGreen());
+
+ }
+
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/AnimateDeadTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/AnimateDeadTest.java
index f675596a864..ee77d60ed77 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/AnimateDeadTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/AnimateDeadTest.java
@@ -121,4 +121,37 @@ public class AnimateDeadTest extends CardTestPlayerBase {
assertGraveyardCount(playerA, "Animate Dead", 1);
assertPermanentCount(playerA, "Animate Dead", 0);
}
+
+ /**
+ * Animate Dead is incorrectly not entering the graveyard when the animated
+ * target is sacrificed.
+ */
+ @Test
+ public void testAnimateAndSacrificeTarget() {
+ // Target opponent sacrifices a creature.
+ addCard(Zone.HAND, playerB, "Cruel Edict"); // {1}{B}
+ addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
+ addCard(Zone.GRAVEYARD, playerB, "Silvercoat Lion", 1);
+
+ addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
+ // Enchant creature card in a graveyard
+ // When Animate Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard"
+ // and gains "enchant creature put onto the battlefield with Animate Dead." Return enchanted creature card to the battlefield
+ // under your control and attach Animate Dead to it. When Animate Dead leaves the battlefield, that creature's controller sacrifices it.
+ // Enchanted creature gets -1/-0.
+ addCard(Zone.HAND, playerA, "Animate Dead"); // {1}{B}
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Animate Dead", "Silvercoat Lion");
+
+ castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Cruel Edict", playerA);
+
+ setStopAt(2, PhaseStep.BEGIN_COMBAT);
+ execute();
+
+ assertGraveyardCount(playerB, "Cruel Edict", 1);
+ assertGraveyardCount(playerB, "Silvercoat Lion", 1);
+
+ assertGraveyardCount(playerA, "Animate Dead", 1);
+ }
+
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/ObscuringAetherTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/ObscuringAetherTest.java
new file mode 100644
index 00000000000..471ad8bebaa
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/ObscuringAetherTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2010 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 org.mage.test.cards.facedown;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class ObscuringAetherTest extends CardTestPlayerBase {
+
+ /**
+ * Obscuring Aether cannot turn into a face down 2/2 like it should. When
+ * activating the ability to turn it over it, it dies immediately.
+ *
+ */
+ // test that cards exiled using Ghastly Conscription return face down
+ @Test
+ public void testTurnFaceDown() {
+ addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
+ // Face-down creature spells you cast cost {1} less to cast.
+ // {1}{G}: Turn Obscuring Aether face down.
+ addCard(Zone.HAND, playerA, "Obscuring Aether");
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Obscuring Aether");
+
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G}: Turn");
+
+ setStopAt(1, PhaseStep.BEGIN_COMBAT);
+ execute();
+
+ assertHandCount(playerA, "Obscuring Aether", 0);
+ assertGraveyardCount(playerA, "Obscuring Aether", 0);
+
+ assertPermanentCount(playerA, "", 1);
+ assertPowerToughness(playerA, "", 2, 2);
+
+ }
+
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/ReflectingPoolTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/ReflectingPoolTest.java
index 7ab29a93f0d..b55de2a10f7 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/mana/ReflectingPoolTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/ReflectingPoolTest.java
@@ -27,8 +27,10 @@
*/
package org.mage.test.cards.mana;
+import mage.abilities.mana.ManaOptions;
import mage.constants.PhaseStep;
import mage.constants.Zone;
+import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
@@ -68,4 +70,23 @@ public class ReflectingPoolTest extends CardTestPlayerBase {
}
+ /**
+ * Reflecting Pool does not see what mana Exotic Orchard can produce
+ */
+ @Test
+ public void testWithExoticOrchard() {
+ addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
+
+ // {T}: Add to your mana pool one mana of any type that a land you control could produce.
+ addCard(Zone.BATTLEFIELD, playerA, "Reflecting Pool", 1);
+ // {T}: Add to your mana pool one mana of any color that a land an opponent controls could produce.
+ addCard(Zone.BATTLEFIELD, playerA, "Exotic Orchard", 1);
+
+ setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
+ execute();
+
+ ManaOptions options = playerA.getAvailableManaTest(currentGame);
+ Assert.assertEquals("Player should be able to create 2 red mana", "{R}{R}", options.get(0).toString());
+
+ }
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReturnOnlyFromGraveyardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReturnOnlyFromGraveyardTest.java
index cc8bb46cf73..fba692a07d6 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReturnOnlyFromGraveyardTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReturnOnlyFromGraveyardTest.java
@@ -61,6 +61,7 @@ public class ReturnOnlyFromGraveyardTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Academy Rector");
+ setChoice(playerA, "When enchanted creature dies"); // Select triggered ability to execute last
setChoice(playerA, "Yes");
addTarget(playerA, "Primal Rage");
@@ -94,7 +95,8 @@ public class ReturnOnlyFromGraveyardTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Lightning Bolt", "Academy Rector");
- setChoice(playerA, "Yes");
+ setChoice(playerA, "When enchanted creature dies"); // Select triggered ability to execute last
+ setChoice(playerA, "Yes"); // May exile it
addTarget(playerA, "Primal Rage");
setStopAt(1, PhaseStep.END_COMBAT);
diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java
index 34d6d52a5e7..4d1136e4b42 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java
@@ -21,7 +21,7 @@ public class CantBeBlockedByAllTargetEffect extends RestrictionEffect {
private final FilterCreaturePermanent filterBlockedBy;
public CantBeBlockedByAllTargetEffect(FilterCreaturePermanent filterBlockedBy, Duration duration) {
- super(Duration.WhileOnBattlefield);
+ super(duration);
this.filterBlockedBy = filterBlockedBy;
staticText = "Target creature"
+ " can't be blocked "
diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java
index 0afee43a10f..43d7ce2faa5 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java
@@ -196,8 +196,8 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl implemen
break;
case PTChangingEffects_7:
if (sublayer == SubLayer.SetPT_7b) {
-// permanent.getPower().setValue(2);
-// permanent.getToughness().setValue(2);
+ permanent.getPower().setValue(2);
+ permanent.getToughness().setValue(2);
}
}
} else if (duration.equals(Duration.Custom) && foundPermanent == true) {
diff --git a/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java
index 398c1f27410..989b558f609 100644
--- a/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java
+++ b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java
@@ -69,6 +69,12 @@ public class AnyColorLandsProduceManaAbility extends ActivatedManaAbilityImpl {
public List getNetMana(Game game) {
return ((AnyColorLandsProduceManaEffect) getEffects().get(0)).getNetMana(game, this);
}
+
+ @Override
+ public boolean definesMana() {
+ return true;
+ }
+
}
class AnyColorLandsProduceManaEffect extends ManaEffect {
@@ -155,7 +161,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
}
private Mana getManaTypes(Game game, Ability source) {
- List lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game);
+ List lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
Mana types = new Mana();
for (Permanent land : lands) {
Abilities mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java
index a67267fe398..d5965330f5e 100644
--- a/Mage/src/main/java/mage/cards/CardImpl.java
+++ b/Mage/src/main/java/mage/cards/CardImpl.java
@@ -656,7 +656,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
@Override
public void removeCounters(String name, int amount, Game game) {
for (int i = 0; i < amount; i++) {
- getCounters(game).removeCounter(name, 1);
+ if (!getCounters(game).removeCounter(name, 1)) {
+ break;
+ }
GameEvent event = GameEvent.getEvent(GameEvent.EventType.COUNTER_REMOVED, objectId, getControllerOrOwner());
event.setData(name);
game.fireEvent(event);
diff --git a/Mage/src/main/java/mage/cards/decks/DeckValidator.java b/Mage/src/main/java/mage/cards/decks/DeckValidator.java
index 383e1ad8a05..bc73bc61d95 100644
--- a/Mage/src/main/java/mage/cards/decks/DeckValidator.java
+++ b/Mage/src/main/java/mage/cards/decks/DeckValidator.java
@@ -67,4 +67,8 @@ public abstract class DeckValidator implements Serializable {
}
}
}
+
+ public int getEdhPowerLevel(Deck deck) {
+ return 0;
+ }
}
diff --git a/Mage/src/main/java/mage/counters/Counters.java b/Mage/src/main/java/mage/counters/Counters.java
index 21842e59783..c52c7d6cefb 100644
--- a/Mage/src/main/java/mage/counters/Counters.java
+++ b/Mage/src/main/java/mage/counters/Counters.java
@@ -74,26 +74,30 @@ public class Counters extends HashMap implements Serializable {
}
}
- public void removeCounter(String name) {
- removeCounter(name, 1);
+ public boolean removeCounter(String name) {
+ return removeCounter(name, 1);
}
- public void removeCounter(CounterType counterType, int amount) {
+ public boolean removeCounter(CounterType counterType, int amount) {
if (this.containsKey(counterType.getName())) {
get(counterType.getName()).remove(amount);
if (get(counterType.getName()).count == 0) {
this.remove(counterType.getName());
- }
+ }
+ return true;
}
+ return false;
}
- public void removeCounter(String name, int amount) {
+ public boolean removeCounter(String name, int amount) {
if (this.containsKey(name)) {
this.get(name).remove(amount);
if (this.get(name).getCount() == 0) {
this.remove(name);
}
+ return true;
}
+ return false;
}
public void removeAllCounters(CounterType counterType){
diff --git a/Mage/src/main/java/mage/game/ZonesHandler.java b/Mage/src/main/java/mage/game/ZonesHandler.java
index f78a74e9ee7..ede698ad585 100644
--- a/Mage/src/main/java/mage/game/ZonesHandler.java
+++ b/Mage/src/main/java/mage/game/ZonesHandler.java
@@ -288,7 +288,7 @@ public class ZonesHandler {
private static Card takeAttributesFromSpell(Card card, ZoneChangeEvent event, Game game) {
if (Zone.STACK.equals(event.getFromZone())) {
Spell spell = game.getStack().getSpell(event.getTargetId());
- if (spell != null) {
+ if (spell != null && !spell.isFaceDown(game)) {
boolean doCopy = false;
if (!card.getColor(game).equals(spell.getColor(game))) {
doCopy = true;
diff --git a/Mage/src/main/java/mage/game/match/MatchOptions.java b/Mage/src/main/java/mage/game/match/MatchOptions.java
index 37901b91bea..3bcd909ab8b 100644
--- a/Mage/src/main/java/mage/game/match/MatchOptions.java
+++ b/Mage/src/main/java/mage/game/match/MatchOptions.java
@@ -58,6 +58,7 @@ public class MatchOptions implements Serializable {
protected SkillLevel skillLevel;
protected boolean rollbackTurnsAllowed;
protected int quitRatio;
+ protected int edhPowerLevel;
protected boolean rated;
protected int numSeatsForMatch;
@@ -208,6 +209,14 @@ public class MatchOptions implements Serializable {
public void setQuitRatio(int quitRatio) {
this.quitRatio = quitRatio;
}
+
+ public int getEdhPowerLevel() {
+ return edhPowerLevel;
+ }
+
+ public void setEdhPowerLevel(int edhPowerLevel) {
+ this.edhPowerLevel = edhPowerLevel;
+ }
public boolean isRated() {
return rated;
diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java
index 039f0b70756..15a6f39a606 100644
--- a/Mage/src/main/java/mage/players/PlayerImpl.java
+++ b/Mage/src/main/java/mage/players/PlayerImpl.java
@@ -1877,7 +1877,9 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public void removeCounters(String name, int amount, Ability source, Game game) {
for (int i = 0; i < amount; i++) {
- counters.removeCounter(name, 1);
+ if (!counters.removeCounter(name, 1)) {
+ break;
+ }
GameEvent event = GameEvent.getEvent(GameEvent.EventType.COUNTER_REMOVED,
getId(), (source == null ? null : source.getSourceId()), (source == null ? null : source.getControllerId()));
event.setData(name);