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 @@
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/TopPanel.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/TopPanel.js
+++ ps/trunk/binaries/data/mods/public/gui/session/TopPanel.js
@@ -0,0 +1,19 @@
+/**
+ * This class owns all classes that are part of the top panel.
+ */
+class TopPanel
+{
+ constructor(playerViewControl, diplomacyDialog, tradeDialog, objectivesDialog, gameSpeedControl)
+ {
+ this.counterManager = new CounterManager(playerViewControl);
+ this.civIcon = new CivIcon(playerViewControl);
+ this.buildLabel = new BuildLabel(playerViewControl);
+
+ this.followPlayer = new FollowPlayer(playerViewControl);
+
+ this.diplomacyDialogButton = new DiplomacyDialogButton(playerViewControl, diplomacyDialog);
+ this.gameSpeedButton = new GameSpeedButton(gameSpeedControl);
+ this.objectivesDialogButton = new ObjectivesDialogButton(objectivesDialog);
+ this.tradeDialogButton = new TradeDialogButton(playerViewControl, tradeDialog);
+ }
+}
Index: ps/trunk/binaries/data/mods/public/gui/session/TopPanel.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/TopPanel.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/TopPanel.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/chat/Chat.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/chat/Chat.js
+++ ps/trunk/binaries/data/mods/public/gui/session/chat/Chat.js
@@ -4,7 +4,7 @@
*/
class Chat
{
- constructor()
+ constructor(playerViewControl)
{
this.ChatWindow = new ChatWindow();
this.ChatOverlay = new ChatOverlay();
@@ -35,6 +35,9 @@
this.ChatHistory.displayChatHistory();
});
+ registerPlayersFinishedHandler(this.onUpdatePlayers.bind(this));
+ playerViewControl.registerViewedPlayerChangeHandler(this.onUpdatePlayers.bind(this));
+
Engine.SetGlobalHotkey("chat", this.openPage.bind(this));
Engine.SetGlobalHotkey("privatechat", this.openPage.bind(this));
Engine.SetGlobalHotkey("teamchat", () => { this.openPage(g_IsObserver ? "/observers" : "/allies"); });
Index: ps/trunk/binaries/data/mods/public/gui/session/chat/ChatWindow.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/chat/ChatWindow.js
+++ ps/trunk/binaries/data/mods/public/gui/session/chat/ChatWindow.js
@@ -35,6 +35,7 @@
this.extendedChat.checked = Engine.ConfigDB_GetValue("user", "chat.session.extended") == "true";
+ this.chatDialogPanel.onWindowResized = this.resizeChatWindow.bind(this);
this.resizeChatWindow();
}
Index: ps/trunk/binaries/data/mods/public/gui/session/developer_overlay.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/developer_overlay.js
+++ ps/trunk/binaries/data/mods/public/gui/session/developer_overlay.js
@@ -1,13 +1,15 @@
-function DeveloperOverlay()
+function DeveloperOverlay(playerViewControl)
{
this.commandHeight = 20;
this.displayState = false;
this.timeWarp = false;
- this.changePerspective = false;
this.controlAll = false;
-
+ this.playerViewControl = playerViewControl;
Engine.GetGUIObjectByName("devCommandsOverlay").onPress = this.toggle;
this.layout();
+
+ registerSimulationUpdateHandler(this.update.bind(this));
+ registerEntitySelectionChangeHandler(this.update.bind(this));
}
DeveloperOverlay.prototype.getCommands = function() {
@@ -25,13 +27,14 @@
{
"label": translate("Change perspective"),
"onPress": checked => {
- this.setChangePerspective(checked);
+ this.playerViewControl.setChangePerspective(checked);
},
},
{
"label": translate("Display selection state"),
"onPress": checked => {
this.displayState = checked;
+ this.update();
},
},
{
@@ -173,19 +176,11 @@
DeveloperOverlay.prototype.updateValues = function()
{
- let commands = this.getCommands();
- for (let i = 0; i < commands.length; ++i)
- {
- let command = commands[i];
-
- let body = Engine.GetGUIObjectByName("dev_command[" + i + "]");
- if (body.hidden)
- continue;
-
+ this.getCommands().forEach((command, i) => {
let checkbox = Engine.GetGUIObjectByName("dev_command_checkbox[" + i + "]");
if (command.checked)
checkbox.checked = command.checked();
- }
+ });
};
DeveloperOverlay.prototype.toggle = function()
@@ -215,8 +210,15 @@
DeveloperOverlay.prototype.update = function()
{
+ let playerState = g_SimState.players[g_ViewedPlayer];
+ this.controlAll = playerState ? playerState.controlsAll : false;
+
this.updateValues();
+ this.updateEntityState();
+}
+DeveloperOverlay.prototype.updateEntityState = function()
+{
let debug = Engine.GetGUIObjectByName("debugEntityState");
if (!this.displayState)
@@ -252,19 +254,6 @@
return this.timeWarp;
};
-DeveloperOverlay.prototype.isChangePerspective = function() {
- return this.changePerspective;
-};
-
-DeveloperOverlay.prototype.setChangePerspective = function(value) {
- this.changePerspective = value;
- selectViewPlayer(g_ViewedPlayer);
-};
-
DeveloperOverlay.prototype.isControlAll = function() {
return this.controlAll;
};
-
-DeveloperOverlay.prototype.setControlAll = function(value) {
- this.controlAll = value;
-};
Index: ps/trunk/binaries/data/mods/public/gui/session/diplomacy/DiplomacyDialog.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/diplomacy/DiplomacyDialog.js
+++ ps/trunk/binaries/data/mods/public/gui/session/diplomacy/DiplomacyDialog.js
@@ -4,7 +4,7 @@
*/
class DiplomacyDialog
{
- constructor(diplomacyColors)
+ constructor(playerViewControl, diplomacyColors)
{
this.diplomacyDialogCeasefireCounter = new DiplomacyDialogCeasefireCounter();
this.diplomacyDialogColorsButton = new DiplomacyDialogColorsButton(diplomacyColors);
@@ -12,34 +12,40 @@
this.diplomacyDialogPanel = Engine.GetGUIObjectByName("diplomacyDialogPanel");
Engine.GetGUIObjectByName("diplomacyClose").onPress = this.close.bind(this);
+
+ registerPlayersInitHandler(this.onPlayersInit.bind(this));
+ registerSimulationUpdateHandler(this.onViewedPlayerChange.bind(this));
+ playerViewControl.registerViewedPlayerChangeHandler(this.updateIfOpen.bind(this));
}
- onPlayerInit()
+ onPlayersInit()
{
this.diplomacyDialogPlayerControlManager = new DiplomacyDialogPlayerControlManager();
this.resize();
}
+ onViewedPlayerChange()
+ {
+ if (g_ViewedPlayer >= 1)
+ this.updateIfOpen();
+ else
+ this.close();
+ }
+
onSpyResponse(notification, player)
{
this.diplomacyDialogPlayerControlManager.onSpyResponse(notification, player);
}
- update()
+ updateIfOpen()
{
- if (!this.isOpen())
- return;
-
- if (g_ViewedPlayer >= 1)
+ if (this.isOpen())
this.updatePanels();
- else
- this.close();
}
updatePanels()
{
this.diplomacyDialogCeasefireCounter.update();
- this.diplomacyDialogColorsButton.update();
this.diplomacyDialogPlayerControlManager.update();
}
Index: ps/trunk/binaries/data/mods/public/gui/session/diplomacy/DiplomacyDialogColorsButton.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/diplomacy/DiplomacyDialogColorsButton.js
+++ ps/trunk/binaries/data/mods/public/gui/session/diplomacy/DiplomacyDialogColorsButton.js
@@ -5,22 +5,25 @@
{
constructor(diplomacyColors)
{
- this.diplomacyColors = diplomacyColors;
-
this.diplomacyColorsWindowButton = Engine.GetGUIObjectByName("diplomacyColorsWindowButton");
this.diplomacyColorsWindowButtonIcon = Engine.GetGUIObjectByName("diplomacyColorsWindowButtonIcon");
this.diplomacyColorsWindowButton.onPress = diplomacyColors.toggle.bind(diplomacyColors);
+ registerHotkeyChangeHandler(this.onHotkeyChange.bind(this));
+ diplomacyColors.registerDiplomacyColorsChangeHandler(this.onDiplomacyColorsChange.bind(this))
}
- update()
+ onHotkeyChange()
{
this.diplomacyColorsWindowButton.tooltip =
colorizeHotkey("%(hotkey)s" + " ", "session.diplomacycolors") +
translate(this.Tooltip);
+ }
+ onDiplomacyColorsChange(enabled)
+ {
this.diplomacyColorsWindowButtonIcon.sprite =
"stretched:" +
- (this.diplomacyColors.isEnabled() ? this.SpriteEnabled : this.SpriteDisabled);
+ (enabled ? this.SpriteEnabled : this.SpriteDisabled);
}
}
Index: ps/trunk/binaries/data/mods/public/gui/session/hotkeys/misc.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/hotkeys/misc.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/hotkeys/misc.xml
@@ -39,10 +39,6 @@
-
- togglePause();
-
-
Engine.QuickSave(getSavedGameData());
Index: ps/trunk/binaries/data/mods/public/gui/session/menu.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/menu.js
+++ ps/trunk/binaries/data/mods/public/gui/session/menu.js
@@ -29,19 +29,21 @@
var g_IsMenuOpen = false;
-var g_IsObjectivesOpen = false;
-
/**
* Remember last viewed summary panel and charts.
*/
var g_SummarySelectedData;
-function initMenu()
+function initMenu(playerViewControl, pauseControl)
{
Engine.GetGUIObjectByName("menu").size = "100%-164 " + MENU_TOP + " 100% " + MENU_BOTTOM;
+ Engine.GetGUIObjectByName("lobbyButton").enabled = Engine.HasXmppClient();
+ playerViewControl.registerViewedPlayerChangeHandler(updateResignButton);
+ updatePauseButton();
+ pauseControl.registerPauseHandler(updatePauseButton);
// TODO: Atlas should pass g_GameAttributes.settings
- for (let button of ["menuExitButton", "summaryButton", "objectivesButton"])
+ for (let button of ["menuExitButton", "summaryButton"])
Engine.GetGUIObjectByName(button).enabled = !Engine.IsAtlasRunning();
}
@@ -81,6 +83,22 @@
g_IsMenuOpen = !g_IsMenuOpen;
}
+function updatePauseButton()
+{
+ let pauseButton = Engine.GetGUIObjectByName("pauseButton");
+ pauseButton.caption = g_PauseControl.explicitPause ? translate("Resume") : translate("Pause");
+ pauseButton.enabled = !g_IsObserver || !g_IsNetworked || g_IsController;
+ pauseButton.onPress = () => {
+ closeMenu();
+ g_PauseControl.setPaused(!g_PauseControl.explicitPause, true);
+ };
+}
+
+function updateResignButton()
+{
+ Engine.GetGUIObjectByName("menuResignButton").enabled = !g_IsObserver;
+}
+
function optionsMenuButton()
{
closeOpenDialogs();
@@ -104,26 +122,25 @@
function resignMenuButton()
{
closeOpenDialogs();
- pauseGame();
+ g_PauseControl.implicitPause();
messageBox(
400, 200,
translate("Are you sure you want to resign?"),
translate("Confirmation"),
[translate("No"), translate("Yes")],
- [resumeGame, resignGame]
- );
+ [resumeGame, resignGame]);
}
function exitMenuButton()
{
closeOpenDialogs();
- pauseGame();
+ g_PauseControl.implicitPause();
let messageTypes = {
"host": {
"caption": translate("Are you sure you want to quit? Leaving will disconnect all other players."),
- "buttons": [resumeGame, leaveGame]
+ "buttons": [resumeGame, endGame]
},
"client": {
"caption": translate("Are you sure you want to quit?"),
@@ -131,7 +148,7 @@
},
"singleplayer": {
"caption": translate("Are you sure you want to quit?"),
- "buttons": [resumeGame, leaveGame]
+ "buttons": [resumeGame, endGame]
}
};
@@ -154,14 +171,13 @@
translate("Do you want to resign or will you return soon?"),
translate("Confirmation"),
[translate("I will return"), translate("I resign")],
- [leaveGame, resignGame],
- [true, false]
- );
+ [endGame, resignGame]);
}
function openDeleteDialog(selection)
{
closeOpenDialogs();
+ g_PauseControl.implicitPause();
let deleteSelectedEntities = function(selectionArg)
{
@@ -169,6 +185,7 @@
"type": "delete-entities",
"entities": selectionArg
});
+ resumeGame();
};
messageBox(
@@ -184,7 +201,7 @@
function openSave()
{
closeOpenDialogs();
- pauseGame();
+ g_PauseControl.implicitPause();
Engine.PushGuiPage(
"page_loadgame.xml",
@@ -195,7 +212,7 @@
function openOptions()
{
closeOpenDialogs();
- pauseGame();
+ g_PauseControl.implicitPause();
Engine.PushGuiPage(
"page_options.xml",
@@ -216,73 +233,6 @@
!Engine.GetGUIObjectByName("tutorialText").caption;
}
-function updateGameSpeedControl()
-{
- Engine.GetGUIObjectByName("gameSpeedButton").hidden = g_IsNetworked;
-
- let player = g_Players[Engine.GetPlayerID()];
- g_GameSpeeds = getGameSpeedChoices(!player || player.state != "active");
-
- let gameSpeed = Engine.GetGUIObjectByName("gameSpeed");
- gameSpeed.list = g_GameSpeeds.Title;
- gameSpeed.list_data = g_GameSpeeds.Speed;
-
- let simRate = Engine.GetSimRate();
-
- let gameSpeedIdx = g_GameSpeeds.Speed.indexOf(+simRate.toFixed(2));
- if (gameSpeedIdx == -1)
- warn("Unknown gamespeed:" + simRate);
-
- gameSpeed.selected = gameSpeedIdx != -1 ? gameSpeedIdx : g_GameSpeeds.Default;
- gameSpeed.onSelectionChange = function() {
- changeGameSpeed(+this.list_data[this.selected]);
- };
-}
-
-function toggleGameSpeed()
-{
- let gameSpeed = Engine.GetGUIObjectByName("gameSpeed");
- gameSpeed.hidden = !gameSpeed.hidden;
-}
-
-function toggleObjectives()
-{
- let open = g_IsObjectivesOpen;
- closeOpenDialogs();
-
- if (!open)
- openObjectives();
-}
-
-function openObjectives()
-{
- g_IsObjectivesOpen = true;
-
- let player = g_Players[Engine.GetPlayerID()];
- let playerState = player && player.state;
- let isActive = !playerState || playerState == "active";
-
- Engine.GetGUIObjectByName("gameDescriptionText").caption = getGameDescription();
-
- let objectivesPlayerstate = Engine.GetGUIObjectByName("objectivesPlayerstate");
- objectivesPlayerstate.hidden = isActive;
- objectivesPlayerstate.caption = g_PlayerStateMessages[playerState] || "";
-
- let gameDescription = Engine.GetGUIObjectByName("gameDescription");
- let gameDescriptionSize = gameDescription.size;
- gameDescriptionSize.top = Engine.GetGUIObjectByName(
- isActive ? "objectivesTitle" : "objectivesPlayerstate").size.bottom;
- gameDescription.size = gameDescriptionSize;
-
- Engine.GetGUIObjectByName("objectivesPanel").hidden = false;
-}
-
-function closeObjectives()
-{
- g_IsObjectivesOpen = false;
- Engine.GetGUIObjectByName("objectivesPanel").hidden = true;
-}
-
/**
* Allows players to see their own summary.
* If they have shared ally vision researched, they are able to see the summary of there allies too.
@@ -290,7 +240,7 @@
function openGameSummary()
{
closeOpenDialogs();
- pauseGame();
+ g_PauseControl.implicitPause();
let extendedSimState = Engine.GuiInterfaceCall("GetExtendedSimulationState");
Engine.PushGuiPage(
@@ -309,13 +259,17 @@
},
"selectedData": g_SummarySelectedData
},
- resumeGameAndSaveSummarySelectedData);
+ data =>
+ {
+ g_SummarySelectedData = data.summarySelectedData;
+ g_PauseControl.implicitResume();
+ });
}
function openStrucTree(page)
{
closeOpenDialogs();
- pauseGame();
+ g_PauseControl.implicitPause();
Engine.PushGuiPage(
page,
@@ -340,103 +294,18 @@
}
}
-/**
- * Pause or resume the game.
- *
- * @param explicit - true if the player explicitly wants to pause or resume.
- * If this argument isn't set, a multiplayer game won't be paused and the pause overlay
- * won't be shown in single player.
- */
-function pauseGame(pause = true, explicit = false)
-{
- // The NetServer only supports pausing after all clients finished loading the game.
- if (g_IsNetworked && (!explicit || !g_IsNetworkedActive))
- return;
-
- if (explicit)
- g_Paused = pause;
-
- Engine.SetPaused(g_Paused || pause, !!explicit);
-
- if (g_IsNetworked)
- {
- setClientPauseState(Engine.GetPlayerGUID(), g_Paused);
- return;
- }
-
- updatePauseOverlay();
-}
-
-function resumeGame(explicit = false)
-{
- pauseGame(false, explicit);
-}
-
-function resumeGameAndSaveSummarySelectedData(data)
-{
- g_SummarySelectedData = data.summarySelectedData;
- resumeGame(data.explicitResume);
-}
-
-/**
- * Called when the current player toggles a pause button.
- */
-function togglePause()
-{
- if (!Engine.GetGUIObjectByName("pauseButton").enabled)
- return;
-
- closeOpenDialogs();
-
- pauseGame(!g_Paused, true);
-}
-
-/**
- * Called when a client pauses or resumes in a multiplayer game.
- */
-function setClientPauseState(guid, paused)
-{
- // Update the list of pausing clients.
- let index = g_PausingClients.indexOf(guid);
- if (paused && index == -1)
- g_PausingClients.push(guid);
- else if (!paused && index != -1)
- g_PausingClients.splice(index, 1);
-
- updatePauseOverlay();
-
- Engine.SetPaused(!!g_PausingClients.length, false);
-}
-
-/**
- * Update the pause overlay.
- */
-function updatePauseOverlay()
-{
- Engine.GetGUIObjectByName("pauseButton").caption = g_Paused ? translate("Resume") : translate("Pause");
- Engine.GetGUIObjectByName("resumeMessage").hidden = !g_Paused;
-
- Engine.GetGUIObjectByName("pausedByText").hidden = !g_IsNetworked;
- Engine.GetGUIObjectByName("pausedByText").caption = sprintf(translate("Paused by %(players)s"),
- { "players": g_PausingClients.map(guid => colorizePlayernameByGUID(guid)).join(translateWithContext("Separator for a list of players", ", ")) });
-
- Engine.GetGUIObjectByName("pauseOverlay").hidden = !(g_Paused || g_PausingClients.length);
- Engine.GetGUIObjectByName("pauseOverlay").onPress = g_Paused ? togglePause : function() {};
-}
-
function openManual()
{
closeOpenDialogs();
- pauseGame();
+ g_PauseControl.implicitPause();
Engine.PushGuiPage("page_manual.xml", {}, resumeGame);
}
function closeOpenDialogs()
{
closeMenu();
- closeObjectives();
-
g_Chat.closePage();
g_DiplomacyDialog.close();
+ g_ObjectivesDialog.close();
g_TradeDialog.close();
}
Index: ps/trunk/binaries/data/mods/public/gui/session/menu.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/menu.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/menu.xml
@@ -79,13 +79,11 @@
- Pause
- togglePause();
-
+ />
{
- setClientPauseState(msg.guid, msg.pause);
+ g_PauseControl.setClientPauseState(msg.guid, msg.pause);
},
"clients-loading": msg => {
handleClientsLoadingMessage(msg.guids);
@@ -388,7 +388,7 @@
{
Engine.GetGUIObjectByName("tutorialWarning").caption = translate("Click to quit this tutorial.");
Engine.GetGUIObjectByName("tutorialReady").caption = translate("Quit");
- Engine.GetGUIObjectByName("tutorialReady").onPress = leaveGame;
+ Engine.GetGUIObjectByName("tutorialReady").onPress = endGame;
}
else
Engine.GetGUIObjectByName("tutorialWarning").caption = translate("Click when ready.");
@@ -579,7 +579,7 @@
function onClientLeave(guid)
{
- setClientPauseState(guid, false);
+ g_PauseControl.setClientPauseState(guid, false);
for (let id in g_Players)
if (g_Players[id].guid == guid)
@@ -689,5 +689,5 @@
}
}
- pauseGame();
+ g_PauseControl.implicitPause();
}
Index: ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMapDiplomacyColorsButton.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMapDiplomacyColorsButton.js
+++ ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMapDiplomacyColorsButton.js
@@ -8,22 +8,26 @@
this.diplomacyColorsButton = Engine.GetGUIObjectByName("diplomacyColorsButton");
this.diplomacyColorsButton.onPress = diplomacyColors.toggle.bind(diplomacyColors);
- this.diplomacyColors = diplomacyColors;
+ diplomacyColors.registerDiplomacyColorsChangeHandler(this.onDiplomacyColorsChange.bind(this));
+ registerHotkeyChangeHandler(this.onHotkeyChange.bind(this));
}
- update()
+ onHotkeyChange()
{
this.diplomacyColorsButton.tooltip =
colorizeHotkey("%(hotkey)s" + " ", "session.diplomacycolors") +
translate(this.Tooltip);
+ }
+ onDiplomacyColorsChange(enabled)
+ {
this.diplomacyColorsButton.sprite =
"stretched:" +
- (this.diplomacyColors.isEnabled() ? this.SpriteEnabled : this.SpriteDisabled);
+ (enabled ? this.SpriteEnabled : this.SpriteDisabled);
this.diplomacyColorsButton.sprite_over =
"stretched:" +
- (this.diplomacyColors.isEnabled() ? this.SpriteEnabledOver : this.SpriteDisabledOver);
+ (enabled ? this.SpriteEnabledOver : this.SpriteDisabledOver);
}
}
Index: ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMapIdleWorkerButton.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMapIdleWorkerButton.js
+++ ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMapIdleWorkerButton.js
@@ -3,19 +3,26 @@
*/
class MiniMapIdleWorkerButton
{
- constructor(idleClasses)
+ constructor(playerViewControl, idleClasses)
{
this.idleWorkerButton = Engine.GetGUIObjectByName("idleWorkerButton");
this.idleWorkerButton.onPress = this.onPress.bind(this);
this.idleClasses = idleClasses;
+
+ registerHotkeyChangeHandler(this.onHotkeyChange.bind(this));
+ registerSimulationUpdateHandler(this.rebuild.bind(this));
+ playerViewControl.registerViewedPlayerChangeHandler(this.rebuild.bind(this));
}
- update()
+ onHotkeyChange()
{
this.idleWorkerButton.tooltip =
colorizeHotkey("%(hotkey)s" + " ", "selection.idleworker") +
translate(this.Tooltip);
+ }
+ rebuild()
+ {
this.idleWorkerButton.enabled = Engine.GuiInterfaceCall("HasIdleUnits", {
"viewedPlayer": g_ViewedPlayer,
"idleClasses": this.idleClasses,
Index: ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMapPanel.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMapPanel.js
+++ ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMapPanel.js
@@ -3,16 +3,10 @@
*/
class MiniMapPanel
{
- constructor(diplomacyColors, idleWorkerClasses)
+ constructor(playerViewControl, diplomacyColors, idleWorkerClasses)
{
this.diplomacyColorsButton = new MiniMapDiplomacyColorsButton(diplomacyColors);
- this.idleWorkerButton = new MiniMapIdleWorkerButton(idleWorkerClasses);
+ this.idleWorkerButton = new MiniMapIdleWorkerButton(playerViewControl, idleWorkerClasses);
this.minimap = new Minimap();
}
-
- update()
- {
- this.diplomacyColorsButton.update();
- this.idleWorkerButton.update();
- }
}
Index: ps/trunk/binaries/data/mods/public/gui/session/objectives/ObjectivesDialog.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/objectives/ObjectivesDialog.js
+++ ps/trunk/binaries/data/mods/public/gui/session/objectives/ObjectivesDialog.js
@@ -0,0 +1,59 @@
+class ObjectivesDialog
+{
+ constructor(playerViewControl)
+ {
+ this.gameDescription = Engine.GetGUIObjectByName("gameDescription");
+ this.objectivesPlayerstate = Engine.GetGUIObjectByName("objectivesPlayerstate");
+ this.objectivesPanel = Engine.GetGUIObjectByName("objectivesPanel");
+ this.objectivesTitle = Engine.GetGUIObjectByName("objectivesTitle");
+
+ // TODO: atlas should support this
+ if (g_GameAttributes.settings)
+ Engine.GetGUIObjectByName("gameDescriptionText").caption = getGameDescription();
+
+ Engine.GetGUIObjectByName("closeObjectives").onPress = this.close.bind(this);
+
+ registerPlayersInitHandler(this.rebuild.bind(this));
+ registerPlayersFinishedHandler(this.rebuild.bind(this));
+ playerViewControl.registerPlayerIDChangeHandler(this.rebuild.bind(this));
+ }
+
+ open()
+ {
+ this.objectivesPanel.hidden = false;
+ }
+
+ close()
+ {
+ this.objectivesPanel.hidden = true;
+ }
+
+ isOpen()
+ {
+ return !this.objectivesPanel.hidden;
+ }
+
+ toggle()
+ {
+ let open = this.isOpen();
+
+ closeOpenDialogs();
+
+ if (!open)
+ this.open();
+ }
+
+ rebuild()
+ {
+ let player = g_Players[Engine.GetPlayerID()];
+ let playerState = player && player.state;
+ let isActive = !playerState || playerState == "active";
+
+ this.objectivesPlayerstate.hidden = isActive;
+ this.objectivesPlayerstate.caption = g_PlayerStateMessages[playerState] || "";
+
+ let size = this.gameDescription.size;
+ size.top = (isActive ? this.objectivesTitle : this.objectivesPlayerstate).size.bottom;
+ this.gameDescription.size = size;
+ }
+}
Index: ps/trunk/binaries/data/mods/public/gui/session/objectives/ObjectivesDialog.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/objectives/ObjectivesDialog.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/objectives/ObjectivesDialog.xml
@@ -0,0 +1,47 @@
+
+
+
+ Objectives
+
+
+
+
+
+
+
+
+
+ Close
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/objectives_window.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/objectives_window.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/objectives_window.xml
@@ -1,48 +0,0 @@
-
-
-
- Objectives
-
-
-
-
-
-
-
-
-
- Close
- closeObjectives();
-
-
-
-
Index: ps/trunk/binaries/data/mods/public/gui/session/selection_panels.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/selection_panels.js
+++ ps/trunk/binaries/data/mods/public/gui/session/selection_panels.js
@@ -1147,7 +1147,7 @@
*/
function showTemplateDetails(templateName, civCode)
{
- pauseGame();
+ g_PauseControl.implicitPause();
Engine.PushGuiPage(
"page_viewer.xml",
Index: ps/trunk/binaries/data/mods/public/gui/session/session.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/session.js
+++ ps/trunk/binaries/data/mods/public/gui/session/session.js
@@ -11,25 +11,16 @@
const g_VictoryConditions = g_Settings && g_Settings.VictoryConditions;
var g_Chat;
-var g_DiplomacyButton;
var g_DiplomacyColors;
var g_DiplomacyDialog;
+var g_GameSpeedControl;
var g_MiniMapPanel;
+var g_ObjectivesDialog;
+var g_PauseControl;
+var g_PauseOverlay;
+var g_PlayerViewControl;
var g_TradeDialog;
-var g_TradeDialogButton;
-
-var g_GameSpeeds;
-
-/**
- * Colors to flash when pop limit reached.
- */
-var g_DefaultPopulationColor = "white";
-var g_PopulationAlertColor = "orange";
-
-/**
- * Seen in the tooltip of the top panel.
- */
-var g_ResourceTitleFont = "sans-bold-16";
+var g_TopPanel;
/**
* A random file will be played. TODO: more variety
@@ -78,16 +69,6 @@
var g_ConfirmExit = false;
/**
- * True if the current player has paused the game explicitly.
- */
-var g_Paused = false;
-
-/**
- * The list of GUIDs of players who have currently paused the game, if the game is networked.
- */
-var g_PausingClients = [];
-
-/**
* The playerID selected in the change perspective tool.
*/
var g_ViewedPlayer = Engine.GetPlayerID();
@@ -139,11 +120,6 @@
var g_ShowAllStatusBars = false;
/**
- * Blink the population counter if the player can't train more units.
- */
-var g_IsTrainingBlocked = false;
-
-/**
* Cache of simulation state and template data (apart from TechnologyData, updated on every simulation update).
*/
var g_SimState;
@@ -154,6 +130,33 @@
var g_ResourceData = new Resources();
/**
+ * These handlers are called each time a new turn was simulated.
+ * Use this as sparely as possible.
+ */
+var g_SimulationUpdateHandlers = [];
+
+/**
+ * These handlers are called after the player states have been initialized.
+ */
+var g_PlayersInitHandlers = [];
+
+/**
+ * These handlers are called when a player has been defeated or won the game.
+ */
+var g_PlayerFinishedHandlers = [];
+
+/**
+ * These events are fired whenever the player added or removed entities from the selection.
+ */
+var g_EntitySelectionChangeHandlers = [];
+
+/**
+ * These events are fired when the user has performed a hotkey assignment change.
+ * Currently only fired on init, but to be fired from any hotkey editor dialog.
+ */
+var g_HotkeyChangeHandlers = [];
+
+/**
* Top coordinate of the research list.
* Changes depending on the number of displayed counters.
*/
@@ -267,20 +270,40 @@
restoreSavedGameData(initData.savedGUIData);
}
- g_Chat = new Chat();
- g_DeveloperOverlay = new DeveloperOverlay();
g_DiplomacyColors = new DiplomacyColors();
- g_DiplomacyDialog = new DiplomacyDialog(g_DiplomacyColors);
- g_DiplomacyButton = new DiplomacyButton(g_DiplomacyDialog);
- g_MiniMapPanel = new MiniMapPanel(g_DiplomacyColors, g_WorkerTypes);
- g_TradeDialog = new TradeDialog();
- g_TradeDialogButton = new TradeDialogButton(g_TradeDialog);
+
+ g_PlayerViewControl = new PlayerViewControl();
+ g_PlayerViewControl.registerViewedPlayerChangeHandler(g_DiplomacyColors.updateDisplayedPlayerColors.bind(g_DiplomacyColors));
+ g_DiplomacyColors.registerDiplomacyColorsChangeHandler(g_PlayerViewControl.rebuild.bind(g_PlayerViewControl));
+ g_DiplomacyColors.registerDiplomacyColorsChangeHandler(updateGUIObjects);
+ g_PlayerViewControl.registerPreViewedPlayerChangeHandler(removeStatusBarDisplay);
+ g_PlayerViewControl.registerViewedPlayerChangeHandler(resetTemplates);
+
+ g_Chat = new Chat(g_PlayerViewControl);
+ g_DeveloperOverlay = new DeveloperOverlay(g_PlayerViewControl);
+ g_DiplomacyDialog = new DiplomacyDialog(g_PlayerViewControl, g_DiplomacyColors);
+ g_GameSpeedControl = new GameSpeedControl(g_PlayerViewControl);
+ g_MiniMapPanel = new MiniMapPanel(g_PlayerViewControl, g_DiplomacyColors, g_WorkerTypes);
+ g_ObjectivesDialog = new ObjectivesDialog(g_PlayerViewControl);
+ g_PauseControl = new PauseControl();
+ g_PauseOverlay = new PauseOverlay(g_PauseControl);
+ g_TradeDialog = new TradeDialog(g_PlayerViewControl);
+ g_TopPanel = new TopPanel(g_PlayerViewControl, g_DiplomacyDialog, g_TradeDialog, g_ObjectivesDialog, g_GameSpeedControl);
initSelectionPanels();
LoadModificationTemplates();
updatePlayerData();
initializeMusic(); // before changing the perspective
- initGUIObjects();
+ initMenu(g_PlayerViewControl, g_PauseControl);
+ initPanelEntities();
+ Engine.SetBoundingBoxDebugOverlay(false);
+ updateEnabledRangeOverlayTypes();
+
+ for (let handler of g_PlayersInitHandlers)
+ handler();
+
+ for (let handler of g_HotkeyChangeHandlers)
+ handler();
if (hotloadData)
{
@@ -290,21 +313,36 @@
}
sendLobbyPlayerlistUpdate();
+
+ // TODO: use event instead
onSimulationUpdate();
+
setTimeout(displayGamestateNotifications, 1000);
}
-function initGUIObjects()
+function registerPlayersInitHandler(handler)
{
- initMenu();
- updateGameSpeedControl();
- g_TradeDialog.resize();
- initPanelEntities();
- g_DiplomacyColors.onPlayerInit();
- initViewedPlayerDropdown();
- Engine.SetBoundingBoxDebugOverlay(false);
- updateEnabledRangeOverlayTypes();
- g_DiplomacyDialog.onPlayerInit();
+ g_PlayersInitHandlers.push(handler);
+}
+
+function registerPlayersFinishedHandler(handler)
+{
+ g_PlayerFinishedHandlers.push(handler);
+}
+
+function registerSimulationUpdateHandler(handler)
+{
+ g_SimulationUpdateHandlers.push(handler);
+}
+
+function registerEntitySelectionChangeHandler(handler)
+{
+ g_EntitySelectionChangeHandlers.push(handler);
+}
+
+function registerHotkeyChangeHandler(handler)
+{
+ g_HotkeyChangeHandlers.push(handler);
}
function updatePlayerData()
@@ -364,16 +402,6 @@
g_DiplomacyColors.updateDisplayedPlayerColors();
}
-/**
- * Depends on the current player (g_IsObserver).
- */
-function updateHotkeyTooltips()
-{
- Engine.GetGUIObjectByName("objectivesButton").tooltip =
- colorizeHotkey("%(hotkey)s" + " ", "session.gui.objectives.toggle") +
- translate("Objectives");
-}
-
function initPanelEntities()
{
Engine.GetGUIObjectByName("panelEntityPanel").children.forEach((button, slot) => {
@@ -419,64 +447,14 @@
playAmbient();
}
-function initViewedPlayerDropdown()
+function resetTemplates()
{
- updateViewedPlayerDropdown();
-
- // Select "observer" in the view player dropdown when rejoining as a defeated player
- let player = g_Players[Engine.GetPlayerID()];
- Engine.GetGUIObjectByName("viewPlayer").selected = player && player.state == "defeated" ? 0 : Engine.GetPlayerID() + 1;
-}
-
-function updateViewedPlayerDropdown()
-{
- let viewPlayer = Engine.GetGUIObjectByName("viewPlayer");
- viewPlayer.list_data = [-1].concat(g_Players.map((player, i) => i));
- viewPlayer.list = [translate("Observer")].concat(g_Players.map(
- (player, i) => colorizePlayernameHelper("■", i) + " " + player.name
- ));
-}
-
-/**
- * Change perspective tool.
- * Shown to observers or when enabling the developers option.
- */
-function selectViewPlayer(playerID)
-{
- if (playerID < -1 || playerID > g_Players.length - 1)
- return;
-
- if (g_ShowAllStatusBars)
- recalculateStatusBarDisplay(true);
-
- g_IsObserver = isPlayerObserver(Engine.GetPlayerID());
-
- if (g_IsObserver || g_DeveloperOverlay.isChangePerspective())
- {
- if (g_ViewedPlayer != playerID)
- clearSelection();
- g_ViewedPlayer = playerID;
- }
-
- if (g_DeveloperOverlay.isChangePerspective())
- {
- Engine.SetPlayerID(g_ViewedPlayer);
- g_IsObserver = isPlayerObserver(g_ViewedPlayer);
- }
-
- Engine.SetViewedPlayer(g_ViewedPlayer);
- g_DiplomacyColors.updateDisplayedPlayerColors();
- updateTopPanel();
- g_Chat.onUpdatePlayers();
- updateHotkeyTooltips();
-
// Update GUI and clear player-dependent cache
g_TemplateData = {};
Engine.GuiInterfaceCall("ResetTemplateModified");
- onSimulationUpdate();
- g_DiplomacyDialog.update();
- g_TradeDialog.update();
+ // TODO: do this more selectively
+ onSimulationUpdate();
}
/**
@@ -523,14 +501,16 @@
sendLobbyPlayerlistUpdate();
updatePlayerData();
- g_Chat.onUpdatePlayers();
- updateGameSpeedControl();
+
+ // TODO: The other calls in this function should move too
+ for (let handler of g_PlayerFinishedHandlers)
+ handler();
if (players.indexOf(g_ViewedPlayer) == -1)
return;
// Select "observer" item on loss. On win enable observermode without changing perspective
- Engine.GetGUIObjectByName("viewPlayer").selected = won ? g_ViewedPlayer + 1 : 0;
+ g_PlayerViewControl.selectViewPlayer(won ? g_ViewedPlayer + 1 : 0);
if (players.indexOf(Engine.GetPlayerID()) == -1 || Engine.IsAtlasRunning())
return;
@@ -544,100 +524,21 @@
g_ConfirmExit = won ? "won" : "defeated";
}
-/**
- * Sets civ icon for the currently viewed player.
- * Hides most gui objects for observers.
- */
-function updateTopPanel()
+function resumeGame()
{
- let isPlayer = g_ViewedPlayer > 0;
-
- let civIcon = Engine.GetGUIObjectByName("civIcon");
- civIcon.hidden = !isPlayer;
- if (isPlayer)
- {
- civIcon.sprite = "stretched:" + g_CivData[g_Players[g_ViewedPlayer].civ].Emblem;
- Engine.GetGUIObjectByName("civIconOverlay").tooltip =
- sprintf(
- translate("%(civ)s\n%(hotkey_civinfo)s / %(hotkey_structree)s: View History / Structure Tree\nLast opened will be reopened on click."), {
- "civ": setStringTags(g_CivData[g_Players[g_ViewedPlayer].civ].Name, { "font": "sans-bold-stroke-14" }),
- "hotkey_civinfo": colorizeHotkey("%(hotkey)s", "civinfo"),
- "hotkey_structree": colorizeHotkey("%(hotkey)s", "structree")
- });
- }
-
- // Following gaia can be interesting on scripted maps
- Engine.GetGUIObjectByName("optionFollowPlayer").hidden = !g_IsObserver || g_ViewedPlayer == -1;
-
- let viewPlayer = Engine.GetGUIObjectByName("viewPlayer");
- viewPlayer.hidden = !g_IsObserver && !g_DeveloperOverlay.isChangePerspective();
-
- let followPlayerLabel = Engine.GetGUIObjectByName("followPlayerLabel");
- followPlayerLabel.hidden = Engine.GetTextWidth(followPlayerLabel.font, followPlayerLabel.caption + " ") +
- followPlayerLabel.getComputedSize().left > viewPlayer.getComputedSize().left;
-
- let resCodes = g_ResourceData.GetCodes();
- let r = 0;
- for (let res of resCodes)
- {
- if (!Engine.GetGUIObjectByName("resource[" + r + "]"))
- {
- warn("Current GUI limits prevent displaying more than " + r + " resources in the top panel!");
- break;
- }
- Engine.GetGUIObjectByName("resource[" + r + "]_icon").sprite = "stretched:session/icons/resources/" + res + ".png";
- Engine.GetGUIObjectByName("resource[" + r + "]").hidden = !isPlayer;
- ++r;
- }
- horizontallySpaceObjects("resourceCounts", 5);
- hideRemaining("resourceCounts", r);
-
- let resPop = Engine.GetGUIObjectByName("population");
- let resPopSize = resPop.size;
- resPopSize.left = Engine.GetGUIObjectByName("resource[" + (r - 1) + "]").size.right;
- resPop.size = resPopSize;
-
- Engine.GetGUIObjectByName("population").hidden = !isPlayer;
- g_DiplomacyButton.update();
- g_TradeDialogButton.update();
-
- Engine.GetGUIObjectByName("observerText").hidden = isPlayer;
-
- let alphaLabel = Engine.GetGUIObjectByName("alphaLabel");
- alphaLabel.hidden = isPlayer && !viewPlayer.hidden;
- alphaLabel.size = isPlayer ? "50%+44 0 100%-283 100%" : "155 0 85%-279 100%";
-
- Engine.GetGUIObjectByName("pauseButton").enabled = !g_IsObserver || !g_IsNetworked || g_IsController;
- Engine.GetGUIObjectByName("menuResignButton").enabled = !g_IsObserver;
- Engine.GetGUIObjectByName("lobbyButton").enabled = Engine.HasXmppClient();
+ g_PauseControl.implicitResume();
}
-/**
- * Resign a player.
- * @param leaveGameAfterResign If player is quitting after resignation.
- */
-function resignGame(leaveGameAfterResign)
+function resignGame()
{
- if (g_IsObserver || g_Disconnected)
- return;
-
Engine.PostNetworkCommand({
"type": "resign"
});
-
- if (!leaveGameAfterResign)
- resumeGame(true);
+ g_PauseControl.implicitResume();
}
-/**
- * Leave the game
- * @param willRejoin If player is going to be rejoining a networked game.
- */
-function leaveGame(willRejoin)
+function endGame()
{
- if (!willRejoin && !g_IsObserver)
- resignGame(true);
-
// Before ending the game
let replayDirectory = Engine.GetCurrentReplayDirectory();
let simData = Engine.GuiInterfaceCall("GetReplayMetadata");
@@ -724,6 +625,9 @@
// When selection changed, get the entityStates of new entities
GetMultipleEntityStates(g_Selection.toList().filter(entId => !g_EntityStates[entId]));
+ for (let handler of g_EntitySelectionChangeHandlers)
+ handler();
+
updateGUIObjects();
// Display rally points for selected buildings
@@ -734,29 +638,10 @@
recalculateStatusBarDisplay();
updateTimers();
-
updateMenuPosition(tickLength);
-
- // When training is blocked, flash population (alternates color every 500msec)
- Engine.GetGUIObjectByName("resourcePop").textcolor = g_IsTrainingBlocked && now % 1000 < 500 ? g_PopulationAlertColor : g_DefaultPopulationColor;
-
Engine.GuiInterfaceCall("ClearRenamedEntities");
}
-function onWindowResized()
-{
- // Update followPlayerLabel
- updateTopPanel();
-
- g_Chat.ChatWindow.resizeChatWindow();
-}
-
-function changeGameSpeed(speed)
-{
- if (!g_IsNetworked)
- Engine.SetSimRate(speed);
-}
-
function onSimulationUpdate()
{
// Templates change depending on technologies and auras, so they have to be reloaded after such a change.
@@ -774,6 +659,10 @@
GetMultipleEntityStates(g_Selection.toList());
+ for (let handler of g_SimulationUpdateHandlers)
+ handler();
+
+ // TODO: Move to handlers
updateCinemaPath();
handleNotifications();
updateGUIObjects();
@@ -791,6 +680,7 @@
return;
closeOpenDialogs();
+ g_PauseControl.implicitPause();
// Don't ask for exit if other humans are still playing
let askExit = !Engine.HasNetServer() || g_Players.every((player, i) =>
@@ -809,8 +699,7 @@
translate("VICTORIOUS!") :
translate("DEFEATED!"),
askExit ? [translate("No"), translate("Yes")] : [translate("OK")],
- askExit ? [resumeGame, leaveGame] : [resumeGame]
- );
+ askExit ? [resumeGame, endGame] : [resumeGame]);
g_ConfirmExit = false;
}
@@ -829,6 +718,7 @@
Engine.Renderer_SetSilhouettesEnabled(!isPlayingCinemaPath && Engine.ConfigDB_GetValue("user", "silhouettes") == "true");
}
+// TODO: Use event subscription onSimulationUpdate, onEntitySelectionChange, onPlayerViewChange, ... instead
function updateGUIObjects()
{
g_Selection.update();
@@ -843,18 +733,11 @@
displayPanelEntities();
updateGroups();
- updatePlayerDisplay();
updateResearchDisplay();
updateSelectionDetails();
updateBuildingPlacementPreview();
updateTimeNotifications();
- if (g_ViewedPlayer > 0)
- {
- let playerState = GetSimState().players[g_ViewedPlayer];
- g_DeveloperOverlay.setControlAll(playerState && playerState.controlsAll);
- }
-
if (!g_IsObserver)
{
// Update music state on basis of battle state.
@@ -862,29 +745,18 @@
if (battleState)
global.music.setState(global.music.states[battleState]);
}
-
- updateViewedPlayerDropdown();
- g_DeveloperOverlay.update();
- g_DiplomacyDialog.update();
- g_MiniMapPanel.update();
- g_TradeDialog.update();
-}
-
-function saveResPopTooltipSort()
-{
- Engine.ConfigDB_CreateAndWriteValueToFile("user", "gui.session.respoptooltipsort", String((+Engine.ConfigDB_GetValue("user", "gui.session.respoptooltipsort") + 2) % 3 - 1), "config/user.cfg");
}
function onReplayFinished()
{
closeOpenDialogs();
- pauseGame();
+ g_PauseControl.implicitPause();
messageBox(400, 200,
translateWithContext("replayFinished", "The replay has finished. Do you want to quit?"),
translateWithContext("replayFinished", "Confirmation"),
[translateWithContext("replayFinished", "No"), translateWithContext("replayFinished", "Yes")],
- [resumeGame, leaveGame]);
+ [resumeGame, endGame]);
}
/**
@@ -1065,88 +937,6 @@
}
}
-/**
- * Create ally player stat tooltip.
- * @param {string} resource - Resource type, on which values will be sorted.
- * @param {object} playerStates - Playerstates from players whos stats are viewed in the tooltip.
- * @param {number} sort - 0 no order, -1 descending, 1 ascending order.
- * @returns {string} Tooltip string.
- */
-function getAllyStatTooltip(resource, playerStates, sort)
-{
- let tooltip = [];
-
- for (let player in playerStates)
- tooltip.push({
- "playername": colorizePlayernameHelper("■", player) + " " + g_Players[player].name,
- "statValue": resource == "pop" ?
- sprintf(translate("%(popCount)s/%(popLimit)s/%(popMax)s"), playerStates[player]) :
- Math.round(playerStates[player].resourceCounts[resource]),
- "orderValue": resource == "pop" ? playerStates[player].popCount :
- Math.round(playerStates[player].resourceCounts[resource])
- });
- if (sort)
- tooltip.sort((a, b) => sort * (b.orderValue - a.orderValue));
- return "\n" + tooltip.map(stat => sprintf(translate("%(playername)s: %(statValue)s"), stat)).join("\n");
-}
-
-function updatePlayerDisplay()
-{
- let allPlayerStates = GetSimState().players;
- let viewedPlayerState = allPlayerStates[g_ViewedPlayer];
- let viewablePlayerStates = {};
- for (let player in allPlayerStates)
- if (player != 0 &&
- player != g_ViewedPlayer &&
- g_Players[player].state != "defeated" &&
- (g_IsObserver ||
- viewedPlayerState.hasSharedLos &&
- g_Players[player].isMutualAlly[g_ViewedPlayer]))
- viewablePlayerStates[player] = allPlayerStates[player];
-
- if (!viewedPlayerState)
- return;
-
- let tooltipSort = +Engine.ConfigDB_GetValue("user", "gui.session.respoptooltipsort");
-
- let orderHotkeyTooltip = Object.keys(viewablePlayerStates).length <= 1 ? "" :
- "\n" + sprintf(translate("%(order)s: %(hotkey)s to change order."), {
- "hotkey": setStringTags("\\[Click]", g_HotkeyTags),
- "order": tooltipSort == 0 ? translate("Unordered") : tooltipSort == 1 ? translate("Descending") : translate("Ascending")
- });
-
- let resCodes = g_ResourceData.GetCodes();
- for (let r = 0; r < resCodes.length; ++r)
- {
- let resourceObj = Engine.GetGUIObjectByName("resource[" + r + "]");
- if (!resourceObj)
- break;
-
- let res = resCodes[r];
-
- let tooltip = '[font="' + g_ResourceTitleFont + '"]' +
- resourceNameFirstWord(res) + '[/font]';
-
- let descr = g_ResourceData.GetResource(res).description;
- if (descr)
- tooltip += "\n" + translate(descr);
-
- tooltip += orderHotkeyTooltip + getAllyStatTooltip(res, viewablePlayerStates, tooltipSort);
-
- resourceObj.tooltip = tooltip;
-
- Engine.GetGUIObjectByName("resource[" + r + "]_count").caption = Math.floor(viewedPlayerState.resourceCounts[res]);
- }
-
- Engine.GetGUIObjectByName("resourcePop").caption = sprintf(translate("%(popCount)s/%(popLimit)s"), viewedPlayerState);
- Engine.GetGUIObjectByName("population").tooltip = translate("Population (current / limit)") + "\n" +
- sprintf(translate("Maximum population: %(popCap)s"), { "popCap": viewedPlayerState.popMax }) +
- orderHotkeyTooltip +
- getAllyStatTooltip("pop", viewablePlayerStates, tooltipSort);
-
- g_IsTrainingBlocked = viewedPlayerState.trainingBlocked;
-}
-
function selectAndMoveTo(ent)
{
let entState = GetEntityState(ent);
@@ -1243,6 +1033,12 @@
});
}
+function removeStatusBarDisplay()
+{
+ if (g_ShowAllStatusBars)
+ recalculateStatusBarDisplay(true);
+}
+
/**
* Inverts the given configuration boolean and returns the current state.
* For example "silhouettes".
Index: ps/trunk/binaries/data/mods/public/gui/session/session.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/session.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/session.xml
@@ -9,7 +9,9 @@
+
+
@@ -17,10 +19,6 @@
onTick();
-
- onWindowResized();
-
-
restoreSavedGameData(arguments[0]);
@@ -63,23 +61,12 @@
tooltip_style="sessionToolTip"
>
Exit
- leaveGame();
+ endGame();
-
-
-
-
- Game Paused
-
-
- Click to Resume Game
-
-
- togglePause();
-
+
@@ -103,9 +90,10 @@
+
-
-
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel.xml
@@ -1,57 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- Follow Player
- g_FollowPlayer = !g_FollowPlayer;
-
-
-
-
- Follow Player
-
-
-
-
-
-
-
- Choose player to view
- selectViewPlayer(this.selected - 1);
-
-
-
-
-
-
- Observer Mode
-
-
-
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/BuildLabel.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/BuildLabel.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/BuildLabel.js
@@ -0,0 +1,26 @@
+/**
+ * This class displays the version information in the top panel.
+ */
+class BuildLabel
+{
+ constructor(playerViewControl)
+ {
+ this.viewPlayer = Engine.GetGUIObjectByName("viewPlayer");
+ this.buildLabel = Engine.GetGUIObjectByName("buildLabel");
+
+ Engine.GetGUIObjectByName("buildTimeLabel").caption = getBuildString();
+
+ playerViewControl.registerViewedPlayerChangeHandler(this.onViewedPlayerChanged.bind(this));
+ }
+
+ onViewedPlayerChanged()
+ {
+ let isPlayer = g_ViewedPlayer > 0;
+ this.buildLabel.hidden = isPlayer && !this.viewPlayer.hidden;
+ this.buildLabel.size = isPlayer ? this.SizePlayer : this.SizeObserver;
+ }
+}
+
+BuildLabel.prototype.SizePlayer = "50%+44 0 100%-283 100%";
+
+BuildLabel.prototype.SizeObserver = "155 0 85%-279 100%";
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/BuildLabel.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/BuildLabel.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/BuildLabel.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+ ALPHA XXIV
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/CivIcon.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/CivIcon.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/CivIcon.js
@@ -0,0 +1,42 @@
+/**
+ * This displas the emblem of the civilization of the currently viewed player in the top panel.
+ * If clicked, it opens the structure tree or history dialog for the last viewed civilization.
+ */
+class CivIcon
+{
+ constructor(playerViewControl)
+ {
+ this.civIcon = Engine.GetGUIObjectByName("civIcon");
+ this.civIconOverlay = Engine.GetGUIObjectByName("civIconOverlay");
+ this.civIconOverlay.onPress = this.onPress.bind(this);
+ playerViewControl.registerViewedPlayerChangeHandler(this.rebuild.bind(this));
+ registerHotkeyChangeHandler(this.rebuild.bind(this));
+ }
+
+ onPress()
+ {
+ openStrucTree(g_CivInfo.page);
+ }
+
+ rebuild()
+ {
+ let hidden = g_ViewedPlayer <= 0;
+ this.civIcon.hidden = hidden;
+ if (hidden)
+ return;
+
+ let civData = g_CivData[g_Players[g_ViewedPlayer].civ];
+
+ this.civIcon.sprite = "stretched:" + civData.Emblem;
+ this.civIconOverlay.tooltip = sprintf(translate(this.OverlayTooltip), {
+ "civ": setStringTags(civData.Name, this.CivTags),
+ "hotkey_civinfo": colorizeHotkey("%(hotkey)s", "civinfo"),
+ "hotkey_structree": colorizeHotkey("%(hotkey)s", "structree")
+ });
+ }
+}
+
+CivIcon.prototype.OverlayTooltip =
+ markForTranslation("%(civ)s\n%(hotkey_civinfo)s / %(hotkey_structree)s: View History / Structure Tree\nLast opened will be reopened on click.");
+
+CivIcon.prototype.CivTags = { "font": "sans-bold-stroke-14" };
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/CivIcon.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/CivIcon.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/CivIcon.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/CounterManager.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/CounterManager.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/CounterManager.js
@@ -0,0 +1,132 @@
+/**
+ * This class manages the counters in the top panel.
+ * For allies who researched team vision and observers,
+ * it displays the resources in a tooltip in a player chosen order.
+ */
+class CounterManager
+{
+ constructor(playerViewControl)
+ {
+ this.allyPlayerStates = {};
+
+ this.counters = [];
+
+ this.resourceCounts = Engine.GetGUIObjectByName("resourceCounts");
+
+ // TODO: filter resources depending on JSON file
+ for (let resCode of g_ResourceData.GetCodes())
+ this.addCounter(resCode, CounterResource);
+
+ this.addCounter("population", CounterPopulation);
+
+ this.init();
+
+ registerSimulationUpdateHandler(this.rebuild.bind(this));
+ playerViewControl.registerViewedPlayerChangeHandler(this.rebuild.bind(this));
+ }
+
+ addCounter(resCode, type)
+ {
+ let panelCount = this.resourceCounts.children.length;
+ if (this.counters.length + 1 > panelCount)
+ throw "There are " + (this.counters.length + 1) + " resource counters to display, but only " + panelCount + " panel items!";
+
+ let id = "[" + this.counters.length + "]";
+ this.counters.push(
+ new type(
+ resCode,
+ Engine.GetGUIObjectByName("resource" + id),
+ Engine.GetGUIObjectByName("resource" + id + "_icon"),
+ Engine.GetGUIObjectByName("resource" + id + "_count")));
+ }
+
+ init()
+ {
+ horizontallySpaceObjects("resourceCounts", this.counters.length);
+ hideRemaining("resourceCounts", this.counters.length);
+
+ for (let counter of this.counters)
+ {
+ counter.icon.sprite = "stretched:session/icons/resources/" + counter.resCode + ".png";
+ counter.panel.onPress = this.onPress.bind(this);
+ }
+ }
+
+ onPress()
+ {
+ Engine.ConfigDB_CreateAndWriteValueToFile(
+ "user",
+ "gui.session.respoptooltipsort",
+ String((+Engine.ConfigDB_GetValue("user", "gui.session.respoptooltipsort") + 2) % 3 - 1),
+ "config/user.cfg");
+ this.rebuild();
+ }
+
+ rebuild()
+ {
+ let hidden = g_ViewedPlayer <= 0;
+ this.resourceCounts.hidden = hidden;
+ if (hidden)
+ return;
+
+ let viewedPlayerState = g_SimState.players[g_ViewedPlayer];
+ this.allyPlayerStates = {};
+ for (let player in g_SimState.players)
+ if (player != 0 &&
+ player != g_ViewedPlayer &&
+ g_Players[player].state != "defeated" &&
+ (g_IsObserver ||
+ viewedPlayerState.hasSharedLos &&
+ g_Players[player].isMutualAlly[g_ViewedPlayer]))
+ this.allyPlayerStates[player] = g_SimState.players[player];
+
+ this.selectedOrder = +Engine.ConfigDB_GetValue("user", "gui.session.respoptooltipsort");
+ this.orderTooltip = this.getOrderTooltip();
+
+ for (let counter of this.counters)
+ {
+ let hidden = g_ViewedPlayer <= 0;
+ counter.panel.hidden = hidden;
+ if (!hidden)
+ counter.rebuild(viewedPlayerState, this.getAllyStatTooltip.bind(this));
+ }
+ }
+
+ getOrderTooltip()
+ {
+ if (!Object.keys(this.allyPlayerStates).length)
+ return "";
+
+ return "\n" + sprintf(translate("%(order)s: %(hotkey)s to change order."), {
+ "hotkey": setStringTags("\\[Click]", g_HotkeyTags),
+ "order":
+ this.selectedOrder == 0 ?
+ translate("Unordered") :
+ this.selectedOrder == 1 ?
+ translate("Descending") :
+ translate("Ascending")
+ })
+ }
+
+ getAllyStatTooltip(getTooltipData)
+ {
+ let tooltipData = [];
+
+ for (let playerID in this.allyPlayerStates)
+ {
+ let playername = colorizePlayernameHelper("■", playerID) + " " + g_Players[playerID].name;
+ tooltipData.push(getTooltipData(this.allyPlayerStates[playerID], playername));
+ }
+
+ if (this.selectedOrder)
+ tooltipData.sort((a, b) => this.selectedOrder * (b.orderValue - a.orderValue));
+
+ return this.orderTooltip +
+ tooltipData.reduce((result, data) =>
+ result + "\n" + sprintf(translate(this.AllyStatTooltip), data), "");
+ }
+}
+
+CounterManager.ResourceTitleTags = { "font": "sans-bold-16" };
+
+CounterManager.prototype.AllyStatTooltip = markForTranslation("%(playername)s: %(statValue)s");
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/CounterPopulation.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/CounterPopulation.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/CounterPopulation.js
@@ -0,0 +1,68 @@
+/**
+ * This class manages the population counter in the top panel.
+ * It flashes the counter if the training of any owned entity is blocked.
+ */
+class CounterPopulation
+{
+ constructor(resCode, panel, icon, count)
+ {
+ this.resCode = resCode;
+ this.panel = panel;
+ this.icon = icon;
+ this.count = count;
+ this.count.onTick = this.onTick.bind(this);
+ this.isTrainingBlocked = false;
+ this.color = this.DefaultPopulationColor;
+ }
+
+ rebuild(playerState, getAllyStatTooltip)
+ {
+ this.count.caption = sprintf(translate(this.CounterCaption), playerState);
+
+ this.isTrainingBlocked = playerState.trainingBlocked;
+
+ this.panel.tooltip =
+ setStringTags(translate(this.PopulationTooltip), CounterManager.ResourceTitleTags) + "\n" +
+ sprintf(translate(this.MaximumPopulationTooltip), { "popCap": playerState.popMax }) +
+ getAllyStatTooltip(this.getTooltipData.bind(this));
+ }
+
+ getTooltipData(playerState, playername)
+ {
+ return {
+ "playername": playername,
+ "statValue": sprintf(translate(this.AllyPopulationTooltip), playerState),
+ "orderValue": playerState.popCount
+ };
+ }
+
+ onTick()
+ {
+ if (this.panel.hidden)
+ return;
+
+ let newColor = this.isTrainingBlocked && Date.now() % 1000 < 500 ?
+ this.PopulationAlertColor :
+ this.DefaultPopulationColor;
+
+ if (newColor == this.color)
+ return;
+
+ this.color = newColor;
+ this.count.textcolor = newColor;
+ }
+}
+
+CounterPopulation.prototype.CounterCaption = markForTranslation("%(popCount)s/%(popLimit)s");
+
+CounterPopulation.prototype.PopulationTooltip = markForTranslation("Population (current / limit)");
+
+CounterPopulation.prototype.MaximumPopulationTooltip = markForTranslation("Maximum population: %(popCap)s");
+
+CounterPopulation.prototype.AllyPopulationTooltip = markForTranslation("%(popCount)s/%(popLimit)s/%(popMax)s");
+
+/**
+ * Colors to flash when pop limit reached.
+ */
+CounterPopulation.prototype.DefaultPopulationColor = "white";
+CounterPopulation.prototype.PopulationAlertColor = "orange";
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/CounterResource.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/CounterResource.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/CounterResource.js
@@ -0,0 +1,37 @@
+/**
+ * This class manages the counter in the top panel for one resource type.
+ */
+class CounterResource
+{
+ constructor(resCode, panel, icon, count)
+ {
+ this.resCode = resCode;
+ this.panel = panel;
+ this.icon = icon;
+ this.count = count;
+ }
+
+ rebuild(playerState, getAllyStatTooltip)
+ {
+ this.count.caption = Math.floor(playerState.resourceCounts[this.resCode]);
+
+ // TODO: Set the tooltip only if hovered?
+ let description = g_ResourceData.GetResource(this.resCode).description;
+ if (description)
+ description = "\n" + translate(description);
+
+ this.panel.tooltip =
+ setStringTags(resourceNameFirstWord(this.resCode), CounterManager.ResourceTitleTags) +
+ description +
+ getAllyStatTooltip(this.getTooltipData.bind(this));
+ }
+
+ getTooltipData(playerState, playername)
+ {
+ return {
+ "playername": playername,
+ "statValue": Math.round(playerState.resourceCounts[this.resCode]),
+ "orderValue": Math.round(playerState.resourceCounts[this.resCode])
+ };
+ }
+}
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/Counters.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/Counters.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/Counters.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/DiplomacyButton.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/DiplomacyButton.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/DiplomacyButton.js
@@ -1,22 +0,0 @@
-/**
- * This class handles the button which opens the diplomacy dialog.
- */
-class DiplomacyButton
-{
- constructor(diplomacyDialog)
- {
- this.diplomacyButton = Engine.GetGUIObjectByName("diplomacyButton");
- this.diplomacyButton.enabled = !Engine.IsAtlasRunning();
- this.diplomacyButton.onPress = diplomacyDialog.toggle.bind(diplomacyDialog);
- }
-
- update()
- {
- this.diplomacyButton.hidden = g_ViewedPlayer < 1;
- this.diplomacyButton.tooltip =
- colorizeHotkey("%(hotkey)s" + " ", "session.gui.diplomacy.toggle") +
- translate(this.Tooltip);
- }
-}
-
-DiplomacyButton.prototype.Tooltip = markForTranslation("Diplomacy");
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/FollowPlayer.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/FollowPlayer.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/FollowPlayer.js
@@ -0,0 +1,35 @@
+/**
+ * This class manages the checkbox that enables the observermode option to follow the commands of a player.
+ */
+class FollowPlayer
+{
+ constructor(playerViewControl)
+ {
+ this.viewPlayer = Engine.GetGUIObjectByName("viewPlayer");
+ this.followPlayerLabel = Engine.GetGUIObjectByName("followPlayerLabel");
+ this.optionFollowPlayer = Engine.GetGUIObjectByName("optionFollowPlayer");
+ this.followPlayer = Engine.GetGUIObjectByName("followPlayer");
+
+ this.followPlayer.onPress = this.onPress.bind(this);
+ this.followPlayer.onWindowResized = this.onWindowResized.bind(this);
+ playerViewControl.registerViewedPlayerChangeHandler(this.onViewedPlayerChange.bind(this));
+ }
+
+ onPress()
+ {
+ g_FollowPlayer = !g_FollowPlayer;
+ }
+
+ onViewedPlayerChange()
+ {
+ // Following gaia can be interesting on scripted maps
+ this.optionFollowPlayer.hidden = !g_IsObserver || g_ViewedPlayer == -1;
+ }
+
+ onWindowResized()
+ {
+ this.followPlayerLabel.hidden =
+ this.followPlayerLabel.getComputedSize().left + this.followPlayerLabel.getTextSize().width >
+ this.viewPlayer.getComputedSize().left;
+ }
+}
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/FollowPlayer.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/FollowPlayer.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/FollowPlayer.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ Follow Player
+
+
+
+ Follow Player
+
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/DiplomacyDialogButton.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/DiplomacyDialogButton.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/DiplomacyDialogButton.js
@@ -0,0 +1,29 @@
+/**
+ * This class handles the button which opens the diplomacy dialog.
+ */
+class DiplomacyDialogButton
+{
+ constructor(playerViewControl, diplomacyDialog)
+ {
+ this.diplomacyButton = Engine.GetGUIObjectByName("diplomacyButton");
+ this.diplomacyButton.enabled = !Engine.IsAtlasRunning();
+ this.diplomacyButton.onPress = diplomacyDialog.toggle.bind(diplomacyDialog);
+
+ registerHotkeyChangeHandler(this.onHotkeyChange.bind(this));
+ playerViewControl.registerViewedPlayerChangeHandler(this.onViewedPlayerChange.bind(this));
+ }
+
+ onHotkeyChange()
+ {
+ this.diplomacyButton.tooltip =
+ colorizeHotkey("%(hotkey)s" + " ", "session.gui.diplomacy.toggle") +
+ translate(this.Tooltip);
+ }
+
+ onViewedPlayerChange()
+ {
+ this.diplomacyButton.hidden = g_ViewedPlayer < 1;
+ }
+}
+
+DiplomacyDialogButton.prototype.Tooltip = markForTranslation("Diplomacy");
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/DiplomacyDialogButton.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/DiplomacyDialogButton.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/DiplomacyDialogButton.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/GameSpeedButton.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/GameSpeedButton.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/GameSpeedButton.js
@@ -0,0 +1,12 @@
+/**
+ * This class handles the button that shows the gamespeed control.
+ */
+class GameSpeedButton
+{
+ constructor(gameSpeedControl)
+ {
+ let gameSpeedButton = Engine.GetGUIObjectByName("gameSpeedButton");
+ gameSpeedButton.onPress = gameSpeedControl.toggle.bind(gameSpeedControl);
+ gameSpeedButton.hidden = g_IsNetworked;
+ }
+}
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/GameSpeedButton.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/GameSpeedButton.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/GameSpeedButton.xml
@@ -0,0 +1,11 @@
+
+
+ Game Speed
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/ObjectivesDialogButton.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/ObjectivesDialogButton.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/ObjectivesDialogButton.js
@@ -0,0 +1,23 @@
+/**
+ * This class handles the button that displays the games objectives.
+ */
+class ObjectivesDialogButton
+{
+ constructor(objectivesDialog)
+ {
+ this.objectivesButton = Engine.GetGUIObjectByName("objectivesButton");
+ this.objectivesButton.enabled = !Engine.IsAtlasRunning();
+ this.objectivesButton.onPress = objectivesDialog.toggle.bind(objectivesDialog);
+
+ registerHotkeyChangeHandler(this.onHotkeyChange.bind(this));
+ }
+
+ onHotkeyChange()
+ {
+ this.objectivesButton.tooltip =
+ colorizeHotkey("%(hotkey)s" + " ", "session.gui.objectives.toggle") +
+ translate(this.Tooltip);
+ }
+}
+
+ObjectivesDialogButton.prototype.Tooltip = markForTranslation("Objectives");
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/ObjectivesDialogButton.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/ObjectivesDialogButton.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/ObjectivesDialogButton.xml
@@ -0,0 +1,16 @@
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/TradeDialogButton.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/TradeDialogButton.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/TradeDialogButton.js
@@ -0,0 +1,31 @@
+/**
+ * This class handles the button which opens the diplomacy dialog.
+ */
+class TradeDialogButton
+{
+ constructor(playerViewControl, tradeDialog)
+ {
+ this.tradeButton = Engine.GetGUIObjectByName("tradeButton");
+ this.tradeButton.onPress = tradeDialog.toggle.bind(tradeDialog);
+ this.isAvailable =
+ g_ResourceData.GetTradableCodes().length ||
+ g_ResourceData.GetBarterableCodes().length;
+
+ playerViewControl.registerViewedPlayerChangeHandler(this.onViewedPlayerChange.bind(this));
+ registerHotkeyChangeHandler(this.onHotkeyChange.bind(this));
+ }
+
+ onHotkeyChange()
+ {
+ this.tradeButton.tooltip =
+ colorizeHotkey("%(hotkey)s" + " ", "session.gui.barter.toggle") +
+ translate(this.Tooltip);
+ }
+
+ onViewedPlayerChange()
+ {
+ this.tradeButton.hidden = g_ViewedPlayer < 1 || !this.isAvailable;
+ }
+}
+
+TradeDialogButton.prototype.Tooltip = markForTranslation("Barter & Trade");
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/TradeDialogButton.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/TradeDialogButton.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/IconButtons/TradeDialogButton.xml
@@ -0,0 +1,10 @@
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/MenuButton.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/MenuButton.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/MenuButton.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Menu
+
+
+ toggleMenu();
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/PlayerViewControl.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/PlayerViewControl.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/PlayerViewControl.js
@@ -0,0 +1,111 @@
+/**
+ * This class manages the player selection dropdown.
+ * This dropdown is available in observermode and when enabling the developers option.
+ * For observers, the user can view the player but not send commands.
+ * If the developer feature is enabled and cheats enabled, the player becomes
+ * assigned to and can control the selected player.
+ */
+class PlayerViewControl
+{
+ constructor(diplomacyColors)
+ {
+ // State
+ this.viewPlayer = Engine.GetGUIObjectByName("viewPlayer");
+ this.observerText = Engine.GetGUIObjectByName("observerText");
+ this.changePerspective = false;
+ this.playerIDChangeHandlers = [];
+ this.viewedPlayerChangeHandlers = [];
+ this.preViewedPlayerChangeHandlers = [];
+
+ // Events
+ this.viewPlayer.onSelectionChange = this.onSelectionChange.bind(this);
+ registerPlayersInitHandler(this.onPlayersInit.bind(this));
+ this.registerViewedPlayerChangeHandler(this.rebuild.bind(this));
+ }
+
+ registerPlayerIDChangeHandler(handler)
+ {
+ this.playerIDChangeHandlers.push(handler);
+ }
+
+ registerViewedPlayerChangeHandler(handler)
+ {
+ this.viewedPlayerChangeHandlers.push(handler);
+ }
+
+ registerPreViewedPlayerChangeHandler(handler)
+ {
+ this.preViewedPlayerChangeHandlers.push(handler);
+ }
+
+ rebuild()
+ {
+ this.viewPlayer.list_data = [-1].concat(g_Players.map((player, i) => i));
+ this.viewPlayer.list = [translate(this.ObserverTitle)].concat(g_Players.map(
+ (player, i) => colorizePlayernameHelper("■", i) + " " + player.name
+ ));
+ this.viewPlayer.hidden = !g_IsObserver && !this.changePerspective;
+ this.observerText.hidden = g_ViewedPlayer > 0;
+ }
+
+ onPlayersInit()
+ {
+ this.rebuild();
+
+ // Select "observer" in the view player dropdown when rejoining as a defeated player
+ let playerState = g_Players[Engine.GetPlayerID()];
+ this.viewPlayer.selected = playerState && playerState.state == "defeated" ? 0 : Engine.GetPlayerID() + 1;
+ }
+
+ setChangePerspective(enabled)
+ {
+ this.changePerspective = enabled;
+ this.rebuild();
+ this.onSelectionChange();
+ }
+
+ selectViewPlayer(playerID)
+ {
+ this.viewPlayer.selected = playerID;
+ }
+
+ onSelectionChange()
+ {
+ let playerID = this.viewPlayer.selected - 1;
+ if (playerID < -1 || playerID > g_Players.length - 1)
+ {
+ error("Can't assume invalid player ID: " + playerID);
+ return;
+ }
+
+ for (let handler of this.preViewedPlayerChangeHandlers)
+ handler();
+
+ // TODO: should set this state variable only once in this scope
+ g_IsObserver = isPlayerObserver(Engine.GetPlayerID());
+
+ if (g_IsObserver || this.changePerspective)
+ {
+ if (g_ViewedPlayer != playerID)
+ clearSelection();
+ g_ViewedPlayer = playerID;
+ }
+
+ if (this.changePerspective)
+ {
+ Engine.SetPlayerID(g_ViewedPlayer);
+ g_IsObserver = isPlayerObserver(g_ViewedPlayer);
+ }
+ Engine.SetViewedPlayer(g_ViewedPlayer);
+
+ // Send events after all states were updated
+ if (this.changePerspective)
+ for (let handler of this.playerIDChangeHandlers)
+ handler();
+
+ for (let handler of this.viewedPlayerChangeHandlers)
+ handler();
+ }
+}
+
+PlayerViewControl.prototype.ObserverTitle = markForTranslation("Observer");
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/PlayerViewControl.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/PlayerViewControl.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/PlayerViewControl.xml
@@ -0,0 +1,20 @@
+
+
+
+ Choose player to view
+
+
+
+ Observer Mode
+
+
+
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/TradeDialogButton.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/TradeDialogButton.js
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/TradeDialogButton.js
@@ -1,23 +0,0 @@
-/**
- * This class handles the button which opens the diplomacy dialog.
- */
-class TradeDialogButton
-{
- constructor(tradeDialog)
- {
- this.tradeButton = Engine.GetGUIObjectByName("tradeButton");
- this.tradeButton.onPress = tradeDialog.toggle.bind(tradeDialog);
- this.isAvailable = g_ResourceData.GetTradableCodes().length || g_ResourceData.GetBarterableCodes().length;
- }
-
- update()
- {
- this.tradeButton.hidden = g_ViewedPlayer < 1 || !this.isAvailable;
-
- this.tradeButton.tooltip =
- colorizeHotkey("%(hotkey)s" + " ", "session.gui.barter.toggle") +
- translate(this.Tooltip);
- }
-}
-
-TradeDialogButton.prototype.Tooltip = markForTranslation("Barter & Trade");
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_diplomacy.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_diplomacy.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_diplomacy.xml
@@ -1,11 +0,0 @@
-
-
-
-
-
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_game_speed.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_game_speed.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_game_speed.xml
@@ -1,20 +0,0 @@
-
-
-
- Game Speed
-
-
- toggleGameSpeed();
-
-
-
-
- Choose game speed
-
-
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_menu.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_menu.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_menu.xml
@@ -1,19 +0,0 @@
-
-
-
-
-
- Menu
-
-
- toggleMenu();
-
-
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_objectives.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_objectives.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_objectives.xml
@@ -1,19 +0,0 @@
-
-
-
-
- toggleObjectives();
-
-
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_trade.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_trade.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/button_trade.xml
@@ -1,10 +0,0 @@
-
-
-
-
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/civ_icon.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/civ_icon.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/civ_icon.xml
@@ -1,11 +0,0 @@
-
-
-
-
- openStrucTree(g_CivInfo.page)
-
-
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/label.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/label.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/label.xml
@@ -1,19 +0,0 @@
-
-
-
- ALPHA XXIV
-
-
-
- this.caption = getBuildString()
-
-
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/resource_population.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/resource_population.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/resource_population.xml
@@ -1,10 +0,0 @@
-
-
-
-
-
-
- saveResPopTooltipSort();
- updatePlayerDisplay();
-
-
Index: ps/trunk/binaries/data/mods/public/gui/session/top_panel/resources.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/top_panel/resources.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/top_panel/resources.xml
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
- saveResPopTooltipSort();
- updatePlayerDisplay();
-
-
-
-
Index: ps/trunk/binaries/data/mods/public/gui/session/trade/TradeDialog.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/trade/TradeDialog.js
+++ ps/trunk/binaries/data/mods/public/gui/session/trade/TradeDialog.js
@@ -3,14 +3,19 @@
*/
class TradeDialog
{
- constructor()
+ constructor(playerViewControl)
{
this.tradePanel = new this.TradePanel();
this.barterPanel = new this.BarterPanel();
this.tradeDialogPanel = Engine.GetGUIObjectByName("tradeDialogPanel");
+ registerPlayersInitHandler(this.onPlayersInit.bind(this));
Engine.GetGUIObjectByName("closeTrade").onPress = this.close.bind(this);
+
+ registerSimulationUpdateHandler(this.updateIfOpen.bind(this))
+ registerEntitySelectionChangeHandler(this.updateIfOpen.bind(this));
+ playerViewControl.registerViewedPlayerChangeHandler(this.onViewedPlayerChange.bind(this));
}
open()
@@ -34,6 +39,14 @@
return !this.tradeDialogPanel.hidden;
}
+ onViewedPlayerChange()
+ {
+ if (g_ViewedPlayer >= 1)
+ this.updateIfOpen();
+ else
+ this.close();
+ }
+
toggle()
{
let open = this.isOpen();
@@ -43,12 +56,10 @@
this.open();
}
- update()
+ updateIfOpen()
{
- if (!this.isOpen())
- return;
-
- this.updatePanels();
+ if (this.isOpen())
+ this.updatePanels();
}
updatePanels()
@@ -57,7 +68,7 @@
this.tradePanel.update();
}
- resize()
+ onPlayersInit()
{
let size = this.tradeDialogPanel.size;