mirror of
https://github.com/magefree/mage.git
synced 2025-12-22 03:22:00 -08:00
Added a quit match option. FFA game gets no more killed if host left mage or quitted match.
This commit is contained in:
parent
ec9bb538ed
commit
7b260c960b
15 changed files with 178 additions and 54 deletions
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -74,16 +74,16 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -358,6 +358,7 @@ public class TableController {
|
|||
String creator = null;
|
||||
String opponent = null;
|
||||
for (Entry<UUID, UUID> entry: userPlayerMap.entrySet()) {
|
||||
if (!match.getPlayer(entry.getValue()).hasQuitted()) {
|
||||
User user = UserManager.getInstance().getUser(entry.getKey());
|
||||
if (user != null) {
|
||||
user.gameStarted(match.getGame().getId(), entry.getValue());
|
||||
|
|
@ -376,6 +377,7 @@ public class TableController {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ServerMessagesUtil.getInstance().incGamesStarted();
|
||||
|
||||
// log about game started
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,11 +736,13 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
|
|||
|
||||
@Override
|
||||
public void end() {
|
||||
if (!state.isGameOver()) {
|
||||
state.endGame();
|
||||
for (Player player: state.getPlayers().values()) {
|
||||
player.abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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,11 +165,13 @@ public abstract class MatchImpl implements Match {
|
|||
protected void initGame(Game game) throws GameException {
|
||||
shufflePlayers();
|
||||
for (MatchPlayer matchPlayer: this.players) {
|
||||
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,9 +219,11 @@ public abstract class MatchImpl implements Match {
|
|||
@Override
|
||||
public void sideboard() {
|
||||
for (MatchPlayer player: this.players) {
|
||||
if (!player.hasQuitted()) {
|
||||
player.setSideboarding();
|
||||
player.getPlayer().sideboard(this, player.getDeck());
|
||||
}
|
||||
}
|
||||
synchronized(this) {
|
||||
while (!isDoneSideboarding()) {
|
||||
try {
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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,9 +1319,11 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
|||
if (!this.wins) {
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST, null, null, playerId));
|
||||
}
|
||||
if (!hasLeft()) {
|
||||
game.leave(playerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canLose(Game game) {
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue