Added a quit match option. FFA game gets no more killed if host left mage or quitted match.

This commit is contained in:
LevelX2 2013-07-02 22:15:49 +02:00
parent ec9bb538ed
commit 7b260c960b
15 changed files with 178 additions and 54 deletions

View file

@ -75,22 +75,38 @@ public class PlayAreaPanel extends javax.swing.JPanel {
JMenuItem menuItem;
Pmenu = new JPopupMenu();
menuItem = new JMenuItem("Concede");
menuItem = new JMenuItem("Concede game");
Pmenu.add(menuItem);
// Concede
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (JOptionPane.showConfirmDialog(PlayAreaPanel.this, "Are you sure you want to concede?", "Confirm concede", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
if (JOptionPane.showConfirmDialog(PlayAreaPanel.this, "Are you sure you want to concede the game?", "Confirm concede game", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
MageFrame.getSession().concedeGame(gameId);
}
}
});
menuItem = new JMenuItem("Quit match");
Pmenu.add(menuItem);
// Quit match
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (JOptionPane.showConfirmDialog(PlayAreaPanel.this, "Are you sure you want to quit the match?", "Confirm quit match", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
MageFrame.getSession().quitMatch(gameId);
}
}
});
menuItem = new JMenuItem("Cancel");
Pmenu.add(menuItem);
battlefieldPanel.getMainPanel().addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent Me) {
if (Me.isPopupTrigger() && playingMode) {
Pmenu.show(Me.getComponent(), Me.getX(), Me.getY());

View file

@ -100,6 +100,7 @@ public interface MageServer {
void sendPlayerBoolean(UUID gameId, String sessionId, Boolean data) throws MageException;
void sendPlayerInteger(UUID gameId, String sessionId, Integer data) throws MageException;
void concedeGame(UUID gameId, String sessionId) throws MageException;
void quitMatch(UUID gameId, String sessionId) throws MageException;
void undo(UUID gameId, String sessionId) throws MageException;
GameView getGameView(UUID gameId, String sessionId, UUID playerId) throws MageException;

View file

@ -929,6 +929,21 @@ public class SessionImpl implements Session {
return false;
}
@Override
public boolean quitMatch(UUID gameId) {
try {
if (isConnected()) {
server.quitMatch(gameId, sessionId);
return true;
}
} catch (MageException ex) {
handleMageException(ex);
} catch (Throwable t) {
handleThrowable(t);
}
return false;
}
@Override
public boolean undo(UUID gameId) {
try {

View file

@ -53,6 +53,8 @@ public interface GamePlay {
boolean concedeGame(UUID gameId);
boolean quitMatch(UUID gameId);
boolean submitDeck(UUID tableId, DeckCardLists deck);
boolean updateDeck(UUID tableId, DeckCardLists deck);

View file

@ -74,15 +74,15 @@ public class CommanderDuel extends GameImpl<CommanderDuel> {
@Override
public void quit(UUID playerId) {
super.quit(playerId);
end();
}
@Override
public Set<UUID> getOpponents(UUID playerId) {
Set<UUID> opponents = new HashSet<UUID>();
for (UUID opponentId: this.getPlayer(playerId).getInRange()) {
if (!opponentId.equals(playerId))
if (!opponentId.equals(playerId)) {
opponents.add(opponentId);
}
}
return opponents;
}

View file

@ -71,7 +71,6 @@ public class TwoPlayerDuel extends GameImpl<TwoPlayerDuel> {
@Override
public void quit(UUID playerId) {
super.quit(playerId);
end();
}
@Override
@ -85,11 +84,6 @@ public class TwoPlayerDuel extends GameImpl<TwoPlayerDuel> {
return opponents;
}
@Override
public void leave(UUID playerId) {
super.leave(playerId);
}
@Override
public TwoPlayerDuel copy() {
return new TwoPlayerDuel(this);

View file

@ -358,22 +358,24 @@ public class TableController {
String creator = null;
String opponent = null;
for (Entry<UUID, UUID> entry: userPlayerMap.entrySet()) {
User user = UserManager.getInstance().getUser(entry.getKey());
if (user != null) {
user.gameStarted(match.getGame().getId(), entry.getValue());
if (creator == null) {
creator = user.getName();
} else {
if (opponent == null) {
opponent = user.getName();
if (!match.getPlayer(entry.getValue()).hasQuitted()) {
User user = UserManager.getInstance().getUser(entry.getKey());
if (user != null) {
user.gameStarted(match.getGame().getId(), entry.getValue());
if (creator == null) {
creator = user.getName();
} else {
if (opponent == null) {
opponent = user.getName();
}
}
}
}
else {
TableManager.getInstance().removeTable(table.getId());
GameManager.getInstance().removeGame(match.getGame().getId());
logger.warn("Unable to find player " + entry.getKey());
break;
else {
TableManager.getInstance().removeTable(table.getId());
GameManager.getInstance().removeGame(match.getGame().getId());
logger.warn("Unable to find player " + entry.getKey());
break;
}
}
}
ServerMessagesUtil.getInstance().incGamesStarted();

View file

@ -306,6 +306,10 @@ public class GameController implements GameCallback {
game.concede(getPlayerId(userId));
}
public void quit(UUID userId) {
game.quit(getPlayerId(userId));
}
public void undo(UUID userId) {
game.undo(getPlayerId(userId));
}

View file

@ -103,6 +103,12 @@ public class GameManager {
}
}
public void quitMatch(UUID gameId, UUID userId) {
if (gameControllers.containsKey(gameId)) {
gameControllers.get(gameId).quit(userId);
}
}
public void undo(UUID gameId, UUID userId) {
if (gameControllers.containsKey(gameId)) {
gameControllers.get(gameId).undo(userId);

View file

@ -417,7 +417,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
player.won(this);
}
}
state.endGame();
end();
endTime = new Date();
return true;
}
@ -736,9 +736,11 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
@Override
public void end() {
state.endGame();
for (Player player: state.getPlayers().values()) {
player.abort();
if (!state.isGameOver()) {
state.endGame();
for (Player player: state.getPlayers().values()) {
player.abort();
}
}
}
@ -797,8 +799,8 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
public synchronized void quit(UUID playerId) {
Player player = state.getPlayer(playerId);
if (player != null) {
leave(playerId);
fireInformEvent(player.getName() + " has left the game.");
player.quit(this);
fireInformEvent(player.getName() + " has quitted the match.");
}
}
@ -1580,9 +1582,12 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
@Override
public synchronized void leave(UUID playerId) {
Player player = getPlayer(playerId);
if (player.hasLeft()) {
return;
}
player.leave();
if (this.isGameOver()) {
// no need to remove objects if only one player is left
// no need to remove objects if only one player is left so the game is over
return;
}
//20100423 - 800.4a

View file

@ -398,7 +398,7 @@ public class GameState implements Serializable, Copyable<GameState> {
public PlayerList getPlayerList(UUID playerId) {
PlayerList newPlayerList = new PlayerList();
for (Player player: players.values()) {
if (!player.hasLeft() && !player.hasLost()) {
if (!player.hasLeft()&& !player.hasLost()) {
newPlayerList.add(player.getId());
}
}

View file

@ -117,12 +117,20 @@ public abstract class MatchImpl implements Match {
@Override
public boolean isMatchOver() {
int activePlayers = 0;
for (MatchPlayer player: players) {
if (!player.hasQuitted()) {
activePlayers++;
}
if (player.getWins() >= options.getWinsNeeded()) {
endTime = new Date();
return true;
}
}
if (activePlayers < 2) {
endTime = new Date();
return true;
}
return false;
}
@ -157,10 +165,12 @@ public abstract class MatchImpl implements Match {
protected void initGame(Game game) throws GameException {
shufflePlayers();
for (MatchPlayer matchPlayer: this.players) {
matchPlayer.getPlayer().init(game);
game.loadCards(matchPlayer.getDeck().getCards(), matchPlayer.getPlayer().getId());
game.loadCards(matchPlayer.getDeck().getSideboard(), matchPlayer.getPlayer().getId());
game.addPlayer(matchPlayer.getPlayer(), matchPlayer.getDeck());
if (!matchPlayer.hasQuitted()) {
matchPlayer.getPlayer().init(game);
game.loadCards(matchPlayer.getDeck().getCards(), matchPlayer.getPlayer().getId());
game.loadCards(matchPlayer.getDeck().getSideboard(), matchPlayer.getPlayer().getId());
game.addPlayer(matchPlayer.getPlayer(), matchPlayer.getDeck());
}
}
game.setPriorityTime(options.getPriorityTime());
}
@ -175,6 +185,9 @@ public abstract class MatchImpl implements Match {
for (MatchPlayer player: this.players) {
Player p = game.getPlayer(player.getPlayer().getId());
if (p != null) {
if (p.hasQuitted()) {
player.setQuitted(true);
}
if (p.hasWon()) {
player.addWin();
}
@ -191,7 +204,7 @@ public abstract class MatchImpl implements Match {
Game game = getGame();
for (MatchPlayer player: this.players) {
Player p = game.getPlayer(player.getPlayer().getId());
if (p != null && p.hasLost()) {
if (p != null && p.hasLost() && !p.hasQuitted()) {
loserId = p.getId();
}
}
@ -206,8 +219,10 @@ public abstract class MatchImpl implements Match {
@Override
public void sideboard() {
for (MatchPlayer player: this.players) {
player.setSideboarding();
player.getPlayer().sideboard(this, player.getDeck());
if (!player.hasQuitted()) {
player.setSideboarding();
player.getPlayer().sideboard(this, player.getDeck());
}
}
synchronized(this) {
while (!isDoneSideboarding()) {
@ -221,7 +236,7 @@ public abstract class MatchImpl implements Match {
@Override
public boolean isDoneSideboarding() {
for (MatchPlayer player: this.players) {
if (!player.isDoneSideboarding()) {
if (!player.hasQuitted() && !player.isDoneSideboarding()) {
return false;
}
}
@ -261,7 +276,11 @@ public abstract class MatchImpl implements Match {
for (MatchPlayer mp :this.getPlayers()) {
sb.append("- ").append(mp.getPlayer().getName());
sb.append(" (").append(mp.getWins()).append(mp.getWins()==1?" win / ":" wins / ");
sb.append(mp.getLoses()).append(mp.getLoses()==1?" loss)\n":" losses)\n");
sb.append(mp.getLoses()).append(mp.getLoses()==1?" loss)":" losses)");
if (mp.hasQuitted()) {
sb.append(" QUITTED");
}
sb.append("\n");
}
sb.append("\n").append(this.getWinsNeeded()).append(this.getWinsNeeded() == 1 ? " win":" wins").append(" needed to win the match\n");
sb.append("\nGame has started\n");

View file

@ -40,7 +40,9 @@ public class MatchPlayer {
private int wins;
private int loses;
private Deck deck;
private Player player;
private boolean quitted;
private boolean doneSideboarding;
public MatchPlayer(Player player, Deck deck) {
@ -49,6 +51,7 @@ public class MatchPlayer {
this.wins = 0;
this.loses = 0;
this.doneSideboarding = true;
this.quitted = false;
}
public int getWins() {
@ -102,4 +105,11 @@ public class MatchPlayer {
return this.doneSideboarding;
}
public boolean hasQuitted() {
return quitted;
}
public void setQuitted(boolean quitted) {
this.quitted = quitted;
}
}

View file

@ -99,6 +99,8 @@ public interface Player extends MageItem, Copyable<Player> {
boolean hasLost();
boolean hasWon();
boolean hasQuitted();
void quit(Game game);
boolean hasLeft();
/**
* Player is still active in game (has not left, lost or won the game).

View file

@ -28,16 +28,41 @@
package mage.players;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.Mana;
import mage.abilities.*;
import mage.abilities.Abilities;
import mage.abilities.AbilitiesImpl;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.Mode;
import mage.abilities.PlayLandAbility;
import mage.abilities.SpecialAction;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.common.PassAbility;
import mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility;
import mage.abilities.costs.AdjustingSourceCosts;
import mage.abilities.costs.AlternativeCost;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.common.LoseControlOnOtherPlayersControllerEffect;
import mage.abilities.keyword.*;
import mage.abilities.keyword.FlashbackAbility;
import mage.abilities.keyword.HexproofAbility;
import mage.abilities.keyword.InfectAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.abilities.keyword.ProtectionAbility;
import mage.abilities.keyword.ShroudAbility;
import mage.abilities.mana.ManaAbility;
import mage.abilities.mana.ManaOptions;
import mage.actions.MageDrawAction;
@ -46,7 +71,13 @@ import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.cards.SplitCard;
import mage.cards.decks.Deck;
import mage.constants.*;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.RangeOfInfluence;
import mage.constants.SpellAbilityType;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.counters.Counter;
import mage.counters.CounterType;
import mage.counters.Counters;
@ -72,9 +103,6 @@ import mage.target.common.TargetDiscard;
import mage.watchers.common.BloodthirstWatcher;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Serializable {
@ -84,6 +112,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
/**
* Means what exactly?
* No more actions?
*/
protected boolean abort;
protected final UUID playerId;
@ -113,7 +142,12 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
* Note! This differs from passedTurn as it doesn't care about spells and abilities in the stack and will pass them as well.
*/
protected boolean passedAllTurns;
// conceded or connection lost game
protected boolean left;
// quitted match
protected boolean quitted;
protected RangeOfInfluence range;
protected Set<UUID> inRange = new HashSet<UUID>();
protected boolean isTestMode = false;
@ -174,6 +208,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
this.turns = player.turns;
this.left = player.left;
this.quitted = player.quitted;
this.range = player.range;
this.canGainLife = player.canGainLife;
this.canLoseLife = player.canLoseLife;
@ -220,8 +255,8 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
this.manaPool = player.getManaPool().copy();
this.turns = player.getTurns();
this.left = player.hasLeft();
this.quitted = player.hasQuitted();
this.range = player.getRange();
this.canGainLife = player.isCanGainLife();
this.canLoseLife = player.isCanLoseLife();
@ -274,6 +309,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
this.wins = false;
this.loses = false;
this.left = false;
// quittet won't be reset because the player stays quit
this.passed = false;
this.passedTurn = false;
this.passedAllTurns = false;
@ -367,7 +403,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
if (!playerId.equals(this.getId())) {
this.playersUnderYourControl.add(playerId);
Player player = game.getPlayer(playerId);
if (!player.hasLeft() && !player.hasLost()) {
if (!player.hasLeft()&& !player.hasLost()) {
player.setGameUnderYourControl(false);
player.setTurnControlledBy(this.getId());
}
@ -1217,7 +1253,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
@Override
public void resetPassed() {
if (!this.loses && !this.left) {
if (!this.loses && !this.hasLeft()) {
this.passed = false;
}
else {
@ -1225,10 +1261,14 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
}
}
@Override
public void quit(Game game) {
quitted = true;
this.concede(game);
}
@Override
public void concede(Game game) {
this.loses = true;
this.abort();
game.leave(playerId);
}
@ -1279,7 +1319,9 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
if (!this.wins) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST, null, null, playerId));
}
game.leave(playerId);
if (!hasLeft()) {
game.leave(playerId);
}
}
}
@ -1802,4 +1844,10 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
public int getPriorityTimeLeft() {
return priorityTimeLeft;
}
@Override
public boolean hasQuitted() {
return quitted;
}
}