From d7f100b24b302995a7f4d18dd44f1101e4c29a23 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 8 Nov 2014 01:33:29 +0100 Subject: [PATCH] * Added "Duel Commander" format (fixes #436). --- .../src/mage/deck/Commander.java | 236 +++++++++--------- .../src/mage/deck/DuelCommander.java | 92 +++++++ .../src/mage/game/CommanderDuel.java | 4 +- .../src/mage/game/CommanderDuelMatch.java | 10 +- .../src/mage/game/CommanderFreeForAll.java | 4 +- .../mage/game/CommanderFreeForAllMatch.java | 9 +- .../src/mage/game/FreeForAll.java | 9 +- .../src/mage/game/FreeForAllMatch.java | 2 +- .../src/mage/game/TwoPlayerDuel.java | 9 +- .../src/mage/game/TwoPlayerMatch.java | 2 +- Mage.Server/config/config.xml | 1 + Mage.Server/release/config/config.xml | 3 +- .../mage/test/serverside/PlayGameTest.java | 2 +- .../test/serverside/TestPlayRandomGame.java | 2 +- .../base/CardTestMultiPlayerBase.java | 4 +- .../serverside/base/CardTestPlayerBase.java | 4 +- .../CommanderReplacementEffect.java | 11 +- Mage/src/mage/cards/decks/DeckValidator.java | 2 +- Mage/src/mage/game/GameCommanderImpl.java | 29 ++- Mage/src/mage/game/GameImpl.java | 11 +- Mage/src/mage/game/match/MatchImpl.java | 1 - 21 files changed, 280 insertions(+), 167 deletions(-) create mode 100644 Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java 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 7c1ccbcbaf6..d01fbaf59b5 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 @@ -1,31 +1,30 @@ -/* -* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + /* + * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.deck; import java.util.ArrayList; @@ -33,7 +32,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; - import mage.cards.Card; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; @@ -44,155 +42,157 @@ import mage.filter.FilterMana; * * @author Plopman */ - - public class Commander extends DeckValidator { - protected List banned = new ArrayList<>(); - + protected List banned = new ArrayList<>(); + protected List bannedCommander = new ArrayList<>(); + private static final String regexBlack = ".*\\x7b.{0,2}B.{0,2}\\x7d.*"; - private static final String regexBlue = ".*\\x7b.{0,2}U.{0,2}\\x7d.*"; - private static final String regexRed = ".*\\x7b.{0,2}R.{0,2}\\x7d.*"; + private static final String regexBlue = ".*\\x7b.{0,2}U.{0,2}\\x7d.*"; + private static final String regexRed = ".*\\x7b.{0,2}R.{0,2}\\x7d.*"; private static final String regexGreen = ".*\\x7b.{0,2}G.{0,2}\\x7d.*"; private static final String regexWhite = ".*\\x7b.{0,2}W.{0,2}\\x7d.*"; - public Commander(){ - super("Commander"); - - banned.add("Ancestral Recall"); - banned.add("Balance"); - banned.add("Biorhythm"); - banned.add("Black Lotus"); - banned.add("Braids, Cabal Minion"); - banned.add("Channel"); - banned.add("Coalition Victory"); - banned.add("Emrakul, the Aeons Torn"); - banned.add("Erayo, Soratami Ascendant"); - banned.add("Fastbond"); - banned.add("Gifts Ungiven"); - banned.add("Griselbrand"); - banned.add("Karakas"); - banned.add("Library of Alexandria"); - banned.add("Limited Resources"); - banned.add("Mox Emerald"); - banned.add("Mox Jet"); - banned.add("Mox Pearl"); - banned.add("Mox Ruby"); - banned.add("Mox Sapphire"); - banned.add("Painter's Servant"); - banned.add("Panoptic Mirror"); - banned.add("Primeval Titan"); - banned.add("Protean Hulk"); - banned.add("Recurring Nightmare"); - banned.add("Rofellos, Llanowar Emissary"); - banned.add("Sundering Titan"); - banned.add("Sway of the Stars"); - banned.add("Sylvan Primordial"); - banned.add("Time Vault"); - banned.add("Time Walk"); - banned.add("Tinker"); - banned.add("Tolarian Academy"); - banned.add("Trade Secrets"); - banned.add("Upheaval"); - banned.add("Worldfire"); - banned.add("Yawgmoth's Bargain"); - + public Commander() { + this("Commander"); + banned.add("Ancestral Recall"); + banned.add("Balance"); + banned.add("Biorhythm"); + banned.add("Black Lotus"); + banned.add("Braids, Cabal Minion"); + banned.add("Channel"); + banned.add("Coalition Victory"); + banned.add("Emrakul, the Aeons Torn"); + banned.add("Erayo, Soratami Ascendant"); + banned.add("Fastbond"); + banned.add("Gifts Ungiven"); + banned.add("Griselbrand"); + banned.add("Karakas"); + banned.add("Library of Alexandria"); + banned.add("Limited Resources"); + banned.add("Mox Emerald"); + banned.add("Mox Jet"); + banned.add("Mox Pearl"); + banned.add("Mox Ruby"); + banned.add("Mox Sapphire"); + banned.add("Painter's Servant"); + banned.add("Panoptic Mirror"); + banned.add("Primeval Titan"); + banned.add("Protean Hulk"); + banned.add("Recurring Nightmare"); + banned.add("Rofellos, Llanowar Emissary"); + banned.add("Sundering Titan"); + banned.add("Sway of the Stars"); + banned.add("Sylvan Primordial"); + banned.add("Time Vault"); + banned.add("Time Walk"); + banned.add("Tinker"); + banned.add("Tolarian Academy"); + banned.add("Trade Secrets"); + banned.add("Upheaval"); + banned.add("Worldfire"); + banned.add("Yawgmoth's Bargain"); } - - + + public Commander(String name) { + super(name); + } + @Override public boolean validate(Deck deck) { boolean valid = true; - + if (deck.getCards().size() != 99) { invalid.put("Deck", "Must contain 99 cards: has " + deck.getCards().size() + " cards"); valid = false; } List basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", - "Snow-Covered Forest", "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains")); + "Snow-Covered Forest", "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains")); Map counts = new HashMap<>(); countCards(counts, deck.getCards()); countCards(counts, deck.getSideboard()); - for (Map.Entry entry: counts.entrySet()) { + for (Map.Entry entry : counts.entrySet()) { if (entry.getValue() > 1) { - if (!basicLandNames.contains(entry.getKey()) && !entry.getKey().equals("Relentless Rats")&& !entry.getKey().equals("Shadowborn Apostle")) { + if (!basicLandNames.contains(entry.getKey()) && !entry.getKey().equals("Relentless Rats") && !entry.getKey().equals("Shadowborn Apostle")) { invalid.put(entry.getKey(), "Too many: " + entry.getValue()); valid = false; } } } - - for (String bannedCard: banned) { + + for (String bannedCard : banned) { if (counts.containsKey(bannedCard)) { invalid.put(bannedCard, "Banned"); valid = false; } } - - if(deck.getSideboard().size() == 1){ - Card commander = (Card)deck.getSideboard().toArray()[0]; - if(commander != null && commander.getCardType().contains(CardType.CREATURE) && commander.getSupertype().contains("Legendary")){ - FilterMana color = getColorIdentity(commander); - for(Card card : deck.getCards()){ - if(!cardHasValideColor(color, card)){ - invalid.put(card.getName(), "Invalid color"); - valid = false; + + if (deck.getSideboard().size() == 1) { + Card commander = (Card) deck.getSideboard().toArray()[0]; + if (commander != null && commander.getCardType().contains(CardType.CREATURE) && commander.getSupertype().contains("Legendary")) { + if (!bannedCommander.contains(commander.getName())) { + FilterMana color = getColorIdentity(commander); + for (Card card : deck.getCards()) { + if (!cardHasValideColor(color, card)) { + invalid.put(card.getName(), "Invalid color"); + valid = false; + } } + } else { + invalid.put("Commander", "Commander banned"); + valid = false; } - } - else{ + } else { invalid.put("Commander", "Commander invalide"); valid = false; } + } else { + invalid.put("Commander", "Sideboard must contain only the commander"); } - else{ - invalid.put("Commander", "Sideboard must contain only the commander"); - } - + return valid; } - - public FilterMana getColorIdentity(Card card){ + + public FilterMana getColorIdentity(Card card) { FilterMana mana = new FilterMana(); mana.setBlack(card.getManaCost().getText().matches(regexBlack)); mana.setBlue(card.getManaCost().getText().matches(regexBlue)); mana.setGreen(card.getManaCost().getText().matches(regexGreen)); mana.setRed(card.getManaCost().getText().matches(regexRed)); mana.setWhite(card.getManaCost().getText().matches(regexWhite)); - - for(String rule : card.getRules()){ + + for (String rule : card.getRules()) { rule = rule.replaceAll("(?i)", ""); // Ignoring reminder text in italic - if(rule.matches(regexBlack)){ + if (rule.matches(regexBlack)) { mana.setBlack(true); } - if(rule.matches(regexBlue)){ + if (rule.matches(regexBlue)) { mana.setBlue(true); } - if(rule.matches(regexGreen)){ + if (rule.matches(regexGreen)) { mana.setGreen(true); } - if(rule.matches(regexRed)){ + if (rule.matches(regexRed)) { mana.setRed(true); } - if(rule.matches(regexWhite)){ + if (rule.matches(regexWhite)) { mana.setWhite(true); - } - } + } + } return mana; } - - public boolean cardHasValideColor(FilterMana commander, Card card){ + + public boolean cardHasValideColor(FilterMana commander, Card card) { FilterMana cardColor = getColorIdentity(card); - if(cardColor.isBlack() && !commander.isBlack() - || cardColor.isBlue() && !commander.isBlue() - || cardColor.isGreen() && !commander.isGreen() - || cardColor.isRed() && !commander.isRed() - || cardColor.isWhite() && !commander.isWhite()){ + if (cardColor.isBlack() && !commander.isBlack() + || cardColor.isBlue() && !commander.isBlue() + || cardColor.isGreen() && !commander.isGreen() + || cardColor.isRed() && !commander.isRed() + || cardColor.isWhite() && !commander.isWhite()) { return false; } return true; } - } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java new file mode 100644 index 00000000000..9f8b5ab916b --- /dev/null +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java @@ -0,0 +1,92 @@ +/* + * 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 mage.deck; + +/** + * + * @author LevelX2 + */ +public class DuelCommander extends Commander { + + public DuelCommander() { + super("Duel Commander"); + banned.add("Ancestral Recall"); + banned.add("Ancient Tomb"); + banned.add("Balance"); + banned.add("Back to Basics"); + banned.add("Black Lotus"); + banned.add("Cataclysm"); + banned.add("Channel"); + banned.add("Crucible of Worlds"); + banned.add("Gifts Ungiven"); + banned.add("Grim Monolith"); + banned.add("Grindstone"); + banned.add("Hermit Druid"); + banned.add("Humility"); + banned.add("Imperial Seal"); + banned.add("Karakas"); + banned.add("Library of Alexandria"); + banned.add("Loyal Retainers"); + banned.add("Mana Crypt"); + banned.add("Mana Drain"); + banned.add("Mana Vault"); + banned.add("Mind Twist"); + banned.add("Mishra’s Workshop"); + banned.add("Mox Emerald"); + banned.add("Mox Jet"); + banned.add("Mox Pearl"); + banned.add("Mox Ruby"); + banned.add("Mox Sapphire"); + banned.add("Natural Order"); + banned.add("Necropotence"); + banned.add("Oath of Druids"); + banned.add("Protean Hulk"); + banned.add("Sensei’s Divining Top"); + banned.add("Serra Ascendant"); + banned.add("Shahrazad"); + banned.add("Sol Ring"); + banned.add("Strip Mine"); + banned.add("The Tabernacle at Pendrell Vale"); + banned.add("Time Vault"); + banned.add("Time Walk"); + banned.add("Tinker"); + banned.add("Tolarian Academy"); + banned.add("Vampiric Tutor"); + banned.add("Winter Orb"); + banned.add("Yawgmoth’s Bargain"); + + bannedCommander.add("Braids, Cabal Minion"); + bannedCommander.add("Derevi, Empyrial Tactician"); + bannedCommander.add("Edric, Spymaster of Trest"); + bannedCommander.add("Erayo, Soratami Ascendant"); + bannedCommander.add("Oloro, Ageless Ascetic"); + bannedCommander.add("Rofellos, Llanowar Emissary"); + bannedCommander.add("Zur the Enchanter"); + } + +} diff --git a/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuel.java b/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuel.java index cb063489aa0..860324cc8e8 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuel.java +++ b/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuel.java @@ -34,8 +34,8 @@ import mage.game.match.MatchType; public class CommanderDuel extends GameCommanderImpl { - public CommanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans) { - super(attackOption, range, freeMulligans); + public CommanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { + super(attackOption, range, freeMulligans, startLife); } public CommanderDuel(final CommanderDuel game) { diff --git a/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java b/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java index c9c9d88e69d..1fa48a61332 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java +++ b/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java @@ -43,8 +43,16 @@ public class CommanderDuelMatch extends MatchImpl { @Override public void startGame() throws GameException { - CommanderDuel game = new CommanderDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans()); + int startLife = 40; + boolean alsoLibrary = false; + // Don't like it to compare but seems like it's complicated to do it in another way + if (options.getDeckType().equals("Variant Magic - Duel Commander")) { + startLife = 30; + alsoLibrary = true; + } + CommanderDuel game = new CommanderDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); game.setStartMessage(this.createGameStartMessage()); + game.setAlsoLibrary(alsoLibrary); initGame(game); games.add(game); } diff --git a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAll.java b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAll.java index 1abd447f035..9332dfe964e 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAll.java +++ b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAll.java @@ -40,8 +40,8 @@ public class CommanderFreeForAll extends GameCommanderImpl { private int numPlayers; - public CommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans) { - super(attackOption, range, freeMulligans); + public CommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { + super(attackOption, range, freeMulligans, startLife); } public CommanderFreeForAll(final CommanderFreeForAll game) { diff --git a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAllMatch.java index 261ad6ecfc2..29abd7d9199 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAllMatch.java +++ b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAllMatch.java @@ -43,8 +43,15 @@ public class CommanderFreeForAllMatch extends MatchImpl { @Override public void startGame() throws GameException { - CommanderFreeForAll game = new CommanderFreeForAll(options.getAttackOption(), options.getRange(), options.getFreeMulligans()); + int startLife = 40; + boolean alsoLibrary = false; + if (options.getDeckType().equals("Duel Commander")) { + startLife = 30; + alsoLibrary = true; + } + CommanderFreeForAll game = new CommanderFreeForAll(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); game.setStartMessage(this.createGameStartMessage()); + game.setAlsoLibrary(alsoLibrary); initGame(game); games.add(game); } diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java index 1af1a1728a7..9ec9ec45a50 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java @@ -44,8 +44,8 @@ public class FreeForAll extends GameImpl { private int numPlayers; - public FreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans) { - super(attackOption, range, freeMulligans); + public FreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { + super(attackOption, range, freeMulligans, startLife); } public FreeForAll(final FreeForAll game) { @@ -67,11 +67,6 @@ public class FreeForAll extends GameImpl { this.numPlayers = numPlayers; } - @Override - public int getLife() { - return 20; - } - @Override public Set getOpponents(UUID playerId) { Set opponents = new HashSet<>(); diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java index c043b3168f7..5d15b04834f 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java @@ -43,7 +43,7 @@ public class FreeForAllMatch extends MatchImpl { @Override public void startGame() throws GameException { - FreeForAll game = new FreeForAll(options.getAttackOption(), options.getRange(), options.getFreeMulligans()); + FreeForAll game = new FreeForAll(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), 20); game.setStartMessage(this.createGameStartMessage()); initGame(game); games.add(game); diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java index 5559663984b..41f2c60d263 100644 --- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java @@ -40,8 +40,8 @@ import mage.players.Player; public class TwoPlayerDuel extends GameImpl { - public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans) { - super(attackOption, range, freeMulligans); + public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { + super(attackOption, range, freeMulligans, startLife); } public TwoPlayerDuel(final TwoPlayerDuel game) { @@ -58,11 +58,6 @@ public class TwoPlayerDuel extends GameImpl { return 2; } - @Override - public int getLife() { - return 20; - } - @Override protected void init(UUID choosingPlayerId, GameOptions gameOptions) { super.init(choosingPlayerId, gameOptions); diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java index ac9f63546ac..4d81f2eeec1 100644 --- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java @@ -43,7 +43,7 @@ public class TwoPlayerMatch extends MatchImpl { @Override public void startGame() throws GameException { - TwoPlayerDuel game = new TwoPlayerDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans()); + TwoPlayerDuel game = new TwoPlayerDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans(),20); // Sets a start message about the match score game.setStartMessage(this.createGameStartMessage()); initGame(game); diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index b4d4cad3cf5..32016984090 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -87,6 +87,7 @@ + diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index f4a92083e3d..73743075813 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -65,7 +65,8 @@ - + + diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java index 2678f0a75cf..0e6390f9f05 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java @@ -32,7 +32,7 @@ public class PlayGameTest extends MageTestBase { @Ignore @Test public void playOneGame() throws GameException, FileNotFoundException, IllegalArgumentException { - Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, 0); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, 0, 20); Player computerA = createPlayer("ComputerA", "Computer - minimax hybrid"); // Player playerA = createPlayer("ComputerA", "Computer - mad"); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java b/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java index 4f8c56d0243..029eff40c7b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java @@ -39,7 +39,7 @@ public class TestPlayRandomGame extends MageTestBase { } private void playOneGame() throws GameException, FileNotFoundException, IllegalArgumentException { - Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, 0); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, 0, 20); Player computerA = createRandomPlayer("ComputerA"); Deck deck = generateRandomDeck(); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java index cd1113cc55d..e891527b51c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java @@ -45,7 +45,7 @@ public abstract class CardTestMultiPlayerBase extends CardTestPlayerAPIImpl { System.gc(); } - Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, 0); + Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, 0, 20); playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); @@ -86,7 +86,7 @@ public abstract class CardTestMultiPlayerBase extends CardTestPlayerAPIImpl { System.gc(); } - Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, 0); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, 0, 20); playerA = createNewPlayer("ComputerA"); playerA.setTestMode(true); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBase.java index e5da7ed42cd..1de0c092797 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBase.java @@ -55,7 +55,7 @@ public abstract class CardTestPlayerBase extends CardTestPlayerAPIImpl { System.gc(); } - Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, 0); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, 0, 20); playerA = createNewPlayer("PlayerA"); playerA.setTestMode(true); @@ -110,7 +110,7 @@ public abstract class CardTestPlayerBase extends CardTestPlayerAPIImpl { System.gc(); } - Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, 0); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, 0, 20); playerA = createNewPlayer("ComputerA"); playerA.setTestMode(true); diff --git a/Mage/src/mage/abilities/effects/common/continious/CommanderReplacementEffect.java b/Mage/src/mage/abilities/effects/common/continious/CommanderReplacementEffect.java index b3556363dc3..b1263e92901 100644 --- a/Mage/src/mage/abilities/effects/common/continious/CommanderReplacementEffect.java +++ b/Mage/src/mage/abilities/effects/common/continious/CommanderReplacementEffect.java @@ -54,17 +54,20 @@ import mage.players.Player; public class CommanderReplacementEffect extends ReplacementEffectImpl { private final UUID commanderId; + private final boolean alsoLibrary; - public CommanderReplacementEffect(UUID commanderId) { + public CommanderReplacementEffect(UUID commanderId, boolean alsoLibrary) { super(Duration.WhileOnBattlefield, Outcome.Benefit); staticText = "If a commander would be put into its owner’s graveyard from anywhere, that player may put it into the command zone instead. If a commander would be put into the exile zone from anywhere, its owner may put it into the command zone instead."; this.commanderId = commanderId; this.duration = Duration.EndOfGame; + this.alsoLibrary = alsoLibrary; } public CommanderReplacementEffect(final CommanderReplacementEffect effect) { super(effect); this.commanderId = effect.commanderId; + this.alsoLibrary = effect.alsoLibrary; } @Override @@ -112,7 +115,11 @@ public class CommanderReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.ZONE_CHANGE && (((ZoneChangeEvent)event).getToZone() == Zone.GRAVEYARD || ((ZoneChangeEvent)event).getToZone() == Zone.EXILED)) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE && ( + ((ZoneChangeEvent)event).getToZone() == Zone.GRAVEYARD || + ((ZoneChangeEvent)event).getToZone() == Zone.EXILED || + (alsoLibrary && ((ZoneChangeEvent)event).getToZone() == Zone.LIBRARY)) + ) { if (commanderId != null) { if (((ZoneChangeEvent)event).getFromZone().equals(Zone.STACK)) { Spell spell = game.getStack().getSpell(event.getTargetId()); diff --git a/Mage/src/mage/cards/decks/DeckValidator.java b/Mage/src/mage/cards/decks/DeckValidator.java index 4b67a4acc5c..383e1ad8a05 100644 --- a/Mage/src/mage/cards/decks/DeckValidator.java +++ b/Mage/src/mage/cards/decks/DeckValidator.java @@ -41,7 +41,7 @@ public abstract class DeckValidator implements Serializable { protected String name; - protected Map invalid = new HashMap(); + protected Map invalid = new HashMap<>(); public DeckValidator(String name) { this.name = name; diff --git a/Mage/src/mage/game/GameCommanderImpl.java b/Mage/src/mage/game/GameCommanderImpl.java index c18d84dd3de..80495b974a6 100644 --- a/Mage/src/mage/game/GameCommanderImpl.java +++ b/Mage/src/mage/game/GameCommanderImpl.java @@ -57,23 +57,17 @@ public abstract class GameCommanderImpl extends GameImpl { private final Map mulliganedCards = new HashMap<>(); private final Set commanderCombatWatcher = new HashSet<>(); + + protected boolean alsoLibrary; // replace also commander going to library - public GameCommanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans) { - super(attackOption, range, freeMulligans); + public GameCommanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { + super(attackOption, range, freeMulligans, startLife); } public GameCommanderImpl(final GameCommanderImpl game) { super(game); } - // MTG Rules 20121001 - // 903.7. Once the starting player has been determined, each player sets his or her life total to 40 and - // draws a hand of seven cards. - @Override - public int getLife() { - return 40; - } - @Override protected void init(UUID choosingPlayerId, GameOptions gameOptions) { super.init(choosingPlayerId, gameOptions); @@ -87,10 +81,10 @@ public abstract class GameCommanderImpl extends GameImpl { if (commander != null) { player.setCommanderId(commander.getId()); commander.moveToZone(Zone.COMMAND, null, this, true); - ability.addEffect(new CommanderReplacementEffect(commander.getId())); + ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoLibrary)); ability.addEffect(new CommanderCostModification(commander.getId())); ability.addEffect(new CommanderManaReplacementEffect(player.getId(), commander.getSpellAbility().getManaCosts().getMana())); - getState().setValue(commander.getId() + "_castCount", new Integer(0)); + getState().setValue(commander.getId() + "_castCount", 0); CommanderCombatDamageWatcher watcher = new CommanderCombatDamageWatcher(commander.getId()); getState().getWatchers().add(watcher); this.commanderCombatWatcher.add(watcher); @@ -135,16 +129,16 @@ public abstract class GameCommanderImpl extends GameImpl { int deduction = 1; if (freeMulligans > 0) { if (usedFreeMulligans != null && usedFreeMulligans.containsKey(player.getId())) { - int used = usedFreeMulligans.get(player.getId()).intValue(); + int used = usedFreeMulligans.get(player.getId()); if (used < freeMulligans ) { deduction = 0; - usedFreeMulligans.put(player.getId(), new Integer(used+1)); + usedFreeMulligans.put(player.getId(), used+1); } } else { deduction = 0;{ } - usedFreeMulligans.put(player.getId(), new Integer(1)); + usedFreeMulligans.put(player.getId(), 1); } } player.drawCards(numCards - deduction, this); @@ -210,4 +204,9 @@ public abstract class GameCommanderImpl extends GameImpl { public boolean isOpponent(Player player, UUID playerToCheck) { return !player.getId().equals(playerToCheck); } + + public void setAlsoLibrary(boolean alsoLibrary) { + this.alsoLibrary = alsoLibrary; + } + } diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index 31b67bd91d6..0dc6b9fe753 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -194,12 +194,15 @@ public abstract class GameImpl implements Game, Serializable { private boolean saveGame = false; private int priorityTime; - public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans) { + private final int startLife; + + public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { this.id = UUID.randomUUID(); this.range = range; this.freeMulligans = freeMulligans; this.attackOption = attackOption; this.state = new GameState(); + this.startLife = startLife; // this.actions = new LinkedList(); } @@ -235,6 +238,7 @@ public abstract class GameImpl implements Game, Serializable { this.scopeRelevant = game.scopeRelevant; this.priorityTime = game.priorityTime; this.saveGame = game.saveGame; + this.startLife = game.startLife; } @Override @@ -2525,5 +2529,10 @@ public abstract class GameImpl implements Game, Serializable { public UUID getStartingPlayerId() { return startingPlayerId; } + + @Override + public int getLife() { + return startLife; + } } diff --git a/Mage/src/mage/game/match/MatchImpl.java b/Mage/src/mage/game/match/MatchImpl.java index 4cf394ecd76..8fee4249992 100644 --- a/Mage/src/mage/game/match/MatchImpl.java +++ b/Mage/src/mage/game/match/MatchImpl.java @@ -44,7 +44,6 @@ import mage.game.events.TableEvent; import mage.game.events.TableEvent.EventType; import mage.game.events.TableEventSource; import mage.players.Player; -import mage.players.PlayerList; import mage.util.DateFormat; import org.apache.log4j.Logger;