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; JMenuItem menuItem;
Pmenu = new JPopupMenu(); Pmenu = new JPopupMenu();
menuItem = new JMenuItem("Concede");
menuItem = new JMenuItem("Concede game");
Pmenu.add(menuItem); Pmenu.add(menuItem);
// Concede // Concede
menuItem.addActionListener(new ActionListener() { menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) { 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); 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"); menuItem = new JMenuItem("Cancel");
Pmenu.add(menuItem); Pmenu.add(menuItem);
battlefieldPanel.getMainPanel().addMouseListener(new MouseAdapter() { battlefieldPanel.getMainPanel().addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent Me) { public void mouseReleased(MouseEvent Me) {
if (Me.isPopupTrigger() && playingMode) { if (Me.isPopupTrigger() && playingMode) {
Pmenu.show(Me.getComponent(), Me.getX(), Me.getY()); 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 sendPlayerBoolean(UUID gameId, String sessionId, Boolean data) throws MageException;
void sendPlayerInteger(UUID gameId, String sessionId, Integer data) throws MageException; void sendPlayerInteger(UUID gameId, String sessionId, Integer data) throws MageException;
void concedeGame(UUID gameId, String sessionId) 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; void undo(UUID gameId, String sessionId) throws MageException;
GameView getGameView(UUID gameId, String sessionId, UUID playerId) 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; 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 @Override
public boolean undo(UUID gameId) { public boolean undo(UUID gameId) {
try { try {

View file

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

View file

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

View file

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

View file

@ -358,6 +358,7 @@ public class TableController {
String creator = null; String creator = null;
String opponent = null; String opponent = null;
for (Entry<UUID, UUID> entry: userPlayerMap.entrySet()) { for (Entry<UUID, UUID> entry: userPlayerMap.entrySet()) {
if (!match.getPlayer(entry.getValue()).hasQuitted()) {
User user = UserManager.getInstance().getUser(entry.getKey()); User user = UserManager.getInstance().getUser(entry.getKey());
if (user != null) { if (user != null) {
user.gameStarted(match.getGame().getId(), entry.getValue()); user.gameStarted(match.getGame().getId(), entry.getValue());
@ -376,6 +377,7 @@ public class TableController {
break; break;
} }
} }
}
ServerMessagesUtil.getInstance().incGamesStarted(); ServerMessagesUtil.getInstance().incGamesStarted();
// log about game started // log about game started

View file

@ -306,6 +306,10 @@ public class GameController implements GameCallback {
game.concede(getPlayerId(userId)); game.concede(getPlayerId(userId));
} }
public void quit(UUID userId) {
game.quit(getPlayerId(userId));
}
public void undo(UUID userId) { public void undo(UUID userId) {
game.undo(getPlayerId(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) { public void undo(UUID gameId, UUID userId) {
if (gameControllers.containsKey(gameId)) { if (gameControllers.containsKey(gameId)) {
gameControllers.get(gameId).undo(userId); 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); player.won(this);
} }
} }
state.endGame(); end();
endTime = new Date(); endTime = new Date();
return true; return true;
} }
@ -736,11 +736,13 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
@Override @Override
public void end() { public void end() {
if (!state.isGameOver()) {
state.endGame(); state.endGame();
for (Player player: state.getPlayers().values()) { for (Player player: state.getPlayers().values()) {
player.abort(); player.abort();
} }
} }
}
@Override @Override
public void addTableEventListener(Listener<TableEvent> listener) { public void addTableEventListener(Listener<TableEvent> listener) {
@ -797,8 +799,8 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
public synchronized void quit(UUID playerId) { public synchronized void quit(UUID playerId) {
Player player = state.getPlayer(playerId); Player player = state.getPlayer(playerId);
if (player != null) { if (player != null) {
leave(playerId); player.quit(this);
fireInformEvent(player.getName() + " has left the game."); fireInformEvent(player.getName() + " has quitted the match.");
} }
} }
@ -1580,9 +1582,12 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
@Override @Override
public synchronized void leave(UUID playerId) { public synchronized void leave(UUID playerId) {
Player player = getPlayer(playerId); Player player = getPlayer(playerId);
if (player.hasLeft()) {
return;
}
player.leave(); player.leave();
if (this.isGameOver()) { 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; return;
} }
//20100423 - 800.4a //20100423 - 800.4a

View file

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

View file

@ -40,7 +40,9 @@ public class MatchPlayer {
private int wins; private int wins;
private int loses; private int loses;
private Deck deck; private Deck deck;
private Player player; private Player player;
private boolean quitted;
private boolean doneSideboarding; private boolean doneSideboarding;
public MatchPlayer(Player player, Deck deck) { public MatchPlayer(Player player, Deck deck) {
@ -49,6 +51,7 @@ public class MatchPlayer {
this.wins = 0; this.wins = 0;
this.loses = 0; this.loses = 0;
this.doneSideboarding = true; this.doneSideboarding = true;
this.quitted = false;
} }
public int getWins() { public int getWins() {
@ -102,4 +105,11 @@ public class MatchPlayer {
return this.doneSideboarding; 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 hasLost();
boolean hasWon(); boolean hasWon();
boolean hasQuitted();
void quit(Game game);
boolean hasLeft(); boolean hasLeft();
/** /**
* Player is still active in game (has not left, lost or won the game). * Player is still active in game (has not left, lost or won the game).

View file

@ -28,16 +28,41 @@
package mage.players; 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.MageObject;
import mage.Mana; 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.PassAbility;
import mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility;
import mage.abilities.costs.AdjustingSourceCosts; import mage.abilities.costs.AdjustingSourceCosts;
import mage.abilities.costs.AlternativeCost; import mage.abilities.costs.AlternativeCost;
import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.common.LoseControlOnOtherPlayersControllerEffect; 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.ManaAbility;
import mage.abilities.mana.ManaOptions; import mage.abilities.mana.ManaOptions;
import mage.actions.MageDrawAction; import mage.actions.MageDrawAction;
@ -46,7 +71,13 @@ import mage.cards.Cards;
import mage.cards.CardsImpl; import mage.cards.CardsImpl;
import mage.cards.SplitCard; import mage.cards.SplitCard;
import mage.cards.decks.Deck; 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.Counter;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.counters.Counters; import mage.counters.Counters;
@ -72,9 +103,6 @@ import mage.target.common.TargetDiscard;
import mage.watchers.common.BloodthirstWatcher; import mage.watchers.common.BloodthirstWatcher;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Serializable { 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? * Means what exactly?
* No more actions?
*/ */
protected boolean abort; protected boolean abort;
protected final UUID playerId; 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. * 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; protected boolean passedAllTurns;
// conceded or connection lost game
protected boolean left; protected boolean left;
// quitted match
protected boolean quitted;
protected RangeOfInfluence range; protected RangeOfInfluence range;
protected Set<UUID> inRange = new HashSet<UUID>(); protected Set<UUID> inRange = new HashSet<UUID>();
protected boolean isTestMode = false; protected boolean isTestMode = false;
@ -174,6 +208,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
this.turns = player.turns; this.turns = player.turns;
this.left = player.left; this.left = player.left;
this.quitted = player.quitted;
this.range = player.range; this.range = player.range;
this.canGainLife = player.canGainLife; this.canGainLife = player.canGainLife;
this.canLoseLife = player.canLoseLife; 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.manaPool = player.getManaPool().copy();
this.turns = player.getTurns(); this.turns = player.getTurns();
this.left = player.hasLeft(); this.left = player.hasLeft();
this.quitted = player.hasQuitted();
this.range = player.getRange(); this.range = player.getRange();
this.canGainLife = player.isCanGainLife(); this.canGainLife = player.isCanGainLife();
this.canLoseLife = player.isCanLoseLife(); this.canLoseLife = player.isCanLoseLife();
@ -274,6 +309,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
this.wins = false; this.wins = false;
this.loses = false; this.loses = false;
this.left = false; this.left = false;
// quittet won't be reset because the player stays quit
this.passed = false; this.passed = false;
this.passedTurn = false; this.passedTurn = false;
this.passedAllTurns = false; this.passedAllTurns = false;
@ -1217,7 +1253,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
@Override @Override
public void resetPassed() { public void resetPassed() {
if (!this.loses && !this.left) { if (!this.loses && !this.hasLeft()) {
this.passed = false; this.passed = false;
} }
else { 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 @Override
public void concede(Game game) { public void concede(Game game) {
this.loses = true;
this.abort();
game.leave(playerId); game.leave(playerId);
} }
@ -1279,9 +1319,11 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
if (!this.wins) { if (!this.wins) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST, null, null, playerId)); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST, null, null, playerId));
} }
if (!hasLeft()) {
game.leave(playerId); game.leave(playerId);
} }
} }
}
@Override @Override
public boolean canLose(Game game) { public boolean canLose(Game game) {
@ -1802,4 +1844,10 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
public int getPriorityTimeLeft() { public int getPriorityTimeLeft() {
return priorityTimeLeft; return priorityTimeLeft;
} }
@Override
public boolean hasQuitted() {
return quitted;
}
} }