diff --git a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java index a738721cfe..b748988ab9 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java @@ -26,7 +26,7 @@ * or implied, of BetaSteward_at_googlemail.com. */ -/* + /* * ConnectDialog.java * * Created on 20-Jan-2010, 9:37:07 PM @@ -391,6 +391,7 @@ public class ConnectDialog extends MageDialog { connection.setUsername(this.txtUserName.getText().trim()); connection.setPassword(this.txtPassword.getText().trim()); connection.setForceDBComparison(this.chkForceUpdateDB.isSelected()); + connection.setUserIdStr(System.getProperty("user.name")); MageFrame.getPreferences().put(KEY_CONNECT_FLAG, ((CountryItemEditor) cbFlag.getEditor()).getImageItem()); PreferencesDialog.setProxyInformation(connection); diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 4423038e08..1c63bcec16 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -3520,6 +3520,7 @@ public class PreferencesDialog extends javax.swing.JDialog { if (selectedAvatarId == 0) { getSelectedAvatar(); } + String userStrId = System.getProperty("user.name"); return new UserData(UserGroup.PLAYER, PreferencesDialog.selectedAvatarId, PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_ABILITY_PICKER_FORCED, "true").equals("true"), @@ -3533,7 +3534,8 @@ public class PreferencesDialog extends javax.swing.JDialog { PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PASS_PRIORITY_CAST, "true").equals("true"), PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PASS_PRIORITY_ACTIVATION, "true").equals("true"), PreferencesDialog.getCachedValue(PreferencesDialog.KEY_AUTO_ORDER_TRIGGER, "true").equals("true"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_USE_FIRST_MANA_ABILITY, "false").equals("true") + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), + userStrId ); } diff --git a/Mage.Common/src/mage/interfaces/MageServer.java b/Mage.Common/src/mage/interfaces/MageServer.java index 817ccf84a9..d7da351f8b 100644 --- a/Mage.Common/src/mage/interfaces/MageServer.java +++ b/Mage.Common/src/mage/interfaces/MageServer.java @@ -62,7 +62,7 @@ public interface MageServer { boolean resetPassword(String sessionId, String email, String authToken, String password) throws MageException; - boolean connectUser(String userName, String password, String sessionId, MageVersion version) throws MageException; + boolean connectUser(String userName, String password, String sessionId, MageVersion version, String userIdStr) throws MageException; boolean connectAdmin(String password, String sessionId, MageVersion version) throws MageException; @@ -72,7 +72,7 @@ public interface MageServer { List getMissingCardsData(List classNames); // user methods - boolean setUserData(String userName, String sessionId, UserData userData, String clientVersion) throws MageException; + boolean setUserData(String userName, String sessionId, UserData userData, String clientVersion, String userIdStr) throws MageException; void sendFeedbackMessage(String sessionId, String username, String title, String type, String message, String email) throws MageException; diff --git a/Mage.Common/src/mage/remote/Connection.java b/Mage.Common/src/mage/remote/Connection.java index 2a989da8dc..87e1f634be 100644 --- a/Mage.Common/src/mage/remote/Connection.java +++ b/Mage.Common/src/mage/remote/Connection.java @@ -55,6 +55,7 @@ public class Connection { private String proxyPassword; private int clientCardDatabaseVersion; private boolean forceDBComparison; + private String userIdStr; private UserData userData; @@ -167,6 +168,14 @@ public class Connection { this.username = username; } + public String getUserIdStr() { + return userIdStr; + } + + public void setUserIdStr(String userIdStr) { + this.userIdStr = userIdStr; + } + public String getPassword() { return password; } diff --git a/Mage.Common/src/mage/remote/SessionImpl.java b/Mage.Common/src/mage/remote/SessionImpl.java index 594bf09430..f1cfa362fc 100644 --- a/Mage.Common/src/mage/remote/SessionImpl.java +++ b/Mage.Common/src/mage/remote/SessionImpl.java @@ -222,9 +222,9 @@ public class SessionImpl implements Session { boolean registerResult; if (connection.getAdminPassword() == null) { // for backward compatibility. don't remove twice call - first one does nothing but for version checking - registerResult = server.connectUser(connection.getUsername(), connection.getPassword(), sessionId, client.getVersion()); + registerResult = server.connectUser(connection.getUsername(), connection.getPassword(), sessionId, client.getVersion(), connection.getUserIdStr()); if (registerResult) { - server.setUserData(connection.getUsername(), sessionId, connection.getUserData(), client.getVersion().toString()); + server.setUserData(connection.getUsername(), sessionId, connection.getUserData(), client.getVersion().toString(), connection.getUserIdStr()); } } else { registerResult = server.connectAdmin(connection.getAdminPassword(), sessionId, client.getVersion()); @@ -1466,7 +1466,7 @@ public class SessionImpl implements Session { } return false; } - + @Override public boolean setActivation(String userName, boolean active) { try { @@ -1571,7 +1571,7 @@ public class SessionImpl implements Session { public boolean updatePreferencesForServer(UserData userData) { try { if (isConnected()) { - server.setUserData(connection.getUsername(), sessionId, userData, null); + server.setUserData(connection.getUsername(), sessionId, userData, null, null); } return true; } catch (MageException ex) { diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java index adf31bb5b6..bbc4a7340f 100644 --- a/Mage.Common/src/mage/utils/MageVersion.java +++ b/Mage.Common/src/mage/utils/MageVersion.java @@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable { public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_PATCH = 21; - public final static String MAGE_VERSION_MINOR_PATCH = "V1"; + public final static String MAGE_VERSION_MINOR_PATCH = "V2"; public final static String MAGE_VERSION_INFO = ""; private final int major; diff --git a/Mage.Common/src/mage/view/UserView.java b/Mage.Common/src/mage/view/UserView.java index d8d5e6a1de..1b4a9d082a 100644 --- a/Mage.Common/src/mage/view/UserView.java +++ b/Mage.Common/src/mage/view/UserView.java @@ -46,8 +46,9 @@ public class UserView implements Serializable { private final Date muteChatUntil; private final String clientVersion; private final String email; + private final String userIdStr; - public UserView(String userName, String host, String sessionId, Date timeConnected, String gameInfo, String userState, Date muteChatUntil, String clientVersion, String email) { + public UserView(String userName, String host, String sessionId, Date timeConnected, String gameInfo, String userState, Date muteChatUntil, String clientVersion, String email, String userIdStr) { this.userName = userName; this.host = host; this.sessionId = sessionId; @@ -57,6 +58,7 @@ public class UserView implements Serializable { this.muteChatUntil = muteChatUntil; this.clientVersion = clientVersion; this.email = email; + this.userIdStr = userIdStr; } public String getUserName() { @@ -90,9 +92,12 @@ public class UserView implements Serializable { public Date getTimeConnected() { return timeConnected; } - + public String getEmail() { return email; } + public String getUserIdStr() { + return userIdStr; + } } 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.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index d4384d241c..f642694fd5 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -132,7 +132,7 @@ public class MageServerImpl implements MageServer { } return true; } - + @Override public boolean resetPassword(String sessionId, String email, String authToken, String password) throws MageException { if (!ConfigSettings.getInstance().isAuthenticationActivated()) { @@ -158,13 +158,13 @@ public class MageServerImpl implements MageServer { } @Override - public boolean connectUser(String userName, String password, String sessionId, MageVersion version) throws MageException { + public boolean connectUser(String userName, String password, String sessionId, MageVersion version, String userIdStr) throws MageException { try { if (version.compareTo(Main.getVersion()) != 0) { logger.info("MageVersionException: userName=" + userName + ", version=" + version); throw new MageVersionException(version, Main.getVersion()); } - return SessionManager.getInstance().connectUser(sessionId, userName, password); + return SessionManager.getInstance().connectUser(sessionId, userName, password, userIdStr); } catch (MageException ex) { if (ex instanceof MageVersionException) { throw (MageVersionException) ex; @@ -175,11 +175,11 @@ public class MageServerImpl implements MageServer { } @Override - public boolean setUserData(final String userName, final String sessionId, final UserData userData, final String clientVersion) throws MageException { + public boolean setUserData(final String userName, final String sessionId, final UserData userData, final String clientVersion, final String userIdStr) throws MageException { return executeWithResult("setUserData", sessionId, new ActionWithBooleanResult() { @Override public Boolean execute() throws MageException { - return SessionManager.getInstance().setUserData(userName, sessionId, userData, clientVersion); + return SessionManager.getInstance().setUserData(userName, sessionId, userData, clientVersion, userIdStr); } }); } @@ -943,7 +943,8 @@ public class MageServerImpl implements MageServer { user.getUserState().toString(), user.getChatLockedUntil(), user.getClientVersion(), - user.getEmail() + user.getEmail(), + user.getUserIdStr() )); } return users; diff --git a/Mage.Server/src/main/java/mage/server/Session.java b/Mage.Server/src/main/java/mage/server/Session.java index ab6f404de2..e4c4e7d3c1 100644 --- a/Mage.Server/src/main/java/mage/server/Session.java +++ b/Mage.Server/src/main/java/mage/server/Session.java @@ -264,12 +264,13 @@ public class Session { this.userId = user.getId(); } - public boolean setUserData(String userName, UserData userData, String clientVersion) { + public boolean setUserData(String userName, UserData userData, String clientVersion, String userIdStr) { User user = UserManager.getInstance().getUserByName(userName); if (user != null) { if (clientVersion != null) { user.setClientVersion(clientVersion); } + user.setUserIdStr(userIdStr); if (user.getUserData() == null || user.getUserData().getGroupId() == UserGroup.DEFAULT.getGroupId()) { user.setUserData(userData); } else { diff --git a/Mage.Server/src/main/java/mage/server/SessionManager.java b/Mage.Server/src/main/java/mage/server/SessionManager.java index 34b148da7a..faaecf004b 100644 --- a/Mage.Server/src/main/java/mage/server/SessionManager.java +++ b/Mage.Server/src/main/java/mage/server/SessionManager.java @@ -88,7 +88,7 @@ public class SessionManager { return true; } - public boolean connectUser(String sessionId, String userName, String password) throws MageException { + public boolean connectUser(String sessionId, String userName, String password, String userIdStr) throws MageException { Session session = sessions.get(sessionId); if (session != null) { String returnMessage = session.connectUser(userName, password); @@ -117,10 +117,10 @@ public class SessionManager { return false; } - public boolean setUserData(String userName, String sessionId, UserData userData, String clientVersion) throws MageException { + public boolean setUserData(String userName, String sessionId, UserData userData, String clientVersion, String userIdStr) throws MageException { Session session = sessions.get(sessionId); if (session != null) { - session.setUserData(userName, userData, clientVersion); + session.setUserData(userName, userData, clientVersion, userIdStr); return true; } return false; @@ -217,7 +217,7 @@ public class SessionManager { if (session != null) { return UserManager.getInstance().getUser(sessions.get(sessionId).getUserId()); } - logger.error(String.format("Session %s could not be found",sessionId)); + logger.error(String.format("Session %s could not be found", sessionId)); return Optional.empty(); } diff --git a/Mage.Server/src/main/java/mage/server/User.java b/Mage.Server/src/main/java/mage/server/User.java index c4411ff94f..94ee9b84c3 100644 --- a/Mage.Server/src/main/java/mage/server/User.java +++ b/Mage.Server/src/main/java/mage/server/User.java @@ -96,6 +96,7 @@ public class User { private Date lockedUntil; private final AuthorizedUser authorizedUser; private String clientVersion; + private String userIdStr; public User(String userName, String host, AuthorizedUser authorizedUser) { this.userId = UUID.randomUUID(); @@ -127,6 +128,7 @@ public class User { this.tablesToDelete = new ArrayList<>(); this.sessionId = ""; this.clientVersion = ""; + this.userIdStr = ""; } public String getName() { @@ -178,6 +180,14 @@ public class User { this.clientVersion = clientVersion; } + public void setUserIdStr(String userIdStr) { + this.userIdStr = userIdStr; + } + + public String getUserIdStr() { + return this.userIdStr; + } + public String getClientVersion() { return clientVersion; } @@ -199,7 +209,7 @@ public class User { public void lostConnection() { // Because watched games don't get restored after reconnection call stop watching - for (Iterator iterator = watchedGames.iterator(); iterator.hasNext(); ) { + for (Iterator iterator = watchedGames.iterator(); iterator.hasNext();) { UUID gameId = iterator.next(); GameManager.getInstance().stopWatching(gameId, userId); iterator.remove(); @@ -781,7 +791,7 @@ public class User { } return number; } - + public String getEmail() { if (authorizedUser != null) { return authorizedUser.email; diff --git a/Mage.Sets/src/mage/cards/t/TrueConviction.java b/Mage.Sets/src/mage/cards/t/TrueConviction.java index e73a96b93a..9e3e4051f4 100644 --- a/Mage.Sets/src/mage/cards/t/TrueConviction.java +++ b/Mage.Sets/src/mage/cards/t/TrueConviction.java @@ -25,19 +25,19 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.cards.t; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Duration; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; @@ -47,14 +47,18 @@ import mage.filter.common.FilterCreaturePermanent; */ public class TrueConviction extends CardImpl { - public TrueConviction (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}{W}{W}"); + public TrueConviction(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{W}{W}"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, new FilterCreaturePermanent()))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, new FilterCreaturePermanent()))); + // Creatures you control have double strike and lifelink. + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, new FilterCreaturePermanent())); + Effect effect = new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, new FilterCreaturePermanent()); + effect.setText(" and lifelink"); + ability.addEffect(effect); + this.addAbility(ability); } - public TrueConviction (final TrueConviction card) { + public TrueConviction(final TrueConviction card) { super(card); } diff --git a/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java b/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java index baf3c52bd1..fd9ba8fc68 100644 --- a/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java +++ b/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java @@ -7,14 +7,15 @@ package mage.sets; import java.util.ArrayList; import java.util.List; +import mage.cards.CardGraphicInfo; import mage.cards.ExpansionSet; +import mage.cards.FrameStyle; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.cards.w.Wastes; -import mage.constants.SetType; import mage.constants.Rarity; -import mage.cards.CardGraphicInfo; +import mage.constants.SetType; /** * @@ -218,8 +219,8 @@ public class OathOfTheGatewatch extends ExpansionSet { cards.add(new SetCardInfo("Wandering Fumarole", 182, Rarity.RARE, mage.cards.w.WanderingFumarole.class)); cards.add(new SetCardInfo("Warden of Geometries", 11, Rarity.COMMON, mage.cards.w.WardenOfGeometries.class)); cards.add(new SetCardInfo("Warping Wail", 12, Rarity.UNCOMMON, mage.cards.w.WarpingWail.class)); - cards.add(new SetCardInfo("Wastes", 183, Rarity.COMMON, Wastes.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Wastes", 184, Rarity.COMMON, Wastes.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Wastes", 183, Rarity.COMMON, Wastes.class, new CardGraphicInfo(FrameStyle.BFZ_FULL_ART_BASIC, true))); + cards.add(new SetCardInfo("Wastes", 184, Rarity.COMMON, Wastes.class, new CardGraphicInfo(FrameStyle.BFZ_FULL_ART_BASIC, true))); cards.add(new SetCardInfo("Weapons Trainer", 160, Rarity.UNCOMMON, mage.cards.w.WeaponsTrainer.class)); cards.add(new SetCardInfo("Witness the End", 82, Rarity.COMMON, mage.cards.w.WitnessTheEnd.class)); cards.add(new SetCardInfo("World Breaker", 126, Rarity.MYTHIC, mage.cards.w.WorldBreaker.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameTest.java index 12794c9280..e5f4ba40a6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameTest.java @@ -47,6 +47,7 @@ public class PlayerLeftGameTest extends CardTestMultiPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { + // Start Life = 2 Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 2); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); @@ -197,4 +198,35 @@ public class PlayerLeftGameTest extends CardTestMultiPlayerBase { assertGraveyardCount(playerB, "Silvercoat Lion", 1); } + /** + * Situation: I attacked an opponent with some creatures with True + * Conviction in play. There were multiple "deals combat damage to a + * player"-triggers (Edric, Spymaster of Trest, Daxos of Meletis et al), + * then the opponent lost the game during the first strike combat + * damage-step . In the second combat damage step the triggers went on the + * stack again, although there was no player being dealt damage (multiplayer + * game, so the game wasn't over yet). I don't think these abilities should + * trigger again here. + */ + @Test + public void TestPlayerDiesDuringFirstStrikeDamageStep() { + // Creatures you control have double strike and lifelink. + addCard(Zone.BATTLEFIELD, playerD, "True Conviction"); + // Whenever a creature deals combat damage to one of your opponents, its controller may draw a card. + addCard(Zone.BATTLEFIELD, playerD, "Edric, Spymaster of Trest"); + addCard(Zone.BATTLEFIELD, playerD, "Dross Crocodile", 8); // Creature 5/1 + + attack(2, playerD, "Dross Crocodile", playerC); + + setStopAt(3, PhaseStep.END_TURN); + execute(); + + assertLife(playerC, -3); + assertLife(playerD, 7); + + assertHandCount(playerD, 2); // 1 (normal draw) + 1 from True Convition + assertPermanentCount(playerC, 0); + + } + } diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 0662049895..9bac098b3f 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -60,7 +60,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 50; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 69; + private static final long CARD_CONTENT_VERSION = 70; private final TreeSet landTypes = new TreeSet(); private Dao cardDao; private Set classNames; 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); + } +} diff --git a/Mage/src/main/java/mage/game/combat/CombatGroup.java b/Mage/src/main/java/mage/game/combat/CombatGroup.java index b18d6f7610..c0fca4fbb1 100644 --- a/Mage/src/main/java/mage/game/combat/CombatGroup.java +++ b/Mage/src/main/java/mage/game/combat/CombatGroup.java @@ -399,7 +399,9 @@ public class CombatGroup implements Serializable, Copyable { } } else { Player defender = game.getPlayer(defenderId); - defender.damage(amount, attacker.getId(), game, true, true); + if (defender.isInGame()) { + defender.damage(amount, attacker.getId(), game, true, true); + } } } diff --git a/Mage/src/main/java/mage/players/net/UserData.java b/Mage/src/main/java/mage/players/net/UserData.java index b5d52c9d0a..b6bb290d8f 100644 --- a/Mage/src/main/java/mage/players/net/UserData.java +++ b/Mage/src/main/java/mage/players/net/UserData.java @@ -23,6 +23,7 @@ public class UserData implements Serializable { protected boolean passPriorityActivation; protected boolean autoOrderTrigger; protected boolean useFirstManaAbility = false; + private String userIdStr; protected String matchHistory; protected int matchQuitRatio; @@ -36,7 +37,7 @@ public class UserData implements Serializable { public UserData(UserGroup userGroup, int avatarId, boolean showAbilityPickerForced, boolean allowRequestShowHandCards, boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps, String flagName, boolean askMoveToGraveOrder, boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted, - boolean passPriorityCast, boolean passPriorityActivation, boolean autoOrderTrigger, boolean useFirstManaAbility) { + boolean passPriorityCast, boolean passPriorityActivation, boolean autoOrderTrigger, boolean useFirstManaAbility, String userIdStr) { this.groupId = userGroup.getGroupId(); this.avatarId = avatarId; this.showAbilityPickerForced = showAbilityPickerForced; @@ -55,6 +56,7 @@ public class UserData implements Serializable { this.matchQuitRatio = 0; this.tourneyHistory = ""; this.tourneyQuitRatio = 0; + this.userIdStr = userIdStr; } public void update(UserData userData) { @@ -72,11 +74,12 @@ public class UserData implements Serializable { this.passPriorityActivation = userData.passPriorityActivation; this.autoOrderTrigger = userData.autoOrderTrigger; this.useFirstManaAbility = userData.useFirstManaAbility; + this.userIdStr = userData.userIdStr; // todo: why we don't copy user stats here? } public static UserData getDefaultUserDataView() { - return new UserData(UserGroup.DEFAULT, 0, false, false, true, null, getDefaultFlagName(), false, true, true, false, false, false, false); + return new UserData(UserGroup.DEFAULT, 0, false, false, true, null, getDefaultFlagName(), false, true, true, false, false, false, false, ""); } public void setGroupId(int groupId) {