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);