diff --git a/.gitattributes b/.gitattributes index ff02e544ea8..ba02d3b76dd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14163,6 +14163,7 @@ src/main/java/forge/control/ChatArea.java -text src/main/java/forge/control/ControlBazaarUI.java -text src/main/java/forge/control/FControl.java -text src/main/java/forge/control/FControlGameEventHandler.java -text +src/main/java/forge/control/FControlGamePlayback.java -text src/main/java/forge/control/InputQueue.java svneol=native#text/plain src/main/java/forge/control/KeyboardShortcuts.java -text src/main/java/forge/control/Lobby.java -text @@ -14234,6 +14235,7 @@ src/main/java/forge/game/event/GameEventDuelFinished.java -text src/main/java/forge/game/event/GameEventDuelOutcome.java -text src/main/java/forge/game/event/GameEventFlipCoin.java -text src/main/java/forge/game/event/GameEventGameRestarted.java -text +src/main/java/forge/game/event/GameEventGameStarted.java -text src/main/java/forge/game/event/GameEventLandPlayed.java -text src/main/java/forge/game/event/GameEventLifeLoss.java -text src/main/java/forge/game/event/GameEventManaBurn.java -text diff --git a/src/main/java/forge/control/FControl.java b/src/main/java/forge/control/FControl.java index f96c5113854..a37b7723c64 100644 --- a/src/main/java/forge/control/FControl.java +++ b/src/main/java/forge/control/FControl.java @@ -24,6 +24,7 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.File; +import java.util.ArrayList; import java.util.List; import javax.swing.ImageIcon; import javax.swing.JLayeredPane; @@ -60,6 +61,7 @@ import forge.gui.match.controllers.CStack; import forge.gui.match.nonsingleton.VField; import forge.gui.match.views.VAntes; import forge.gui.toolbox.CardFaceSymbols; +import forge.gui.toolbox.FOverlay; import forge.gui.toolbox.FSkin; import forge.net.NetServer; import forge.properties.NewConstants; @@ -127,7 +129,7 @@ public enum FControl { Singletons.getView().getFrame().setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); if (!FControl.this.game.isGameOver()) - CDock.SINGLETON_INSTANCE.concede(); + stopGame(); else { Singletons.getControl().changeState(FControl.Screens.HOME_SCREEN); SOverlayUtils.hideOverlay(); @@ -350,6 +352,28 @@ public enum FControl { public Game getObservedGame() { return game; } + + public final void stopGame() { + List pp = new ArrayList(); + for(Player p : game.getPlayers()) { + if ( p.getOriginalLobbyPlayer() == getLobby().getGuiPlayer() ) + pp.add(p); + } + boolean hasHuman = !pp.isEmpty(); + + if ( pp.isEmpty() ) + pp.addAll(game.getPlayers()); // no human? then all players surrender! + + for(Player p: pp) + p.concede(); + + boolean humanHasPriority = game.getPhaseHandler().getPriorityPlayer().getLobbyPlayer() == getLobby().getGuiPlayer(); + + if ( hasHuman && humanHasPriority ) + game.getAction().checkGameOverCondition(); + else + game.isGameOver(); // this is synchronized method - it's used to make Game-0 thread see changes made here + } private InputQueue inputQueue; public InputQueue getInputQueue() { @@ -358,6 +382,7 @@ public enum FControl { private final FControlGameEventHandler fcVisitor = new FControlGameEventHandler(this); + private final FControlGamePlayback playbackControl = new FControlGamePlayback(this); public void attachToGame(Game game0) { // TODO: Detach from other game we might be looking at @@ -382,14 +407,20 @@ public enum FControl { CMessage.SINGLETON_INSTANCE.getInputControl().setGame(game); - // models shall notify controllers of changes - - - // some observers were set in CMatchUI.initMatch - // Listen to DuelOutcome event to show ViewWinLose game.subscribeToEvents(fcVisitor); + // Add playback controls to match if needed + boolean hasHuman = false; + for(Player p : game.getPlayers()) { + if ( p.getController().getLobbyPlayer() == getLobby().getGuiPlayer() ) + hasHuman = true; + } + if (!hasHuman) { + game.subscribeToEvents(playbackControl); + } + + VAntes.SINGLETON_INSTANCE.setModel(game.getRegisteredPlayers()); diff --git a/src/main/java/forge/control/FControlGameEventHandler.java b/src/main/java/forge/control/FControlGameEventHandler.java index 2ec6ce02c9c..9f4720d0024 100644 --- a/src/main/java/forge/control/FControlGameEventHandler.java +++ b/src/main/java/forge/control/FControlGameEventHandler.java @@ -26,16 +26,15 @@ import forge.gui.match.nonsingleton.VHand; import forge.gui.match.nonsingleton.VField.PhaseLabel; public class FControlGameEventHandler extends IGameEventVisitor.Base { - public final FControl fc; + private final FControl fc; public FControlGameEventHandler(FControl fc ) { this.fc = fc; } - - private final AtomicBoolean phaseUpdPlanned = new AtomicBoolean(false); - + @Subscribe public void receiveGameEvent(final GameEvent ev) { ev.visit(this); } - + + private final AtomicBoolean phaseUpdPlanned = new AtomicBoolean(false); @Override public Void visit(final GameEventTurnPhase ev) { if ( phaseUpdPlanned.getAndSet(true) ) return null; @@ -50,15 +49,13 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { PhaseLabel lbl = matchUi.getFieldViewFor(p).getLabelFor(ph); matchUi.resetAllPhaseButtons(); - if (lbl != null) { - lbl.setActive(true); - } - - + if (lbl != null) lbl.setActive(true); } }); + + return null; } - + @Override public Void visit(GameEventAnteCardsSelected ev) { // Require EDT here? @@ -99,6 +96,4 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { } }); return null; } - - } \ No newline at end of file diff --git a/src/main/java/forge/control/FControlGamePlayback.java b/src/main/java/forge/control/FControlGamePlayback.java new file mode 100644 index 00000000000..3b2c3f8b74b --- /dev/null +++ b/src/main/java/forge/control/FControlGamePlayback.java @@ -0,0 +1,100 @@ +package forge.control; + +import com.google.common.eventbus.Subscribe; + +import forge.game.event.GameEvent; +import forge.game.event.GameEventBlockerAssigned; +import forge.game.event.GameEventGameStarted; +import forge.game.event.GameEventLandPlayed; +import forge.game.event.GameEventSpellResolved; +import forge.game.event.GameEventTurnPhase; +import forge.game.event.IGameEventVisitor; +import forge.game.player.Player; +import forge.gui.match.CMatchUI; + +public class FControlGamePlayback extends IGameEventVisitor.Base { + private final FControl fc; + public FControlGamePlayback(FControl fc ) { + this.fc = fc; + } + + @Subscribe + public void receiveGameEvent(final GameEvent ev) { ev.visit(this); } + + private int phasesDelay = 400; + private int combatDelay = 400; + private int resolveDelay = 600; + + private void pauseForEvent(int delay) { + try { + Thread.sleep(delay); + } catch (InterruptedException e) { + // TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log. + e.printStackTrace(); + } + } + + + + + @Override + public Void visit(GameEventBlockerAssigned event) { + pauseForEvent(combatDelay); + return super.visit(event); + } + + + /* (non-Javadoc) + * @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventTurnPhase) + */ + @Override + public Void visit(GameEventTurnPhase ev) { + boolean isUiToStop = CMatchUI.SINGLETON_INSTANCE.stopAtPhase(ev.playerTurn, ev.phase); + + switch(ev.phase) { + case COMBAT_END: + case COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY: + case COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY: + if( fc.getObservedGame().getPhaseHandler().inCombat() ) + pauseForEvent(combatDelay); + break; + default: + if( isUiToStop ) + pauseForEvent(phasesDelay); + break; + } + + return null; + } + + /* (non-Javadoc) + * @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventGameStarted) + */ + @Override + public Void visit(GameEventGameStarted event) { + boolean hasHuman = false; + for(Player p : event.players) { + if ( p.getController().getLobbyPlayer() == fc.getLobby().getGuiPlayer() ) + hasHuman = true; + } + + + // show input here to adjust speed if no human playing + + return null; + } + + + @Override + public Void visit(GameEventLandPlayed event) { + pauseForEvent(resolveDelay); + return super.visit(event); + } + + @Override + public Void visit(GameEventSpellResolved event) { + pauseForEvent(resolveDelay); + return null; + } + +} \ No newline at end of file diff --git a/src/main/java/forge/game/Game.java b/src/main/java/forge/game/Game.java index 55875aed1cc..72195544edb 100644 --- a/src/main/java/forge/game/Game.java +++ b/src/main/java/forge/game/Game.java @@ -491,7 +491,10 @@ public class Game { public Player getNextPlayerAfter(final Player playerTurn) { int iPlayer = roIngamePlayers.indexOf(playerTurn); - if (-1 == iPlayer && !roIngamePlayers.isEmpty()) { // if playerTurn has just lost + if (roIngamePlayers.isEmpty()) + return null; + + if (-1 == iPlayer) { // if playerTurn has just lost int iAlive; iPlayer = allPlayers.indexOf(playerTurn); do { @@ -507,7 +510,6 @@ public class Game { } return roIngamePlayers.get(iPlayer); - } public int getPosition(Player player, Player startingPlayer) { diff --git a/src/main/java/forge/game/GameAction.java b/src/main/java/forge/game/GameAction.java index a9b603fdb48..aa70b66da7f 100644 --- a/src/main/java/forge/game/GameAction.java +++ b/src/main/java/forge/game/GameAction.java @@ -63,6 +63,8 @@ import forge.game.event.GameEventCardDestroyed; import forge.game.event.GameEventCardRegenerated; import forge.game.event.GameEventCardSacrificed; import forge.game.event.GameEventDuelFinished; +import forge.game.event.GameEventFlipCoin; +import forge.game.event.GameEventGameStarted; import forge.game.player.GameLossReason; import forge.game.player.HumanPlay; import forge.game.player.Player; @@ -72,6 +74,7 @@ import forge.game.zone.Zone; import forge.game.zone.ZoneType; import forge.gui.GuiChoose; import forge.gui.GuiDialog; +import forge.util.Aggregates; import forge.util.maps.CollectionSuppliers; import forge.util.maps.HashMapOfLists; import forge.util.maps.MapOfLists; @@ -786,75 +789,6 @@ public class GameAction { game.getStack().add(activate); } - /** - *

