mirror of https://github.com/FreeCol/freecol.git
832 lines
26 KiB
Java
832 lines
26 KiB
Java
/**
|
|
* Copyright (C) 2002-2015 The FreeCol Team
|
|
*
|
|
* This file is part of FreeCol.
|
|
*
|
|
* FreeCol is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* FreeCol is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with FreeCol. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package net.sf.freecol.client;
|
|
|
|
import java.awt.Dimension;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import javax.swing.SwingUtilities;
|
|
|
|
import net.sf.freecol.FreeCol;
|
|
import net.sf.freecol.client.control.ConnectController;
|
|
import net.sf.freecol.client.control.InGameController;
|
|
import net.sf.freecol.client.control.InGameInputHandler;
|
|
import net.sf.freecol.client.control.MapEditorController;
|
|
import net.sf.freecol.client.control.PreGameController;
|
|
import net.sf.freecol.client.control.PreGameInputHandler;
|
|
import net.sf.freecol.client.control.SoundController;
|
|
import net.sf.freecol.client.gui.GUI;
|
|
import net.sf.freecol.client.gui.SwingGUI;
|
|
import net.sf.freecol.client.gui.action.ActionManager;
|
|
import net.sf.freecol.client.networking.UserServerAPI;
|
|
import net.sf.freecol.common.FreeColSeed;
|
|
import net.sf.freecol.common.debug.FreeColDebugger;
|
|
import net.sf.freecol.common.i18n.Messages;
|
|
import net.sf.freecol.common.io.FreeColDataFile;
|
|
import net.sf.freecol.common.io.FreeColDirectories;
|
|
import net.sf.freecol.common.io.FreeColModFile;
|
|
import net.sf.freecol.common.io.FreeColSavegameFile;
|
|
import net.sf.freecol.common.io.FreeColTcFile;
|
|
import net.sf.freecol.common.model.Colony;
|
|
import net.sf.freecol.common.model.Game;
|
|
import net.sf.freecol.common.model.Player;
|
|
import net.sf.freecol.common.model.Specification;
|
|
import net.sf.freecol.common.model.StringTemplate;
|
|
import net.sf.freecol.common.networking.ServerAPI;
|
|
import net.sf.freecol.common.resources.ResourceManager;
|
|
import net.sf.freecol.common.resources.ResourceMapping;
|
|
import net.sf.freecol.server.FreeColServer;
|
|
import net.sf.freecol.server.FreeColServer.GameState;
|
|
|
|
|
|
/**
|
|
* The main control class for the FreeCol client. This class both
|
|
* starts and keeps references to the GUI and the control objects.
|
|
*/
|
|
public final class FreeColClient {
|
|
|
|
private static final Logger logger = Logger.getLogger(FreeColClient.class.getName());
|
|
|
|
private final ConnectController connectController;
|
|
|
|
private final PreGameController preGameController;
|
|
|
|
private final PreGameInputHandler preGameInputHandler;
|
|
|
|
private final InGameController inGameController;
|
|
|
|
private final InGameInputHandler inGameInputHandler;
|
|
|
|
private final MapEditorController mapEditorController;
|
|
|
|
private SoundController soundController;
|
|
|
|
/** The server that has been started from the client-GUI. */
|
|
private FreeColServer freeColServer = null;
|
|
|
|
/** Encapsulation of the server API. */
|
|
private final ServerAPI serverAPI;
|
|
|
|
|
|
/** The GUI encapsulation. */
|
|
private final GUI gui;
|
|
|
|
/** The encapsulation of the actions. */
|
|
private final ActionManager actionManager;
|
|
|
|
/** The game itself. */
|
|
private Game game;
|
|
|
|
/** The player that `owns' this client. */
|
|
private Player player;
|
|
|
|
/** The client options specific to this player. */
|
|
private ClientOptions clientOptions;
|
|
|
|
/** A worker to perform game loading. */
|
|
private final Worker worker;
|
|
|
|
/**
|
|
* Indicates if the game has started, has nothing to do with
|
|
* whether or not the client is logged in.
|
|
*/
|
|
private boolean inGame = false;
|
|
|
|
/** Are we using the map editor? */
|
|
private boolean mapEditor;
|
|
|
|
/** Is this a single player game? */
|
|
private boolean singlePlayer;
|
|
|
|
/**
|
|
* Indicated whether or not there is an open connection to the
|
|
* server. This is not an indication of the existence of a
|
|
* Connection Object, but instead it is an indication of an
|
|
* approved login to a server.
|
|
*/
|
|
private boolean loggedIn = false;
|
|
|
|
/** Run in headless mode. */
|
|
private final boolean headless;
|
|
|
|
|
|
public FreeColClient(final InputStream splashStream,
|
|
final String fontName) {
|
|
this(splashStream, fontName, FreeCol.GUI_SCALE_DEFAULT, true);
|
|
}
|
|
|
|
/**
|
|
* Creates a new <code>FreeColClient</code>. Creates the control
|
|
* objects.
|
|
*
|
|
* @param splashStream A stream to read the splash image from.
|
|
* @param fontName An optional override of the main font.
|
|
* @param scale The scale factor for gui elements.
|
|
* @param headless Run in headless mode.
|
|
*/
|
|
public FreeColClient(final InputStream splashStream, final String fontName,
|
|
final float scale, boolean headless) {
|
|
mapEditor = false;
|
|
this.headless = headless
|
|
|| System.getProperty("java.awt.headless", "false").equals("true");
|
|
if (this.headless) {
|
|
if (!FreeColDebugger.isInDebugMode()
|
|
|| FreeColDebugger.getDebugRunTurns() <= 0) {
|
|
fatal(Messages.message("client.headlessDebug"));
|
|
}
|
|
}
|
|
|
|
// Get the splash screen up early on to show activity.
|
|
gui = (this.headless) ? new GUI(this, scale)
|
|
: new SwingGUI(this, scale);
|
|
gui.displaySplashScreen(splashStream);
|
|
|
|
// Look for base data directory. Failure is fatal.
|
|
File baseDirectory = FreeColDirectories.getBaseDirectory();
|
|
FreeColDataFile baseData = null;
|
|
String ioeMessage = null;
|
|
if (baseDirectory.exists() && baseDirectory.isDirectory()) {
|
|
try {
|
|
baseData = new FreeColDataFile(baseDirectory);
|
|
} catch (IOException ioe) {
|
|
ioeMessage = ioe.getMessage();
|
|
}
|
|
}
|
|
if (baseData == null) {
|
|
fatal(Messages.message(StringTemplate.template("client.baseData")
|
|
.addName("%dir%", baseDirectory.getName()))
|
|
+ ((ioeMessage == null) ? "" : "\n" + ioeMessage));
|
|
}
|
|
ResourceManager.setBaseMapping(baseData.getResourceMapping());
|
|
|
|
// Once the basic resources are in place construct other things.
|
|
|
|
serverAPI = new UserServerAPI(gui);
|
|
|
|
// Control. Controllers expect GUI to be available.
|
|
connectController = new ConnectController(this);
|
|
preGameController = new PreGameController(this);
|
|
preGameInputHandler = new PreGameInputHandler(this);
|
|
inGameController = new InGameController(this);
|
|
inGameInputHandler = new InGameInputHandler(this);
|
|
mapEditorController = new MapEditorController(this);
|
|
|
|
worker = new Worker();
|
|
worker.start();
|
|
|
|
// Load resources.
|
|
// - base resources
|
|
// - resources in the default "classic" ruleset,
|
|
// - resources in the default actions
|
|
//
|
|
// FIXME: probably should not need to load "classic", but there
|
|
// are a bunch of things in there (e.g. order buttons) that first
|
|
// need to move to base because the action manager requires them.
|
|
//
|
|
// Not so easy, since the ActionManager also creates tile
|
|
// improvement actions, which depend on the
|
|
// specification. However, this step could probably be
|
|
// delayed.
|
|
try {
|
|
FreeColTcFile tcData = new FreeColTcFile("classic");
|
|
ResourceManager.setTcMapping(tcData.getResourceMapping());
|
|
} catch (IOException e) {
|
|
fatal(Messages.message("client.classic") + "\n" + e.getMessage());
|
|
}
|
|
|
|
if (!this.headless) {
|
|
// Swing system and look-and-feel initialization.
|
|
try {
|
|
gui.installLookAndFeel(fontName);
|
|
} catch (Exception e) {
|
|
fatal(Messages.message("client.laf") + "\n" + e.getMessage());
|
|
}
|
|
}
|
|
actionManager = new ActionManager(this);
|
|
actionManager.initializeActions(inGameController, connectController);
|
|
}
|
|
|
|
/**
|
|
* Starts the new <code>FreeColClient</code>, including the GUI.
|
|
*
|
|
* @param size An optional window size.
|
|
* @param userMsg An optional message key to be displayed early.
|
|
* @param sound True if sounds should be played
|
|
* @param showOpeningVideo Display the opening video.
|
|
* @param savedGame An optional saved game.
|
|
* @param spec If non-null, a <code>Specification</code> to use to start
|
|
* a new game immediately.
|
|
*/
|
|
public void startClient(final Dimension size,
|
|
final String userMsg,
|
|
final boolean sound,
|
|
final boolean showOpeningVideo,
|
|
final File savedGame,
|
|
final Specification spec) {
|
|
if (headless && savedGame == null && spec == null) {
|
|
fatal(Messages.message("client.headlessRequires"));
|
|
}
|
|
|
|
// Load the client options, which handle reloading the
|
|
// resources specified in the active mods.
|
|
this.clientOptions = loadClientOptions(savedGame);
|
|
this.clientOptions.fixClientOptions();
|
|
|
|
// Reset the mod resources as a result of the client option update.
|
|
ResourceMapping modMappings = new ResourceMapping();
|
|
for (FreeColModFile f : this.clientOptions.getActiveMods()) {
|
|
modMappings.addAll(f.getResourceMapping());
|
|
}
|
|
ResourceManager.setModMapping(modMappings);
|
|
// Update the actions, resources may have changed.
|
|
if (this.actionManager != null) updateActions();
|
|
|
|
// Initialize Sound (depends on client options)
|
|
this.soundController = new SoundController(this, sound);
|
|
|
|
// Start the GUI (headless-safe)
|
|
gui.hideSplashScreen();
|
|
gui.startGUI(size);
|
|
|
|
// Now the GUI is going, either:
|
|
// - load the saved game if one was supplied
|
|
// - use the debug shortcut to immediately start a new game with
|
|
// supplied specification
|
|
// - display the opening video (which goes on to display the
|
|
// main panel when it completes)
|
|
// - display the main panel and let the user choose what to
|
|
// do (which will often be to progress through the
|
|
// NewPanel to a call to the connect controller to start a game)
|
|
if (savedGame != null) {
|
|
soundController.playSound("sound.intro.general");
|
|
SwingUtilities.invokeLater(() -> {
|
|
if (!connectController.startSavedGame(savedGame, userMsg)) {
|
|
gui.showMainPanel(userMsg);
|
|
}
|
|
});
|
|
} else if (spec != null) { // Debug or fast start
|
|
soundController.playSound("sound.intro.general");
|
|
SwingUtilities.invokeLater(() -> {
|
|
if (!connectController.startSinglePlayerGame(spec, true)) {
|
|
gui.showMainPanel(userMsg);
|
|
}
|
|
});
|
|
} else if (showOpeningVideo) {
|
|
SwingUtilities.invokeLater(() -> {
|
|
gui.showOpeningVideo(userMsg);
|
|
});
|
|
} else {
|
|
soundController.playSound("sound.intro.general");
|
|
SwingUtilities.invokeLater(() -> {
|
|
gui.showMainPanel(userMsg);
|
|
});
|
|
}
|
|
|
|
String quit = FreeCol.CLIENT_THREAD + "Quit Game";
|
|
Runtime.getRuntime().addShutdownHook(new Thread(quit) {
|
|
@Override
|
|
public void run() {
|
|
getConnectController().quitGame(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Loads the client options.
|
|
* There are several sources:
|
|
* 1) Base options (data/base/client-options.xml)
|
|
* 2) Standard action manager actions
|
|
* 3) Saved game
|
|
* 4) User options
|
|
*
|
|
* The base and action manager options are definitive, so they can
|
|
* just be added/loaded. The others are from sources that may be
|
|
* out of date (i.e. options can be in the wrong group, or no longer
|
|
* exist), so they must be merged cautiously.
|
|
*
|
|
* @param savedGameFile An optional saved game <code>File</code>
|
|
* to load options from.
|
|
* @return The loaded <code>ClientOptions</code>.
|
|
*/
|
|
private ClientOptions loadClientOptions(File savedGameFile) {
|
|
ClientOptions clop = new ClientOptions();
|
|
logger.info("Load default client options.");
|
|
clop.load(FreeColDirectories.getBaseClientOptionsFile());
|
|
|
|
if (actionManager != null) {
|
|
logger.info("Load client options from the action manager.");
|
|
clop.add(actionManager);
|
|
}
|
|
|
|
if (savedGameFile != null) {
|
|
try {
|
|
FreeColSavegameFile fcsf
|
|
= new FreeColSavegameFile(savedGameFile);
|
|
logger.info("Merge client options from saved game: "
|
|
+ savedGameFile.getPath());
|
|
clop.merge(fcsf);
|
|
} catch (IOException ioe) {
|
|
logger.log(Level.WARNING, "Could not open saved game "
|
|
+ savedGameFile.getPath(), ioe);
|
|
}
|
|
}
|
|
|
|
final File userOptions = FreeColDirectories.getClientOptionsFile();
|
|
if (userOptions != null && userOptions.exists()) {
|
|
logger.info("Merge client options from user options file: "
|
|
+ userOptions.getPath());
|
|
clop.merge(userOptions);
|
|
}
|
|
|
|
//logger.info("Final client options: " + clop.toString());
|
|
return clop;
|
|
}
|
|
|
|
/**
|
|
* Quit and exit with an error.
|
|
*
|
|
* @param err The error message.
|
|
*/
|
|
public static void fatal(String err) {
|
|
logger.log(Level.SEVERE, err);
|
|
FreeCol.fatal(err);
|
|
}
|
|
|
|
|
|
// Accessors
|
|
|
|
/**
|
|
* Gets the controller responsible for starting a server and
|
|
* connecting to it.
|
|
*
|
|
* @return The <code>ConnectController</code>.
|
|
*/
|
|
public ConnectController getConnectController() {
|
|
return connectController;
|
|
}
|
|
|
|
/**
|
|
* Gets the controller that will be used before the game has been started.
|
|
*
|
|
* @return The <code>PreGameController</code>.
|
|
*/
|
|
public PreGameController getPreGameController() {
|
|
return preGameController;
|
|
}
|
|
|
|
/**
|
|
* Gets the input handler that will be used before the game has been
|
|
* started.
|
|
*
|
|
* @return The <code>PreGameInputHandler</code>.
|
|
*/
|
|
public PreGameInputHandler getPreGameInputHandler() {
|
|
return preGameInputHandler;
|
|
}
|
|
|
|
/**
|
|
* Gets the controller that will be used when the game has been started.
|
|
*
|
|
* @return The <code>InGameController</code>.
|
|
*/
|
|
public InGameController getInGameController() {
|
|
return inGameController;
|
|
}
|
|
|
|
/**
|
|
* Gets the input handler that will be used when the game has been started.
|
|
*
|
|
* @return The <code>InGameInputHandler</code>.
|
|
*/
|
|
public InGameInputHandler getInGameInputHandler() {
|
|
return inGameInputHandler;
|
|
}
|
|
|
|
/**
|
|
* Gets the controller for the map editor, if we are in the map editor.
|
|
*
|
|
* @return The map editor controller, if any.
|
|
*/
|
|
public MapEditorController getMapEditorController() {
|
|
return mapEditorController;
|
|
}
|
|
|
|
/**
|
|
* Gets the controller for the sound.
|
|
*
|
|
* @return The sound controller, if any.
|
|
*/
|
|
public SoundController getSoundController() {
|
|
return soundController;
|
|
}
|
|
|
|
/**
|
|
* Gets the <code>FreeColServer</code> started by the client.
|
|
*
|
|
* @return The <code>FreeColServer</code> or <code>null</code> if no
|
|
* server has been started.
|
|
*/
|
|
public FreeColServer getFreeColServer() {
|
|
return freeColServer;
|
|
}
|
|
|
|
/**
|
|
* Sets the <code>FreeColServer</code> which has been started by the
|
|
* client gui.
|
|
*
|
|
* @param freeColServer The <code>FreeColServer</code>.
|
|
* @see #getFreeColServer()
|
|
*/
|
|
public void setFreeColServer(FreeColServer freeColServer) {
|
|
this.freeColServer = freeColServer;
|
|
}
|
|
|
|
/**
|
|
* Meaningfully named access to the ServerAPI.
|
|
*
|
|
* @return A ServerAPI.
|
|
*/
|
|
public ServerAPI askServer() {
|
|
return serverAPI;
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets the GUI attached to this client.
|
|
*
|
|
* @return The current <code>GUI</code>.
|
|
*/
|
|
public GUI getGUI() {
|
|
return gui;
|
|
}
|
|
|
|
/**
|
|
* Gets the action manager.
|
|
*
|
|
* @return The action manager.
|
|
*/
|
|
public ActionManager getActionManager() {
|
|
return actionManager;
|
|
}
|
|
|
|
/**
|
|
* Gets the <code>Game</code> that we are currently playing.
|
|
*
|
|
* @return The current <code>Game</code>.
|
|
* @see #setGame
|
|
*/
|
|
public Game getGame() {
|
|
return game;
|
|
}
|
|
|
|
/**
|
|
* Sets the <code>Game</code> that we are currently playing.
|
|
*
|
|
* @param game The new <code>Game</code>.
|
|
* @see #getGame
|
|
*/
|
|
public void setGame(Game game) {
|
|
this.game = game;
|
|
}
|
|
|
|
/**
|
|
* Gets the <code>Player</code> that uses this client.
|
|
*
|
|
* @return The <code>Player</code> made to represent this clients user.
|
|
* @see #setMyPlayer(Player)
|
|
*/
|
|
public Player getMyPlayer() {
|
|
return player;
|
|
}
|
|
|
|
/**
|
|
* Sets the <code>Player</code> that uses this client.
|
|
*
|
|
* @param player The <code>Player</code> made to represent this clients
|
|
* user.
|
|
* @see #getMyPlayer()
|
|
*/
|
|
public void setMyPlayer(Player player) {
|
|
this.player = player;
|
|
}
|
|
|
|
/**
|
|
* Gets the object keeping the current client options.
|
|
*
|
|
* @return The <code>ClientOptions</code> attached to this
|
|
* <code>FreeColClient</code>.
|
|
*/
|
|
public ClientOptions getClientOptions() {
|
|
return clientOptions;
|
|
}
|
|
|
|
/**
|
|
* Convenience accessor for checking whether to display tutorial messages.
|
|
*
|
|
* @return True if tutorial messages should be displayed.
|
|
*/
|
|
public boolean tutorialMode() {
|
|
return getClientOptions().getBoolean("model.option.guiShowTutorial");
|
|
}
|
|
|
|
/**
|
|
* Has the game started?
|
|
*
|
|
* @return <i>true</i> if the game has started.
|
|
* @see #setInGame
|
|
*/
|
|
public boolean isInGame() {
|
|
return inGame;
|
|
}
|
|
|
|
/**
|
|
* Set the game start state.
|
|
*
|
|
* @param inGame Whether or not the game has started.
|
|
*/
|
|
public void setInGame(boolean inGame) {
|
|
this.inGame = inGame;
|
|
}
|
|
|
|
/**
|
|
* Are we using the map editor?
|
|
*
|
|
* @return True if the map editor is enabled.
|
|
*/
|
|
public boolean isMapEditor() {
|
|
return mapEditor;
|
|
}
|
|
|
|
/**
|
|
* Sets the map editor state.
|
|
*
|
|
* @param mapEditor True if the map editor is enabled.
|
|
*/
|
|
public void setMapEditor(boolean mapEditor) {
|
|
this.mapEditor = mapEditor;
|
|
}
|
|
|
|
/**
|
|
* Is the user playing in single player mode?
|
|
*
|
|
* @return True if the user is playing in single player mode.
|
|
* @see #setSinglePlayer
|
|
*/
|
|
public boolean isSinglePlayer() {
|
|
return singlePlayer;
|
|
}
|
|
|
|
/**
|
|
* Sets whether or not this game is a single player game.
|
|
*
|
|
* @param singlePlayer Whether or not this game is a single player game.
|
|
* @see #isSinglePlayer
|
|
*/
|
|
public void setSinglePlayer(boolean singlePlayer) {
|
|
this.singlePlayer = singlePlayer;
|
|
}
|
|
|
|
/**
|
|
* Is this client logged in to a server?
|
|
*
|
|
* @return True if this client is logged in to a server.
|
|
*/
|
|
public boolean isLoggedIn() {
|
|
return loggedIn;
|
|
}
|
|
|
|
/**
|
|
* Sets whether or not this client is logged in to a server.
|
|
*
|
|
* @param loggedIn Whether or not this client is logged in to a server.
|
|
*/
|
|
public void setLoggedIn(boolean loggedIn) {
|
|
this.loggedIn = loggedIn;
|
|
}
|
|
|
|
/**
|
|
* Is the game in headless mode?
|
|
*
|
|
* @return a <code>boolean</code> value
|
|
*/
|
|
public boolean isHeadless() {
|
|
return headless;
|
|
}
|
|
|
|
|
|
// Utilities
|
|
|
|
/**
|
|
* Updates the game actions. Generally useful when menu actions
|
|
* should change due to the current game context.
|
|
*/
|
|
public void updateActions() {
|
|
actionManager.update();
|
|
}
|
|
|
|
/**
|
|
* Sets the actions derived from the specification.
|
|
*
|
|
* @param specification The <code>Specification</code> to use.
|
|
*/
|
|
public void addSpecificationActions(Specification specification) {
|
|
actionManager.addSpecificationActions(specification);
|
|
}
|
|
|
|
|
|
/**
|
|
* Checks if this client is the game admin.
|
|
*
|
|
* @return True if the client is the game admin and the game has begun.
|
|
*/
|
|
public boolean isAdmin() {
|
|
return player != null && player.isAdmin();
|
|
}
|
|
|
|
/**
|
|
* Verifies if this client can save the current game
|
|
*
|
|
* Clients that do not have the server running, or that have not
|
|
* the required permissions cannot save and should have the menu
|
|
* entry disabled
|
|
*
|
|
* @return True if this client can save the game in progress.
|
|
*/
|
|
public boolean canSaveCurrentGame() {
|
|
return freeColServer != null
|
|
&& (isAdmin() || freeColServer.getGameState() != GameState.IN_GAME);
|
|
}
|
|
|
|
/**
|
|
* Is the current player the client owner player?
|
|
*
|
|
* @return True if the current player is owned by this client.
|
|
*/
|
|
public boolean currentPlayerIsMyPlayer() {
|
|
return inGame
|
|
&& game != null
|
|
&& player != null
|
|
&& player.equals(game.getCurrentPlayer());
|
|
}
|
|
|
|
/**
|
|
* Common utility routine to retrieve animation speed.
|
|
*
|
|
* @param player The <code>Player</code> to be animated.
|
|
* @return The animation speed.
|
|
*/
|
|
public int getAnimationSpeed(Player player) {
|
|
String key = (getMyPlayer() == player)
|
|
? ClientOptions.MOVE_ANIMATION_SPEED
|
|
: ClientOptions.ENEMY_MOVE_ANIMATION_SPEED;
|
|
return getClientOptions().getInteger(key);
|
|
}
|
|
|
|
/**
|
|
* Get a list of the player colonies.
|
|
*
|
|
* @return The players colonies sorted according to the chosen comparator.
|
|
*/
|
|
public List<Colony> getMySortedColonies() {
|
|
return (clientOptions == null || player == null)
|
|
? Collections.<Colony>emptyList()
|
|
: clientOptions.getSortedColonies(player);
|
|
}
|
|
|
|
/**
|
|
* Give the worker some work.
|
|
*
|
|
* @param runnable The <code>Runnable</code> to do.
|
|
*/
|
|
public void setWork(Runnable runnable) {
|
|
worker.schedule(runnable);
|
|
}
|
|
|
|
// Fundamental game start/stop/continue actions
|
|
|
|
/**
|
|
* If currently in a game, displays a quit dialog and if desired,
|
|
* logs out of the current game.
|
|
*
|
|
* When the game is clear, show the new game panel.
|
|
*
|
|
* Called from the New action, often from the button on the MainPanel,
|
|
* and IGC.victory()
|
|
*
|
|
* @param prompt If true, prompt to confirm stopping the game.
|
|
*/
|
|
public void newGame(boolean prompt) {
|
|
Specification specification = null;
|
|
if (getGame() != null) {
|
|
if (isMapEditor()) {
|
|
specification = getGame().getSpecification();
|
|
} else if (!prompt || gui.confirmStopGame()) {
|
|
getConnectController().quitGame(true);
|
|
FreeColSeed.incrementFreeColSeed();
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
gui.removeInGameComponents();
|
|
gui.showNewPanel(specification);
|
|
}
|
|
|
|
/**
|
|
* Continue playing after winning the game.
|
|
*/
|
|
public void continuePlaying() {
|
|
askServer().continuePlaying();
|
|
}
|
|
|
|
/**
|
|
* Start the game skipping turns.
|
|
*
|
|
* @param turns The number of turns to skip.
|
|
*/
|
|
public void skipTurns(int turns) {
|
|
if (freeColServer == null) return;
|
|
if (turns <= 0) {
|
|
freeColServer.getInGameController().setSkippedTurns(0);
|
|
return;
|
|
}
|
|
gui.closeMenus();
|
|
freeColServer.getInGameController().setSkippedTurns(turns);
|
|
askServer().startSkipping();
|
|
}
|
|
|
|
/**
|
|
* Quits the application.
|
|
*/
|
|
public void askToQuit() {
|
|
if (gui.confirm("quitDialog.areYouSure.text", "ok", "cancel")) quit();
|
|
}
|
|
|
|
/**
|
|
* Retire from the game.
|
|
*/
|
|
public void retire() {
|
|
if (gui.confirm("retireDialog.areYouSure.text", "ok", "cancel")) {
|
|
Player player = getMyPlayer();
|
|
player.changePlayerType(Player.PlayerType.RETIRED);
|
|
askServer().retire();
|
|
gui.showHighScoresPanel(null, askServer().getHighScores());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Quits the application without any questions.
|
|
*/
|
|
public void quit() {
|
|
getConnectController().quitGame(isSinglePlayer());
|
|
try { // delete outdated autosave files
|
|
long validPeriod = 1000L * 24L * 60L * 60L // days to ms
|
|
* clientOptions.getInteger(ClientOptions.AUTOSAVE_VALIDITY);
|
|
long timeNow = System.currentTimeMillis();
|
|
File autoSave = FreeColDirectories.getAutosaveDirectory();
|
|
String[] flist;
|
|
if (validPeriod != 0L && autoSave != null
|
|
&& (flist = autoSave.list()) != null) {
|
|
for (String f : flist) {
|
|
if (!f.endsWith("." + FreeCol.FREECOL_SAVE_EXTENSION)) continue;
|
|
// delete files which are older than user option allows
|
|
File saveGameFile = new File(autoSave, f);
|
|
if (saveGameFile.lastModified() + validPeriod < timeNow) {
|
|
saveGameFile.delete();
|
|
}
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
logger.log(Level.WARNING, "Failed to delete autosave", e);
|
|
}
|
|
try {
|
|
gui.quit();
|
|
} catch (Exception e) {
|
|
System.exit(1);
|
|
}
|
|
System.exit(0);
|
|
}
|
|
}
|