Index: ps/trunk/binaries/data/mods/public/gui/session/DiplomacyColors.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/DiplomacyColors.js +++ ps/trunk/binaries/data/mods/public/gui/session/DiplomacyColors.js @@ -12,9 +12,18 @@ // The array of displayed player colors (either the diplomacy color or regular color for each player). this.displayedPlayerColors = undefined; + + this.diplomacyColorsChangeHandlers = []; + + registerPlayersInitHandler(this.onPlayersInit.bind(this)); + } + + registerDiplomacyColorsChangeHandler(handler) + { + this.diplomacyColorsChangeHandlers.push(handler); } - onPlayerInit() + onPlayersInit() { this.computeTeamColors(); } @@ -61,7 +70,8 @@ "selected": g_Selection.toList() }); - updateGUIObjects(); + for (let handler of this.diplomacyColorsChangeHandlers) + handler(this.enabled); } computeTeamColors() Index: ps/trunk/binaries/data/mods/public/gui/session/GameSpeedControl.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/GameSpeedControl.js +++ ps/trunk/binaries/data/mods/public/gui/session/GameSpeedControl.js @@ -0,0 +1,45 @@ +/** + * This class controls the gamespeed. + * The control is only available in singleplayer and replaymode. + * Fast forwarding is enabled if and only if there is no human player assigned. + */ +class GameSpeedControl +{ + constructor(playerViewControl) + { + this.gameSpeed = Engine.GetGUIObjectByName("gameSpeed"); + this.gameSpeed.onSelectionChange = this.onSelectionChange.bind(this); + + registerPlayersInitHandler(this.rebuild.bind(this)); + registerPlayersFinishedHandler(this.rebuild.bind(this)); + playerViewControl.registerPlayerIDChangeHandler(this.rebuild.bind(this)); + } + + rebuild() + { + let player = g_Players[Engine.GetPlayerID()]; + + let gameSpeeds = prepareForDropdown(g_Settings.GameSpeeds.filter(speed => + !speed.FastForward || !player || player.state != "active")); + + this.gameSpeed.list = gameSpeeds.Title; + this.gameSpeed.list_data = gameSpeeds.Speed; + + let simRate = Engine.GetSimRate(); + + // If the gamespeed is something like 0.100001 from the gamesetup, set it to 0.1 + let gameSpeedIdx = gameSpeeds.Speed.indexOf(+simRate.toFixed(2)); + this.gameSpeed.selected = gameSpeedIdx != -1 ? gameSpeedIdx : gameSpeeds.Default; + } + + toggle() + { + this.gameSpeed.hidden = !this.gameSpeed.hidden; + } + + onSelectionChange() + { + if (!g_IsNetworked) + Engine.SetSimRate(+this.gameSpeed.list_data[this.gameSpeed.selected]); + } +} Index: ps/trunk/binaries/data/mods/public/gui/session/GameSpeedControl.xml =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/GameSpeedControl.xml +++ ps/trunk/binaries/data/mods/public/gui/session/GameSpeedControl.xml @@ -0,0 +1,12 @@ + + Index: ps/trunk/binaries/data/mods/public/gui/session/PauseControl.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/PauseControl.js +++ ps/trunk/binaries/data/mods/public/gui/session/PauseControl.js @@ -0,0 +1,86 @@ +/** + * Controller to pause or resume the game and remember which players paused the game. + * + * If the current player ordered a pause manually, it is called explicit pause. + * If the player opened a dialog in singleplayer mode, the game is paused implicitly. + */ +class PauseControl +{ + constructor() + { + /** + * This is true if the current player has paused the game using the pause button or hotkey. + * The game may also be paused without this being true in singleplayermode when opening a dialog. + */ + this.explicitPause = false; + + /** + * List of GUIDs of players who have currently paused the game, if the game is networked. + */ + this.pausingClients = []; + + /** + * Event handlers called when anyone paused. + */ + this.pauseHandlers = []; + } + + registerPauseHandler(handler) + { + this.pauseHandlers.push(handler); + } + + callPauseHandlers() + { + for (let handler of this.pauseHandlers) + handler(); + } + + /** + * Called from UI dialogs, but only in singleplayermode. + */ + implicitPause() + { + this.setPaused(true, false); + } + + implicitResume() + { + this.setPaused(false, false); + } + + setPaused(pause, explicit) + { + // Don't pause the game in multiplayer mode when opening dialogs. + // The NetServer only supports pausing after all clients finished loading the game. + if (g_IsNetworked && (!explicit || !g_IsNetworkedActive)) + return; + + if (explicit) + this.explicitPause = pause; + + // If explicit, send network message informing other clients + Engine.SetPaused(this.explicitPause || pause || g_Disconnected, explicit); + + if (g_IsNetworked) + this.setClientPauseState(Engine.GetPlayerGUID(), this.explicitPause); + else + this.callPauseHandlers(); + } + + /** + * Called when a client pauses or resumes in a multiplayer game. + */ + setClientPauseState(guid, paused) + { + // Update the list of pausing clients. + let index = this.pausingClients.indexOf(guid); + if (paused && index == -1) + this.pausingClients.push(guid); + else if (!paused && index != -1) + this.pausingClients.splice(index, 1); + + Engine.SetPaused(!!this.pausingClients.length, false); + this.callPauseHandlers(); + } +} Index: ps/trunk/binaries/data/mods/public/gui/session/PauseOverlay.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/PauseOverlay.js +++ ps/trunk/binaries/data/mods/public/gui/session/PauseOverlay.js @@ -0,0 +1,44 @@ +/** + * Displays an overlay while any player pauses the game. + * Indicates which players have paused. + */ +class PauseOverlay +{ + constructor(pauseControl) + { + this.pauseControl = pauseControl; + + this.pausedByText = Engine.GetGUIObjectByName("pausedByText"); + this.pausedByText.hidden = !g_IsNetworked; + + this.pauseOverlay = Engine.GetGUIObjectByName("pauseOverlay"); + this.pauseOverlay.onPress = this.onPress.bind(this); + + this.resumeMessage = Engine.GetGUIObjectByName("resumeMessage"); + + pauseControl.registerPauseHandler(this.onPauseChange.bind(this)); + } + + onPress() + { + if (this.pauseControl.explicitPause) + this.pauseControl.setPaused(false, true); + } + + onPauseChange() + { + let hidden = !this.pauseControl.explicitPause && !this.pauseControl.pausingClients.length; + this.pauseOverlay.hidden = hidden; + if (hidden) + return; + + this.resumeMessage.hidden = !this.pauseControl.explicitPause; + + this.pausedByText.caption = sprintf(translate(this.PausedByCaption), { + "players": this.pauseControl.pausingClients.map(guid => + colorizePlayernameByGUID(guid)).join(translateWithContext("Separator for a list of players", ", ")) + }); + } +} + +PauseOverlay.prototype.PausedByCaption = markForTranslation("Paused by %(players)s"); Index: ps/trunk/binaries/data/mods/public/gui/session/PauseOverlay.xml =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/PauseOverlay.xml +++ ps/trunk/binaries/data/mods/public/gui/session/PauseOverlay.xml @@ -0,0 +1,16 @@ + +