mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-18 14:23:56 -07:00
Implement session event subscription system and rewrite TopPanel, PlayerViewControl, GameSpeed, Pausing, ObjectivesDialog to use object orientation, refs #5387.
New controller classes: PlayerViewControl, PauseControl, GameSpeedControl New viewer classes: ObjectivesDialog, PauseOverlay, FollowPlayer, TopPanel (BuildLabel, CivIcon, CounterManager, CounterPopulation, CounterResource refs 7e14a33411/D1113, GameSpeedButton, ObjectivesDialogButton) New events: SimulationUpdate, EntitySelectionChange, ViewedPlayerChange, PreViewedPlayerChangeHandler, PlayerIDChange, PlayersInit, PlayersFinished, Pause, DiplomacyColorsChange, HotkeyChange, refs #2604 Improves GUI onSimuationUpdate performance without selected entities by allegedly 30%. Delete misleading dead code resign command from leaveGame and rename to endGame. The command is not sent via network (seefa85527baf) nor processed in simulation, because the Game instance is deleted immediately thereafter, introduced infcedcae052, refsa3e1c68b9a,39ffb0a6bd,9f796068f8. Remove explicitResume 0 value frome57c99c6f6and8ae67ed15fwhich should have been a false if defined, and is equivalent to the default. Restore fast forwarding option from cd571035bb/D595 for developers changing the perspective to observer or player following56308ec1ad. Add pausing for the delete dialog missing following7a7ebaa983. Differential Revision: https://code.wildfiregames.com/D2378 This was SVN commit r23076.
This commit is contained in:
parent
ed11b3f039
commit
e3f43f6352
50 changed files with 1128 additions and 709 deletions
|
|
@ -12,9 +12,18 @@ class DiplomacyColors
|
|||
|
||||
// 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));
|
||||
}
|
||||
|
||||
onPlayerInit()
|
||||
registerDiplomacyColorsChangeHandler(handler)
|
||||
{
|
||||
this.diplomacyColorsChangeHandlers.push(handler);
|
||||
}
|
||||
|
||||
onPlayersInit()
|
||||
{
|
||||
this.computeTeamColors();
|
||||
}
|
||||
|
|
@ -61,7 +70,8 @@ class DiplomacyColors
|
|||
"selected": g_Selection.toList()
|
||||
});
|
||||
|
||||
updateGUIObjects();
|
||||
for (let handler of this.diplomacyColorsChangeHandlers)
|
||||
handler(this.enabled);
|
||||
}
|
||||
|
||||
computeTeamColors()
|
||||
|
|
|
|||
45
binaries/data/mods/public/gui/session/GameSpeedControl.js
Normal file
45
binaries/data/mods/public/gui/session/GameSpeedControl.js
Normal file
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
12
binaries/data/mods/public/gui/session/GameSpeedControl.xml
Normal file
12
binaries/data/mods/public/gui/session/GameSpeedControl.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object
|
||||
name="gameSpeed"
|
||||
type="dropdown"
|
||||
style="ModernDropDown"
|
||||
size="100%-390 40 100%-230 65"
|
||||
hidden="true"
|
||||
tooltip_style="sessionToolTip"
|
||||
dropdown_size="300"
|
||||
>
|
||||
<translatableAttribute id="tooltip">Choose game speed</translatableAttribute>
|
||||
</object>
|
||||
86
binaries/data/mods/public/gui/session/PauseControl.js
Normal file
86
binaries/data/mods/public/gui/session/PauseControl.js
Normal file
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
44
binaries/data/mods/public/gui/session/PauseOverlay.js
Normal file
44
binaries/data/mods/public/gui/session/PauseOverlay.js
Normal file
|
|
@ -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");
|
||||
16
binaries/data/mods/public/gui/session/PauseOverlay.xml
Normal file
16
binaries/data/mods/public/gui/session/PauseOverlay.xml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object type="button" name="pauseOverlay" tooltip_style="sessionToolTip" hidden="true" z="0">
|
||||
|
||||
<object type="image" sprite="sessionOverlayBackground" ghost="true"/>
|
||||
|
||||
<object size="50%-128 40%-20 50%+128 40%+20" type="text" style="PauseText" ghost="true">
|
||||
<translatableAttribute id="caption">Game Paused</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<object name="resumeMessage" size="50%-128 40%+20 50%+128 40%+40" type="text" style="ResumeMessageText" ghost="true">
|
||||
<translatableAttribute id="caption">Click to Resume Game</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<object name="pausedByText" size="30% 40%+50 70% 100%" type="text" style="netStatusPlayersText" ghost="true" hidden="true"/>
|
||||
|
||||
</object>
|
||||
19
binaries/data/mods/public/gui/session/TopPanel.js
Normal file
19
binaries/data/mods/public/gui/session/TopPanel.js
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
9
binaries/data/mods/public/gui/session/TopPanel.xml
Normal file
9
binaries/data/mods/public/gui/session/TopPanel.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="topPanel"
|
||||
type="image"
|
||||
sprite="topPanel"
|
||||
size="-3 0 100%+3 36"
|
||||
>
|
||||
<include directory="gui/session/top_panel/"/>
|
||||
<include directory="gui/session/top_panel/IconButtons/"/>
|
||||
</object>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
class Chat
|
||||
{
|
||||
constructor()
|
||||
constructor(playerViewControl)
|
||||
{
|
||||
this.ChatWindow = new ChatWindow();
|
||||
this.ChatOverlay = new ChatOverlay();
|
||||
|
|
@ -35,6 +35,9 @@ class Chat
|
|||
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"); });
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class ChatWindow
|
|||
|
||||
this.extendedChat.checked = Engine.ConfigDB_GetValue("user", "chat.session.extended") == "true";
|
||||
|
||||
this.chatDialogPanel.onWindowResized = this.resizeChatWindow.bind(this);
|
||||
this.resizeChatWindow();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 @@ DeveloperOverlay.prototype.getCommands = function() {
|
|||
{
|
||||
"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.layout = function()
|
|||
|
||||
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.toggle = function()
|
|||
|
||||
DeveloperOverlay.prototype.update = function()
|
||||
{
|
||||
this.updateValues();
|
||||
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 @@ DeveloperOverlay.prototype.isTimeWarpEnabled = function() {
|
|||
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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
class DiplomacyDialog
|
||||
{
|
||||
constructor(diplomacyColors)
|
||||
constructor(playerViewControl, diplomacyColors)
|
||||
{
|
||||
this.diplomacyDialogCeasefireCounter = new DiplomacyDialogCeasefireCounter();
|
||||
this.diplomacyDialogColorsButton = new DiplomacyDialogColorsButton(diplomacyColors);
|
||||
|
|
@ -12,34 +12,40 @@ class DiplomacyDialog
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,22 +5,25 @@ class DiplomacyDialogColorsButton
|
|||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,10 +39,6 @@
|
|||
</action>
|
||||
</object>
|
||||
|
||||
<object hotkey="pause">
|
||||
<action on="Press">togglePause();</action>
|
||||
</object>
|
||||
|
||||
<object hotkey="quicksave">
|
||||
<action on="Press">Engine.QuickSave(getSavedGameData());</action>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -29,19 +29,21 @@ var g_CivInfo = {
|
|||
|
||||
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 @@ function toggleMenu()
|
|||
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 chatMenuButton()
|
|||
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 @@ function exitMenuButton()
|
|||
},
|
||||
"singleplayer": {
|
||||
"caption": translate("Are you sure you want to quit?"),
|
||||
"buttons": [resumeGame, leaveGame]
|
||||
"buttons": [resumeGame, endGame]
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -154,14 +171,13 @@ function resignQuestion()
|
|||
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 @@ function openDeleteDialog(selection)
|
|||
"type": "delete-entities",
|
||||
"entities": selectionArg
|
||||
});
|
||||
resumeGame();
|
||||
};
|
||||
|
||||
messageBox(
|
||||
|
|
@ -184,7 +201,7 @@ function openDeleteDialog(selection)
|
|||
function openSave()
|
||||
{
|
||||
closeOpenDialogs();
|
||||
pauseGame();
|
||||
g_PauseControl.implicitPause();
|
||||
|
||||
Engine.PushGuiPage(
|
||||
"page_loadgame.xml",
|
||||
|
|
@ -195,7 +212,7 @@ function openSave()
|
|||
function openOptions()
|
||||
{
|
||||
closeOpenDialogs();
|
||||
pauseGame();
|
||||
g_PauseControl.implicitPause();
|
||||
|
||||
Engine.PushGuiPage(
|
||||
"page_options.xml",
|
||||
|
|
@ -216,73 +233,6 @@ function toggleTutorial()
|
|||
!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 closeObjectives()
|
|||
function openGameSummary()
|
||||
{
|
||||
closeOpenDialogs();
|
||||
pauseGame();
|
||||
g_PauseControl.implicitPause();
|
||||
|
||||
let extendedSimState = Engine.GuiInterfaceCall("GetExtendedSimulationState");
|
||||
Engine.PushGuiPage(
|
||||
|
|
@ -309,13 +259,17 @@ function openGameSummary()
|
|||
},
|
||||
"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 @@ function storeCivInfoPage(data)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,13 +79,11 @@
|
|||
<!-- Pause / Resume Button -->
|
||||
<object type="button"
|
||||
name="pauseButton"
|
||||
hotkey="pause"
|
||||
style="StoneButtonFancy"
|
||||
size="0 192 100% 220"
|
||||
tooltip_style="sessionToolTip"
|
||||
>
|
||||
<translatableAttribute id="caption">Pause</translatableAttribute>
|
||||
<action on="Press">togglePause();</action>
|
||||
</object>
|
||||
/>
|
||||
|
||||
<!-- Resign button -->
|
||||
<object type="button"
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ var g_NetMessageTypes = {
|
|||
handlePlayerAssignmentsMessage(msg);
|
||||
},
|
||||
"paused": msg => {
|
||||
setClientPauseState(msg.guid, msg.pause);
|
||||
g_PauseControl.setClientPauseState(msg.guid, msg.pause);
|
||||
},
|
||||
"clients-loading": msg => {
|
||||
handleClientsLoadingMessage(msg.guids);
|
||||
|
|
@ -388,7 +388,7 @@ function updateTutorial(notification)
|
|||
{
|
||||
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 onClientJoin(guid)
|
|||
|
||||
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 @@ function openDialog(dialogName, data, player)
|
|||
}
|
||||
}
|
||||
|
||||
pauseGame();
|
||||
g_PauseControl.implicitPause();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,22 +8,26 @@ class MiniMapDiplomacyColorsButton
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -39,9 +39,8 @@
|
|||
/>
|
||||
</object>
|
||||
|
||||
<object size="50%-64 100%-50 50%+64 100%-22" type="button" style="StoneButton">
|
||||
<object name="closeObjectives" size="50%-64 100%-50 50%+64 100%-22" type="button" style="StoneButton">
|
||||
<translatableAttribute id="caption">Close</translatableAttribute>
|
||||
<action on="Press">closeObjectives();</action>
|
||||
</object>
|
||||
|
||||
</object>
|
||||
|
|
@ -1147,7 +1147,7 @@ function initSelectionPanels()
|
|||
*/
|
||||
function showTemplateDetails(templateName, civCode)
|
||||
{
|
||||
pauseGame();
|
||||
g_PauseControl.implicitPause();
|
||||
|
||||
Engine.PushGuiPage(
|
||||
"page_viewer.xml",
|
||||
|
|
|
|||
|
|
@ -11,25 +11,16 @@ const g_VictoryDurations = prepareForDropdown(g_Settings && g_Settings.VictoryDu
|
|||
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
|
||||
|
|
@ -77,16 +68,6 @@ var g_HasRejoined = false;
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
|
@ -138,11 +119,6 @@ var g_ShowGUI = true;
|
|||
*/
|
||||
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).
|
||||
*/
|
||||
|
|
@ -153,6 +129,33 @@ var g_TechnologyData = {};
|
|||
|
||||
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 @@ function init(initData, hotloadData)
|
|||
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 @@ function init(initData, hotloadData)
|
|||
}
|
||||
|
||||
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 @@ function updateDisplayedPlayerColors()
|
|||
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 @@ function initializeMusic()
|
|||
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 @@ function playersFinished(players, victoryString, won)
|
|||
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 @@ function playersFinished(players, victoryString, won)
|
|||
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 @@ function onTick()
|
|||
// 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 @@ function onTick()
|
|||
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 @@ function onSimulationUpdate()
|
|||
|
||||
GetMultipleEntityStates(g_Selection.toList());
|
||||
|
||||
for (let handler of g_SimulationUpdateHandlers)
|
||||
handler();
|
||||
|
||||
// TODO: Move to handlers
|
||||
updateCinemaPath();
|
||||
handleNotifications();
|
||||
updateGUIObjects();
|
||||
|
|
@ -791,6 +680,7 @@ function confirmExit()
|
|||
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 @@ function confirmExit()
|
|||
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 @@ function updateCinemaPath()
|
|||
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 @@ function updateGUIObjects()
|
|||
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 @@ function updateGUIObjects()
|
|||
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 @@ function updateGroups()
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 recalculateStatusBarDisplay(remove = false)
|
|||
});
|
||||
}
|
||||
|
||||
function removeStatusBarDisplay()
|
||||
{
|
||||
if (g_ShowAllStatusBars)
|
||||
recalculateStatusBarDisplay(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts the given configuration boolean and returns the current state.
|
||||
* For example "silhouettes".
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
<script directory="gui/session/diplomacy/playercontrols/"/>
|
||||
<script directory="gui/session/minimap/"/>
|
||||
<script directory="gui/session/top_panel/"/>
|
||||
<script directory="gui/session/top_panel/IconButtons/"/>
|
||||
<script directory="gui/session/trade/"/>
|
||||
<script directory="gui/session/objectives/"/>
|
||||
|
||||
<object name="session">
|
||||
|
||||
|
|
@ -17,10 +19,6 @@
|
|||
onTick();
|
||||
</action>
|
||||
|
||||
<action on="WindowResized">
|
||||
onWindowResized();
|
||||
</action>
|
||||
|
||||
<action on="SavegameLoaded">
|
||||
restoreSavedGameData(arguments[0]);
|
||||
</action>
|
||||
|
|
@ -63,23 +61,12 @@
|
|||
tooltip_style="sessionToolTip"
|
||||
>
|
||||
<translatableAttribute id="caption">Exit</translatableAttribute>
|
||||
<action on="Press">leaveGame();</action>
|
||||
<action on="Press">endGame();</action>
|
||||
</object>
|
||||
<object name="loadingClientsText" size="50%-300 50%+60 50%+300 50%+110" type="text" style="netStatusPlayersText" hidden="true"/>
|
||||
</object>
|
||||
|
||||
<!-- Pause Overlay -->
|
||||
<object type="button" name="pauseOverlay" tooltip_style="sessionToolTip" hidden="true" z="0">
|
||||
<object type="image" sprite="sessionOverlayBackground" ghost="true"/>
|
||||
<object size="50%-128 40%-20 50%+128 40%+20" type="text" style="PauseText" ghost="true">
|
||||
<translatableAttribute id="caption">Game Paused</translatableAttribute>
|
||||
</object>
|
||||
<object name="resumeMessage" size="50%-128 40%+20 50%+128 40%+40" type="text" style="ResumeMessageText" ghost="true">
|
||||
<translatableAttribute id="caption">Click to Resume Game</translatableAttribute>
|
||||
</object>
|
||||
<object name="pausedByText" size="30% 40%+50 70% 100%" type="text" style="netStatusPlayersText" ghost="true" hidden="true"/>
|
||||
<action on="Press">togglePause();</action>
|
||||
</object>
|
||||
<include file="gui/session/PauseOverlay.xml"/>
|
||||
|
||||
<!-- Notification Area -->
|
||||
<object name="notificationPanel" type="image" size="50%-300 60 50%+300 120" ghost="true">
|
||||
|
|
@ -103,9 +90,10 @@
|
|||
<include directory="gui/session/chat/"/>
|
||||
<include directory="gui/session/dialogs/"/>
|
||||
<include directory="gui/session/diplomacy/"/>
|
||||
<include directory="gui/session/objectives/"/>
|
||||
<include file="gui/session/developer_overlay.xml"/>
|
||||
<include file="gui/session/objectives_window.xml"/>
|
||||
<include file="gui/session/top_panel.xml"/>
|
||||
<include file="gui/session/GameSpeedControl.xml"/>
|
||||
<include file="gui/session/TopPanel.xml"/>
|
||||
<include file="gui/session/trade/TradeDialog.xml"/>
|
||||
<include file="gui/session/tutorial_panel.xml"/>
|
||||
<include file="gui/session/menu.xml"/>
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="topPanel"
|
||||
type="image"
|
||||
sprite="topPanel"
|
||||
size="-3 0 100%+3 36"
|
||||
>
|
||||
<!-- most elements are defined in this directory -->
|
||||
<include directory="gui/session/top_panel/"/>
|
||||
|
||||
<!-- ================================ ================================ -->
|
||||
<!-- "Follow Player" option for observers -->
|
||||
<!-- ================================ ================================ -->
|
||||
<object name="optionFollowPlayer" size="50%+54 4 50%+256 100%" hidden="true">
|
||||
|
||||
<!-- Checkbox -->
|
||||
<object name="followPlayer"
|
||||
type="checkbox"
|
||||
checked="false"
|
||||
style="ModernTickBox"
|
||||
size="0 4 20 100%"
|
||||
tooltip_style="sessionToolTip"
|
||||
>
|
||||
<translatableAttribute id="tooltip" context="observer mode">Follow Player</translatableAttribute>
|
||||
<action on="Press">g_FollowPlayer = !g_FollowPlayer;</action>
|
||||
</object>
|
||||
|
||||
<!-- Label -->
|
||||
<object name="followPlayerLabel" type="text" size="20 2 100% 100%" text_align="left" textcolor="white">
|
||||
<translatableAttribute id="caption" context="observer mode">Follow Player</translatableAttribute>
|
||||
</object>
|
||||
</object>
|
||||
|
||||
<!-- ================================ ================================ -->
|
||||
<!-- Switch the view perspective to another player's (for observers and for eased development) -->
|
||||
<!-- ================================ ================================ -->
|
||||
<object
|
||||
size="85%-279 5 100%-293 100%-5"
|
||||
name="viewPlayer"
|
||||
type="dropdown"
|
||||
hidden="true"
|
||||
z="50"
|
||||
style="ModernDropDown"
|
||||
tooltip_style="sessionToolTipBold"
|
||||
dropdown_size="500"
|
||||
>
|
||||
<translatableAttribute id="tooltip">Choose player to view</translatableAttribute>
|
||||
<action on="SelectionChange">selectViewPlayer(this.selected - 1);</action>
|
||||
</object>
|
||||
|
||||
<!-- ================================ ================================ -->
|
||||
<!-- Observer Mode Label -->
|
||||
<!-- ================================ ================================ -->
|
||||
<object size="50 4 50% 100%-2" name="observerText" type="text" style="ModernLeftLabelText" hidden="true">
|
||||
<translatableAttribute id="caption">Observer Mode</translatableAttribute>
|
||||
</object>
|
||||
|
||||
</object>
|
||||
|
|
@ -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%";
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object size="50%+20 0 100%-226 100%" name="alphaLabel" type="text" style="ModernLabelText" text_valign="top" ghost="true">
|
||||
<object name="buildLabel" ghost="true">
|
||||
|
||||
<!-- IMPORTANT: remember to update pregame/ProjectInformation.js in sync with this: -->
|
||||
<translatableAttribute id="caption">ALPHA XXIV</translatableAttribute>
|
||||
<object type="text" style="ModernLabelText" text_valign="top" ghost="true">
|
||||
<translatableAttribute id="caption">ALPHA XXIV</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<!-- Displays build date and revision number-->
|
||||
<object
|
||||
name="buildTimeLabel"
|
||||
type="text"
|
||||
size="50%-128 0 50%+128 100%-2"
|
||||
style="ModernLabelText"
|
||||
ghost="true"
|
||||
size="50%-128 0 50%+128 100%-2"
|
||||
font="sans-stroke-12"
|
||||
textcolor="white"
|
||||
text_align="center"
|
||||
text_valign="bottom"
|
||||
>
|
||||
<action on="Load">this.caption = getBuildString()</action>
|
||||
</object>
|
||||
/>
|
||||
</object>
|
||||
42
binaries/data/mods/public/gui/session/top_panel/CivIcon.js
Normal file
42
binaries/data/mods/public/gui/session/top_panel/CivIcon.js
Normal file
|
|
@ -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" };
|
||||
|
|
@ -5,7 +5,5 @@
|
|||
name="civIcon"
|
||||
tooltip_style="sessionToolTipBold"
|
||||
>
|
||||
<object name="civIconOverlay" style="CivIconOverlay" type="button">
|
||||
<action on="Press">openStrucTree(g_CivInfo.page)</action>
|
||||
</object>
|
||||
<object name="civIconOverlay" style="CivIconOverlay" type="button"/>
|
||||
</object>
|
||||
|
|
@ -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");
|
||||
|
|
@ -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";
|
||||
|
|
@ -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])
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- This list encompasses resources and population -->
|
||||
<object size="0 0 50%-90-52 100%" name="resourceCounts">
|
||||
<repeat count="4">
|
||||
<repeat count="5">
|
||||
<object name="resource[n]" size="0 0 89 100%" type="button" style="resourceCounter" tooltip_style="sessionToolTipBold">
|
||||
<object size="0 -2 40 38" type="image" name="resource[n]_icon" ghost="true"/>
|
||||
<object size="34 0 100%-2 100%-2" type="text" style="resourceText" name="resource[n]_count"/>
|
||||
<action on="Press">
|
||||
saveResPopTooltipSort();
|
||||
updatePlayerDisplay();
|
||||
</action>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="optionFollowPlayer" size="50%+54 4 50%+256 100%" hidden="true">
|
||||
|
||||
<object name="followPlayer"
|
||||
type="checkbox"
|
||||
checked="false"
|
||||
style="ModernTickBox"
|
||||
size="0 4 20 100%"
|
||||
tooltip_style="sessionToolTip"
|
||||
>
|
||||
<translatableAttribute id="tooltip" context="observer mode">Follow Player</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<object name="followPlayerLabel" type="text" size="20 2 100% 100%" text_align="left" textcolor="white">
|
||||
<translatableAttribute id="caption" context="observer mode">Follow Player</translatableAttribute>
|
||||
</object>
|
||||
|
||||
</object>
|
||||
|
|
@ -1,22 +1,29 @@
|
|||
/**
|
||||
* This class handles the button which opens the diplomacy dialog.
|
||||
*/
|
||||
class DiplomacyButton
|
||||
class DiplomacyDialogButton
|
||||
{
|
||||
constructor(diplomacyDialog)
|
||||
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));
|
||||
}
|
||||
|
||||
update()
|
||||
onHotkeyChange()
|
||||
{
|
||||
this.diplomacyButton.hidden = g_ViewedPlayer < 1;
|
||||
this.diplomacyButton.tooltip =
|
||||
colorizeHotkey("%(hotkey)s" + " ", "session.gui.diplomacy.toggle") +
|
||||
translate(this.Tooltip);
|
||||
}
|
||||
|
||||
onViewedPlayerChange()
|
||||
{
|
||||
this.diplomacyButton.hidden = g_ViewedPlayer < 1;
|
||||
}
|
||||
}
|
||||
|
||||
DiplomacyButton.prototype.Tooltip = markForTranslation("Diplomacy");
|
||||
DiplomacyDialogButton.prototype.Tooltip = markForTranslation("Diplomacy");
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object
|
||||
type="button"
|
||||
name="gameSpeedButton"
|
||||
size="100%-284 4 100%-256 32"
|
||||
style="iconButton"
|
||||
tooltip_style="sessionToolTip"
|
||||
>
|
||||
<translatableAttribute id="tooltip">Game Speed</translatableAttribute>
|
||||
<object size="5 5 100%-5 100%-5" type="image" sprite="stretched:session/icons/resources/time_small.png" ghost="true"/>
|
||||
</object>
|
||||
|
|
@ -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");
|
||||
|
|
@ -13,7 +13,4 @@
|
|||
sprite="stretched:session/icons/objectives.png"
|
||||
ghost="true"
|
||||
/>
|
||||
<action on="Press">
|
||||
toggleObjectives();
|
||||
</action>
|
||||
</object>
|
||||
|
|
@ -3,21 +3,29 @@
|
|||
*/
|
||||
class TradeDialogButton
|
||||
{
|
||||
constructor(tradeDialog)
|
||||
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;
|
||||
this.isAvailable =
|
||||
g_ResourceData.GetTradableCodes().length ||
|
||||
g_ResourceData.GetBarterableCodes().length;
|
||||
|
||||
playerViewControl.registerViewedPlayerChangeHandler(this.onViewedPlayerChange.bind(this));
|
||||
registerHotkeyChangeHandler(this.onHotkeyChange.bind(this));
|
||||
}
|
||||
|
||||
update()
|
||||
onHotkeyChange()
|
||||
{
|
||||
this.tradeButton.hidden = g_ViewedPlayer < 1 || !this.isAvailable;
|
||||
|
||||
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");
|
||||
|
|
@ -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");
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object>
|
||||
<object
|
||||
size="85%-282 5 100%-290 31"
|
||||
name="viewPlayer"
|
||||
type="dropdown"
|
||||
hidden="true"
|
||||
z="50"
|
||||
style="ModernDropDown"
|
||||
tooltip_style="sessionToolTipBold"
|
||||
dropdown_size="500"
|
||||
>
|
||||
<translatableAttribute id="tooltip">Choose player to view</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<object size="50 4 50% 100%-2" name="observerText" type="text" style="ModernLeftLabelText" hidden="true">
|
||||
<translatableAttribute id="caption">Observer Mode</translatableAttribute>
|
||||
</object>
|
||||
|
||||
</object>
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object>
|
||||
<object
|
||||
type="button"
|
||||
name="gameSpeedButton"
|
||||
size="100%-284 4 100%-256 32"
|
||||
style="iconButton"
|
||||
tooltip_style="sessionToolTip"
|
||||
>
|
||||
<translatableAttribute id="tooltip">Game Speed</translatableAttribute>
|
||||
<object size="5 5 100%-5 100%-5" type="image" sprite="stretched:session/icons/resources/time_small.png" ghost="true"/>
|
||||
<action on="Press">
|
||||
toggleGameSpeed();
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<object size="100%-390 40 100%-230 65" name="gameSpeed" type="dropdown" style="ModernDropDown" hidden="true" tooltip_style="sessionToolTip" dropdown_size="300">
|
||||
<translatableAttribute id="tooltip">Choose game speed</translatableAttribute>
|
||||
</object>
|
||||
</object>
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<object name="population" size="0 0 50%-52 100%" type="button" style="resourceCounter" tooltip_style="sessionToolTipBold">
|
||||
<object size="0 -2 40 38" type="image" sprite="stretched:session/icons/resources/population.png" ghost="true"/>
|
||||
<object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourcePop"/>
|
||||
<action on="Press">
|
||||
saveResPopTooltipSort();
|
||||
updatePlayerDisplay();
|
||||
</action>
|
||||
</object>
|
||||
|
|
@ -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 @@ class TradeDialog
|
|||
return !this.tradeDialogPanel.hidden;
|
||||
}
|
||||
|
||||
onViewedPlayerChange()
|
||||
{
|
||||
if (g_ViewedPlayer >= 1)
|
||||
this.updateIfOpen();
|
||||
else
|
||||
this.close();
|
||||
}
|
||||
|
||||
toggle()
|
||||
{
|
||||
let open = this.isOpen();
|
||||
|
|
@ -43,12 +56,10 @@ class TradeDialog
|
|||
this.open();
|
||||
}
|
||||
|
||||
update()
|
||||
updateIfOpen()
|
||||
{
|
||||
if (!this.isOpen())
|
||||
return;
|
||||
|
||||
this.updatePanels();
|
||||
if (this.isOpen())
|
||||
this.updatePanels();
|
||||
}
|
||||
|
||||
updatePanels()
|
||||
|
|
@ -57,7 +68,7 @@ class TradeDialog
|
|||
this.tradePanel.update();
|
||||
}
|
||||
|
||||
resize()
|
||||
onPlayersInit()
|
||||
{
|
||||
let size = this.tradeDialogPanel.size;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue