Index: ps/trunk/binaries/data/config/default.cfg
===================================================================
--- ps/trunk/binaries/data/config/default.cfg
+++ ps/trunk/binaries/data/config/default.cfg
@@ -169,6 +169,7 @@
realtime.toggle = "Alt+T" ; Toggle current display of computer time
session.devcommands.toggle = "Alt+D" ; Toggle developer commands panel
timeelapsedcounter.toggle = "F12" ; Toggle time elapsed counter
+ceasefirecounter.toggle = unused ; Toggle ceasefire counter
session.showstatusbars = Tab ; Toggle display of status bars
session.highlightguarding = PgDn ; Toggle highlight of guarding units
session.highlightguarded = PgUp ; Toggle highlight of guarded units
Index: ps/trunk/binaries/data/mods/public/gui/common/OverlayCounter.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/common/OverlayCounter.js
+++ ps/trunk/binaries/data/mods/public/gui/common/OverlayCounter.js
@@ -0,0 +1,47 @@
+/**
+ * This is an abstract base class managing one counter shown.
+ * Classes implementing this class require a Config property and may have a Hotkey property.
+ */
+class OverlayCounter
+{
+ constructor(overlayCounterManager)
+ {
+ this.overlayCounterManager = overlayCounterManager;
+ this.updateEnabled();
+
+ registerConfigChangeHandler(this.onConfigChange.bind(this));
+
+ if (this.Hotkey)
+ Engine.SetGlobalHotkey(this.Hotkey, this.toggle.bind(this));
+ }
+
+ onConfigChange(changes)
+ {
+ if (changes.has(this.Config))
+ this.updateEnabled();
+ }
+
+ isEnabled()
+ {
+ return Engine.ConfigDB_GetValue("user", this.Config) == "true";
+ }
+
+ updateEnabled()
+ {
+ this.overlayCounterManager.setCounterEnabled(this, this.isEnabled());
+ }
+
+ toggle()
+ {
+ Engine.ConfigDB_CreateValue("user", this.Config, String(!this.isEnabled()));
+ this.updateEnabled();
+ }
+}
+
+/**
+ * The properties of this prototype are defined in other files. Each of them is a class
+ * managing a counter shown on the current page and may extend the OverlayCounter class.
+ */
+class OverlayCounterTypes
+{
+}
Index: ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterFPS.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterFPS.js
+++ ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterFPS.js
@@ -0,0 +1,32 @@
+/**
+ * This counter displays the current framerate in the screen corner.
+ */
+OverlayCounterTypes.prototype.FPS = class extends OverlayCounter
+{
+ constructor(overlayCounterManager)
+ {
+ super(overlayCounterManager);
+
+ // Tiny performance improvement
+ this.caption = translate(this.Caption);
+
+ // Minimize object construction
+ this.fpsObject = {};
+ }
+
+ /**
+ * This function is called frequently and thus minimized.
+ */
+ get()
+ {
+ this.fpsObject.fps = Engine.GetFPS();
+ return sprintf(this.caption, this.fpsObject);
+ }
+};
+
+// dennis-ignore: *
+OverlayCounterTypes.prototype.FPS.prototype.Caption = markForTranslation("FPS: %(fps)4s");
+
+OverlayCounterTypes.prototype.FPS.prototype.Config = "overlay.fps";
+
+OverlayCounterTypes.prototype.FPS.prototype.Hotkey = "fps.toggle";
Index: ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterManager.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterManager.js
+++ ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterManager.js
@@ -0,0 +1,119 @@
+/**
+ * Since every GUI page can display the FPS or realtime counter,
+ * this manager is initialized for every GUI page.
+ */
+var g_OverlayCounterManager;
+
+class OverlayCounterManager
+{
+ constructor(dataCounter)
+ {
+ this.dataCounter = dataCounter;
+ this.lineHeight = dataCounter.size.bottom - dataCounter.size.top;
+ this.counters = [];
+ this.enabledCounters = [];
+ this.lastTick = undefined;
+ this.lastLineCount = 0;
+ this.resizeHandlers = [];
+
+ for (let name of this.availableCounterNames())
+ {
+ let counter = new OverlayCounterTypes.prototype[name](this);
+ this.counters.push(counter);
+ counter.updateEnabled();
+ }
+
+ this.dataCounter.onTick = this.onTick.bind(this);
+ }
+
+ /**
+ * Mods may overwrite this to change the order of the counters shown.
+ */
+ availableCounterNames()
+ {
+ return Object.keys(OverlayCounterTypes.prototype);
+ }
+
+ deleteCounter(counter)
+ {
+ let filter = count => count != counter;
+ this.counters = this.counters.filter(filter);
+ this.enabledCounters = this.enabledCounters.filter(filter);
+ }
+
+ /**
+ * This function allows enabling and disabling of timers while preserving the counter order.
+ */
+ setCounterEnabled(counter, enabled)
+ {
+ if (enabled)
+ this.enabledCounters = this.counters.filter(count =>
+ this.enabledCounters.indexOf(count) != -1 || count == counter);
+ else
+ this.enabledCounters = this.enabledCounters.filter(count => count != counter);
+
+ // Update instantly
+ this.lastTick = undefined;
+ this.onTick();
+ }
+
+ /**
+ * Handlers subscribed here will be informed then the dimension of the overlay changed.
+ * This allows placing the buttons below the counter.
+ */
+ registerResizeHandler(handler)
+ {
+ this.resizeHandlers.push(handler);
+ }
+
+ onTick()
+ {
+ // Don't rebuild the caption every frame
+ let now = Date.now();
+ if (now < this.lastTick + this.Delay)
+ return;
+
+ this.lastTick = now;
+
+ let lineCount = 0;
+ let txt = "";
+
+ for (let counter of this.enabledCounters)
+ {
+ let newTxt = counter.get();
+ if (!newTxt)
+ continue;
+
+ ++lineCount;
+ txt += newTxt + "\n";
+ }
+
+ if (lineCount)
+ this.dataCounter.caption = txt;
+
+ // The caption changes more often than not,
+ // but adding or removing lines happens rarely.
+ if (this.lastLineCount == lineCount)
+ return;
+
+ let offset = this.lineHeight * lineCount;
+
+ if (lineCount)
+ {
+ let size = this.dataCounter.size;
+ size.bottom = size.top + offset;
+ this.dataCounter.size = size;
+ }
+
+ this.dataCounter.hidden = !lineCount;
+
+ for (let handler of this.resizeHandlers)
+ handler(offset);
+ }
+}
+
+/**
+ * To minimize the computation performed every frame, this duration
+ * in milliseconds determines how often the caption is rebuilt.
+ */
+OverlayCounterManager.prototype.Delay = 250;
Index: ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterRealtime.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterRealtime.js
+++ ps/trunk/binaries/data/mods/public/gui/common/OverlayCounterRealtime.js
@@ -0,0 +1,21 @@
+/**
+ * Shows the current time to the player in their current timezone.
+ */
+OverlayCounterTypes.prototype.Realtime = class extends OverlayCounter
+{
+ constructor(overlayCounterManager)
+ {
+ super(overlayCounterManager);
+ this.date = new Date();
+ }
+
+ get()
+ {
+ this.date.setTime(Date.now());
+ return this.date.toLocaleTimeString();
+ }
+};
+
+OverlayCounterTypes.prototype.Realtime.prototype.Config = "overlay.realtime";
+
+OverlayCounterTypes.prototype.Realtime.prototype.Hotkey = "realtime.toggle";
Index: ps/trunk/binaries/data/mods/public/gui/common/functions_global_object.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/common/functions_global_object.js
+++ ps/trunk/binaries/data/mods/public/gui/common/functions_global_object.js
@@ -1,29 +1,3 @@
-function updateCounters()
-{
- let counters = [];
-
- if (Engine.ConfigDB_GetValue("user", "overlay.fps") === "true")
- // dennis-ignore: *
- counters.push(sprintf(translate("FPS: %(fps)4s"), { "fps": Engine.GetFPS() }));
-
- if (Engine.ConfigDB_GetValue("user", "overlay.realtime") === "true")
- counters.push((new Date()).toLocaleTimeString());
-
- // If game has been started
- if (typeof appendSessionCounters != "undefined")
- appendSessionCounters(counters);
-
- let dataCounter = Engine.GetGUIObjectByName("dataCounter");
- dataCounter.caption = counters.join("\n") + "\n";
- dataCounter.hidden = !counters.length;
- dataCounter.size = sprintf("%(left)s %(top)s %(right)s %(bottom)s", {
- "left": "100%%-100",
- "top": "40",
- "right": "100%%-5",
- "bottom": 40 + 14 * counters.length
- });
-}
-
/**
* Update the overlay with the most recent network warning of each client.
*/
Index: ps/trunk/binaries/data/mods/public/gui/common/functions_utility.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/common/functions_utility.js
+++ ps/trunk/binaries/data/mods/public/gui/common/functions_utility.js
@@ -9,6 +9,27 @@
};
/**
+ * These events are fired when the user has closed the options page.
+ * The handlers are provided a Set storing which config values have changed.
+ * TODO: This should become a GUI event sent by the engine.
+ */
+var g_ConfigChangeHandlers = new Set();
+
+function registerConfigChangeHandler(handler)
+{
+ g_ConfigChangeHandlers.add(handler);
+}
+
+/**
+ * @param changes - a Set of config names
+ */
+function fireConfigChangeHandlers(changes)
+{
+ for (let handler of g_ConfigChangeHandlers)
+ handler(changes);
+}
+
+/**
* Returns translated history and gameplay data of all civs, optionally including a mock gaia civ.
*/
function loadCivData(selectableOnly, gaia)
Index: ps/trunk/binaries/data/mods/public/gui/common/global.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/common/global.xml
+++ ps/trunk/binaries/data/mods/public/gui/common/global.xml
@@ -39,43 +39,15 @@
type="text"
ghost="true"
z="199"
- size="100%-90 40 100%-5 40"
+ size="100%-100 40 100%-5 54"
font="mono-10"
textcolor="white"
text_align="right"
text_valign="top"
sprite="color: 0 0 0 100"
- >
-
- updateCounters();
-
-
-
-
-
-
-
-
Index: ps/trunk/binaries/data/mods/public/gui/options/options.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/options/options.js
+++ ps/trunk/binaries/data/mods/public/gui/options/options.js
@@ -243,6 +243,7 @@
Engine.ConfigDB_SetChanges("user", true);
g_ChangedKeys.add(option.config);
+ fireConfigChangeHandlers(new Set([option.config]));
if (option.function)
Engine[option.function](value);
Index: ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuItems.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuItems.js
+++ ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuItems.js
@@ -141,7 +141,10 @@
"caption": translate("Options"),
"tooltip": translate("Adjust game settings."),
"onPress": () => {
- Engine.PushGuiPage("page_options.xml");
+ Engine.PushGuiPage(
+ "page_options.xml",
+ {},
+ fireConfigChangeHandlers);
}
},
{
Index: ps/trunk/binaries/data/mods/public/gui/session/DiplomacyColors.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/DiplomacyColors.js
+++ ps/trunk/binaries/data/mods/public/gui/session/DiplomacyColors.js
@@ -17,6 +17,7 @@
registerPlayersInitHandler(this.onPlayersInit.bind(this));
registerConfigChangeHandler(this.onConfigChange.bind(this));
+ registerCeasefireEndedHandler(this.onCeasefireEnded.bind(this));
}
registerDiplomacyColorsChangeHandler(handler)
Index: ps/trunk/binaries/data/mods/public/gui/session/OverlayCounterElapsedTime.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/OverlayCounterElapsedTime.js
+++ ps/trunk/binaries/data/mods/public/gui/session/OverlayCounterElapsedTime.js
@@ -0,0 +1,37 @@
+/**
+ * This class shows the simulated match time below the FPS counter.
+ */
+OverlayCounterTypes.prototype.ElapsedTime = class extends OverlayCounter
+{
+ constructor(overlayCounterManager)
+ {
+ super(overlayCounterManager);
+
+ // Performance optimization
+ this.caption = translate(this.Caption);
+ this.sprintfData = {};
+ }
+
+ get()
+ {
+ if (!g_SimState)
+ return "";
+
+ let time = timeToString(g_SimState.timeElapsed);
+
+ let speed = Engine.GetSimRate();
+ if (speed == 1)
+ return time;
+
+ this.sprintfData.time = time;
+ this.sprintfData.speed = Engine.FormatDecimalNumberIntoString(speed);
+ return sprintf(this.caption, this.sprintfData);
+ }
+};
+
+// Translation: The "x" means "times", with the mathematical meaning of multiplication.
+OverlayCounterTypes.prototype.ElapsedTime.prototype.Caption = markForTranslation("%(time)s (%(speed)sx)");
+
+OverlayCounterTypes.prototype.ElapsedTime.prototype.Config = "gui.session.timeelapsedcounter";
+
+OverlayCounterTypes.prototype.ElapsedTime.prototype.Hotkey = "timeelapsedcounter.toggle";
Index: ps/trunk/binaries/data/mods/public/gui/session/OverlayCounterRemainingCeasefire.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/OverlayCounterRemainingCeasefire.js
+++ ps/trunk/binaries/data/mods/public/gui/session/OverlayCounterRemainingCeasefire.js
@@ -0,0 +1,28 @@
+/**
+ * Adds the ceasefire counter to the global FPS and
+ * realtime counters shown in the top right corner.
+ */
+OverlayCounterTypes.prototype.RemainingCeasefire = class extends OverlayCounter
+{
+ constructor(overlayCounterManager)
+ {
+ super(overlayCounterManager);
+ registerCeasefireEndedHandler(this.onCeasefireEnded.bind(this));
+ }
+
+ onCeasefireEnded()
+ {
+ this.overlayCounterManager.deleteCounter(this);
+ }
+
+ get()
+ {
+ if (!g_SimState)
+ return "";
+ return timeToString(g_SimState.ceasefireTimeRemaining);
+ }
+};
+
+OverlayCounterTypes.prototype.RemainingCeasefire.prototype.Config = "gui.session.ceasefirecounter";
+
+OverlayCounterTypes.prototype.RemainingCeasefire.prototype.Hotkey = "ceasefirecounter.toggle";
Index: ps/trunk/binaries/data/mods/public/gui/session/messages.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/messages.js
+++ ps/trunk/binaries/data/mods/public/gui/session/messages.js
@@ -19,6 +19,11 @@
var g_PlayerAssignmentsChangeHandlers = new Set();
/**
+ * These handlers are called when the ceasefire time has run out.
+ */
+var g_CeasefireEndedHandlers = new Set();
+
+/**
* Handle all netmessage types that can occur.
*/
var g_NetMessageTypes = {
@@ -151,7 +156,8 @@
"ceasefire-ended": function(notification, player)
{
updatePlayerData();
- g_DiplomacyColors.OnCeasefireEnded();
+ for (let handler of g_CeasefireEndedHandlers)
+ handler();
},
"tutorial": function(notification, player)
{
@@ -291,6 +297,11 @@
g_PlayerAssignmentsChangeHandlers.add(handler);
}
+function registerCeasefireEndedHandler(handler)
+{
+ g_CeasefireEndedHandlers.add(handler);
+}
+
/**
* Loads all known cheat commands.
*/
Index: ps/trunk/binaries/data/mods/public/gui/session/session.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/session.js
+++ ps/trunk/binaries/data/mods/public/gui/session/session.js
@@ -160,12 +160,6 @@
var g_HotkeyChangeHandlers = new Set();
/**
- * These events are fired when the user has closed the options page.
- * The handlers are provided a Set storing which config values have changed.
- */
-var g_ConfigChangeHandlers = new Set();
-
-/**
* List of additional entities to highlight.
*/
var g_ShowGuarding = false;
@@ -353,20 +347,6 @@
g_HotkeyChangeHandlers.add(handler);
}
-function registerConfigChangeHandler(handler)
-{
- g_ConfigChangeHandlers.add(handler);
-}
-
-/**
- * @param changes - a Set of config names
- */
-function fireConfigChangeHandlers(changes)
-{
- for (let handler of g_ConfigChangeHandlers)
- handler(changes);
-}
-
function updatePlayerData()
{
let simState = GetSimState();
@@ -870,30 +850,3 @@
{
Engine.PlayAmbientSound(pickRandom(g_Ambient), true);
}
-
-/**
- * Adds the ingame time and ceasefire counter to the global FPS and
- * realtime counters shown in the top right corner.
- */
-function appendSessionCounters(counters)
-{
- let simState = GetSimState();
-
- if (Engine.ConfigDB_GetValue("user", "gui.session.timeelapsedcounter") === "true")
- {
- let currentSpeed = Engine.GetSimRate();
- if (currentSpeed != 1.0)
- // Translation: The "x" means "times", with the mathematical meaning of multiplication.
- counters.push(sprintf(translate("%(time)s (%(speed)sx)"), {
- "time": timeToString(simState.timeElapsed),
- "speed": Engine.FormatDecimalNumberIntoString(currentSpeed)
- }));
- else
- counters.push(timeToString(simState.timeElapsed));
- }
-
- if (simState.ceasefireActive && Engine.ConfigDB_GetValue("user", "gui.session.ceasefirecounter") === "true")
- counters.push(timeToString(simState.ceasefireTimeRemaining));
-
- g_ResearchProgress.setTopOffset(14 * counters.length);
-}
Index: ps/trunk/binaries/data/mods/public/gui/session/session.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/session.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/session.xml
@@ -41,20 +41,6 @@
-
-
-
-
-
-