mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
A slow-down to AI vs AI games (not finished yet),
Closing the window during AI vs AI match leads to a draw
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -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
|
||||
|
||||
@@ -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();
|
||||
@@ -351,6 +353,28 @@ public enum FControl {
|
||||
return game;
|
||||
}
|
||||
|
||||
public final void stopGame() {
|
||||
List<Player> pp = new ArrayList<Player>();
|
||||
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() {
|
||||
return inputQueue;
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -26,16 +26,15 @@ import forge.gui.match.nonsingleton.VHand;
|
||||
import forge.gui.match.nonsingleton.VField.PhaseLabel;
|
||||
|
||||
public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
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,12 +49,10 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
PhaseLabel lbl = matchUi.getFieldViewFor(p).getLabelFor(ph);
|
||||
|
||||
matchUi.resetAllPhaseButtons();
|
||||
if (lbl != null) {
|
||||
lbl.setActive(true);
|
||||
}
|
||||
|
||||
|
||||
if (lbl != null) lbl.setActive(true);
|
||||
} });
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -99,6 +96,4 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
} });
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
100
src/main/java/forge/control/FControlGamePlayback.java
Normal file
100
src/main/java/forge/control/FControlGamePlayback.java
Normal file
@@ -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<Void> {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* checkEndGameSate.
|
||||
* </p>
|
||||
*
|
||||
* @return a boolean.
|
||||
*/
|
||||
private final GameEndReason checkEndGameState(final Game game) {
|
||||
|
||||
GameEndReason reason = null;
|
||||
// award loses as SBE
|
||||
List<Player> losers = null;
|
||||
for (Player p : game.getPlayers()) {
|
||||
if (p.checkLoseCondition()) { // this will set appropriate outcomes
|
||||
// Run triggers
|
||||
if (losers == null) {
|
||||
losers = new ArrayList<Player>(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<Player>(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<Player> losers = null;
|
||||
for (Player p : game.getPlayers()) {
|
||||
if (p.checkLoseCondition()) { // this will set appropriate outcomes
|
||||
// Run triggers
|
||||
if (losers == null) {
|
||||
losers = new ArrayList<Player>(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<Player>(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* destroyPlaneswalkers.
|
||||
@@ -1475,28 +1472,50 @@ public class GameAction {
|
||||
}
|
||||
}
|
||||
|
||||
public void startGame(final Player firstPlayer) {
|
||||
Player first = firstPlayer;
|
||||
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());
|
||||
|
||||
do {
|
||||
if ( game.isGameOver() ) break; // conceded during "play or draw"
|
||||
|
||||
// Draw <handsize> 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);
|
||||
for (final Player p1 : game.getPlayers())
|
||||
p1.drawCards(p1.getMaxHandSize());
|
||||
|
||||
performMulligans(first, game.getType() == GameType.Commander);
|
||||
|
||||
if ( game.isGameOver() ) break; // conceded during "mulligan" prompt
|
||||
|
||||
// should I restore everyting exiled by Karn here, or before Mulligans is fine?
|
||||
|
||||
game.setAge(GameAge.Play);
|
||||
|
||||
// THIS CODE WILL WORK WITH PHASE = NULL {
|
||||
if(game.getType() == GameType.Planechase)
|
||||
firstPlayer.initPlane();
|
||||
first.initPlane();
|
||||
|
||||
handleLeylinesAndChancellors();
|
||||
checkStateEffects();
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
26
src/main/java/forge/game/event/GameEventGameStarted.java
Normal file
26
src/main/java/forge/game/event/GameEventGameStarted.java
Normal file
@@ -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<Player> players;
|
||||
|
||||
public GameEventGameStarted(Player firstTurn, Iterable<Player> players) {
|
||||
super();
|
||||
this.firstTurn = firstTurn;
|
||||
this.players = players;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,6 +20,7 @@ public interface IGameEventVisitor<T> {
|
||||
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<T> {
|
||||
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<T> {
|
||||
public T visit(GameEventPlayerDamaged event) { return null; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -714,14 +714,14 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
||||
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)) {
|
||||
if (game.getStack().isEmpty()) {
|
||||
|
||||
@@ -2066,7 +2066,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
* Concede.
|
||||
*/
|
||||
public final void concede() { // No cantLose checks - just lose
|
||||
FThreads.assertExecutedByEdt(false);
|
||||
setOutcome(PlayerOutcome.concede());
|
||||
}
|
||||
|
||||
@@ -2705,6 +2704,10 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return getController().getLobbyPlayer();
|
||||
}
|
||||
|
||||
public final LobbyPlayer getOriginalLobbyPlayer() {
|
||||
return controllerCreator.getLobbyPlayer();
|
||||
}
|
||||
|
||||
public final boolean isMindSlaved() {
|
||||
return controller.getLobbyPlayer() != controllerCreator.getLobbyPlayer();
|
||||
}
|
||||
|
||||
@@ -102,8 +102,8 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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} */
|
||||
|
||||
@@ -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;
|
||||
@@ -81,22 +82,7 @@ public enum CDock implements ICDoc {
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user