From 6ae4ac3c5e93ee4b2a1eb7be391fe87bc4081446 Mon Sep 17 00:00:00 2001
From: BetaSteward <betasteward@gmail>
Date: Sun, 26 Dec 2010 00:34:34 -0500
Subject: [PATCH] changes to support matches

---
 .../mage/client/dialog/NewTableDialog.java    |  19 ++--
 .../main/java/mage/client/remote/Session.java |   8 +-
 .../java/mage/client/table/TablesPanel.java   |  24 ++--
 Mage.Common/src/mage/interfaces/Server.java   |   8 +-
 Mage.Common/src/mage/view/GameTypeView.java   |   4 +-
 .../src/mage/game/FreeForAll.java             |   3 +-
 .../src/mage/game/FreeForAllMatch.java        |  51 +++++++++
 .../src/mage/game/FreeForAllType.java         |  13 ++-
 .../src/mage/game/TwoPlayerDuel.java          |   5 +-
 .../src/mage/game/TwoPlayerDuelType.java      |  13 ++-
 .../src/mage/game/TwoPlayerMatch.java         |  51 +++++++++
 Mage.Server/config/config.xml                 |   4 +-
 Mage.Server/plugins/mage-deck-constructed.jar | Bin 3164 -> 3165 bytes
 Mage.Server/plugins/mage-deck-limited.jar     | Bin 2389 -> 2391 bytes
 Mage.Server/plugins/mage-game-freeforall.jar  | Bin 4366 -> 5303 bytes
 .../plugins/mage-game-twoplayerduel.jar       | Bin 3932 -> 4838 bytes
 Mage.Server/plugins/mage-player-ai.jar        | Bin 28910 -> 28914 bytes
 Mage.Server/plugins/mage-player-aiminimax.jar | Bin 36468 -> 36468 bytes
 Mage.Server/plugins/mage-player-human.jar     | Bin 11204 -> 11206 bytes
 .../src/main/java/mage/server/Main.java       |   6 +-
 .../src/main/java/mage/server/ServerImpl.java |  10 +-
 .../java/mage/server/game/GameFactory.java    |  32 +++---
 .../main/java/mage/server/game/GamesRoom.java |   4 +-
 .../java/mage/server/game/GamesRoomImpl.java  |   6 +-
 .../mage/server/game/TableController.java     |  71 +++++++-----
 .../java/mage/server/game/TableManager.java   |  10 +-
 .../java/org/mage/test/base/MageBase.java     |  17 ++-
 Mage/src/mage/game/Game.java                  |   3 +-
 Mage/src/mage/game/GameImpl.java              |  17 ++-
 Mage/src/mage/game/{ => match}/Match.java     |  13 ++-
 Mage/src/mage/game/{ => match}/MatchImpl.java |  53 ++++++---
 Mage/src/mage/game/match/MatchOptions.java    | 104 ++++++++++++++++++
 .../mage/game/{ => match}/MatchPlayer.java    |   2 +-
 .../{GameType.java => match/MatchType.java}   |  20 +++-
 34 files changed, 443 insertions(+), 128 deletions(-)
 create mode 100644 Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java
 create mode 100644 Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java
 rename Mage/src/mage/game/{ => match}/Match.java (87%)
 rename Mage/src/mage/game/{ => match}/MatchImpl.java (66%)
 create mode 100644 Mage/src/mage/game/match/MatchOptions.java
 rename Mage/src/mage/game/{ => match}/MatchPlayer.java (98%)
 rename Mage/src/mage/game/{GameType.java => match/MatchType.java} (80%)

diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java
index b18a86b854..09d9c8f9e5 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java
@@ -53,6 +53,7 @@ import mage.client.remote.Session;
 import mage.client.table.TablePlayerPanel;
 import mage.client.util.Event;
 import mage.client.util.Listener;
+import mage.game.match.MatchOptions;
 import mage.sets.Sets;
 import mage.util.Logging;
 import mage.view.GameTypeView;
@@ -277,18 +278,16 @@ public class NewTableDialog extends MageDialog {
 
 	private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed
 		GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem();
-		List<String> playerTypes = new ArrayList<String>();
-		playerTypes.add("Human");
+		MatchOptions options = new MatchOptions("Quick Start Game", gameType.getName());
+		options.getPlayerTypes().add("Human");
 		for (TablePlayerPanel player: players) {
-			playerTypes.add(player.getPlayerType());
+			options.getPlayerTypes().add(player.getPlayerType());
 		}
-		table = session.createTable(
-				roomId,
-				gameType.getName(),
-				(String)this.cbDeckType.getSelectedItem(),
-				playerTypes,
-				(MultiplayerAttackOption)this.cbAttackOption.getSelectedItem(), 
-				(RangeOfInfluence)this.cbRange.getSelectedItem());
+		options.setDeckType((String) this.cbDeckType.getSelectedItem());
+		options.setAttackOption((MultiplayerAttackOption) this.cbAttackOption.getSelectedItem());
+		options.setRange((RangeOfInfluence) this.cbRange.getSelectedItem());
+		options.setWinsNeeded(1);
+		table = session.createTable(roomId, options);
 		try {
 			if (session.joinTable(roomId, table.getTableId(), this.player1Panel.getPlayerName(), Sets.loadDeck(this.player1Panel.getDeckFile()))) {
 				for (TablePlayerPanel player: players) {
diff --git a/Mage.Client/src/main/java/mage/client/remote/Session.java b/Mage.Client/src/main/java/mage/client/remote/Session.java
index af7841411d..1093013070 100644
--- a/Mage.Client/src/main/java/mage/client/remote/Session.java
+++ b/Mage.Client/src/main/java/mage/client/remote/Session.java
@@ -49,7 +49,9 @@ import mage.client.components.MageUI;
 import mage.client.game.GamePanel;
 import mage.client.util.Config;
 import mage.game.GameException;
+import mage.game.match.MatchType;
 import mage.interfaces.MageException;
+import mage.game.match.MatchOptions;
 import mage.interfaces.Server;
 import mage.interfaces.ServerState;
 import mage.interfaces.callback.CallbackClientDaemon;
@@ -396,9 +398,9 @@ public class Session {
 		return false;
 	}
 
-	public TableView createTable(UUID roomId, String gameType, String deckType, List<String> playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) {
+	public TableView createTable(UUID roomId, MatchOptions matchOptions) {
 		try {
-			return server.createTable(sessionId, roomId, gameType, deckType, playerTypes, attackOption, range);
+			return server.createTable(sessionId, roomId, matchOptions);
 		} catch (RemoteException ex) {
 			handleRemoteException(ex);
 		} catch (MageException ex) {
@@ -456,7 +458,7 @@ public class Session {
 
 	public boolean startGame(UUID roomId, UUID tableId) {
 		try {
-			server.startGame(sessionId, roomId, tableId);
+			server.startMatch(sessionId, roomId, tableId);
 			return true;
 		} catch (RemoteException ex) {
 			handleRemoteException(ex);
diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java
index 94f01af53e..929c0facab 100644
--- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java
+++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java
@@ -37,9 +37,7 @@ package mage.client.table;
 import java.awt.Color;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Observable;
 import java.util.Observer;
@@ -53,8 +51,9 @@ import javax.swing.JComponent;
 import javax.swing.JOptionPane;
 import javax.swing.Timer;
 import javax.swing.table.AbstractTableModel;
+import mage.Constants.MultiplayerAttackOption;
+import mage.Constants.RangeOfInfluence;
 
-import mage.cards.decks.DeckCardLists;
 import mage.client.MageFrame;
 import mage.client.components.MageComponents;
 import mage.client.dialog.JoinTableDialog;
@@ -63,6 +62,7 @@ import mage.client.dialog.TableWaitingDialog;
 import mage.client.remote.MageRemoteException;
 import mage.client.remote.Session;
 import mage.client.util.ButtonColumn;
+import mage.game.match.MatchOptions;
 import mage.sets.Sets;
 import mage.util.Logging;
 import mage.view.TableView;
@@ -280,16 +280,14 @@ public class TablesPanel extends javax.swing.JPanel implements Observer {
 	private void btnQuickStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnQuickStartActionPerformed
 		TableView table;
 		try {
-			List<String> playerTypes = new ArrayList<String>();
-			playerTypes.add("Human");
-			playerTypes.add("Computer - default");
-			table = session.createTable(
-					roomId,
-					"Two Player Duel",
-					"Constructed",
-					playerTypes,
-					null, null
-			);
+			MatchOptions options = new MatchOptions("1", "Two Player Duel");
+			options.getPlayerTypes().add("Human");
+			options.getPlayerTypes().add("Computer - default");
+			options.setDeckType("Limited");
+			options.setAttackOption(MultiplayerAttackOption.LEFT);
+			options.setRange(RangeOfInfluence.ALL);
+			options.setWinsNeeded(1);
+			table = session.createTable(roomId,	options);
 			session.joinTable(
 					roomId,
 					table.getTableId(),
diff --git a/Mage.Common/src/mage/interfaces/Server.java b/Mage.Common/src/mage/interfaces/Server.java
index 5ce8de4b8a..18ba540d47 100644
--- a/Mage.Common/src/mage/interfaces/Server.java
+++ b/Mage.Common/src/mage/interfaces/Server.java
@@ -28,16 +28,14 @@
 
 package mage.interfaces;
 
+import mage.game.match.MatchOptions;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
 import java.util.List;
 import java.util.UUID;
-import mage.Constants.MultiplayerAttackOption;
-import mage.Constants.RangeOfInfluence;
 import mage.cards.decks.DeckCardLists;
 import mage.game.GameException;
 import mage.interfaces.callback.CallbackServer;
-import mage.view.GameTypeView;
 import mage.view.TableView;
 import mage.view.GameView;
 
@@ -54,7 +52,7 @@ public interface Server extends Remote, CallbackServer {
 	public ServerState getServerState() throws RemoteException, MageException;
 
 	//table methods
-	public TableView createTable(UUID sessionId, UUID roomId, String gameType, String deckType, List<String> playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) throws RemoteException, MageException;
+	public TableView createTable(UUID sessionId, UUID roomId, MatchOptions matchOptions) throws RemoteException, MageException;
 	public boolean joinTable(UUID sessionId, UUID roomId, UUID tableId, String name, DeckCardLists deckList) throws RemoteException, MageException, GameException;
 	public boolean watchTable(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException;
 	public boolean replayTable(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException;
@@ -77,7 +75,7 @@ public interface Server extends Remote, CallbackServer {
 	public UUID getMainRoomId() throws RemoteException, MageException;
 
 	//game methods
-	public void startGame(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException;
+	public void startMatch(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException;
 	public void joinGame(UUID gameId, UUID sessionId) throws RemoteException, MageException;
 	public void watchGame(UUID gameId, UUID sessionId) throws RemoteException, MageException;
 	public void stopWatching(UUID gameId, UUID sessionId) throws RemoteException, MageException;
diff --git a/Mage.Common/src/mage/view/GameTypeView.java b/Mage.Common/src/mage/view/GameTypeView.java
index 97426e47f9..310e405727 100644
--- a/Mage.Common/src/mage/view/GameTypeView.java
+++ b/Mage.Common/src/mage/view/GameTypeView.java
@@ -29,7 +29,7 @@
 package mage.view;
 
 import java.io.Serializable;
-import mage.game.GameType;
+import mage.game.match.MatchType;
 
 /**
  *
@@ -45,7 +45,7 @@ public class GameTypeView implements Serializable {
 	private boolean useRange;
 	private boolean useAttackOption;
 
-	public GameTypeView(GameType gameType) {
+	public GameTypeView(MatchType gameType) {
 		this.name = gameType.getName();
 		this.minPlayers = gameType.getMinPlayers();
 		this.maxPlayers = gameType.getMaxPlayers();
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 478dcb5b93..97c25e4c5f 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
@@ -28,6 +28,7 @@
 
 package mage.game;
 
+import mage.game.match.MatchType;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -59,7 +60,7 @@ public class FreeForAll extends GameImpl<FreeForAll> {
 	}
 
 	@Override
-	public GameType getGameType() {
+	public MatchType getGameType() {
 		return new FreeForAllType();
 	}
 
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
new file mode 100644
index 0000000000..613fcf6af7
--- /dev/null
+++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java
@@ -0,0 +1,51 @@
+/*
+ *  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 BetaSteward_at_googlemail.com
+ */
+public class FreeForAllMatch extends MatchImpl<FreeForAll> {
+
+	public FreeForAllMatch(MatchOptions options) {
+		super(options);
+	}
+
+	@Override
+	public void startGame() throws GameException {
+		FreeForAll game = new FreeForAll(options.getAttackOption(), options.getRange());
+		initGame(game);
+		games.add(game);
+	}
+
+}
diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllType.java b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllType.java
index ee24d0675a..a7fabda172 100644
--- a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllType.java
+++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllType.java
@@ -28,11 +28,13 @@
 
 package mage.game;
 
+import mage.game.match.MatchType;
+
 /**
  *
  * @author BetaSteward_at_googlemail.com
  */
-public class FreeForAllType extends GameType {
+public class FreeForAllType extends MatchType<FreeForAllType> {
 
 	public FreeForAllType() {
 		this.name = "Free For All";
@@ -42,4 +44,13 @@ public class FreeForAllType extends GameType {
 		this.useAttackOption = true;
 		this.useRange = true;
 	}
+
+	protected FreeForAllType(final FreeForAllType matchType) {
+		super(matchType);
+	}
+
+	@Override
+	public FreeForAllType copy() {
+		return new FreeForAllType(this);
+	}
 }
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 fe3b9d76fe..7c53f6eab1 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
@@ -28,6 +28,7 @@
 
 package mage.game;
 
+import mage.game.match.MatchType;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.UUID;
@@ -39,7 +40,7 @@ import mage.game.turn.TurnMod;
 public class TwoPlayerDuel extends GameImpl<TwoPlayerDuel> {
 
 	public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range) {
-		super(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL);
+		super(attackOption, range);
 	}
 
 	public TwoPlayerDuel(final TwoPlayerDuel game) {
@@ -47,7 +48,7 @@ public class TwoPlayerDuel extends GameImpl<TwoPlayerDuel> {
 	}
 
 	@Override
-	public GameType getGameType() {
+	public MatchType getGameType() {
 		return new TwoPlayerDuelType();
 	}
 
diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuelType.java b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuelType.java
index c25aaa8dc2..c15c12f1e4 100644
--- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuelType.java
+++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuelType.java
@@ -28,11 +28,13 @@
 
 package mage.game;
 
+import mage.game.match.MatchType;
+
 /**
  *
  * @author BetaSteward_at_googlemail.com
  */
-public class TwoPlayerDuelType extends GameType {
+public class TwoPlayerDuelType extends MatchType<TwoPlayerDuelType> {
 
 	public TwoPlayerDuelType() {
 		this.name = "Two Player Duel";
@@ -43,4 +45,13 @@ public class TwoPlayerDuelType extends GameType {
 		this.useRange = false;
 	}
 
+	protected TwoPlayerDuelType(final TwoPlayerDuelType matchType) {
+		super(matchType);
+	}
+
+	@Override
+	public TwoPlayerDuelType copy() {
+		return new TwoPlayerDuelType(this);
+	}
+
 }
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
new file mode 100644
index 0000000000..c3f7723146
--- /dev/null
+++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java
@@ -0,0 +1,51 @@
+/*
+ *  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 BetaSteward_at_googlemail.com
+ */
+public class TwoPlayerMatch extends MatchImpl<TwoPlayerDuel> {
+
+	public TwoPlayerMatch(MatchOptions options) {
+		super(options);
+	}
+
+	@Override
+	public void startGame() throws GameException {
+		TwoPlayerDuel game = new TwoPlayerDuel(options.getAttackOption(), options.getRange());
+		initGame(game);
+		games.add(game);
+	}
+	
+}
diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml
index 9733c9db7e..df6998b9b9 100644
--- a/Mage.Server/config/config.xml
+++ b/Mage.Server/config/config.xml
@@ -9,8 +9,8 @@
 		<playerType name="Computer - minimax hybrid" jar="mage-player-aiminimax.jar" className="mage.player.ai.ComputerPlayer3"/>
 	</playerTypes>
 	<gameTypes>
-		<gameType name="Two Player Duel" jar="mage-game-twoplayerduel.jar" className="mage.game.TwoPlayerDuel" typeName="mage.game.TwoPlayerDuelType"/>
-		<gameType name="Free For All" jar="mage-game-freeforall.jar" className="mage.game.FreeForAll" typeName="mage.game.FreeForAllType"/>
+		<gameType name="Two Player Duel" jar="mage-game-twoplayerduel.jar" className="mage.game.TwoPlayerMatch" typeName="mage.game.TwoPlayerDuelType"/>
+		<gameType name="Free For All" jar="mage-game-freeforall.jar" className="mage.game.FreeForAllMatch" typeName="mage.game.FreeForAllType"/>
 	</gameTypes>
 	<deckTypes>
 		<deckType name="Constructed" jar="mage-deck-constructed.jar" className="mage.deck.Constructed"/>
diff --git a/Mage.Server/plugins/mage-deck-constructed.jar b/Mage.Server/plugins/mage-deck-constructed.jar
index cdcc7affaa240bc8c3af37058da4f7cf4db3501c..5ce9f4b46939206ea0c790644abc405b5a2e886e 100644
GIT binary patch
delta 869
zcmca3aaV#jz?+$civa|Bx6Yi%tHRs^q)etTgLtPEz|=cc5Vcv1aUKhZF?l<y7MOm*
zY7C~O*gSbfwoJ8^GIsF$%E-X*W^w_WcYVrTiG!a{pGvrp)4Vo0-*s|+%+_rwDwdv-
zf8S45J$hen;RN>AFJ8#qom?!cGF61%p|nDad!60dcU#wOlbHU5L1tptg=z<<XFraA
zm)+-N*cINl(^m7^rvBr~R{J*Z@s(NsasJ)2{>2+q1Rr||`z4CDEVSGhDz;B>N`~4G
z)}n_(^@o`*K76IOulu5B>gp>VGvX!GmY!JfgEvUB^GcZK2ZrpKq7x64W{HcPSh`~M
z`p7Ji0M8<i50Wn}T(Y*Qhe&T&=n}*+_krB4K>j!bxAzyV4z~N<&v~@3%0O>#wpToJ
zZI2yy@}e~>+j6v$qZah5q}%w*cjRQvo1Qm&vQW<24J+$K`Lb^AebB3%7QlGEA((B|
zbw_Ud(gz1tZvS7?G{Jpdy3OqDynCA(b7OP+ZTf9W?E2o{aLzH_cX+?4_OJRrp{+{_
z&MpxY_@o&+Nv(pX?8~YZz3a0|LfiQcdQPgziEXQ$%Q}4-XLgdGYve|zlqY=p(dHZS
zlNaruS-3_u=-_vq`t?g?kG-rrzqF*+ZqC_Ag)F7w3w<y4FYo%n>M49r(s;V;yd5eB
zV*_H-F00<1&C$7L=Ca%I@r(L7^RBPY)s=8wW&U66zOi3d{@ILM*HyFUG2D{B-S^<~
zJ+|BXIf6nGq}W?8A2_i?(5v}BECq3ZQjo25`mXK8z|_Q8K6yKbb3O0bja<zJ0u2vs
z3*Hwz$mwv8VObvL#jgIF>3Rik(5xxOT(!T`{<i(k&zt13^F-Hq`Exa1OqX?HK4>wn
zbYFDvccYEpY37rqd}lOw<y-ci`?if)*i`=hZ>zN4Z-)a9Y?$`;=)#aW+FMM&=IL9$
zb?pxbPxu$$&B!Fe3`x`A^jX7c0!r1BH*?y9`CmB=z_bRJDVR>+as$&VxvaqSGcIQ^
rt-~FOmaZpphbbU?vK;798&KYXf+dX$IVSJnu$%10Bfyr&2@(YWE!TH~

delta 867
zcmcaBaYuqTz?+$civa{|Ha1V>RbjRUQYKTFLA=unVCtPJh}ta1IFALyn7o};3rs&@
zH3rjCY@WOo%bRUa$bLHUg^_{b)#L&;@A_qTH4c70eQLploaVKu`L2`mW43NfQL*%t
z{QG{g>e2ghi4)jgzjz^ccXF|)%2bi_4y6@3-0SSt&fBuiOk#Qpzs$t03+fI|&wl*g
zuDj34uq(W8r=`}lP5kZ5Rxwfctormntbco#zj%X+;A1agzeLfNg_auw#r6qL$x!<t
zS@ck-{xH+Uf3FPddM*a0uD;?iBVIyn>4^mu3@dwFvR129G;BT7<?+C3D>wI(pet8%
zr%ADfOp+0*akAo@IO{FPRkj?Bi6TzwJKD>x>=p01*v|6ax^#2v?^_3VeAuR0!~8|{
zmrhUXre#u_R(51I?3*y>qfM>arj?aZyK?=!Hf%k#EX<;QMe6sa^1d04tTxPkk}K~0
zjsCHfncZ&h|Hq%3Z9bVjz7bRWxsBK7byoG0+$Re^7uFn?OPc*r_TRe5i~qBytWa&0
zR_kq;uzuwvlY_|{7Kgj$)`TuzZB@eISM<dBwa}Z_Iy+3xh6@*Io$3-*P%f{yxvQ}@
zTlmk{o@CvLT>FwMb?e`1_<gU|TPptI@yR)?i`0zR-*)_~Ue)nmG4qgh^0Q5cg{Q0R
z;9m7P$7*@Cu;N71%O(FmdzZ|8Q1*BKTGnKbug~s3vOebdajT^7?`<h(g&lq;-xjR7
zbvxm=xMLTW&*KFJQWBEpPMIIXVF`!>lz?paMV_5q3`|U=lXq}9*9VvRpY_)D((&{S
z^jH=0!B@xo?Bl0FW!k4g3Os$o3=F~yj5Zl<*kWWFSis8{XkcVu^5ChKx31Q?Gv_y(
zUNC<8)Jy-AzU~K~jc4_}uAlbx@dt|NXr1)&_R(YH`o+Xr(#V$j+Uogp(di;n)tGf3
zJ!N7D@MdHZVTPn=aO$k(Gy$dQ$y+$>!TfKW24Gr~%M?r}a=C%&Ra{nJ`Z<>~nAYWv
mL`&6^xx*At{0Pc4pqv8*OBxq&Oy0|3H`$#>fGw93BnkkyMs%eB

diff --git a/Mage.Server/plugins/mage-deck-limited.jar b/Mage.Server/plugins/mage-deck-limited.jar
index 8e20dbdb8ac636efff605c76d71c47303fc7b641..57ea157b7a8aed85523de920e5a0d7a6634c18b3 100644
GIT binary patch
delta 961
zcmcaAbX|xyz?+$civa|Bx6Yi%tHRr}b*8QQ^<PY>K%wf1b{VREGc7Fz>blm2dzqam
zFt%;3P<D>fi_>F3)p<sN8DzkFRS>mVoN*^3h%xyxlNN}c#B2=anlZZyN^Y5ID?2+U
z@e?Bh!vj_Z2E)mG%+iw&a7fnA4e{;1Z6IQEegC1BI9<z^+onADwMB%>Gx`PlUforH
z9$j6hE9vRCY0BUCQ&o@Nk2}=Fe=XySTfWVC#~{y-3?c2$H$8ZD`BmKOtnNb3z5{|Q
zIrg%vr1b5tzx`NRWO2pQ8Mikl>HaRUT6o#|^z9=brT*W1UpJ#!wNoN|Rsq*)1)ln|
zoohFJ@C#Tp^FjEDR&O3|m*cZ{|Il+wpSm_kIdPtWkJm)UkJ3wwgjTMd^nmf2k+xFf
z>nnOX6TAb%<2PN=STO0yga_Q03Ola6aaduN;M}=H!0Mpwmc?>=6MF6~E^X?cyYJ?a
z+OG*QRrjatWBn!ZHsYj7N-$?}?Jtj_W1qh?o~U1TFZJa%OU;AVIA>cWMjwB4P}=>}
z0;YM4%XvcHKhynlrIES)-oMW$9px(Leau?7vT`+BS?N~WPd1;<{WRZ~%)jyM55E7`
z*1V_}QO)vvIL%X8;Ysi+72gjMZ(f83O8Z}Zv5HT&X)?>t9lPHAvf|eBoqYAk?5<5o
ztS3&$#%;?>xL<$FrOx<qg!hsr`G`1g>z2!Z=Xt-Bs@*YTv%?jaXA5L6?)Mk{$URAI
zhjE&owN0UC)9wYk&MnK{WiBWbY3#YbuCC8cZAa|>ZCev~R^Gc4{pWy%=03B<ng6vS
zjei|YP1)@`|BKm`fBp)ttjjV3EO>ibr01Lb;D;q64hBJBLa{w*e`i-AFzFQou>~|`
zh)w>>svyGWrxRG<=^JKX6l!3!$;fb{kx}4eLpD+7tHw_zyR#|DxTU`SmGUf&Y3;+O
zOu*F1$RxrHPuY`O*-TKA_T*!1rr<RBk4;))AJDek#Pn2sbZv(0(u@x$`?5=dm1Y8Y
zoReGG)xf-UK+*sIk4`?tE(hknW|w67|Nj%yWPWBDUR2u+IY3ex%s?qAU{V*FT*bko
efRPb^j(~wBjRi2ps=O%SGWionEL#N|NFe~lfsKy<

delta 999
zcmcaEbXABqz?+$civa`z<C`b)s_+KHH{1T*(O;bg6snnMm!bAla;c@IK%+?P`YAaR
zUZz#CeQbNSCuUC!1FF{33d|rA-l>A9&0>r@89|K6mzcD`^nWH}Fm1~0DkKuuZ2Ru{
z^OGML85r)dGB6l2Ob+1CsV~US)vL(OnHv(DecM2!c3yoeXZ6-6%kD}X{2VOFGb!&v
z?whq4pL$nco7SVEuDSGo?WQF^ZY%TrNsyJjySTb$UGtJjk2qKG`KKPd`uytRYggGG
zPm*a+4ifyu;c-Hy{{Oba<{EAvPZ^r4AC3C<vBKqe_UY*3A4UJ|y?t+XvudYAefX>b
zuGI=WXFGd0eFzI!H1mP@iB@kOZkP7i?LQRV)TgcuQcj#_;NvyX@gw&VBcYXRCp}=i
zW~8mu`1*>T&IIqk@c7MFG!{&HGU0*orNWLYIsPlm5}Z4i2v{Ao-LhD2PePBK%8v^x
zXY1a%&UdV}-1lMhg7X)rP4#g$6E&E={Jctix{d$*j+|F>r{~R{ER-{M!%E?8r8;tZ
zikI+cJ&-Io<?!|0-9!4a79XDfU45SS(}~+X!NtC3rA-Z1uYNmm`^55d`#;K7cjO)`
z|FJyH_5WmzKyR+?K2nT|@j<GYO~(`5*LU5jSmhR8`a)pNljH4IRj*%<EXbU-TJ28A
z6j5ylw|Dg)HkC5}zNYr!wdC<ACDEGmpQ3IF&UyDe#%ukB<C`tHU3^pcZVCSV9U}PO
z`4UU{u`{Xd>Uy39;vv&-mUw<wb5hDyd-=Ry|Kf6%?XUmm>Pk4TGXE}i-`KBfcbdst
zd(~{W{TBT>+h0z;*LLea=aLl%OnAALH%=^gJejSY5tNi9K*^8;lniZ?cpfgy2l5Jm
z*aDn5CjVqr5h>F?6;j~o8)je-W?-_#XzK<ev!Ka_Y@&=$CwsCf$*`rq{+049jY;?6
zQzl^IWMmRyhNtYw?QABfNqh1MHd9cFoWw3|vL9$qZen_>KAJ9Dpg0^r%mQ%*7~VQQ
zn(WUm2~N@3?9z-}liS(Vz`PCYk}Pi>k1<Vt$Rs@Z0Xr91@GV&IGZQeGOKIb?Lkn&j
p$PUfP{v4L_n7IY6h+#=%AyAF(<SQJ)yeI)T`3pxZTNxWjB>>*#fk6NO

diff --git a/Mage.Server/plugins/mage-game-freeforall.jar b/Mage.Server/plugins/mage-game-freeforall.jar
index 25f863f3dfde0d688e99b3635646e563530c6eb8..170e2d6993bd2e0a4bc64348d9799d1f7696a83a 100644
GIT binary patch
delta 4194
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
G<9`4GO|cRH

delta 3346
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
F=s&R-63YMp

diff --git a/Mage.Server/plugins/mage-game-twoplayerduel.jar b/Mage.Server/plugins/mage-game-twoplayerduel.jar
index 22b21ec61e3cfc6bb084f72f1a1acdad6247ace3..82888f63b1ab46ce292fc87bc305ef52569adc05 100644
GIT binary patch
delta 3734
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
Yofk=B;8$p=C_$8<;PZXw{;$6O4`i{amjD0&

delta 2840
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

diff --git a/Mage.Server/plugins/mage-player-ai.jar b/Mage.Server/plugins/mage-player-ai.jar
index e7b4c9190c35ad34ca822c515cebd7a345ae250c..da0274094b85c257c15a88717a827d99caf1bdd6 100644
GIT binary patch
delta 1068
zcmaF&knz()M&1B#W)?065a``Hb0V(_a}SU*nF6LxD}bqY>dZj7$r6lOVA_?@6hv>X
zWqiaW2xQoL$mPU{urM&hb1*QdOy0;Xy1A9bfCZ#=^A3&|Okl=h?%hmaU5R|r7GTDH
zw+M)cl&1&_Sj5oRo)yd}4)W#zGY&=xK^WJP)-r=cCby+Q9I-jg7|ef}<|L@KWvXq_
z{=@%1FfuUQW@TW|n|v@$dUAY$SpD3P*zPL^BDLH0FXGu}_OfU72?6dV4sPpR3$*v?
z8lElLyv@_&(octP`)8}otP5vb$ba_aN!#!9=9xGJb*6jy)U5JaXTN4%&%|gB?V1HL
z37sc}S)D{b{CmxJuR&yq_W3*WOtNnte=I0--{PK{@AVJQ-@Th{8}YEEFxNo6MD*y!
zdfSax`SuC3NUQx2E&3>QnDOMpXNI*t2R)y!KI3&my)RI;DC*w=ujtM*p^gO&TYWl3
zpQ;sevx|6L`DAu}4bzGON5MS`vh3Q2zs-=~Hk;zYnJDmPq3l-ymf#O!YXogdew7LH
zU0q!GF*f+mz9Z?YCiQO*X1#6uvzPl=_Z!L8%kI>tzT9rPZiTkcZ>7TEBaIie&!1Si
z#Af*%gH_eB+du4NW`DQmpKuT}(<h_Hm+x47Hsf9MDvSL|>XX^u^X??`7anfmtiQVE
zO}&6_mg@`kWosG&p8IGwJ&<_wV$+(n3#+cIa&Ld2Vyn2yZu`P>P2QJ7OfRY}nzUxi
z{d@9p+wv0bA3GLSYy3FETczoJWT19A<MQ9O(>Iw`lpCfuW^B+}@$tw9yU>>Z6Sl0J
zYgl~qVW)T3FSf6xX0gV5dncTjo&Dv*-{Mbl2h0BMU+kK!!LsV`_nya}yo*im%DYas
z&y<m2f+buIP{OrUI52BZJ}?m%0I?}F{)H!>E8v>EK2tp1PbaXz(>Kh(DAd4clab*@
zBcs3qUcNvBBLkBMPqn;twa%S6zuEMH@m1p|PrdX{>Fa***?3mp>-uS5AOELMy>zrr
z`gr^3F>?K4Vl81V64DOtE|ImZ+{qB&&B!Fe49`B3wX#e=seN){mOYqWoMix}uVtBo
zQ>#F>6`1zTb_LT@vpvD|!)$-BI^&!GFx>{EL8<*_jvtuT$_)n74Y@&J`f6?zm^R9b
z2h&sXApDPcF<^c`KE$5hd}lEKa()mmN-mjfRNya<5pJMT01B2g#!g;P;K3%J1rh)N
D*WA%7

delta 1072
zcmezLkn!C^M&1B#W)?065b)gFF_Bk=*#k(KOkqym)iLq30+@QI4x%PYFlvEmS4LA1
zy}6e05tAU0Ve2866C=XHz!1;Dz@RdDBe&>eu^gez(^=$Ln1N<)-of#L3Cvi`y&J+v
z<cqcd8?oOlf(gu!@)ThKGYoz0S;36rAa4#Z<6x8!gmEotEi=fR$!%#`V0v?!F_?at
z<|J6TyxF#-!*s%XMh1qPtPBi#lMkjzPu^c3Twjr!GdJXR)*S<pnsxgR>C|q0l5;so
z>}r5UtHU<lEt<95tJaiGxix9Rlf40--cMCs`<~DH0ROd&l4o;1o)DbmWfPe6C^@v~
zZ|2vGo;wZ^4{e_^c>Bm{3an}<zrX#1)Dnf*%4g43M4q;j;d}7m+{bH~Rjl>-`SmxN
zMg1hMvlTnlhX=~s7M6bdAlh+5VpF_=xW1vxgg5KuFSU!vl<qsVrlt0gM5xm8r~0e5
zOg#}J%EBITdP+oKp3(LKhlMV>`Jc{cHE@ZG95lXExWOo=y>nxNv*#26wu5rF0>3*N
zu)Y_(Q~s)qn{Vsl!k4+hzt$a5Up48x`Q=~R%0G#V_lVyV4y*Uw`T0_QaZF&i$~V_X
z%Q~1Bo6nmV>{;n&nHciDD(_)1JKvtl-})(REKe$rE!|o8%vVa{>Q%lIpHG;-zq{kO
z+@m&5;eRV5Z~m8wy3%z)-zSoBq2J6fmV<^jE~Z9CJAYjf+Rt~;v&<==Hp_V~>-1$a
zvzmNeR3kI@@3r5PbN9f$h^@T8tB!4)=D~7*<D#&4zkI(}>!pT2IDB&s>!O3J790~k
z{5wQ&pF(D^b@H=KhlQt$eC2(0I%ii(m9*kS^Xo7EJ-_}$x#{h%t&3fgHCR?1F7J8#
zDZ1G7?thob4w*7C%&_Fk!2n8$LFx?JIl!cx2gIh(6d*f!L#B8Ndr@rAWKkX+k)EEl
zJi2Rnd_-fKoke<hcz7#zo(k&jGXDHIhxdz5<<3jppS-zkf^$B1U;0`kd^xysr%<<-
z(Pg2@-VIIr92oC5%sF!Eic+k*f1DmefHxzP2s1qQOxDXX0cD@bsaf`*q&s<emI0W)
zm1Pd5MY65HbYQkCn4X#K38tTB`-2m*c}@VB?t;>HbNs;adbz=1x+OOVOyA6n0@G%B
z@nCvJ9)$ljF9xhXB;N{5Pt11))7SHZcu_LQWU~T)1&ja#6#`JOq%kIQ^16H}U=Gq{
Jlg<K(0svi`#V7y(

diff --git a/Mage.Server/plugins/mage-player-aiminimax.jar b/Mage.Server/plugins/mage-player-aiminimax.jar
index d2f5a8333b1dd8f0b52ddee13c94fbdd6bbeb860..c3a0c972fd3080e70c5d5a6ca52546c28e5ee855 100644
GIT binary patch
delta 551
zcmew|hv~~4Cf)#VW)?065a`=Fb0V(_b1#rGnZgX>omK!-@6<umWC=zs5WU%z@evc4
zp~Z5Pi5DnhYyT@smVudpp?@;JvC3uzc420)ycyRS4KRb%SQ8>*Xci<37HJDMWCb&J
zMSS1_Gu9?YKuqOG+r`8OGF3D$X{wMg14FC!WJfO1$?}ctlY00z|H_aN25XS4dCUT4
z{BM{I);W1@GuVNXPc<8ZBsR4yX5s)DWIW?f<K)$CLG=ay3m)WjI9hY?wN85^pm9Tf
z$17776V3D~zrKI%U0+d<vha-XKK_y|#VnybQ$8M3zQwjS_w}x=;(Pe@w=6SSP&UnU
z$qmW7FSw>m-%|T~rT3$+PV*cmKKZcFaQ@448uN{1b)If5S8QvoTktQyn~_O`86K{-
z-~gUn)2;^!-pOm*?LiKl{Jz})Oe=MmgXx1kl9Nk26v6D79iCwNX-6QKw(Nw^y`BDG
z{(UIlxC_E>?Q#Q)pX&+&)5_h!V7js!B7Yi6%l7zz#q)Xs!1Tc$D=_`9#~Dn!^zK0f
I8b@Ca0G|-=tN;K2

delta 551
zcmew|hv~~4Cf)#VW)?065LmWr>O@`@=A}T&WC}BgcUl2Vy;BEKlO-6nK=fu;#z#zG
zh8D|FCSIV3t^KbkSq5eXhW^R?#wwc?*oB$F@@8CTG{6j2V@-&Np;?eDSfnl3kQL0>
z74d-!%vhTo0Wp;$Z5I<C$W+n1q^Ux}3=FN>lO4H4C(AdoPwL^@{3}C77_33E<}nMH
z@xNg<Sm)%q&0q&kKGkdtlGxO;n27^q(6(Lk>?f~o3#y+`Z&6_OBxn~0U#nLkhsZ1b
zn6FYyrkd#@e}Dfv7H(^?G2kKRJ@$%Q7MY>E+K1=57jV40WRWAVu$uRQPSjenX{yhz
zL=~H^2%WI!->;Qth0gdiZdKC!=$veMd48b%{*nz>w%<E0l74IJFXjMmMkWzvc(~ev
z19);xyB;WbC$DX{2RU%^`*s5`t<+%-rVsW=PA=_G1hZ#$c!KGt9f4rlvJ*o0cKU<)
z_n~~_E(pK1%MC1kt}6&kD|ZKj>B?@1{AnmH+v5io&+7>Q(+7L3!1TW!XE5#3y9W_y
H9DO+ee<|<3

diff --git a/Mage.Server/plugins/mage-player-human.jar b/Mage.Server/plugins/mage-player-human.jar
index 37aa8262f09843280fa8ac4f6288081e9856c8dc..2f32a784d2ba60ce304bfa9bc69f0e64506ecfde 100644
GIT binary patch
delta 941
zcmX>Sek`0fz?+$civa}sw$7Z$tHRt1q)etTgLtPEz|=c+5H(qXQ5QsS_F(j60yCyC
ztH^;FyA`K_MJ9)+Xn~bBsu+Xm?JBN<=3A!PI{%P6_?nS{;T9_cgW=?U73s+jRD>ok
z&}Nxzrz%*#Jk@apm!%@hC9$w3*E?ayDt-5=Y)iHNEAVLl;~RN)(jkgZ1^SQY|55ua
zv^1zQeSw-?sOt6iV%5n{*dBMuG$<=^-eneAb$~y9+YdffjmU~;&z3}<wv+3B@#ECT
zYo419*>C$E|Mp;)j^y>W0<Lb2zPFvdWgqq~IAU-xe?s?jiF&>Wxp(s>EoYfqvhT#2
zmfA-aYhC!BmIvJON?GUC#U62biVLIp%xH@R0gI;1|8z!cL6^vcN8FbRJB)JNS8Pmh
zj?_~0>8j3fw`DoVve#|3h`d$p?#}jC7kB*Frui>mlJSbC$9E~!XeCK6*za+$Vxq0^
z)sQ_pf6dfIcUWy)FWhcb&(|MU5yU4{!8ga~!rtB6KkQ`A|N0_I`?{{wjW3_dJ(Rgl
z%%7NkZ~MoyRUO%iU%qZmOZ}gm5va}ee&!}7r@6*!GrEo^xKB^boqJ{R>Z%eBzZg!#
zuQPc|(_&_+t?D!totm=r@4J5=_LMUJzGn97wRYcD7p)(CqFaj&o8NuEbIRKK3$wc|
zja{5W7>@}b{v9It-}%z9uU#`g^ZCaFJ<wl~zxm~~ceyPt_s*Puyq*8_cFnx&|8GZ`
zv^g!XsyS|<X>ZQ_@}Jrz{y+Elv$ji4y4PlPX1|b7&gBJ#ldH8Kv1@eyV}d0y4p0)a
z74m<+y8xKnih<Yyh<ztdRuPA$2fljVGaI>@4Fni2*iNXoC@?$XY|W7;_EtgU4S&p6
z9w*-?Jx%rZ*W_139-r5$bpFHM#0A}Z!)|&AM$Kc;c35+I(=m3N<NOPB*My0m-pF=8
zB6y~gw)(?6@x{VNX7<Wty9!-zT{fe@W5WLWlFd*4?hL&3Kfs%jNrV}m0Ve-fHv#2<
z$z~e%;1pb;VF0FAYnX%Sry90kT2(UuBCqKOrcY`Hf@xVTD=;0U<qW15Xod2k<bcUc
f+Cd7~!T}f*V6dc7M}6`H6)9+t$gzD=2Z;j!5!#u3

delta 929
zcmX>Wek7bXz?+$civa{S?QNaNtHQhyNSRDw2JucSfT?%tAZoG%qb`Wv?7`^C1ZGTO
zR*?fUb}LQ;i%bqt(E=-NR51qA+f`fztClz0UXj#~dBw=UaD$bB!EkcFiuB|O+G3OK
zR0ZqPPd5dK7CCV&(OtvRy<=_9=UG*rIj75hDITdmzVU92+3KvNGLJs~=)Ip3w<tvG
zBg>T|$5%c1bvP-#Cnh;&qHTeT%0g=gC($4OZnNEA#G=Z5K1SX&`)2!LM%jB7_q06o
zKCC}`x4e3TlJ~K#igOMrbtP9Pt(C1&*D&<?p#9{LWqlj-wBNUnKQVN4pQ~@AojBjZ
zPkW;CPvI%sgl4Xu^oa4Ak!s)p-)CZc8dFw0oo=(4YlRZ)k{>-KGK+X_3uWot2$<%@
zG5L|)t-$Y&29Ei`d){ApD<+ra{`k`DWnXGN{T57{|GMkL%9g!$f1SCGb-(FcvFuUh
z%k7pc4_xi6oojKWu)gBUsmVnX4irC_()jM~o>qU^inY$uqju(8II!e;y|Y-L!@pje
z&-;4wuQ|tXFI<1$RQvaQr|zi0A19`W3cQ+<=^AXqX1z-%`}GpJ*sF`33m$oKtn|-W
zVf^@#iNEiPl`B-V-<E%Gf4)}w#`aB)@v#MKRD%v~U$bJW^xl_s=a;@=tKVxq+t}H}
zMKr<2aF4&}N8?Fm>%`B@DX(}miK*VPcCPRBl6+;APib{>bv04@{0n#2WoBQL;A(vJ
zLHF^JKeu?6{GRS%|H0aR#oaWID(P1S|Ghjm_%<K&eYdtleu2&}epu?_0HrS5dosI4
z^MNU?5Qr^+*w=OP6csUGT2QFxJ+qOk*+78dg6)KQi-NF4X5A021<AHF{cX%H;%!nZ
zQfsQuzh=JYk?%YS<;Wkg1`j>sx|00l=A}4fX54zWaCg|@?0-&+vs90I*61AkzUoqt
z1z)CouKbNqX{$+0mU{IjhL5K#{IjM)aJus?gZt(I-i%Bl%<yz?JDEwt7?koSTWHvW
zQ*M=p0hnH^VGgFBYuJKmb<F^Xyrv(RKCKxDrscJ)z;uk3Gniha70Qc}@+Y%s2Pt3+
a1YkIT!IDO8^~n=dq=3O;!1h5MBnAMOft4@-

diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java
index e8425dbc35..9cec754fa9 100644
--- a/Mage.Server/src/main/java/mage/server/Main.java
+++ b/Mage.Server/src/main/java/mage/server/Main.java
@@ -35,7 +35,7 @@ import java.io.FilenameFilter;
 import java.net.InetAddress;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import mage.game.GameType;
+import mage.game.match.MatchType;
 import mage.server.game.DeckValidatorFactory;
 import mage.server.game.GameFactory;
 import mage.server.game.PlayerFactory;
@@ -119,11 +119,11 @@ public class Main {
 		return null;
 	}
 
-	private static GameType loadGameType(GamePlugin plugin) {
+	private static MatchType loadGameType(GamePlugin plugin) {
 		try {
 			classLoader.addURL(new File(pluginFolder + "/" + plugin.getJar()).toURI().toURL());
 			logger.info("Loading game type: " + plugin.getClassName());
-			return (GameType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance();
+			return (MatchType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance();
 		} catch (ClassNotFoundException ex) {
 			logger.log(Level.SEVERE, "Game type not found:" + plugin.getJar() + " - check plugin folder");
 		} catch (Exception ex) {
diff --git a/Mage.Server/src/main/java/mage/server/ServerImpl.java b/Mage.Server/src/main/java/mage/server/ServerImpl.java
index 9585c34595..42093e5511 100644
--- a/Mage.Server/src/main/java/mage/server/ServerImpl.java
+++ b/Mage.Server/src/main/java/mage/server/ServerImpl.java
@@ -43,7 +43,9 @@ import mage.Constants.MultiplayerAttackOption;
 import mage.Constants.RangeOfInfluence;
 import mage.cards.decks.DeckCardLists;
 import mage.game.GameException;
+import mage.game.match.MatchType;
 import mage.interfaces.MageException;
+import mage.game.match.MatchOptions;
 import mage.interfaces.Server;
 import mage.interfaces.ServerState;
 import mage.interfaces.callback.ClientCallback;
@@ -117,9 +119,9 @@ public class ServerImpl extends RemoteServer implements Server {
 	}
 
 	@Override
-	public TableView createTable(UUID sessionId, UUID roomId, String gameType, String deckType, List<String> playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) throws MageException {
+	public TableView createTable(UUID sessionId, UUID roomId, MatchOptions options) throws MageException {
 		try {
-			TableView table = GamesRoomManager.getInstance().getRoom(roomId).createTable(sessionId, gameType, deckType, playerTypes, attackOption, range);
+			TableView table = GamesRoomManager.getInstance().getRoom(roomId).createTable(sessionId, options);
 			logger.info("Table " + table.getTableId() + " created");
 			return table;
 		}
@@ -202,13 +204,13 @@ public class ServerImpl extends RemoteServer implements Server {
 	}
 
 	@Override
-	public void startGame(final UUID sessionId, final UUID roomId, final UUID tableId) throws MageException {
+	public void startMatch(final UUID sessionId, final UUID roomId, final UUID tableId) throws MageException {
 		try {
 			rmiExecutor.execute(
 				new Runnable() {
 					@Override
 					public void run() {
-						TableManager.getInstance().startGame(sessionId, roomId, tableId);
+						TableManager.getInstance().startMatch(sessionId, roomId, tableId);
 					}
 				}
 			);
diff --git a/Mage.Server/src/main/java/mage/server/game/GameFactory.java b/Mage.Server/src/main/java/mage/server/game/GameFactory.java
index 6af3d534bd..e35ee4b9ca 100644
--- a/Mage.Server/src/main/java/mage/server/game/GameFactory.java
+++ b/Mage.Server/src/main/java/mage/server/game/GameFactory.java
@@ -30,17 +30,15 @@ package mage.server.game;
 
 import java.lang.reflect.Constructor;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import mage.Constants.MultiplayerAttackOption;
-import mage.Constants.RangeOfInfluence;
-import mage.game.Game;
+import mage.game.match.Match;
+import mage.game.match.MatchOptions;
 import mage.util.Logging;
-import mage.game.GameType;
+import mage.game.match.MatchType;
 import mage.view.GameTypeView;
 
 /**
@@ -52,8 +50,8 @@ public class GameFactory {
 	private final static GameFactory INSTANCE = new GameFactory();
 	private final static Logger logger = Logging.getLogger(GameFactory.class.getName());
 
-	private Map<String, Class<Game>> games = new HashMap<String, Class<Game>>();
-	private Map<String, GameType> gameTypes = new HashMap<String, GameType>();
+	private Map<String, Class<Match>> games = new HashMap<String, Class<Match>>();
+	private Map<String, MatchType> gameTypes = new HashMap<String, MatchType>();
 	private List<GameTypeView> gameTypeViews = new ArrayList<GameTypeView>();
 
 
@@ -63,31 +61,31 @@ public class GameFactory {
 
 	private GameFactory() {}
 
-	public Game createGame(String gameType, MultiplayerAttackOption attackOption, RangeOfInfluence range) {
+	public Match createMatch(String gameType, MatchOptions options) {
 
-		Game game;
-		Constructor<Game> con;
+		Match match;
+		Constructor<Match> con;
 		try {
-			con = games.get(gameType).getConstructor(new Class[]{MultiplayerAttackOption.class, RangeOfInfluence.class});
-			game = con.newInstance(new Object[] {attackOption, range});
+			con = games.get(gameType).getConstructor(new Class[]{MatchOptions.class});
+			match = con.newInstance(new Object[] {options});
 		} catch (Exception ex) {
 			logger.log(Level.SEVERE, null, ex);
 			return null;
 		}
-		logger.info("Game created: " + game.getId().toString());
+		logger.info("Game created: " + gameType); // + game.getId().toString());
 
-		return game;
+		return match;
 	}
 
 	public List<GameTypeView> getGameTypes() {
 		return gameTypeViews;
 	}
 
-	public void addGameType(String name, GameType gameType, Class game) {
+	public void addGameType(String name, MatchType matchType, Class game) {
 		if (game != null) {
 			this.games.put(name, game);
-			this.gameTypes.put(name, gameType);
-			this.gameTypeViews.add(new GameTypeView(gameType));
+			this.gameTypes.put(name, matchType);
+			this.gameTypeViews.add(new GameTypeView(matchType));
 		}
 	}
 
diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoom.java b/Mage.Server/src/main/java/mage/server/game/GamesRoom.java
index 3e72cdaa06..901a6f12fb 100644
--- a/Mage.Server/src/main/java/mage/server/game/GamesRoom.java
+++ b/Mage.Server/src/main/java/mage/server/game/GamesRoom.java
@@ -34,6 +34,8 @@ import mage.Constants.MultiplayerAttackOption;
 import mage.Constants.RangeOfInfluence;
 import mage.cards.decks.DeckCardLists;
 import mage.game.GameException;
+import mage.game.match.MatchType;
+import mage.game.match.MatchOptions;
 import mage.view.TableView;
 
 /**
@@ -44,7 +46,7 @@ public interface GamesRoom extends Room {
 
 	public List<TableView> getTables();
 	public boolean joinTable(UUID sessionId, UUID tableId, String name, DeckCardLists deckList) throws GameException;
-	public TableView createTable(UUID sessionId, String gameType, String deckType, List<String> playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range);
+	public TableView createTable(UUID sessionId, MatchOptions options);
 	public void removeTable(UUID sessionId, UUID tableId);
 	public TableView getTable(UUID tableId);
 	public void leaveTable(UUID sessionId, UUID tableId);
diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java
index a4fc250fa5..f327c23306 100644
--- a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java
+++ b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java
@@ -39,6 +39,8 @@ import mage.Constants.MultiplayerAttackOption;
 import mage.Constants.RangeOfInfluence;
 import mage.cards.decks.DeckCardLists;
 import mage.game.GameException;
+import mage.game.match.MatchType;
+import mage.game.match.MatchOptions;
 import mage.util.Logging;
 import mage.view.TableView;
 
@@ -71,8 +73,8 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
 	}
 
 	@Override
-	public TableView createTable(UUID sessionId, String gameType, String deckType, List<String> playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) {
-		Table table = TableManager.getInstance().createTable(sessionId, gameType, deckType, playerTypes, attackOption, range);
+	public TableView createTable(UUID sessionId, MatchOptions options) {
+		Table table = TableManager.getInstance().createTable(sessionId, options);
 		tables.put(table.getId(), table);
 		return new TableView(table);
 	}
diff --git a/Mage.Server/src/main/java/mage/server/game/TableController.java b/Mage.Server/src/main/java/mage/server/game/TableController.java
index 31ef031c3b..48da85e1ee 100644
--- a/Mage.Server/src/main/java/mage/server/game/TableController.java
+++ b/Mage.Server/src/main/java/mage/server/game/TableController.java
@@ -55,7 +55,10 @@ import mage.cards.decks.DeckCardLists;
 import mage.game.Game;
 import mage.game.GameException;
 import mage.game.GameStates;
+import mage.game.match.Match;
+import mage.game.match.MatchType;
 import mage.game.Seat;
+import mage.game.match.MatchOptions;
 import mage.players.Player;
 import mage.server.ChatManager;
 import mage.server.Main;
@@ -73,17 +76,19 @@ public class TableController {
 
 	private UUID sessionId;
 	private UUID chatId;
-	private UUID gameId;
+	//private UUID gameId;
 	private Table table;
-	private Game game;
+	private Match match;
+	private MatchOptions options;
 	private ConcurrentHashMap<UUID, UUID> sessionPlayerMap = new ConcurrentHashMap<UUID, UUID>();
 
-	public TableController(UUID sessionId, String gameType, String deckType, List<String> playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) {
+	public TableController(UUID sessionId, MatchOptions options) {
 		this.sessionId = sessionId;
 		chatId = ChatManager.getInstance().createChatSession();
-		game = GameFactory.getInstance().createGame(gameType, attackOption, range);
-		gameId = game.getId();
-		table = new Table(gameType, DeckValidatorFactory.getInstance().createDeckValidator(deckType), playerTypes);
+		this.options = options;
+		match = GameFactory.getInstance().createMatch(options.getGameType(), options);
+		//gameId = game.getId();
+		table = new Table(options.getGameType(), DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes());
 	}
 
 	public synchronized boolean joinTable(UUID sessionId, String name, DeckCardLists deckList) throws GameException {
@@ -100,8 +105,7 @@ public class TableController {
 		}
 		
 		Player player = createPlayer(name, deck, seat.getPlayerType());
-		game.loadCards(deck.getCards(), player.getId());
-		game.loadCards(deck.getSideboard(), player.getId());
+		match.addPlayer(player, deck);
 		table.joinTable(player, seat);
 		logger.info("player joined " + player.getId());
 		//only add human players to sessionPlayerMap
@@ -116,7 +120,7 @@ public class TableController {
 		if (table.getState() != TableState.DUELING) {
 			return false;
 		}
-		SessionManager.getInstance().getSession(sessionId).watchGame(game.getId());
+		SessionManager.getInstance().getSession(sessionId).watchGame(match.getGame().getId());
 		return true;
 	}
 
@@ -141,7 +145,7 @@ public class TableController {
 	}
 
 	private Player createPlayer(String name, Deck deck, String playerType) {
-		Player player = PlayerFactory.getInstance().createPlayer(playerType, name, deck, game.getRangeOfInfluence());
+		Player player = PlayerFactory.getInstance().createPlayer(playerType, name, deck, options.getRange());
 		logger.info("Player created " + player.getId());
 		return player;
 	}
@@ -151,26 +155,43 @@ public class TableController {
 			table.leaveTable(sessionPlayerMap.get(sessionId));
 	}
 
-	public synchronized void startGame(UUID sessionId) {
+	public synchronized void startMatch(UUID sessionId) {
 		if (sessionId.equals(this.sessionId) && table.getState() == TableState.STARTING) {
 			try {
-				table.initGame(game);
+				match.startMatch();
+				startGame();
 			} catch (GameException ex) {
 				logger.log(Level.SEVERE, null, ex);
 			}
-			GameManager.getInstance().createGameSession(game, sessionPlayerMap, table.getId());
-			SessionManager sessionManager = SessionManager.getInstance();
-			for (Entry<UUID, UUID> entry: sessionPlayerMap.entrySet()) {
-				sessionManager.getSession(entry.getKey()).gameStarted(game.getId(), entry.getValue());
-			}
+		}
+	}
+
+	private void startGame() throws GameException {
+		match.startGame();
+		GameManager.getInstance().createGameSession(match.getGame(), sessionPlayerMap, table.getId());
+		SessionManager sessionManager = SessionManager.getInstance();
+		for (Entry<UUID, UUID> entry: sessionPlayerMap.entrySet()) {
+			sessionManager.getSession(entry.getKey()).gameStarted(match.getGame().getId(), entry.getValue());
 		}
 	}
 
 	public void endGame() {
+		match.endGame();
 		table.endGame();
 		saveGame();
-		GameManager.getInstance().removeGame(game.getId());
-		game = null;
+		GameManager.getInstance().removeGame(match.getGame().getId());
+		try {
+			if (!match.isMatchOver()) {
+				startGame();
+			}
+		} catch (GameException ex) {
+			logger.log(Level.SEVERE, null, ex);
+		}
+		endMatch();
+	}
+
+	public void endMatch() {
+		match = null;
 	}
 
 	public void swapSeats(int seatNum1, int seatNum2) {
@@ -188,17 +209,17 @@ public class TableController {
 
 	private void saveGame() {
 		try {
-			OutputStream file = new FileOutputStream("saved/" + game.getId().toString() + ".game");
+			OutputStream file = new FileOutputStream("saved/" + match.getGame().getId().toString() + ".game");
 			OutputStream buffer = new BufferedOutputStream(file);
 			ObjectOutput output = new ObjectOutputStream(new GZIPOutputStream(buffer));
 			try {
-				output.writeObject(game);
-				output.writeObject(game.getGameStates());
+				output.writeObject(match.getGame());
+				output.writeObject(match.getGame().getGameStates());
 			}
 			finally {
 				output.close();
 			}
-			logger.log(Level.INFO, "Saved game:" + game.getId());
+			logger.log(Level.INFO, "Saved game:" + match.getGame().getId());
 		}
 		catch(IOException ex) {
 			logger.log(Level.SEVERE, "Cannot save game.", ex);
@@ -207,7 +228,7 @@ public class TableController {
 
 	private Game loadGame() {
 		try{
-			InputStream file = new FileInputStream("saved/" + gameId.toString() + ".game");
+			InputStream file = new FileInputStream("saved/" + match.getGame().toString() + ".game");
 			InputStream buffer = new BufferedInputStream(file);
 			ObjectInput input = new CopierObjectInputStream(Main.classLoader, new GZIPInputStream(buffer));
 			try {
@@ -224,7 +245,7 @@ public class TableController {
 			logger.log(Level.SEVERE, "Cannot load game. Class not found.", ex);
 		}
 		catch(IOException ex) {
-			logger.log(Level.SEVERE, "Cannot load game:" + game.getId(), ex);
+			logger.log(Level.SEVERE, "Cannot load game:" + match.getGame().getId(), ex);
 		}
 		return null;
 	}
diff --git a/Mage.Server/src/main/java/mage/server/game/TableManager.java b/Mage.Server/src/main/java/mage/server/game/TableManager.java
index 9369d13574..d0ffc29cc4 100644
--- a/Mage.Server/src/main/java/mage/server/game/TableManager.java
+++ b/Mage.Server/src/main/java/mage/server/game/TableManager.java
@@ -38,6 +38,8 @@ import mage.Constants.MultiplayerAttackOption;
 import mage.Constants.RangeOfInfluence;
 import mage.cards.decks.DeckCardLists;
 import mage.game.GameException;
+import mage.game.match.MatchType;
+import mage.game.match.MatchOptions;
 import mage.util.Logging;
 
 /**
@@ -56,8 +58,8 @@ public class TableManager {
 		return INSTANCE;
 	}
 
-	public Table createTable(UUID sessionId, String gameType, String deckType, List<String> playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) {
-		TableController tableController = new TableController(sessionId, gameType, deckType, playerTypes, attackOption, range);
+	public Table createTable(UUID sessionId, MatchOptions options) {
+		TableController tableController = new TableController(sessionId, options);
 		controllers.put(tableController.getTable().getId(), tableController);
 		tables.put(tableController.getTable().getId(), tableController.getTable());
 		return tableController.getTable();
@@ -100,8 +102,8 @@ public class TableManager {
 		return controllers.get(tableId).getChatId();
 	}
 
-	public void startGame(UUID sessionId, UUID roomId, UUID tableId) {
-		controllers.get(tableId).startGame(sessionId);
+	public void startMatch(UUID sessionId, UUID roomId, UUID tableId) {
+		controllers.get(tableId).startMatch(sessionId);
 	}
 
 	public boolean watchTable(UUID sessionId, UUID tableId) {
diff --git a/Mage.Tests/src/test/java/org/mage/test/base/MageBase.java b/Mage.Tests/src/test/java/org/mage/test/base/MageBase.java
index b174d9bbf1..6bda8ab0fc 100644
--- a/Mage.Tests/src/test/java/org/mage/test/base/MageBase.java
+++ b/Mage.Tests/src/test/java/org/mage/test/base/MageBase.java
@@ -21,6 +21,9 @@ import java.util.List;
 import java.util.UUID;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import mage.Constants.MultiplayerAttackOption;
+import mage.Constants.RangeOfInfluence;
+import mage.game.match.MatchOptions;
 
 /**
  * Base for starting Mage server.
@@ -64,14 +67,18 @@ public class MageBase {
             connect("player", "localhost", 17171);
             UUID roomId = server.getMainRoomId();
 
-            List<String> playerTypes = new ArrayList<String>();
-            playerTypes.add("Human");
-            playerTypes.add("Computer - default");
-            TableView table = server.createTable(sessionId, roomId, "Two Player Duel", "Limited", playerTypes, null, null);
+			MatchOptions options = new MatchOptions("1", "Two Player Duel");
+			options.getPlayerTypes().add("Human");
+			options.getPlayerTypes().add("Computer - default");
+			options.setDeckType("Limited");
+			options.setAttackOption(MultiplayerAttackOption.LEFT);
+			options.setRange(RangeOfInfluence.ALL);
+			options.setWinsNeeded(1);
+            TableView table = server.createTable(sessionId, roomId, options);
             System.out.println("Cards in the deck: " + Sets.loadDeck("UW Control.dck").getCards().size());
             server.joinTable(sessionId, roomId, table.getTableId(), "Human", Sets.loadDeck("UW Control.dck"));
             server.joinTable(sessionId, roomId, table.getTableId(), "Computer", Sets.loadDeck("UW Control.dck"));
-            server.startGame(sessionId, roomId, table.getTableId());
+            server.startMatch(sessionId, roomId, table.getTableId());
 
             synchronized (syncStart) {
                 int waitTime = 7000;
diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java
index 952c43e4cc..0bf3bc24f8 100644
--- a/Mage/src/mage/game/Game.java
+++ b/Mage/src/mage/game/Game.java
@@ -28,6 +28,7 @@
 
 package mage.game;
 
+import mage.game.match.MatchType;
 import mage.cards.Card;
 import mage.game.stack.SpellStack;
 import mage.MageObject;
@@ -64,7 +65,7 @@ import mage.players.Players;
 
 public interface Game extends MageItem, Serializable {
 
-	public GameType getGameType();
+	public MatchType getGameType();
 	public int getNumPlayers();
 	public int getLife();
 	public RangeOfInfluence getRangeOfInfluence();
diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java
index 280324324a..40b4ad16f0 100644
--- a/Mage/src/mage/game/GameImpl.java
+++ b/Mage/src/mage/game/GameImpl.java
@@ -28,6 +28,7 @@
 
 package mage.game;
 
+import mage.game.match.MatchType;
 import java.io.IOException;
 import mage.game.stack.SpellStack;
 import java.io.Serializable;
@@ -315,7 +316,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
 			player = players.getNext(this);
 		}
 
-		winnerId = findWinner();
+		winnerId = findWinnersAndLosers();
 
 		saveState();
 	}
@@ -380,13 +381,21 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
 		}
 	}
 
-	protected UUID findWinner() {
+	protected UUID findWinnersAndLosers() {
+		UUID winner = null;
 		for (Player player: state.getPlayers().values()) {
 			if (player.hasWon() || (!player.hasLost() && !player.hasLeft())) {
-				return player.getId();
+				player.won(this);
+				winner = player.getId();
+				break;
 			}
 		}
-		return null;
+		for (Player player: state.getPlayers().values()) {
+			if (winner != null && !player.getId().equals(winner)) {
+				player.lost(this);
+			}
+		}
+		return winner;
 	}
 
 	protected void endOfTurn() {
diff --git a/Mage/src/mage/game/Match.java b/Mage/src/mage/game/match/Match.java
similarity index 87%
rename from Mage/src/mage/game/Match.java
rename to Mage/src/mage/game/match/Match.java
index ad58ddd650..0c938da223 100644
--- a/Mage/src/mage/game/Match.java
+++ b/Mage/src/mage/game/match/Match.java
@@ -26,10 +26,13 @@
  *  or implied, of BetaSteward_at_googlemail.com.
  */
 
-package mage.game;
+package mage.game.match;
 
 import java.util.List;
+import java.util.UUID;
 import mage.cards.decks.Deck;
+import mage.game.Game;
+import mage.game.GameException;
 import mage.players.Player;
 
 /**
@@ -38,11 +41,13 @@ import mage.players.Player;
  */
 public interface Match {
 
+	public UUID getId();
 	public boolean isMatchOver();
 	public List<MatchPlayer> getPlayers();
 	public void addPlayer(Player player, Deck deck);
-	public int getMaxPlayers();
-	public int getMinPlayers();
-	public void startMatch();
+	public void startMatch() throws GameException;
+	public void startGame() throws GameException;
+	public void endGame();
+	public Game getGame();
 	
 }
diff --git a/Mage/src/mage/game/MatchImpl.java b/Mage/src/mage/game/match/MatchImpl.java
similarity index 66%
rename from Mage/src/mage/game/MatchImpl.java
rename to Mage/src/mage/game/match/MatchImpl.java
index 96e6243d11..0dfa4e1d6d 100644
--- a/Mage/src/mage/game/MatchImpl.java
+++ b/Mage/src/mage/game/match/MatchImpl.java
@@ -26,27 +26,29 @@
  *  or implied, of BetaSteward_at_googlemail.com.
  */
 
-package mage.game;
+package mage.game.match;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 import mage.cards.decks.Deck;
+import mage.game.Game;
+import mage.game.GameException;
 import mage.players.Player;
 
 /**
  *
  * @author BetaSteward_at_googlemail.com
  */
-public class MatchImpl implements Match {
+public abstract class MatchImpl<T extends Game> implements Match {
 
+	protected UUID id = UUID.randomUUID();
 	protected List<MatchPlayer> players = new ArrayList<MatchPlayer>();
-	protected List<Game> games = new ArrayList<Game>();
-	protected int winsNeeded;
-	protected int maxPlayers;
-	protected int minPlayers;
+	protected List<T> games = new ArrayList<T>();
+	protected MatchOptions options;
 	
-	public MatchImpl(int winsNeeded) {
-		this.winsNeeded = winsNeeded;
+	public MatchImpl(MatchOptions options) {
+		this.options = options;
 	}
 
 	@Override
@@ -61,14 +63,19 @@ public class MatchImpl implements Match {
 	}
 
 	@Override
-	public void startMatch() {
+	public void startMatch() throws GameException {
 
 	}
 
+	@Override
+	public UUID getId() {
+		return id;
+	}
+
 	@Override
 	public boolean isMatchOver() {
 		for (MatchPlayer player: players) {
-			if (player.getWins() >= winsNeeded) {
+			if (player.getWins() >= options.getWinsNeeded()) {
 				return true;
 			}
 		}
@@ -76,13 +83,29 @@ public class MatchImpl implements Match {
 	}
 
 	@Override
-	public int getMaxPlayers() {
-		return this.maxPlayers;
+	public T getGame() {
+		return games.get(games.size() -1);
+	}
+
+	protected void initGame(Game game) throws GameException {
+		for (MatchPlayer matchPlayer: this.players) {
+			game.addPlayer(matchPlayer.getPlayer());
+			game.loadCards(matchPlayer.getDeck().getCards(), matchPlayer.getPlayer().getId());
+			game.loadCards(matchPlayer.getDeck().getSideboard(), matchPlayer.getPlayer().getId());
+		}
 	}
 
 	@Override
-	public int getMinPlayers() {
-		return this.minPlayers;
+	public void endGame() {
+		Game game = getGame();
+		for (MatchPlayer player: this.players) {
+			Player p = game.getPlayer(player.getPlayer().getId());
+			if (p != null) {
+				if (p.hasWon())
+					player.addWin();
+				if (p.hasLost())
+					player.addLose();
+			}
+		}
 	}
-
 }
diff --git a/Mage/src/mage/game/match/MatchOptions.java b/Mage/src/mage/game/match/MatchOptions.java
new file mode 100644
index 0000000000..5301c55e5b
--- /dev/null
+++ b/Mage/src/mage/game/match/MatchOptions.java
@@ -0,0 +1,104 @@
+/*
+ *  Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without modification, are
+ *  permitted provided that the following conditions are met:
+ * 
+ *     1. Redistributions of source code must retain the above copyright notice, this list of
+ *        conditions and the following disclaimer.
+ * 
+ *     2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *        of conditions and the following disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ *  The views and conclusions contained in the software and documentation are those of the
+ *  authors and should not be interpreted as representing official policies, either expressed
+ *  or implied, of BetaSteward_at_googlemail.com.
+ */
+
+package mage.game.match;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import mage.Constants.MultiplayerAttackOption;
+import mage.Constants.RangeOfInfluence;
+
+/**
+ *
+ * @author BetaSteward_at_googlemail.com
+ */
+public class MatchOptions implements Serializable {
+
+	protected String name;
+	protected MultiplayerAttackOption attackOption;
+	protected RangeOfInfluence range;
+	protected int winsNeeded;
+	protected String gameType;
+	protected String deckType;
+	protected List<String> playerTypes = new ArrayList<String>();
+
+	public MatchOptions(String name, String gameType) {
+		this.name = name;
+		this.gameType = gameType;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public MultiplayerAttackOption getAttackOption() {
+		return attackOption;
+	}
+
+	public void setAttackOption(MultiplayerAttackOption attackOption) {
+		this.attackOption = attackOption;
+	}
+
+	public RangeOfInfluence getRange() {
+		return range;
+	}
+
+	public void setRange(RangeOfInfluence range) {
+		this.range = range;
+	}
+
+	public int getWinsNeeded() {
+		return winsNeeded;
+	}
+
+	public void setWinsNeeded(int winsNeeded) {
+		this.winsNeeded = winsNeeded;
+	}
+
+	public String getGameType() {
+		return gameType;
+	}
+
+	public void setGameType(String gameType) {
+		this.gameType = gameType;
+	}
+
+	public String getDeckType() {
+		return deckType;
+	}
+
+	public void setDeckType(String deckType) {
+		this.deckType = deckType;
+	}
+
+	public List<String> getPlayerTypes() {
+		return playerTypes;
+	}
+
+}
diff --git a/Mage/src/mage/game/MatchPlayer.java b/Mage/src/mage/game/match/MatchPlayer.java
similarity index 98%
rename from Mage/src/mage/game/MatchPlayer.java
rename to Mage/src/mage/game/match/MatchPlayer.java
index 4402b85c50..cf013ded15 100644
--- a/Mage/src/mage/game/MatchPlayer.java
+++ b/Mage/src/mage/game/match/MatchPlayer.java
@@ -26,7 +26,7 @@
  *  or implied, of BetaSteward_at_googlemail.com.
  */
 
-package mage.game;
+package mage.game.match;
 
 import mage.cards.decks.Deck;
 import mage.players.Player;
diff --git a/Mage/src/mage/game/GameType.java b/Mage/src/mage/game/match/MatchType.java
similarity index 80%
rename from Mage/src/mage/game/GameType.java
rename to Mage/src/mage/game/match/MatchType.java
index 4670e3da2e..d3c58fece0 100644
--- a/Mage/src/mage/game/GameType.java
+++ b/Mage/src/mage/game/match/MatchType.java
@@ -26,15 +26,17 @@
  *  or implied, of BetaSteward_at_googlemail.com.
  */
 
-package mage.game;
+package mage.game.match;
 
 import java.io.Serializable;
+import mage.Constants.MultiplayerAttackOption;
+import mage.Constants.RangeOfInfluence;
 
 /**
  *
  * @author BetaSteward_at_googlemail.com
  */
-public abstract class GameType implements Serializable {
+public abstract class MatchType<T extends MatchType<T>> implements Serializable {
 
 	protected String name;
 	protected int minPlayers;
@@ -44,6 +46,20 @@ public abstract class GameType implements Serializable {
 	protected boolean useRange;
 	protected boolean useAttackOption;
 
+	protected MatchType() {}
+	
+	protected MatchType(final MatchType matchType) {
+		this.name = matchType.name;
+		this.maxPlayers = matchType.maxPlayers;
+		this.minPlayers = matchType.minPlayers;
+		this.numTeams = matchType.numTeams;
+		this.playersPerTeam = matchType.playersPerTeam;
+		this.useRange = matchType.useRange;
+		this.useAttackOption = matchType.useAttackOption;
+	}
+
+	public abstract T copy();
+
 	@Override
 	public String toString() {
 		return name;