From c98bf163be9a70b78bee7b658c2055a231a024b2 Mon Sep 17 00:00:00 2001 From: spjspj Date: Sun, 5 Feb 2017 23:23:51 +1100 Subject: [PATCH] Add Canadian Highlander Deck/Game implementation. Also implements the double-mulligan-on-6,5,4,3,2,1 rule. --- .../src/mage/deck/CanadianHighlander.java | 27 ++- .../Mage.Game.CanadianHighlanderDuel/pom.xml | 50 +++++ .../src/mage/game/CanadianHighlanderDuel.java | 60 ++++++ .../game/CanadianHighlanderDuelMatch.java | 52 +++++ .../mage/game/CanadianHighlanderDuelType.java | 57 ++++++ .../target/maven-archiver/pom.properties | 5 + Mage.Server.Plugins/pom.xml | 3 +- Mage.Server/config/config.xml | 3 +- Mage.Server/pom.xml | 6 + .../mage/game/GameCanadianHighlanderImpl.java | 179 ++++++++++++++++++ 10 files changed, 430 insertions(+), 12 deletions(-) create mode 100644 Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml create mode 100644 Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuel.java create mode 100644 Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelMatch.java create mode 100644 Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelType.java create mode 100644 Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/target/maven-archiver/pom.properties create mode 100644 Mage/src/main/java/mage/game/GameCanadianHighlanderImpl.java diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java index 893eb639fa..00ac1782ec 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java @@ -66,7 +66,7 @@ public class CanadianHighlander extends Constructed { invalid.put("Deck", "Must contain 100 or more singleton cards: has " + (deck.getCards().size()) + " cards"); valid = false; } - + if (deck.getSideboard().size() > 0) { invalid.put("Deck", "Sideboard can't contain any cards: has " + (deck.getSideboard().size()) + " cards"); valid = false; @@ -86,11 +86,11 @@ public class CanadianHighlander extends Constructed { } } - int allowedPoints = 10 * (int) Math.floor(deck.getCards().size()/100.0); + int allowedPoints = 10 * (int) Math.floor(deck.getCards().size() / 100.0); int totalPoints = 0; for (Map.Entry entry : counts.entrySet()) { String cn = entry.getKey(); - if(cn.equals("Balance") + if (cn.equals("Balance") || cn.equals("Dig Through Time") || cn.equals("Fastbond") || cn.equals("Gifts Ungiven") @@ -108,8 +108,9 @@ public class CanadianHighlander extends Constructed { || cn.equals("Treasure Cruise") || cn.equals("True-Name Nemesis")) { totalPoints += 1; + invalid.put(entry.getKey(), " 1 point " + cn); } - if(cn.equals("Doomsday") + if (cn.equals("Doomsday") || cn.equals("Enlightened Tutor") || cn.equals("Imperial Seal") || cn.equals("Mana Crypt") @@ -119,8 +120,9 @@ public class CanadianHighlander extends Constructed { || cn.equals("Survival of the Fittest") || cn.equals("Umezawa's Jitte")) { totalPoints += 2; + invalid.put(entry.getKey(), " 2 points " + cn); } - if(cn.equals("Birthing Pod") + if (cn.equals("Birthing Pod") || cn.equals("Mox Emerald") || cn.equals("Mox Jet") || cn.equals("Mox Pearl") @@ -129,27 +131,32 @@ public class CanadianHighlander extends Constructed { || cn.equals("Protean Hulk") || cn.equals("Vampiric Tutor")) { totalPoints += 3; + invalid.put(entry.getKey(), " 3 points " + cn); } - if(cn.equals("Demonic Tutor") + if (cn.equals("Demonic Tutor") || cn.equals("Hermit Druid") || cn.equals("Sol Ring")) { totalPoints += 4; + invalid.put(entry.getKey(), " 4 points " + cn); } - if(cn.equals("Ancestral Recall") + if (cn.equals("Ancestral Recall") || cn.equals("Natural Order") || cn.equals("Time Walk") || cn.equals("Tinker")) { totalPoints += 5; + invalid.put(entry.getKey(), " 5 points " + cn); } - if(cn.equals("Flash")) { + if (cn.equals("Flash")) { totalPoints += 6; + invalid.put(entry.getKey(), " 6 points " + cn); } - if(cn.equals("Black Lotus") + if (cn.equals("Black Lotus") || cn.equals("Time Vault")) { totalPoints += 7; + invalid.put(entry.getKey(), " 7 points " + cn); } } - if(totalPoints > allowedPoints) { + if (totalPoints > allowedPoints) { invalid.put("Total points too high", "Your calculated point total was " + totalPoints); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml new file mode 100644 index 0000000000..8bd6cbd278 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml @@ -0,0 +1,50 @@ + + + + 4.0.0 + + + org.mage + mage-server-plugins + 1.4.21 + + + mage-game-canadianhighlanderduel + jar + Mage Game Canadian Highlander Two Player + + + + ${project.groupId} + mage + ${project.version} + + + + + src + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.7 + 1.7 + + + + maven-resources-plugin + + UTF-8 + + + + + + mage-game-canadianhighlanderduel + + + + + diff --git a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuel.java b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuel.java new file mode 100644 index 0000000000..1ea0483ef9 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuel.java @@ -0,0 +1,60 @@ +/* +* 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.game; + +import mage.constants.MultiplayerAttackOption; +import mage.constants.RangeOfInfluence; +import mage.game.match.MatchType; + +public class CanadianHighlanderDuel extends GameCanadianHighlanderImpl { + + public CanadianHighlanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { + super(attackOption, range, freeMulligans, startLife); + } + + public CanadianHighlanderDuel(final CanadianHighlanderDuel game) { + super(game); + } + + @Override + public MatchType getGameType() { + return new CanadianHighlanderDuelType(); + } + + @Override + public int getNumPlayers() { + return 2; + } + + @Override + public CanadianHighlanderDuel copy() { + return new CanadianHighlanderDuel(this); + } + +} diff --git a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelMatch.java b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelMatch.java new file mode 100644 index 0000000000..7621a40a40 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelMatch.java @@ -0,0 +1,52 @@ +/* + * 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.game; + +import mage.game.match.MatchImpl; +import mage.game.match.MatchOptions; + +/** + * + * @author spjspj + */ +public class CanadianHighlanderDuelMatch extends MatchImpl { + + public CanadianHighlanderDuelMatch(MatchOptions options) { + super(options); + } + + @Override + public void startGame() throws GameException { + int startLife = 20; + CanadianHighlanderDuel game = new CanadianHighlanderDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + game.setStartMessage(this.createGameStartMessage()); + initGame(game); + games.add(game); + } + +} diff --git a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelType.java b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelType.java new file mode 100644 index 0000000000..b0f92c2442 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelType.java @@ -0,0 +1,57 @@ +/* + * 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.game; + +import mage.game.match.MatchType; + +/** + * + * @author spjspj + */ +public class CanadianHighlanderDuelType extends MatchType { + + public CanadianHighlanderDuelType() { + this.name = "Canadian Highlander Two Player Duel"; + this.maxPlayers = 2; + this.minPlayers = 2; + this.numTeams = 0; + this.useAttackOption = false; + this.useRange = false; + this.sideboardingAllowed = false; + } + + protected CanadianHighlanderDuelType(final CanadianHighlanderDuelType matchType) { + super(matchType); + } + + @Override + public CanadianHighlanderDuelType copy() { + return new CanadianHighlanderDuelType(this); + } +} diff --git a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/target/maven-archiver/pom.properties b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/target/maven-archiver/pom.properties new file mode 100644 index 0000000000..004569ce64 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Sun Feb 05 18:32:22 AEDT 2017 +version=1.4.21 +groupId=org.mage +artifactId=mage-game-canadianhighlanderduel diff --git a/Mage.Server.Plugins/pom.xml b/Mage.Server.Plugins/pom.xml index fa31573855..f97bf3e5a9 100644 --- a/Mage.Server.Plugins/pom.xml +++ b/Mage.Server.Plugins/pom.xml @@ -22,6 +22,7 @@ Mage.Game.FreeForAll Mage.Game.MomirDuel Mage.Game.TinyLeadersDuel + Mage.Game.CanadianHighlanderDuel Mage.Game.TwoPlayerDuel Mage.Player.AI Mage.Player.AIMinimax @@ -34,4 +35,4 @@ Mage.Tournament.Sealed - \ No newline at end of file + diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index d3c3b2bb11..79a66add64 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -72,6 +72,7 @@ + @@ -133,10 +134,10 @@ - + diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index 8815a14850..ee4cf8f560 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -142,6 +142,12 @@ ${project.version} runtime + + ${project.groupId} + mage-game-canadianhighlanderduel + ${project.version} + runtime + ${project.groupId} mage-game-momirduel diff --git a/Mage/src/main/java/mage/game/GameCanadianHighlanderImpl.java b/Mage/src/main/java/mage/game/GameCanadianHighlanderImpl.java new file mode 100644 index 0000000000..e2877b17fa --- /dev/null +++ b/Mage/src/main/java/mage/game/GameCanadianHighlanderImpl.java @@ -0,0 +1,179 @@ +/* + * 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.game; + +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import mage.constants.MultiplayerAttackOption; +import mage.constants.PhaseStep; +import mage.constants.RangeOfInfluence; +import mage.game.turn.TurnMod; +import mage.players.Player; + +public abstract class GameCanadianHighlanderImpl extends GameImpl { + + protected boolean startingPlayerSkipsDraw = true; + protected Map usedMulligans = new LinkedHashMap<>(); + + public GameCanadianHighlanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { + super(attackOption, range, 0, startLife); + } + + public GameCanadianHighlanderImpl(final GameCanadianHighlanderImpl game) { + super(game); + } + + @Override + protected void init(UUID choosingPlayerId) { + super.init(choosingPlayerId); + state.getTurnMods().add(new TurnMod(startingPlayerId, PhaseStep.DRAW)); + } + + private String getNextMulligan(String mulligan) { + if (mulligan.equals("7")) { + return "6a"; + } else if (mulligan.equals("6a")) { + return "6b"; + } else if (mulligan.equals("6b")) { + return "5a"; + } else if (mulligan.equals("5a")) { + return "5b"; + } else if (mulligan.equals("5b")) { + return "4a"; + } else if (mulligan.equals("4a")) { + return "4b"; + } else if (mulligan.equals("4b")) { + return "3a"; + } else if (mulligan.equals("3a")) { + return "3b"; + } else if (mulligan.equals("3b")) { + return "2a"; + } else if (mulligan.equals("2a")) { + return "2b"; + } else if (mulligan.equals("2b")) { + return "1a"; + } else if (mulligan.equals("1a")) { + return "1b"; + } + return "0"; + } + + private int getNextMulliganNum(String mulligan) { + if (mulligan.equals("7")) { + return 6; + } else if (mulligan.equals("6a")) { + return 6; + } else if (mulligan.equals("6b")) { + return 5; + } else if (mulligan.equals("5a")) { + return 5; + } else if (mulligan.equals("5b")) { + return 4; + } else if (mulligan.equals("4a")) { + return 4; + } else if (mulligan.equals("4b")) { + return 3; + } else if (mulligan.equals("3a")) { + return 3; + } else if (mulligan.equals("3b")) { + return 2; + } else if (mulligan.equals("2a")) { + return 2; + } else if (mulligan.equals("2b")) { + return 1; + } else if (mulligan.equals("1a")) { + return 1; + } + return 0; + } + + @Override + public int mulliganDownTo(UUID playerId) { + Player player = getPlayer(playerId); + int deduction = 1; + int numToMulliganTo = -1; + if (usedMulligans != null) { + String mulliganCode = "7"; + if (usedMulligans.containsKey(player.getId())) { + mulliganCode = usedMulligans.get(player.getId()); + } + numToMulliganTo = getNextMulliganNum(mulliganCode); + } + if (numToMulliganTo == -1) { + return player.getHand().size() - deduction; + } + return numToMulliganTo; + } + + @Override + public void mulligan(UUID playerId) { + Player player = getPlayer(playerId); + int numCards = player.getHand().size(); + int numToMulliganTo = numCards; + player.getLibrary().addAll(player.getHand().getCards(this), this); + player.getHand().clear(); + player.shuffleLibrary(null, this); + if (usedMulligans != null) { + String mulliganCode = "7"; + if (usedMulligans.containsKey(player.getId())) { + mulliganCode = usedMulligans.get(player.getId()); + } + numToMulliganTo = getNextMulliganNum(mulliganCode); + usedMulligans.put(player.getId(), getNextMulligan(mulliganCode)); + } + fireInformEvent(new StringBuilder(player.getLogName()) + .append(" mulligans to ") + .append(Integer.toString(numToMulliganTo)) + .append(numToMulliganTo == 1 ? " card" : " cards").toString()); + player.drawCards(numToMulliganTo, this); + } + + @Override + public void endMulligan(UUID playerId) { + super.endMulligan(playerId); + } + + @Override + public Set getOpponents(UUID playerId) { + Set opponents = new HashSet<>(); + for (UUID opponentId : getState().getPlayersInRange(playerId, this)) { + if (!opponentId.equals(playerId)) { + opponents.add(opponentId); + } + } + return opponents; + } + + @Override + public boolean isOpponent(Player player, UUID playerToCheck) { + return !player.getId().equals(playerToCheck); + } +}