- * checkEndGameSate. - *

- * - * @return a boolean. - */ - private final GameEndReason checkEndGameState(final Game game) { - - GameEndReason reason = null; - // award loses as SBE - List losers = null; - for (Player p : game.getPlayers()) { - if (p.checkLoseCondition()) { // this will set appropriate outcomes - // Run triggers - if (losers == null) { - losers = new ArrayList(3); - } - losers.add(p); - } - } - - // Has anyone won by spelleffect? - for (Player p : game.getPlayers()) { - if (!p.hasWon()) { - continue; - } - - // then the rest have lost! - reason = GameEndReason.WinsGameSpellEffect; - for (Player pl : game.getPlayers()) { - if (pl.equals(p)) { - continue; - } - - if (!pl.loseConditionMet(GameLossReason.OpponentWon, p.getOutcome().altWinSourceName)) { - reason = null; // they cannot lose! - } else { - if (losers == null) { - losers = new ArrayList(3); - } - losers.add(p); - } - } - break; - } - - // need a separate loop here, otherwise ConcurrentModificationException is raised - if (losers != null) { - for (Player p : losers) { - game.onPlayerLost(p); - } - } - - // still unclear why this has not caught me conceding - if (reason == null && Iterables.size(Iterables.filter(game.getPlayers(), Player.Predicates.NOT_LOST)) == 1) - { - reason = GameEndReason.AllOpponentsLost; - } - - // ai's cannot finish their game without human yet - so terminate a game if human has left. - /* - if (reason == null && !Iterables.any(game.getPlayers(), Predicates.and(Player.Predicates.NOT_LOST, Player.Predicates.isType(PlayerType.HUMAN)))) { - reason = GameEndReason.AllHumansLost; - } - */ - return reason; - } - /** */ public final void checkStaticAbilities() { FThreads.assertExecutedByEdt(false); @@ -1082,18 +1016,81 @@ public class GameAction { } } // for q=0;q<2 - GameEndReason endGame = this.checkEndGameState(game); - if (endGame != null) { - // Clear Simultaneous triggers at the end of the game - game.setGameOver(endGame); - game.getStack().clearSimultaneousStack(); - } + checkGameOverCondition(); if (!refreeze) { game.getStack().unfreezeStack(); } } // checkStateEffects() + public void checkGameOverCondition() { + GameEndReason reason = this.eliminateLosingPlayers(); + + // still unclear why this has not caught me conceding + if (reason == null ) + { + int cntNotLost = Iterables.size(Iterables.filter(game.getPlayers(), Player.Predicates.NOT_LOST)); + if( cntNotLost == 1 ) + reason = GameEndReason.AllOpponentsLost; + else if ( cntNotLost == 0 ) + reason = GameEndReason.Draw; + else + return; + } + + // Clear Simultaneous triggers at the end of the game + game.setGameOver(reason); + game.getStack().clearSimultaneousStack(); + } + + private GameEndReason eliminateLosingPlayers() { + // award loses as SBE + List losers = null; + for (Player p : game.getPlayers()) { + if (p.checkLoseCondition()) { // this will set appropriate outcomes + // Run triggers + if (losers == null) { + losers = new ArrayList(3); + } + losers.add(p); + } + } + + GameEndReason reason = null; + // Has anyone won by spelleffect? + for (Player p : game.getPlayers()) { + if (!p.hasWon()) { + continue; + } + + // then the rest have lost! + reason = GameEndReason.WinsGameSpellEffect; + for (Player pl : game.getPlayers()) { + if (pl.equals(p)) { + continue; + } + + if (!pl.loseConditionMet(GameLossReason.OpponentWon, p.getOutcome().altWinSourceName)) { + reason = null; // they cannot lose! + } else { + if (losers == null) { + losers = new ArrayList(3); + } + losers.add(p); + } + } + break; + } + + // need a separate loop here, otherwise ConcurrentModificationException is raised + if (losers != null) { + for (Player p : losers) { + game.onPlayerLost(p); + } + } + return reason; + } + /** *

* destroyPlaneswalkers. @@ -1474,33 +1471,55 @@ public class GameAction { } } } + + private Player determineFirstTurnPlayer(final GameOutcome lastGameOutcome) { + // Only cut/coin toss if it's the first game of the match + Player goesFirst = null; + + boolean isFirstGame = lastGameOutcome == null; + if (isFirstGame) { + game.fireEvent(new GameEventFlipCoin()); // Play the Flip Coin sound + goesFirst = Aggregates.random(game.getPlayers()); + } else { + for(Player p : game.getPlayers()) { + if(!lastGameOutcome.isWinner(p.getLobbyPlayer())) { + goesFirst = p; + break; + } + } + } + + boolean willPlay = goesFirst.getController().getWillPlayOnFirstTurn(isFirstGame); + goesFirst = willPlay ? goesFirst : goesFirst.getOpponent(); + return goesFirst; + } + + public void startGame() { + Player first = determineFirstTurnPlayer(game.getMatch().getLastGameOutcome()); - public void startGame(final Player firstPlayer) { - Player first = firstPlayer; do { if ( game.isGameOver() ) break; // conceded during "play or draw" - - // Draw cards - for (final Player p1 : game.getPlayers()) { - p1.drawCards(p1.getMaxHandSize()); - } + + // FControl should determine now if there are any human players. + // Where there are none, it should bring up speed controls + game.fireEvent(new GameEventGameStarted(first, game.getPlayers())); game.setAge(GameAge.Mulligan); - performMulligans(first, game.getType() == GameType.Commander); - - if ( game.isGameOver() ) break; // conceded during "mulligan" prompt + for (final Player p1 : game.getPlayers()) + p1.drawCards(p1.getMaxHandSize()); - // should I restore everyting exiled by Karn here, or before Mulligans is fine? + performMulligans(first, game.getType() == GameType.Commander); + if ( game.isGameOver() ) break; // conceded during "mulligan" prompt game.setAge(GameAge.Play); // THIS CODE WILL WORK WITH PHASE = NULL { if(game.getType() == GameType.Planechase) - firstPlayer.initPlane(); - + first.initPlane(); + handleLeylinesAndChancellors(); checkStateEffects(); - + // Run Trigger beginning of the game final HashMap runParams = new HashMap(); game.getTriggerHandler().runTrigger(TriggerType.NewGame, runParams, false); @@ -1511,7 +1530,7 @@ public class GameAction { first = game.getPhaseHandler().getPlayerTurn(); // needed only for restart } while( game.getAge() == GameAge.RestartedByKarn ); - // will pull UI + // will pull UI dialog, when the UI is listening game.fireEvent(new GameEventDuelFinished()); } @@ -1588,6 +1607,7 @@ public class GameAction { } } + // Invokes given runnable in Game thread pool - used to start game and perform actions from UI (when game-0 waits for input) public void invoke(final Runnable proc) { if( FThreads.isGameThread() ) { proc.run(); diff --git a/src/main/java/forge/game/Match.java b/src/main/java/forge/game/Match.java index b27cfc194ce..94da1cc5d68 100644 --- a/src/main/java/forge/game/Match.java +++ b/src/main/java/forge/game/Match.java @@ -100,8 +100,7 @@ public class Match { currentGame.getAction().invoke(new Runnable() { @Override public void run() { - final Player firstPlayer = determineFirstTurnPlayer(getLastGameOutcome(), currentGame); - currentGame.getAction().startGame(firstPlayer); + currentGame.getAction().startGame(); } }); } @@ -205,26 +204,4 @@ public class Match { return 10; } - - private Player determineFirstTurnPlayer(final GameOutcome lastGameOutcome, final Game game) { - // Only cut/coin toss if it's the first game of the match - Player goesFirst = null; - - boolean isFirstGame = lastGameOutcome == null; - if (isFirstGame) { - game.fireEvent(new GameEventFlipCoin()); // Play the Flip Coin sound - goesFirst = Aggregates.random(game.getPlayers()); - } else { - for(Player p : game.getPlayers()) { - if(!lastGameOutcome.isWinner(p.getLobbyPlayer())) { - goesFirst = p; - break; - } - } - } - - boolean willPlay = goesFirst.getController().getWillPlayOnFirstTurn(isFirstGame); - goesFirst = willPlay ? goesFirst : goesFirst.getOpponent(); - return goesFirst; - } } diff --git a/src/main/java/forge/game/event/GameEventGameStarted.java b/src/main/java/forge/game/event/GameEventGameStarted.java new file mode 100644 index 00000000000..34ac4697a7b --- /dev/null +++ b/src/main/java/forge/game/event/GameEventGameStarted.java @@ -0,0 +1,26 @@ +package forge.game.event; + +import forge.game.player.Player; + +/** + * TODO: Write javadoc for this type. + * + */ +public class GameEventGameStarted extends GameEvent { + + public final Player firstTurn; + public final Iterable players; + + public GameEventGameStarted(Player firstTurn, Iterable players) { + super(); + this.firstTurn = firstTurn; + this.players = players; + } + + + @Override + public T visit(IGameEventVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/src/main/java/forge/game/event/IGameEventVisitor.java b/src/main/java/forge/game/event/IGameEventVisitor.java index f7592208550..151705d661c 100644 --- a/src/main/java/forge/game/event/IGameEventVisitor.java +++ b/src/main/java/forge/game/event/IGameEventVisitor.java @@ -20,6 +20,7 @@ public interface IGameEventVisitor { T visit(GameEventDuelFinished event); T visit(GameEventDuelOutcome event); T visit(GameEventFlipCoin event); + T visit(GameEventGameStarted event); T visit(GameEventGameRestarted event); T visit(GameEventLandPlayed event); T visit(GameEventLifeLoss event); @@ -53,6 +54,7 @@ public interface IGameEventVisitor { public T visit(GameEventDuelFinished event) { return null; } public T visit(GameEventDuelOutcome event) { return null; } public T visit(GameEventFlipCoin event) { return null; } + public T visit(GameEventGameStarted event) { return null; } public T visit(GameEventGameRestarted event) { return null; } public T visit(GameEventLandPlayed event) { return null; } public T visit(GameEventLifeLoss event) { return null; } @@ -69,7 +71,5 @@ public interface IGameEventVisitor { public T visit(GameEventPlayerDamaged event) { return null; } } - - } diff --git a/src/main/java/forge/game/phase/PhaseHandler.java b/src/main/java/forge/game/phase/PhaseHandler.java index 14ea258984e..39b3efcf88a 100644 --- a/src/main/java/forge/game/phase/PhaseHandler.java +++ b/src/main/java/forge/game/phase/PhaseHandler.java @@ -713,14 +713,14 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable { } else if( DEBUG_PHASES ){ System.out.print(" >>\n"); } - - if ( game.isGameOver() ) return; // conceded? + // actingPlayer is the player who may act // the firstAction is the player who gained Priority First in this segment // of Priority - Player nextPlayer = game.getNextPlayerAfter(this.getPriorityPlayer()); + + if ( game.isGameOver() || nextPlayer == null ) return; // conceded? // System.out.println(String.format("%s %s: %s passes priority to %s", playerTurn, phase, actingPlayer, nextPlayer)); if (this.getFirstPriority().equals(nextPlayer)) { diff --git a/src/main/java/forge/game/player/Player.java b/src/main/java/forge/game/player/Player.java index c60e40961cc..cf53009f017 100644 --- a/src/main/java/forge/game/player/Player.java +++ b/src/main/java/forge/game/player/Player.java @@ -2066,7 +2066,6 @@ public class Player extends GameEntity implements Comparable { * Concede. */ public final void concede() { // No cantLose checks - just lose - FThreads.assertExecutedByEdt(false); setOutcome(PlayerOutcome.concede()); } @@ -2704,6 +2703,10 @@ public class Player extends GameEntity implements Comparable { public final LobbyPlayer getLobbyPlayer() { return getController().getLobbyPlayer(); } + + public final LobbyPlayer getOriginalLobbyPlayer() { + return controllerCreator.getLobbyPlayer(); + } public final boolean isMindSlaved() { return controller.getLobbyPlayer() != controllerCreator.getLobbyPlayer(); diff --git a/src/main/java/forge/gui/GuiDialog.java b/src/main/java/forge/gui/GuiDialog.java index 155de0fb627..aa03c349f56 100644 --- a/src/main/java/forge/gui/GuiDialog.java +++ b/src/main/java/forge/gui/GuiDialog.java @@ -101,9 +101,9 @@ public class GuiDialog { // Play the Flip A Coin sound caller.getGame().fireEvent(new GameEventFlipCoin()); - - JOptionPane.showMessageDialog(null, source.getName() + " - " + caller + winMsg, source.getName(), - JOptionPane.PLAIN_MESSAGE); + + message(source.getName() + " - " + caller + winMsg, source.getName()); + return winFlip; } diff --git a/src/main/java/forge/gui/match/ViewWinLose.java b/src/main/java/forge/gui/match/ViewWinLose.java index 0b77481fed1..675e4873bee 100644 --- a/src/main/java/forge/gui/match/ViewWinLose.java +++ b/src/main/java/forge/gui/match/ViewWinLose.java @@ -198,8 +198,10 @@ public class ViewWinLose { nHumansInGame++; } LobbyPlayer winner = match.getLastGameOutcome().getWinner(); - String title = nHumansInGame == 1 ? "You " + (winner == guiPlayer ? "won!" : "lost!") : winner.getName() + " Won!"; - return title; + if ( winner == null ) + return "It's a draw!"; + + return nHumansInGame == 1 ? "You " + (winner == guiPlayer ? "won!" : "lost!") : winner.getName() + " Won!"; } /** @return {@link forge.gui.toolbox.FButton} */ diff --git a/src/main/java/forge/gui/match/controllers/CDock.java b/src/main/java/forge/gui/match/controllers/CDock.java index 5c736c2033d..bcd5d442f82 100644 --- a/src/main/java/forge/gui/match/controllers/CDock.java +++ b/src/main/java/forge/gui/match/controllers/CDock.java @@ -33,6 +33,7 @@ import forge.FThreads; import forge.Singletons; import forge.CardPredicates.Presets; import forge.Command; +import forge.control.FControl; import forge.deck.Deck; import forge.game.Game; import forge.game.phase.CombatUtil; @@ -80,23 +81,8 @@ public enum CDock implements ICDoc { if (FOverlay.SINGLETON_INSTANCE.getPanel().isShowing()) { return; } - - final Player p = findAffectedPlayer(); - if( p == null ) return; - if( p.isMindSlaved() ) { - GuiDialog.message("You cannot make concede a player you temporarily control"); - return; - } - - game.getAction().invoke(new Runnable() { - @Override - public void run() { - p.concede(); - p.getGame().getAction().checkStateEffects(); - } - }); - game = null; // no second entry possible; + Singletons.getControl().stopGame(); } /**