Use @stylistic/brace-style for eslint

Up to now `eslint-plugin-brace-rules` was used to enforce a common brace
style for JavaScript code. This plugin was however updated the last time
over 9 years ago and will be incompatible with ESLint v10, as that
[removes `context.getSourceCode()`][1], the plugin relies on.

To keep the eslint config working with ESLint v10, this replaces
`eslint-plugin-brace-rules` with the [`@stylistic/brace-style`][2] rule
from `@stylistic/eslint-plugin`, a package we already use.

While `@stylistic/brace-style` doesn't offer an option to format braces
in exactly the same way as before, the "allman" style seems to be the
one closest to the existing code.

[1]: https://eslint.org/blog/2025/11/eslint-v10.0.0-alpha.0-released/#removed-deprecated-rule-context-members
[2]: https://eslint.style/rules/brace-style
This commit is contained in:
Dunedan 2025-12-30 09:57:37 +01:00
parent 8f8d1195c2
commit 93ce94655d
No known key found for this signature in database
GPG key ID: 885B16854284E0B2
259 changed files with 4643 additions and 3421 deletions

View file

@ -83,13 +83,12 @@ repos:
args: args:
- --strict - --strict
- repo: https://github.com/eslint/eslint - repo: https://github.com/eslint/eslint
rev: v9.33.0 rev: v9.39.2
hooks: hooks:
- id: eslint - id: eslint
language_version: 22.14.0 language_version: 22.14.0
additional_dependencies: additional_dependencies:
- eslint-plugin-brace-rules@0.1.6 - "@stylistic/eslint-plugin@5.6.1"
- "@stylistic/eslint-plugin@4.4.0"
args: args:
- --max-warnings=0 - --max-warnings=0
- --no-warn-ignored - --no-warn-ignored

View file

@ -6,7 +6,8 @@ var obj1 = Engine.GetGUIObjectByName("obj1");
var obj3 = Engine.GetGUIObjectByName("obj3"); var obj3 = Engine.GetGUIObjectByName("obj3");
obj1.onTick = () => { ++called1; }; obj1.onTick = () => { ++called1; };
Engine.GetGUIObjectByName("obj2").onTick = () => { Engine.GetGUIObjectByName("obj2").onTick = () =>
{
++called2; ++called2;
delete obj1.onTick; delete obj1.onTick;
delete obj3.onTick; delete obj3.onTick;

View file

@ -2,7 +2,7 @@ try
{ {
Engine.callback(); Engine.callback();
} }
catch (e) catch(e)
{ {
log(e.message); log(e.message);
} }

View file

@ -13,7 +13,8 @@ async function waitAndIncrement(promise)
{ {
let resolve; let resolve;
const promise = new Promise(res => { const promise = new Promise(res =>
{
incrementTest(); incrementTest();
resolve = res; resolve = res;
}); });

View file

@ -2,11 +2,13 @@ function TestScript2A() {}
TestScript2A.prototype.Schema = "<ref name='anything'/>"; TestScript2A.prototype.Schema = "<ref name='anything'/>";
TestScript2A.prototype.Init = function() { TestScript2A.prototype.Init = function()
{
this.x = eval(this.template.y); this.x = eval(this.template.y);
}; };
TestScript2A.prototype.GetX = function() { TestScript2A.prototype.GetX = function()
{
return this.x; return this.x;
}; };

View file

@ -1,15 +1,20 @@
function TestScript1A() {} function TestScript1A() {}
TestScript1A.prototype.GetX = function() { TestScript1A.prototype.GetX = function()
{
// Test that .entity is readonly // Test that .entity is readonly
try { try
{
delete this.entity; delete this.entity;
Engine.TS_FAIL("Missed exception"); Engine.TS_FAIL("Missed exception");
} catch (e) { /* noop */ } }
try { catch(e) { /* noop */ }
try
{
this.entity = -1; this.entity = -1;
Engine.TS_FAIL("Missed exception"); Engine.TS_FAIL("Missed exception");
} catch (e) { /* noop */ } }
catch(e) { /* noop */ }
// and return the value // and return the value
return this.entity; return this.entity;

View file

@ -1,6 +1,7 @@
function TestScript1_Helper() {} function TestScript1_Helper() {}
TestScript1_Helper.prototype.GetX = function() { TestScript1_Helper.prototype.GetX = function()
{
return AdditionHelper(1, 2); return AdditionHelper(1, 2);
}; };

View file

@ -2,11 +2,13 @@ function HotloadA() {}
HotloadA.prototype.Schema = "<ref name='anything'/>"; HotloadA.prototype.Schema = "<ref name='anything'/>";
HotloadA.prototype.Init = function() { HotloadA.prototype.Init = function()
{
this.x = +this.template.x; this.x = +this.template.x;
}; };
HotloadA.prototype.GetX = function() { HotloadA.prototype.GetX = function()
{
return this.x; return this.x;
}; };
@ -15,11 +17,13 @@ Engine.RegisterComponentType(IID_Test1, "HotloadA", HotloadA);
function HotloadB() {} function HotloadB() {}
HotloadB.prototype.Init = function() { HotloadB.prototype.Init = function()
{
this.x = +this.template.x; this.x = +this.template.x;
}; };
HotloadB.prototype.GetX = function() { HotloadB.prototype.GetX = function()
{
return this.x * 2; return this.x * 2;
}; };

View file

@ -2,11 +2,13 @@ function HotloadA() {}
HotloadA.prototype.Schema = "<ref name='anything'/>"; HotloadA.prototype.Schema = "<ref name='anything'/>";
HotloadA.prototype.Init = function() { HotloadA.prototype.Init = function()
{
this.x = +this.template.x; this.x = +this.template.x;
}; };
HotloadA.prototype.GetX = function() { HotloadA.prototype.GetX = function()
{
return this.x*10; return this.x*10;
}; };

View file

@ -2,11 +2,13 @@ function Modding() {}
Modding.prototype.Schema = "<ref name='anything'/>"; Modding.prototype.Schema = "<ref name='anything'/>";
Modding.prototype.Init = function() { Modding.prototype.Init = function()
{
this.x = +this.template.x; this.x = +this.template.x;
}; };
Modding.prototype.GetX = function() { Modding.prototype.GetX = function()
{
return this.x; return this.x;
}; };

View file

@ -1,4 +1,5 @@
Modding.prototype.GetX = function() { Modding.prototype.GetX = function()
{
return this.x * 10; return this.x * 10;
}; };

View file

@ -1,14 +1,17 @@
function TestScript1A() {} function TestScript1A() {}
TestScript1A.prototype.Init = function() { TestScript1A.prototype.Init = function()
{
this.x = 100; this.x = 100;
}; };
TestScript1A.prototype.GetX = function() { TestScript1A.prototype.GetX = function()
{
return this.x; return this.x;
}; };
TestScript1A.prototype.OnUpdate = function(msg) { TestScript1A.prototype.OnUpdate = function(msg)
{
this.x += msg.turnLength; this.x += msg.turnLength;
}; };
@ -18,15 +21,18 @@ Engine.RegisterComponentType(IID_Test1, "TestScript1A", TestScript1A);
function TestScript1B() {} function TestScript1B() {}
TestScript1B.prototype.Init = function() { TestScript1B.prototype.Init = function()
{
this.x = 100; this.x = 100;
}; };
TestScript1B.prototype.GetX = function() { TestScript1B.prototype.GetX = function()
{
return this.x; return this.x;
}; };
TestScript1B.prototype.OnGlobalUpdate = function(msg) { TestScript1B.prototype.OnGlobalUpdate = function(msg)
{
this.x += msg.turnLength; this.x += msg.turnLength;
}; };
@ -36,11 +42,13 @@ Engine.RegisterComponentType(IID_Test1, "TestScript1B", TestScript1B);
function TestScript2A() {} function TestScript2A() {}
TestScript2A.prototype.Init = function() { TestScript2A.prototype.Init = function()
{
this.x = 200; this.x = 200;
}; };
TestScript2A.prototype.GetX = function() { TestScript2A.prototype.GetX = function()
{
Engine.BroadcastMessage(MT_Update, { "turnLength": 50 }); Engine.BroadcastMessage(MT_Update, { "turnLength": 50 });
Engine.PostMessage(1, MT_Update, { "turnLength": 500 }); Engine.PostMessage(1, MT_Update, { "turnLength": 500 });
Engine.PostMessage(2, MT_Update, { "turnLength": 5000 }); Engine.PostMessage(2, MT_Update, { "turnLength": 5000 });

View file

@ -1,6 +1,7 @@
function TestScript1_Init() {} function TestScript1_Init() {}
TestScript1_Init.prototype.Init = function() { TestScript1_Init.prototype.Init = function()
{
var param = this.template; var param = this.template;
// print("# ",uneval(param),"\n"); // print("# ",uneval(param),"\n");
if (param) if (param)
@ -9,7 +10,8 @@ TestScript1_Init.prototype.Init = function() {
this.x = 100; this.x = 100;
}; };
TestScript1_Init.prototype.GetX = function() { TestScript1_Init.prototype.GetX = function()
{
return this.x; return this.x;
}; };
@ -19,12 +21,18 @@ Engine.RegisterComponentType(IID_Test1, "TestScript1_Init", TestScript1_Init);
function TestScript1_readonly() {} function TestScript1_readonly() {}
TestScript1_readonly.prototype.GetX = function() { TestScript1_readonly.prototype.GetX = function()
try { this.template = null; } catch (e) { /* noop */ } {
try { delete this.template; } catch (e) { /* noop */ } try { this.template = null; }
try { this.template.x += 1000; } catch (e) { /* noop */ } catch(e) { /* noop */ }
try { delete this.template.x; } catch (e) { /* noop */ } try { delete this.template; }
try { this.template.y = 2000; } catch (e) { /* noop */ } catch(e) { /* noop */ }
try { this.template.x += 1000; }
catch(e) { /* noop */ }
try { delete this.template.x; }
catch(e) { /* noop */ }
try { this.template.y = 2000; }
catch(e) { /* noop */ }
return +(this.template.x || 1) + +(this.template.y || 2); return +(this.template.x || 1) + +(this.template.y || 2);
}; };

View file

@ -1,10 +1,12 @@
function TestScript1A() {} function TestScript1A() {}
TestScript1A.prototype.Init = function() { TestScript1A.prototype.Init = function()
{
this.x = 100; this.x = 100;
}; };
TestScript1A.prototype.GetX = function() { TestScript1A.prototype.GetX = function()
{
var test2 = Engine.QueryInterface(this.entity, IID_Test2); var test2 = Engine.QueryInterface(this.entity, IID_Test2);
return test2.GetX() + (test2.x || 0); return test2.GetX() + (test2.x || 0);
}; };
@ -15,11 +17,13 @@ Engine.RegisterComponentType(IID_Test1, "TestScript1A", TestScript1A);
function TestScript2A() {} function TestScript2A() {}
TestScript2A.prototype.Init = function() { TestScript2A.prototype.Init = function()
{
this.x = 200; this.x = 200;
}; };
TestScript2A.prototype.GetX = function() { TestScript2A.prototype.GetX = function()
{
return this.x; return this.x;
}; };

View file

@ -1,12 +1,14 @@
function TestScript1_values() {} function TestScript1_values() {}
TestScript1_values.prototype.Init = function() { TestScript1_values.prototype.Init = function()
{
this.x = +this.template.x; this.x = +this.template.x;
this.str = "this is a string"; this.str = "this is a string";
this.things = { "a": 1, "b": "2", "c": [3, "4", [5, []]] }; this.things = { "a": 1, "b": "2", "c": [3, "4", [5, []]] };
}; };
TestScript1_values.prototype.GetX = function() { TestScript1_values.prototype.GetX = function()
{
// print(uneval(this)); // print(uneval(this));
return this.x; return this.x;
}; };
@ -17,16 +19,21 @@ Engine.RegisterComponentType(IID_Test1, "TestScript1_values", TestScript1_values
function TestScript1_entity() {} function TestScript1_entity() {}
TestScript1_entity.prototype.GetX = function() { TestScript1_entity.prototype.GetX = function()
{
// Test that .entity is readonly // Test that .entity is readonly
try { try
{
delete this.entity; delete this.entity;
Engine.TS_FAIL("Missed exception"); Engine.TS_FAIL("Missed exception");
} catch (e) { /* OK */ } }
try { catch(e) { /* OK */ }
try
{
this.entity = -1; this.entity = -1;
Engine.TS_FAIL("Missed exception"); Engine.TS_FAIL("Missed exception");
} catch (e) { /* OK */ } }
catch(e) { /* OK */ }
// and return the value // and return the value
return this.entity; return this.entity;
@ -38,13 +45,15 @@ Engine.RegisterComponentType(IID_Test1, "TestScript1_entity", TestScript1_entity
function TestScript1_nontree() {} function TestScript1_nontree() {}
TestScript1_nontree.prototype.Init = function() { TestScript1_nontree.prototype.Init = function()
{
var n = [1]; var n = [1];
this.x = [n, n, null, { "y": n }]; this.x = [n, n, null, { "y": n }];
this.x[2] = this.x; this.x[2] = this.x;
}; };
TestScript1_nontree.prototype.GetX = function() { TestScript1_nontree.prototype.GetX = function()
{
// print(uneval(this)+"\n"); // print(uneval(this)+"\n");
this.x[0][0] += 1; this.x[0][0] += 1;
return this.x[0][0] + this.x[1][0] + this.x[2][0][0] + this.x[3].y[0]; return this.x[0][0] + this.x[1][0] + this.x[2][0][0] + this.x[3].y[0];
@ -56,15 +65,18 @@ Engine.RegisterComponentType(IID_Test1, "TestScript1_nontree", TestScript1_nontr
function TestScript1_custom() {} function TestScript1_custom() {}
TestScript1_custom.prototype.Init = function() { TestScript1_custom.prototype.Init = function()
{
this.y = 2; this.y = 2;
}; };
TestScript1_custom.prototype.Serialize = function() { TestScript1_custom.prototype.Serialize = function()
{
return { "c": 1 }; return { "c": 1 };
}; };
TestScript1_custom.prototype.Deserialize = function(data) { TestScript1_custom.prototype.Deserialize = function(data)
{
this.c = data.c; this.c = data.c;
}; };
@ -74,7 +86,8 @@ Engine.RegisterComponentType(IID_Test1, "TestScript1_custom", TestScript1_custom
function TestScript1_getter() {} function TestScript1_getter() {}
TestScript1_getter.prototype.Init = function() { TestScript1_getter.prototype.Init = function()
{
this.x = 100; this.x = 100;
this.__defineGetter__('x', function() { print("FAIL\n"); die(); return 200; }); this.__defineGetter__('x', function() { print("FAIL\n"); die(); return 200; });
}; };
@ -87,17 +100,20 @@ function TestScript1_consts() {}
TestScript1_consts.prototype.Schema = "<ref name='anything'/>"; TestScript1_consts.prototype.Schema = "<ref name='anything'/>";
TestScript1_consts.prototype.Init = function() { TestScript1_consts.prototype.Init = function()
{
this.cached = (+this.entity) + (+this.template.x); this.cached = (+this.entity) + (+this.template.x);
}; };
TestScript1_consts.prototype.Serialize = null; TestScript1_consts.prototype.Serialize = null;
TestScript1_consts.prototype.Deserialize = function(data) { TestScript1_consts.prototype.Deserialize = function(data)
{
this.Init(); this.Init();
}; };
TestScript1_consts.prototype.GetX = function() { TestScript1_consts.prototype.GetX = function()
{
return this.cached; return this.cached;
}; };

View file

@ -1,14 +1,17 @@
function TestScript1A() {} function TestScript1A() {}
TestScript1A.prototype.Init = function() { TestScript1A.prototype.Init = function()
{
this.x = 101000; this.x = 101000;
}; };
TestScript1A.prototype.GetX = function() { TestScript1A.prototype.GetX = function()
{
return this.x; return this.x;
}; };
TestScript1A.prototype.OnTurnStart = function(msg) { TestScript1A.prototype.OnTurnStart = function(msg)
{
this.x += 1; this.x += 1;
}; };
@ -20,7 +23,8 @@ function TestScript1B() {}
TestScript1B.prototype = Object.create(TestScript1A.prototype); TestScript1B.prototype = Object.create(TestScript1A.prototype);
TestScript1B.prototype.Init = function() { TestScript1B.prototype.Init = function()
{
this.x = 102000; this.x = 102000;
}; };
@ -30,15 +34,18 @@ Engine.RegisterComponentType(IID_Test1, "TestScript1B", TestScript1B);
function TestScript2A() {} function TestScript2A() {}
TestScript2A.prototype.Init = function() { TestScript2A.prototype.Init = function()
{
this.x = 201000; this.x = 201000;
}; };
TestScript2A.prototype.GetX = function() { TestScript2A.prototype.GetX = function()
{
return this.x; return this.x;
}; };
TestScript2A.prototype.OnUpdate = function(msg) { TestScript2A.prototype.OnUpdate = function(msg)
{
this.x += msg.turnLength; this.x += msg.turnLength;
}; };

View file

@ -41,7 +41,8 @@ export async function init(initialColor)
const splitColor = initialColor.split(" "); const splitColor = initialColor.split(" ");
const chanels = labels.map((label, i) => { const chanels = labels.map((label, i) =>
{
Engine.GetGUIObjectByName("colorLabel[" + i + "]").caption = label; Engine.GetGUIObjectByName("colorLabel[" + i + "]").caption = label;
resizeChanel(i); resizeChanel(i);
@ -70,8 +71,10 @@ export async function init(initialColor)
while (true) while (true)
{ {
colorDisplay.sprite = "color:" + currentColor(); colorDisplay.sprite = "color:" + currentColor();
const chanelPromises = chanels.map(chanel => { const chanelPromises = chanels.map(chanel =>
return new Promise(resolve => { {
return new Promise(resolve =>
{
chanel.slider.onValueChange = resolve.bind(undefined, { "value": chanel }); chanel.slider.onValueChange = resolve.bind(undefined, { "value": chanel });
}); });
}); });

View file

@ -23,8 +23,10 @@ function distributeButtonsHorizontally(button, captions)
function setButtonCaptionsAndVisibility(buttons, captions, cancelHotkey, name) function setButtonCaptionsAndVisibility(buttons, captions, cancelHotkey, name)
{ {
return new Promise(resolve => { return new Promise(resolve =>
captions.forEach((caption, i) => { {
captions.forEach((caption, i) =>
{
buttons[i] = Engine.GetGUIObjectByName(name + (i + 1)); buttons[i] = Engine.GetGUIObjectByName(name + (i + 1));
buttons[i].caption = caption; buttons[i].caption = caption;
buttons[i].hidden = false; buttons[i].hidden = false;

View file

@ -3,7 +3,8 @@ var g_IncompatibleModsFile = "gui/incompatible_mods/incompatible_mods.txt";
function init(data) function init(data)
{ {
Engine.GetGUIObjectByName("mainText").caption = Engine.TranslateLines(Engine.ReadFile(g_IncompatibleModsFile)); Engine.GetGUIObjectByName("mainText").caption = Engine.TranslateLines(Engine.ReadFile(g_IncompatibleModsFile));
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
Engine.GetGUIObjectByName("btnClose").onPress = closePageCallback; Engine.GetGUIObjectByName("btnClose").onPress = closePageCallback;
}); });
} }

View file

@ -27,12 +27,14 @@ var g_ModIOState = {
/** /**
* Finished status indicators * Finished status indicators
*/ */
"ready": (progressData, closePageCallback) => { "ready": (progressData, closePageCallback) =>
{
// GameID acquired, ready to fetch mod list // GameID acquired, ready to fetch mod list
if (!g_RequestCancelled) if (!g_RequestCancelled)
updateModList(closePageCallback); updateModList(closePageCallback);
}, },
"listed": progressData => { "listed": progressData =>
{
// List of available mods acquired // List of available mods acquired
// Only run this once (for each update). // Only run this once (for each update).
@ -44,7 +46,8 @@ var g_ModIOState = {
g_ModsAvailableOnline = Engine.ModIoGetMods(); g_ModsAvailableOnline = Engine.ModIoGetMods();
displayMods(); displayMods();
}, },
"success": progressData => { "success": progressData =>
{
// Successfully acquired a mod file // Successfully acquired a mod file
hideDialog(); hideDialog();
Engine.GetGUIObjectByName("downloadButton").enabled = true; Engine.GetGUIObjectByName("downloadButton").enabled = true;
@ -52,20 +55,24 @@ var g_ModIOState = {
/** /**
* In-progress status indicators. * In-progress status indicators.
*/ */
"gameid": progressData => { "gameid": progressData =>
{
// Acquiring GameID from mod.io // Acquiring GameID from mod.io
}, },
"listing": progressData => { "listing": progressData =>
{
// Acquiring list of available mods from mod.io // Acquiring list of available mods from mod.io
}, },
"downloading": progressData => { "downloading": progressData =>
{
// Downloading a mod file // Downloading a mod file
updateProgressBar(progressData.progress, g_ModsAvailableOnline[selectedModIndex()].filesize); updateProgressBar(progressData.progress, g_ModsAvailableOnline[selectedModIndex()].filesize);
}, },
/** /**
* Error/Failure status indicators. * Error/Failure status indicators.
*/ */
"failed_gameid": async(progressData, closePageCallback) => { "failed_gameid": async(progressData, closePageCallback) =>
{
// Game ID couldn't be retrieved // Game ID couldn't be retrieved
const promise = showErrorMessageBox( const promise = showErrorMessageBox(
sprintf(translateWithContext("mod.io error message", "Game ID could not be retrieved.\n\n%(technicalDetails)s"), { sprintf(translateWithContext("mod.io error message", "Game ID could not be retrieved.\n\n%(technicalDetails)s"), {
@ -80,7 +87,8 @@ var g_ModIOState = {
else else
init(); init();
}, },
"failed_listing": async(progressData, closePageCallback) => { "failed_listing": async(progressData, closePageCallback) =>
{
// Mod list couldn't be retrieved // Mod list couldn't be retrieved
const promise = showErrorMessageBox( const promise = showErrorMessageBox(
sprintf(translateWithContext("mod.io error message", "Mod List could not be retrieved.\n\n%(technicalDetails)s"), { sprintf(translateWithContext("mod.io error message", "Mod List could not be retrieved.\n\n%(technicalDetails)s"), {
@ -95,7 +103,8 @@ var g_ModIOState = {
else else
updateModList(closePageCallback); updateModList(closePageCallback);
}, },
"failed_downloading": async(progressData) => { "failed_downloading": async(progressData) =>
{
// File couldn't be retrieved // File couldn't be retrieved
const promise = showErrorMessageBox( const promise = showErrorMessageBox(
sprintf(translateWithContext("mod.io error message", "File download failed.\n\n%(technicalDetails)s"), { sprintf(translateWithContext("mod.io error message", "File download failed.\n\n%(technicalDetails)s"), {
@ -110,7 +119,8 @@ var g_ModIOState = {
else else
downloadMod(); downloadMod();
}, },
"failed_filecheck": async(progressData) => { "failed_filecheck": async(progressData) =>
{
// The file is corrupted // The file is corrupted
const promise = showErrorMessageBox( const promise = showErrorMessageBox(
sprintf(translateWithContext("mod.io error message", "File verification error.\n\n%(technicalDetails)s"), { sprintf(translateWithContext("mod.io error message", "File verification error.\n\n%(technicalDetails)s"), {
@ -126,7 +136,8 @@ var g_ModIOState = {
/** /**
* Default * Default
*/ */
"none": progressData => { "none": progressData =>
{
// Nothing has happened yet. // Nothing has happened yet.
} }
}; };
@ -144,7 +155,8 @@ function init(data)
return Promise.race([ return Promise.race([
promise, promise,
new Promise(closePageCallback => { new Promise(closePageCallback =>
{
Engine.GetGUIObjectByName("backButton").onPress = closePageCallback; Engine.GetGUIObjectByName("backButton").onPress = closePageCallback;
Engine.GetGUIObjectByName("modio").onTick = onTick.bind(null, closePageCallback); Engine.GetGUIObjectByName("modio").onTick = onTick.bind(null, closePageCallback);
}) })
@ -327,7 +339,8 @@ async function progressDialog(dialogCaption, dialogTitle, showProgressBar, butto
const downloadDialog_button = Engine.GetGUIObjectByName("downloadDialog_button"); const downloadDialog_button = Engine.GetGUIObjectByName("downloadDialog_button");
downloadDialog_button.caption = buttonCaption; downloadDialog_button.caption = buttonCaption;
await new Promise(resolve => { await new Promise(resolve =>
{
downloadDialog_button.onPress = resolve; downloadDialog_button.onPress = resolve;
}); });
cancelRequest(); cancelRequest();

View file

@ -1,7 +1,8 @@
function init(data) function init(data)
{ {
Engine.GetGUIObjectByName("mainText").caption = Engine.TranslateLines(Engine.ReadFile("gui/modmod/help/help.txt")); Engine.GetGUIObjectByName("mainText").caption = Engine.TranslateLines(Engine.ReadFile("gui/modmod/help/help.txt"));
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
Engine.GetGUIObjectByName("closeButton").onPress = closePageCallback; Engine.GetGUIObjectByName("closeButton").onPress = closePageCallback;
}); });
} }

View file

@ -68,7 +68,8 @@ function init(data, hotloadData)
if (g_HasIncompatibleMods) if (g_HasIncompatibleMods)
Engine.OpenChildPage("page_incompatible_mods.xml", {}); Engine.OpenChildPage("page_incompatible_mods.xml", {});
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
Engine.GetGUIObjectByName("quitButton").onPress = closePageCallback; Engine.GetGUIObjectByName("quitButton").onPress = closePageCallback;
}); });
} }

View file

@ -21,7 +21,8 @@ async function init(data)
initURLButtons(data.termsURL, data.urlButtons); initURLButtons(data.termsURL, data.urlButtons);
initLanguageSelection(); initLanguageSelection();
const accepted = await new Promise(resolve => { const accepted = await new Promise(resolve =>
{
Engine.GetGUIObjectByName("cancelButton").onPress = resolve.bind(null, false); Engine.GetGUIObjectByName("cancelButton").onPress = resolve.bind(null, false);
Engine.GetGUIObjectByName("connectButton").onPress = resolve.bind(null, true); Engine.GetGUIObjectByName("connectButton").onPress = resolve.bind(null, true);
}); });
@ -40,14 +41,16 @@ function initURLButtons(termsURL, urlButtons)
"url": termsURL "url": termsURL
}); });
urlButtons.forEach((urlButton, i) => { urlButtons.forEach((urlButton, i) =>
{
const button = Engine.GetGUIObjectByName("button[" + i + "]"); const button = Engine.GetGUIObjectByName("button[" + i + "]");
button.caption = urlButton.caption; button.caption = urlButton.caption;
button.hidden = false; button.hidden = false;
button.tooltip = sprintf(translate("Open %(url)s in the browser."), { button.tooltip = sprintf(translate("Open %(url)s in the browser."), {
"url": urlButton.url "url": urlButton.url
}); });
button.onPress = () => { button.onPress = () =>
{
openURL(urlButton.url); openURL(urlButton.url);
}; };
}); });
@ -62,7 +65,8 @@ function initLanguageSelection()
const languageDropdown = Engine.GetGUIObjectByName("languageDropdown"); const languageDropdown = Engine.GetGUIObjectByName("languageDropdown");
languageDropdown.size = (languageLabelWidth + 10) + " 4 100% 100%"; languageDropdown.size = (languageLabelWidth + 10) + " 4 100% 100%";
languageDropdown.list = (() => { languageDropdown.list = (() =>
{
const displayNames = Engine.GetSupportedLocaleDisplayNames(); const displayNames = Engine.GetSupportedLocaleDisplayNames();
const baseNames = Engine.GetSupportedLocaleBaseNames(); const baseNames = Engine.GetSupportedLocaleBaseNames();
@ -80,7 +84,8 @@ function initLanguageSelection()
return list; return list;
})(); })();
languageDropdown.onSelectionChange = () => { languageDropdown.onSelectionChange = () =>
{
Engine.GetGUIObjectByName("mainText").caption = Engine.GetGUIObjectByName("mainText").caption =
sprintf( sprintf(
languageDropdown.selected == 1 ? languageDropdown.selected == 1 ?

View file

@ -14,7 +14,8 @@ print("<th>GL_RENDERER");
print("<th>Output"); print("<th>Output");
print("<th>Warnings"); print("<th>Warnings");
hwdetectTestData.sort(function(a, b) { hwdetectTestData.sort(function(a, b)
{
if (a.renderer_backend.GL_RENDERER < b.renderer_backend.GL_RENDERER) if (a.renderer_backend.GL_RENDERER < b.renderer_backend.GL_RENDERER)
return -1; return -1;
if (b.renderer_backend.GL_RENDERER < a.renderer_backend.GL_RENDERER) if (b.renderer_backend.GL_RENDERER < a.renderer_backend.GL_RENDERER)

View file

@ -1,11 +1,14 @@
import { Plugin } from 'tools/dap/plugin.js'; import { Plugin } from 'tools/dap/plugin.js';
class DapCommands extends Plugin { class DapCommands extends Plugin
constructor(jsDebugger, dapHandler) { {
constructor(jsDebugger, dapHandler)
{
super('DapCommonCommand', 'command'); super('DapCommonCommand', 'command');
jsDebugger.registerHookName('onInitialize', this.name); jsDebugger.registerHookName('onInitialize', this.name);
dapHandler.registerCommand('initialize', (req) => { dapHandler.registerCommand('initialize', (req) =>
{
this.logger.info('Handling initialize command'); this.logger.info('Handling initialize command');
return dapHandler.successResponse(req, { return dapHandler.successResponse(req, {
'supportsConfigurationDoneRequest': true, 'supportsConfigurationDoneRequest': true,
@ -13,26 +16,30 @@ class DapCommands extends Plugin {
}); });
}); });
dapHandler.registerCommand('disconnect', (req) => { dapHandler.registerCommand('disconnect', (req) =>
{
this.logger.info('Handling disconnect command'); this.logger.info('Handling disconnect command');
jsDebugger.setAttached(false); jsDebugger.setAttached(false);
Engine.EndWaitingForMessage(); Engine.EndWaitingForMessage();
return dapHandler.successResponse(req, undefined); return dapHandler.successResponse(req, undefined);
}); });
dapHandler.registerCommand('attach', (req) => { dapHandler.registerCommand('attach', (req) =>
{
this.logger.info('Handling attach command'); this.logger.info('Handling attach command');
jsDebugger.setAttached(true); jsDebugger.setAttached(true);
jsDebugger.pushEvent('initialized', undefined, this.name); jsDebugger.pushEvent('initialized', undefined, this.name);
return dapHandler.successResponse(req, undefined); return dapHandler.successResponse(req, undefined);
}); });
dapHandler.registerCommand('configurationDone', (req) => { dapHandler.registerCommand('configurationDone', (req) =>
{
this.logger.info('Handling configurationDone command'); this.logger.info('Handling configurationDone command');
return dapHandler.successResponse(req, undefined); return dapHandler.successResponse(req, undefined);
}); });
dapHandler.registerCommand('threads', (req) => { dapHandler.registerCommand('threads', (req) =>
{
this.logger.info('Handling threads command'); this.logger.info('Handling threads command');
jsDebugger.triggerHook('onInitialize', undefined); jsDebugger.triggerHook('onInitialize', undefined);
return dapHandler.successResponse(req, { return dapHandler.successResponse(req, {

View file

@ -1,18 +1,22 @@
import { logger } from 'tools/dap/logger.js'; import { logger } from 'tools/dap/logger.js';
export class DapProtocolHandler { export class DapProtocolHandler
constructor(jsDebugger) { {
constructor(jsDebugger)
{
this.commands = {}; this.commands = {};
this.jsDebugger = jsDebugger; this.jsDebugger = jsDebugger;
this.logger = logger.getLogger("DAPProtocolHandler"); this.logger = logger.getLogger("DAPProtocolHandler");
} }
registerCommand(name, fn) { registerCommand(name, fn)
{
this.logger.info(`Registering command: ${name}`); this.logger.info(`Registering command: ${name}`);
this.commands[name] = fn; this.commands[name] = fn;
} }
handleRequest(req) { handleRequest(req)
{
if (req.type !== 'request' || !req.command) if (req.type !== 'request' || !req.command)
{ {
this.logger.error(`Invalid request: ${JSON.stringify(req)}`); this.logger.error(`Invalid request: ${JSON.stringify(req)}`);
@ -28,7 +32,7 @@ export class DapProtocolHandler {
this.logger.info(`Handling command: ${req.command}`); this.logger.info(`Handling command: ${req.command}`);
return handler(req); return handler(req);
} }
catch (error) catch(error)
{ {
this.logger.error(`Error handling command ${req.command}:`, error); this.logger.error(`Error handling command ${req.command}:`, error);
this.logger.error(uneval(error.stack)); this.logger.error(uneval(error.stack));
@ -36,7 +40,8 @@ export class DapProtocolHandler {
} }
} }
successResponse(req, result) { successResponse(req, result)
{
this.logger.info(`Response to ${req.command}`, result); this.logger.info(`Response to ${req.command}`, result);
const response = { const response = {
'type': 'response', 'type': 'response',
@ -48,7 +53,8 @@ export class DapProtocolHandler {
return response; return response;
} }
errorResponse(req, error) { errorResponse(req, error)
{
this.logger.error(`Error in ${req.command}: ${error}`); this.logger.error(`Error in ${req.command}: ${error}`);
const response = { const response = {
'type': 'response', 'type': 'response',

View file

@ -1,7 +1,9 @@
import { logger } from 'tools/dap/logger.js'; import { logger } from 'tools/dap/logger.js';
export class JsDebugger { export class JsDebugger
constructor() { {
constructor()
{
this.debugger = new Debugger(); this.debugger = new Debugger();
this.logger = logger.getLogger("SpiderDebugger"); this.logger = logger.getLogger("SpiderDebugger");
this.events = []; this.events = [];
@ -19,30 +21,36 @@ export class JsDebugger {
'onRsumeInFrame': [], 'onRsumeInFrame': [],
}; };
this.debugger.uncaughtExceptionHook = (e) => { this.debugger.uncaughtExceptionHook = (e) =>
{
this._runHooks('onUncaughtException', e); this._runHooks('onUncaughtException', e);
}; };
this.debugger.onNewGlobalObject = (global) => { this.debugger.onNewGlobalObject = (global) =>
{
this._runHooks('onNewGlobalObject', global); this._runHooks('onNewGlobalObject', global);
}; };
this.debugger.onDebuggerStatement = (frame) => { this.debugger.onDebuggerStatement = (frame) =>
{
this._runHooks('onDebuggerStatement', frame); this._runHooks('onDebuggerStatement', frame);
}; };
this.debugger.onNewScript = (script, global) => { this.debugger.onNewScript = (script, global) =>
{
this._runHooks('onNewScript', { script, global }); this._runHooks('onNewScript', { script, global });
}; };
this.debugger.onEnterFrame = (frame) => { this.debugger.onEnterFrame = (frame) =>
{
this._runHooks('onEnterFrame', frame); this._runHooks('onEnterFrame', frame);
}; };
this.debuggerAttached = false; this.debuggerAttached = false;
} }
_runHooks(event, data) { _runHooks(event, data)
{
this.logger.trace(`Running hook for ${event}`); this.logger.trace(`Running hook for ${event}`);
for (const hookInfo of this.hooks[event]) for (const hookInfo of this.hooks[event])
{ {
@ -53,16 +61,20 @@ export class JsDebugger {
continue; continue;
} }
try { try
{
hookInfo.callback(data); hookInfo.callback(data);
} catch (e) { }
catch(e)
{
this.logger.error(`Error in hook for ${hookInfo.source}-${event}: ${e.message}`); this.logger.error(`Error in hook for ${hookInfo.source}-${event}: ${e.message}`);
this.logger.error(uneval(e.stack)); this.logger.error(uneval(e.stack));
} }
} }
} }
on(event, callback, source) { on(event, callback, source)
{
if (!event || typeof event !== 'string') if (!event || typeof event !== 'string')
{ {
this.logger.warn('Invalid event name'); this.logger.warn('Invalid event name');
@ -90,11 +102,13 @@ export class JsDebugger {
this.logger.debug(`Hook added for event: ${event}`); this.logger.debug(`Hook added for event: ${event}`);
} }
get instance() { get instance()
{
return this.debugger; return this.debugger;
} }
setAttached(attached) { setAttached(attached)
{
this.debuggerAttached = attached; this.debuggerAttached = attached;
if (attached) if (attached)
{ {
@ -108,7 +122,8 @@ export class JsDebugger {
} }
} }
pushEvent(eventName, eventData, source) { pushEvent(eventName, eventData, source)
{
if (!eventName || typeof eventName !== 'string') if (!eventName || typeof eventName !== 'string')
{ {
this.logger.warn('Invalid event name'); this.logger.warn('Invalid event name');
@ -128,7 +143,8 @@ export class JsDebugger {
}); });
} }
stopInframe(frame, onHandler) { stopInframe(frame, onHandler)
{
if (!frame || !(frame instanceof Debugger.Frame)) if (!frame || !(frame instanceof Debugger.Frame))
{ {
this.logger.error('Invalid frame provided to stopInframe'); this.logger.error('Invalid frame provided to stopInframe');
@ -150,7 +166,8 @@ export class JsDebugger {
this.logger.debug("Client continue"); this.logger.debug("Client continue");
} }
registerHookName(event, source) { registerHookName(event, source)
{
if (!event || typeof event !== 'string') if (!event || typeof event !== 'string')
{ {
this.logger.warn('Invalid event name'); this.logger.warn('Invalid event name');
@ -173,7 +190,8 @@ export class JsDebugger {
this.logger.debug(`Hook registered for event: ${event} from source: ${source}`); this.logger.debug(`Hook registered for event: ${event} from source: ${source}`);
} }
triggerHook(event, data) { triggerHook(event, data)
{
if (!event || typeof event !== 'string') if (!event || typeof event !== 'string')
{ {
this.logger.warn('Invalid event name'); this.logger.warn('Invalid event name');

View file

@ -1,9 +1,11 @@
class Logger { class Logger
{
levels = ['trace', 'debug', 'info', 'warn', 'error']; levels = ['trace', 'debug', 'info', 'warn', 'error'];
// Default = 'info'. // Default = 'info'.
levelIndex = 2; levelIndex = 2;
setLevel(level) { setLevel(level)
{
const index = this.levels.indexOf(level); const index = this.levels.indexOf(level);
if (index === -1) if (index === -1)
{ {
@ -12,9 +14,12 @@ class Logger {
this.levelIndex = index; this.levelIndex = index;
} }
constructor() { constructor()
this.levels.forEach((level, index) => { {
this[level] = (...args) => { this.levels.forEach((level, index) =>
{
this[level] = (...args) =>
{
if (index < this.levelIndex) if (index < this.levelIndex)
return; return;
@ -28,14 +33,18 @@ class Logger {
}); });
} }
getLevel() { getLevel()
{
return this.levels[this.levelIndex]; return this.levels[this.levelIndex];
} }
getLogger(className) { getLogger(className)
{
const scopedLogger = {}; const scopedLogger = {};
this.levels.forEach((level) => { this.levels.forEach((level) =>
scopedLogger[level] = (msg) => { {
scopedLogger[level] = (msg) =>
{
this[level](`[${className}]`, msg); this[level](`[${className}]`, msg);
}; };
}); });

View file

@ -1,21 +1,26 @@
import { Plugin } from 'tools/dap/plugin.js'; import { Plugin } from 'tools/dap/plugin.js';
class AttachManager extends Plugin { class AttachManager extends Plugin
constructor(jsDebugger, dapHandler) { {
constructor(jsDebugger, dapHandler)
{
super('AttachManager', 'manager'); super('AttachManager', 'manager');
this.logger.debug('Setting up AttachManager'); this.logger.debug('Setting up AttachManager');
jsDebugger.on('onDebuggerAttached', () => { jsDebugger.on('onDebuggerAttached', () =>
{
this.logger.debug('Debugger attached'); this.logger.debug('Debugger attached');
jsDebugger.instance.addAllGlobalsAsDebuggees(); jsDebugger.instance.addAllGlobalsAsDebuggees();
}, this.name); }, this.name);
jsDebugger.on('onDebuggerDetached', () => { jsDebugger.on('onDebuggerDetached', () =>
{
this.logger.debug('Debugger detached'); this.logger.debug('Debugger detached');
jsDebugger.instance.removeAllDebuggees(); jsDebugger.instance.removeAllDebuggees();
}, this.name); }, this.name);
jsDebugger.on('onNewGlobalObject', (global) => { jsDebugger.on('onNewGlobalObject', (global) =>
{
if (!jsDebugger.debuggerAttached) if (!jsDebugger.debuggerAttached)
return; return;
@ -23,7 +28,8 @@ class AttachManager extends Plugin {
jsDebugger.instance.addDebuggee(global); jsDebugger.instance.addDebuggee(global);
}, this.name); }, this.name);
jsDebugger.on('onUncaughtException', (e) => { jsDebugger.on('onUncaughtException', (e) =>
{
this.logger.error(`Uncaught exception: ${e}`); this.logger.error(`Uncaught exception: ${e}`);
}, this.name); }, this.name);
} }

View file

@ -1,14 +1,17 @@
import { Plugin } from 'tools/dap/plugin.js'; import { Plugin } from 'tools/dap/plugin.js';
class BreakpointManager extends Plugin { class BreakpointManager extends Plugin
constructor(jsDebugger, dapHandler) { {
constructor(jsDebugger, dapHandler)
{
super('BreakpointManager', 'manager'); super('BreakpointManager', 'manager');
this.breakpoints = []; this.breakpoints = [];
this.dbg = jsDebugger.instance; this.dbg = jsDebugger.instance;
this.jsDebugger = jsDebugger; this.jsDebugger = jsDebugger;
this.logger.debug('Setting up BreakpointManager'); this.logger.debug('Setting up BreakpointManager');
jsDebugger.on('onNewScript', ({ script, global }) => { jsDebugger.on('onNewScript', ({ script, global }) =>
{
if (!jsDebugger.debuggerAttached) if (!jsDebugger.debuggerAttached)
return; return;
@ -24,7 +27,8 @@ class BreakpointManager extends Plugin {
this.logger.debug(`Setting breakpoints for script: ${script.url}`); this.logger.debug(`Setting breakpoints for script: ${script.url}`);
const sourceReferenceIndex = jsDebugger.sourcesReferences.findIndex((src) => src.path === url); const sourceReferenceIndex = jsDebugger.sourcesReferences.findIndex((src) => src.path === url);
this.breakpoints[index].lines.forEach((bp, i) => { this.breakpoints[index].lines.forEach((bp, i) =>
{
jsDebugger.pushEvent('breakpoint', { jsDebugger.pushEvent('breakpoint', {
'reason': 'changed', 'reason': 'changed',
'breakpoint': { 'breakpoint': {
@ -40,13 +44,15 @@ class BreakpointManager extends Plugin {
}); });
}, this.name); }, this.name);
jsDebugger.on('onDebuggerDetached', () => { jsDebugger.on('onDebuggerDetached', () =>
{
this.logger.debug('Debugger detached'); this.logger.debug('Debugger detached');
this.dbg.clearAllBreakpoints(); this.dbg.clearAllBreakpoints();
this.breakpoints = []; this.breakpoints = [];
}, this.name); }, this.name);
dapHandler.registerCommand('setBreakpoints', (req) => { dapHandler.registerCommand('setBreakpoints', (req) =>
{
const path = req.arguments.source.path; const path = req.arguments.source.path;
const name = req.arguments.source.name; const name = req.arguments.source.name;
this.logger.debug(`Handling setBreakpoints command for source: ${req.arguments.source.path}`); this.logger.debug(`Handling setBreakpoints command for source: ${req.arguments.source.path}`);
@ -76,7 +82,8 @@ class BreakpointManager extends Plugin {
}); });
} }
createOrUpdateBreakpoint(name, url, lines) { createOrUpdateBreakpoint(name, url, lines)
{
let index = this.breakpoints.findIndex((bp) => (!name || bp.name === name) && bp.url === url); let index = this.breakpoints.findIndex((bp) => (!name || bp.name === name) && bp.url === url);
if (index === -1) if (index === -1)
{ {
@ -89,7 +96,8 @@ class BreakpointManager extends Plugin {
return index + 1; return index + 1;
} }
addBreakpointsByPath(path, instance_script) { addBreakpointsByPath(path, instance_script)
{
const infoBk = this.breakpoints.find((bp) => bp.url === path); const infoBk = this.breakpoints.find((bp) => bp.url === path);
if (!infoBk) if (!infoBk)
@ -100,15 +108,18 @@ class BreakpointManager extends Plugin {
return false; return false;
this.logger.trace(`Found ${scripts.length} scripts for path: ${path}`); this.logger.trace(`Found ${scripts.length} scripts for path: ${path}`);
this.scriptTreeWalk(scripts, (script) => { this.scriptTreeWalk(scripts, (script) =>
{
script.clearAllBreakpoints(); script.clearAllBreakpoints();
}); });
infoBk.lines.forEach((bp) => { infoBk.lines.forEach((bp) =>
{
this.logger.debug(`Setting breakpoint at: ${uneval(bp)}`); this.logger.debug(`Setting breakpoint at: ${uneval(bp)}`);
bp.verified = false; bp.verified = false;
bp.message = "No offset found"; bp.message = "No offset found";
this.scriptTreeWalk(scripts, (script) => { this.scriptTreeWalk(scripts, (script) =>
{
const offsets = script.getPossibleBreakpointOffsets({ const offsets = script.getPossibleBreakpointOffsets({
'line': bp.line, 'line': bp.line,
}); });
@ -128,7 +139,8 @@ class BreakpointManager extends Plugin {
return true; return true;
} }
scriptTreeWalk(script, callback) { scriptTreeWalk(script, callback)
{
if (!script || script.length === 0) if (!script || script.length === 0)
return; return;
@ -143,8 +155,10 @@ class BreakpointManager extends Plugin {
} }
} }
handleBreakpoint(frame) { handleBreakpoint(frame)
this.jsDebugger.stopInframe(frame, () => { {
this.jsDebugger.stopInframe(frame, () =>
{
this.jsDebugger.pushEvent('stopped', { this.jsDebugger.pushEvent('stopped', {
'reason': 'breakpoint', 'reason': 'breakpoint',
'threadId': 1, 'threadId': 1,

View file

@ -1,7 +1,9 @@
import { Plugin } from 'tools/dap/plugin.js'; import { Plugin } from 'tools/dap/plugin.js';
class FrameManager extends Plugin { class FrameManager extends Plugin
constructor(jsDebugger, dapHandler) { {
constructor(jsDebugger, dapHandler)
{
super('FrameManager', 'manager'); super('FrameManager', 'manager');
this.logger.debug('Setting up FrameManager'); this.logger.debug('Setting up FrameManager');
@ -12,7 +14,8 @@ class FrameManager extends Plugin {
jsDebugger.registerHookName('onStepIn', this.name); jsDebugger.registerHookName('onStepIn', this.name);
jsDebugger.registerHookName('onStepOut', this.name); jsDebugger.registerHookName('onStepOut', this.name);
jsDebugger.on('onDebuggerDetached', () => { jsDebugger.on('onDebuggerDetached', () =>
{
this.logger.debug('Debugger detached'); this.logger.debug('Debugger detached');
let frame = jsDebugger.currentFrame; let frame = jsDebugger.currentFrame;
while (frame) while (frame)
@ -24,8 +27,10 @@ class FrameManager extends Plugin {
jsDebugger.currentFrame = undefined; jsDebugger.currentFrame = undefined;
}, this.name); }, this.name);
jsDebugger.on('onDebuggerStatement', (frame) => { jsDebugger.on('onDebuggerStatement', (frame) =>
jsDebugger.stopInframe(frame, () => { {
jsDebugger.stopInframe(frame, () =>
{
this.logger.debug(`Paused on debugger statement in frame: ${frame.script.url}`); this.logger.debug(`Paused on debugger statement in frame: ${frame.script.url}`);
jsDebugger.pushEvent('stopped', { jsDebugger.pushEvent('stopped', {
'reason': 'debugger', 'reason': 'debugger',
@ -35,7 +40,8 @@ class FrameManager extends Plugin {
}); });
}, this.name); }, this.name);
jsDebugger.on('onEnterFrame', (frame) => { jsDebugger.on('onEnterFrame', (frame) =>
{
if (!frame || !frame.older || !frame.older.stepIn || frame.onStep !== undefined) if (!frame || !frame.older || !frame.older.stepIn || frame.onStep !== undefined)
return; return;
@ -43,7 +49,8 @@ class FrameManager extends Plugin {
this.hookFrameDebugger(frame, "stepIn", "Paused on stepIn"); this.hookFrameDebugger(frame, "stepIn", "Paused on stepIn");
}, this.name); }, this.name);
dapHandler.registerCommand('stackTrace', (req) => { dapHandler.registerCommand('stackTrace', (req) =>
{
this.logger.debug('Handling stackTrace command'); this.logger.debug('Handling stackTrace command');
if (!jsDebugger.currentFrame) if (!jsDebugger.currentFrame)
{ {
@ -71,7 +78,8 @@ class FrameManager extends Plugin {
return dapHandler.successResponse(req, { 'stackFrames': stackFrames }); return dapHandler.successResponse(req, { 'stackFrames': stackFrames });
}); });
dapHandler.registerCommand('continue', (req) => { dapHandler.registerCommand('continue', (req) =>
{
this.logger.debug('Handling continue command'); this.logger.debug('Handling continue command');
let frame = jsDebugger.currentFrame; let frame = jsDebugger.currentFrame;
while (frame) while (frame)
@ -84,7 +92,8 @@ class FrameManager extends Plugin {
return dapHandler.successResponse(req, { 'allThreadsContinued': true }); return dapHandler.successResponse(req, { 'allThreadsContinued': true });
}); });
dapHandler.registerCommand('next', (req) => { dapHandler.registerCommand('next', (req) =>
{
this.logger.debug('Handling next command'); this.logger.debug('Handling next command');
if (!jsDebugger.currentFrame) if (!jsDebugger.currentFrame)
{ {
@ -103,7 +112,8 @@ class FrameManager extends Plugin {
return dapHandler.successResponse(req, undefined); return dapHandler.successResponse(req, undefined);
}); });
dapHandler.registerCommand('stepIn', (req) => { dapHandler.registerCommand('stepIn', (req) =>
{
this.logger.debug('Handling stepIn command'); this.logger.debug('Handling stepIn command');
if (!jsDebugger.currentFrame) if (!jsDebugger.currentFrame)
{ {
@ -122,7 +132,8 @@ class FrameManager extends Plugin {
return dapHandler.successResponse(req, undefined); return dapHandler.successResponse(req, undefined);
}); });
dapHandler.registerCommand('stepOut', (req) => { dapHandler.registerCommand('stepOut', (req) =>
{
this.logger.debug('Handling stepOut command'); this.logger.debug('Handling stepOut command');
if (!jsDebugger.currentFrame) if (!jsDebugger.currentFrame)
{ {
@ -142,28 +153,32 @@ class FrameManager extends Plugin {
}); });
} }
extractScriptName(url) { extractScriptName(url)
{
if (!url) if (!url)
return "[No Name]"; return "[No Name]";
const parts = url.split('\\'); const parts = url.split('\\');
return parts[parts.length - 1] || "[No Name]"; return parts[parts.length - 1] || "[No Name]";
} }
hookFrameDebugger(frame, reason, msg) { hookFrameDebugger(frame, reason, msg)
{
if (!frame) if (!frame)
return; return;
const that = this; const that = this;
if (frame.onStep === undefined) if (frame.onStep === undefined)
{ {
frame.onStep = function() { frame.onStep = function()
{
if (this.stepOut === true && this.stepOver !== true) if (this.stepOut === true && this.stepOver !== true)
return; return;
const currentLocation = this.script.getOffsetLocation(frame.offset); const currentLocation = this.script.getOffsetLocation(frame.offset);
if (this.currentLocation?.lineNumber === currentLocation.lineNumber) if (this.currentLocation?.lineNumber === currentLocation.lineNumber)
return; return;
that.jsDebugger.stopInframe(this, () => { that.jsDebugger.stopInframe(this, () =>
{
that.jsDebugger.pushEvent('stopped', { that.jsDebugger.pushEvent('stopped', {
'reason': reason, 'reason': reason,
'threadId': 1, 'threadId': 1,
@ -176,7 +191,8 @@ class FrameManager extends Plugin {
if (frame.onPop === undefined) if (frame.onPop === undefined)
{ {
frame.onPop = function() { frame.onPop = function()
{
if (this.stepIn || this.stepOut) if (this.stepIn || this.stepOut)
that.hookFrameDebugger(this.older, reason, msg); that.hookFrameDebugger(this.older, reason, msg);
that.cleanFrameDebugger(this); that.cleanFrameDebugger(this);
@ -184,7 +200,8 @@ class FrameManager extends Plugin {
} }
} }
cleanFrameDebugger(frame) { cleanFrameDebugger(frame)
{
if (!frame) if (!frame)
return; return;

View file

@ -1,23 +1,28 @@
import { Plugin } from 'tools/dap/plugin.js'; import { Plugin } from 'tools/dap/plugin.js';
class InspectorManager extends Plugin { class InspectorManager extends Plugin
constructor(jsDebugger, dapHandler) { {
constructor(jsDebugger, dapHandler)
{
super('InspectorManager', 'manager'); super('InspectorManager', 'manager');
this.variableReferences = []; this.variableReferences = [];
this.logger.debug('Setting up InspectorManager'); this.logger.debug('Setting up InspectorManager');
jsDebugger.on('onDebuggerDetached', () => { jsDebugger.on('onDebuggerDetached', () =>
{
this.logger.debug('Debugger attached'); this.logger.debug('Debugger attached');
this.variableReferences = []; this.variableReferences = [];
}, this.name); }, this.name);
jsDebugger.on('onContinue', () => { jsDebugger.on('onContinue', () =>
{
this.logger.debug('Continuing execution'); this.logger.debug('Continuing execution');
this.variableReferences = []; this.variableReferences = [];
}, this.name); }, this.name);
dapHandler.registerCommand('scopes', (req) => { dapHandler.registerCommand('scopes', (req) =>
{
this.logger.debug('Handling scopes command'); this.logger.debug('Handling scopes command');
if (!jsDebugger.currentFrame) if (!jsDebugger.currentFrame)
{ {
@ -49,7 +54,8 @@ class InspectorManager extends Plugin {
return dapHandler.successResponse(req, { 'scopes': this.createScopeAndVariableReferences(frame, req.arguments.frameId) }); return dapHandler.successResponse(req, { 'scopes': this.createScopeAndVariableReferences(frame, req.arguments.frameId) });
}); });
dapHandler.registerCommand('variables', (req) => { dapHandler.registerCommand('variables', (req) =>
{
this.logger.debug('Handling variables command'); this.logger.debug('Handling variables command');
if (!jsDebugger.currentFrame) if (!jsDebugger.currentFrame)
{ {
@ -61,7 +67,8 @@ class InspectorManager extends Plugin {
return dapHandler.successResponse(req, { 'variables': variables }); return dapHandler.successResponse(req, { 'variables': variables });
}); });
dapHandler.registerCommand('evaluate', (req) => { dapHandler.registerCommand('evaluate', (req) =>
{
this.logger.debug('Handling evaluate command'); this.logger.debug('Handling evaluate command');
if (!jsDebugger.currentFrame) if (!jsDebugger.currentFrame)
{ {
@ -91,7 +98,7 @@ class InspectorManager extends Plugin {
}); });
return dapHandler.successResponse(req, { 'result': JSON.stringify(result) || "null", 'variablesReference': 0 }); return dapHandler.successResponse(req, { 'result': JSON.stringify(result) || "null", 'variablesReference': 0 });
} }
catch (error) catch(error)
{ {
this.logger.error(`Error evaluating expression: ${error.message}`); this.logger.error(`Error evaluating expression: ${error.message}`);
return dapHandler.errorResponse(req, `Error evaluating expression: ${error.message}`); return dapHandler.errorResponse(req, `Error evaluating expression: ${error.message}`);
@ -99,7 +106,8 @@ class InspectorManager extends Plugin {
}); });
} }
createOrUpdateVariableReference(name, data) { createOrUpdateVariableReference(name, data)
{
let index = this.variableReferences.findIndex((ref) => ref.name === name); let index = this.variableReferences.findIndex((ref) => ref.name === name);
if (index === -1) if (index === -1)
{ {
@ -112,7 +120,8 @@ class InspectorManager extends Plugin {
return index + 1; return index + 1;
} }
createScopeAndVariableReferences(frame, frameId) { createScopeAndVariableReferences(frame, frameId)
{
if (!frame || !frame.onStack || frame.terminated) if (!frame || !frame.onStack || frame.terminated)
{ {
this.logger.error(`Invalid frame: ${frameId}`); this.logger.error(`Invalid frame: ${frameId}`);
@ -181,7 +190,8 @@ class InspectorManager extends Plugin {
return scopes; return scopes;
} }
describeJSObjectCallable(jsObject, varName) { describeJSObjectCallable(jsObject, varName)
{
if (!jsObject || !(jsObject instanceof Debugger.Object) || !jsObject.callable) if (!jsObject || !(jsObject instanceof Debugger.Object) || !jsObject.callable)
{ {
this.logger.error('Invalid JS Object for callable description'); this.logger.error('Invalid JS Object for callable description');
@ -221,7 +231,8 @@ class InspectorManager extends Plugin {
return variable; return variable;
} }
describeJSObjectVariable(jsObject, varRefName, varReference, varName) { describeJSObjectVariable(jsObject, varRefName, varReference, varName)
{
if (!jsObject || !(jsObject instanceof Debugger.Object)) if (!jsObject || !(jsObject instanceof Debugger.Object))
{ {
this.logger.error('Invalid JS Object for description'); this.logger.error('Invalid JS Object for description');
@ -307,7 +318,8 @@ class InspectorManager extends Plugin {
return variable; return variable;
} }
expandVariableReference(variableReferenceIndex, frame) { expandVariableReference(variableReferenceIndex, frame)
{
if (variableReferenceIndex === 0 || this.variableReferences.length < variableReferenceIndex - 1) if (variableReferenceIndex === 0 || this.variableReferences.length < variableReferenceIndex - 1)
{ {
this.logger.warn(`Invalid variable reference index: ${variableReferenceIndex}`); this.logger.warn(`Invalid variable reference index: ${variableReferenceIndex}`);

View file

@ -1,12 +1,15 @@
import { Plugin } from 'tools/dap/plugin.js'; import { Plugin } from 'tools/dap/plugin.js';
class SourcesManager extends Plugin { class SourcesManager extends Plugin
constructor(jsDebugger, dapHandler) { {
constructor(jsDebugger, dapHandler)
{
super('SourcesManager', 'manager'); super('SourcesManager', 'manager');
this.jsDebugger = jsDebugger; this.jsDebugger = jsDebugger;
this.logger.debug('Setting up SourcesManager'); this.logger.debug('Setting up SourcesManager');
jsDebugger.on('onNewScript', ({ script, global }) => { jsDebugger.on('onNewScript', ({ script, global }) =>
{
if (!jsDebugger.debuggerAttached) if (!jsDebugger.debuggerAttached)
return; return;
@ -31,15 +34,18 @@ class SourcesManager extends Plugin {
}, this.name); }, this.name);
}, this.name); }, this.name);
jsDebugger.on('onDebuggerDetached', () => { jsDebugger.on('onDebuggerDetached', () =>
{
this.logger.debug('Debugger detached'); this.logger.debug('Debugger detached');
this.jsDebugger.sourcesReferences = []; this.jsDebugger.sourcesReferences = [];
}, this.name); }, this.name);
jsDebugger.on('onDebuggerAttached', () => { jsDebugger.on('onDebuggerAttached', () =>
{
this.logger.debug('Debugger attached'); this.logger.debug('Debugger attached');
this.jsDebugger.sourcesReferences = []; this.jsDebugger.sourcesReferences = [];
this.jsDebugger.instance.findSources().forEach((source) => { this.jsDebugger.instance.findSources().forEach((source) =>
{
const url = source.url; const url = source.url;
if (this.jsDebugger.sourcesReferences.some((src) => src.path === url)) if (this.jsDebugger.sourcesReferences.some((src) => src.path === url))
return; return;
@ -50,7 +56,8 @@ class SourcesManager extends Plugin {
}); });
}, this.name); }, this.name);
dapHandler.registerCommand('loadedSources', (req) => { dapHandler.registerCommand('loadedSources', (req) =>
{
if (!jsDebugger.debuggerAttached) if (!jsDebugger.debuggerAttached)
{ {
this.logger.error('Debugger not attached, cannot handle loadedSources command'); this.logger.error('Debugger not attached, cannot handle loadedSources command');
@ -66,7 +73,8 @@ class SourcesManager extends Plugin {
return dapHandler.successResponse(req, { 'sources': sources }); return dapHandler.successResponse(req, { 'sources': sources });
}); });
dapHandler.registerCommand('source', (req) => { dapHandler.registerCommand('source', (req) =>
{
if (!jsDebugger.debuggerAttached) if (!jsDebugger.debuggerAttached)
{ {
this.logger.error('Debugger not attached, cannot handle source command'); this.logger.error('Debugger not attached, cannot handle source command');

View file

@ -1,7 +1,9 @@
import { logger } from 'tools/dap/logger.js'; import { logger } from 'tools/dap/logger.js';
export class Plugin { export class Plugin
constructor(name, type) { {
constructor(name, type)
{
this.name = name; this.name = name;
this.type = type; this.type = type;
this.logger = logger.getLogger(name); this.logger = logger.getLogger(name);

View file

@ -11,7 +11,7 @@ class AutoStartClient
const port = +(cmdLineArgs['autostart-port'] ?? 5073); const port = +(cmdLineArgs['autostart-port'] ?? 5073);
Engine.StartNetworkJoin(playerName, ip, port, !('autostart-disable-replay' in cmdLineArgs)); Engine.StartNetworkJoin(playerName, ip, port, !('autostart-disable-replay' in cmdLineArgs));
} }
catch (e) catch(e)
{ {
const message = sprintf(translate("Cannot join game: %(message)s."), { "message": e.message }); const message = sprintf(translate("Cannot join game: %(message)s."), { "message": e.message });
messageBox(400, 200, message, translate("Error")); messageBox(400, 200, message, translate("Error"));

View file

@ -16,7 +16,7 @@ class AutoStartHost
// Password not implemented for autostart. // Password not implemented for autostart.
Engine.StartNetworkHost(playerName, port, "", false, !('autostart-disable-replay' in cmdLineArgs)); Engine.StartNetworkHost(playerName, port, "", false, !('autostart-disable-replay' in cmdLineArgs));
} }
catch (e) catch(e)
{ {
const message = sprintf(translate("Cannot host game: %(message)s."), { "message": e.message }); const message = sprintf(translate("Cannot host game: %(message)s."), { "message": e.message });
messageBox(400, 200, message, translate("Error")); messageBox(400, 200, message, translate("Error"));

View file

@ -120,7 +120,8 @@ function parseCmdLineArgs(settings, cmdLineArgs)
settings.playerCount.setNb(+cmdLineArgs['autostart-players']); settings.playerCount.setNb(+cmdLineArgs['autostart-players']);
} }
const getPlayer = (key, i) => { const getPlayer = (key, i) =>
{
if (!(('autostart-' + key) in cmdLineArgs)) if (!(('autostart-' + key) in cmdLineArgs))
return undefined; return undefined;
var value = cmdLineArgs['autostart-' + key]; var value = cmdLineArgs['autostart-' + key];

View file

@ -183,7 +183,8 @@ GameSettings.prototype.Attributes.PlayerColor = class PlayerColor extends GameSe
_getUnusedColor() _getUnusedColor()
{ {
return this.available.find(color => { return this.available.find(color =>
{
return this.values.every(otherColor => !otherColor || !sameColor(color, otherColor)); return this.values.every(otherColor => !otherColor || !sameColor(color, otherColor));
}); });
} }

View file

@ -94,7 +94,8 @@ GameSettings.prototype.Attributes.PlayerName = class PlayerName extends GameSett
const translatedCountLabel = this.settings.isNetworked ? this.CountLabel : translate(this.CountLabel); const translatedCountLabel = this.settings.isNetworked ? this.CountLabel : translate(this.CountLabel);
const translatedChosenName = this.settings.isNetworked ? chosenName : translate(chosenName); const translatedChosenName = this.settings.isNetworked ? chosenName : translate(chosenName);
const duplicateNameCount = AIPlayerNamesList.reduce((count, name) => { const duplicateNameCount = AIPlayerNamesList.reduce((count, name) =>
{
if (name == chosenName) if (name == chosenName)
count++; count++;
return count; return count;

View file

@ -28,7 +28,8 @@ class DamageTypesMetadata
} }
const hasMetadata = (a) => this.damageTypeData[a] ? -1 : 1; const hasMetadata = (a) => this.damageTypeData[a] ? -1 : 1;
this._sort = (a, b) => { this._sort = (a, b) =>
{
if (this.damageTypeData[a] && this.damageTypeData[b]) if (this.damageTypeData[a] && this.damageTypeData[b])
return this.damageTypeData[a].order - this.damageTypeData[b].order; return this.damageTypeData[a].order - this.damageTypeData[b].order;
return hasMetadata(a) - hasMetadata(b); return hasMetadata(a) - hasMetadata(b);

View file

@ -118,41 +118,41 @@ function DeriveModificationsFromTechnologies(techsDataArray)
* Common definition of the XML schema for in-template modifications. * Common definition of the XML schema for in-template modifications.
*/ */
const ModificationSchema = const ModificationSchema =
"<interleave>" + "<interleave>" +
"<element name='Paths' a:help='Space separated value paths to modify.'>" + "<element name='Paths' a:help='Space separated value paths to modify.'>" +
"<attribute name='datatype'>" + "<attribute name='datatype'>" +
"<value>tokens</value>" + "<value>tokens</value>" +
"</attribute>" + "</attribute>" +
"<text/>" +
"</element>" +
"<element name='Affects' a:help='An array of classes to affect.'>" +
"<attribute name='datatype'>" +
"<value>tokens</value>" +
"</attribute>" +
"<text/>" +
"</element>" +
"<choice>" +
"<element name='Add'>" +
"<data type='decimal' />" +
"</element>" +
"<element name='Multiply'>" +
"<data type='decimal' />" +
"</element>" +
"<element name='Replace'>" +
"<text/>" + "<text/>" +
"</element>" + "</element>" +
"</choice>" + "<element name='Affects' a:help='An array of classes to affect.'>" +
"</interleave>"; "<attribute name='datatype'>" +
"<value>tokens</value>" +
"</attribute>" +
"<text/>" +
"</element>" +
"<choice>" +
"<element name='Add'>" +
"<data type='decimal' />" +
"</element>" +
"<element name='Multiply'>" +
"<data type='decimal' />" +
"</element>" +
"<element name='Replace'>" +
"<text/>" +
"</element>" +
"</choice>" +
"</interleave>";
const ModificationsSchema = const ModificationsSchema =
"<element name='Modifiers' a:help='List of modifiers.'>" + "<element name='Modifiers' a:help='List of modifiers.'>" +
"<oneOrMore>" + "<oneOrMore>" +
"<element>" + "<element>" +
"<anyName />" + "<anyName />" +
ModificationSchema + ModificationSchema +
"</element>" + "</element>" +
"</oneOrMore>" + "</oneOrMore>" +
"</element>"; "</element>";
/** /**
* Derives a single modification (to be applied to entities) from a given XML template. * Derives a single modification (to be applied to entities) from a given XML template.

View file

@ -165,7 +165,8 @@ function GetTemplateDataHelper(template, player, auraTemplates, resources, modif
// @param {string} value_path - Route to the value within the template. // @param {string} value_path - Route to the value within the template.
// @param {string} mod_key - Modification key, if not the same as the value_path. // @param {string} mod_key - Modification key, if not the same as the value_path.
// @param {number} default_value - A value to use if one is not specified in the template. // @param {number} default_value - A value to use if one is not specified in the template.
const getEntityValue = function(value_path, mod_key, default_value = 0) { const getEntityValue = function(value_path, mod_key, default_value = 0)
{
return GetModifiedTemplateDataValue(template, value_path, mod_key, player, modifiers, default_value); return GetModifiedTemplateDataValue(template, value_path, mod_key, player, modifiers, default_value);
}; };
@ -197,7 +198,8 @@ function GetTemplateDataHelper(template, player, auraTemplates, resources, modif
} }
} }
const getAttackEffects = (temp, path) => { const getAttackEffects = (temp, path) =>
{
const effects = {}; const effects = {};
if (temp.Capture) if (temp.Capture)
effects.Capture = getEntityValue(path + "/Capture"); effects.Capture = getEntityValue(path + "/Capture");
@ -220,7 +222,8 @@ function GetTemplateDataHelper(template, player, auraTemplates, resources, modif
ret.attack = {}; ret.attack = {};
for (const type in template.Attack) for (const type in template.Attack)
{ {
const getAttackStat = function(stat) { const getAttackStat = function(stat)
{
return getEntityValue("Attack/" + type + "/" + stat); return getEntityValue("Attack/" + type + "/" + stat);
}; };

View file

@ -237,12 +237,15 @@ var g_CampaignMenu;
function init(initData) function init(initData)
{ {
let run = initData?.filename || CampaignRun.getCurrentRunFilename(); let run = initData?.filename || CampaignRun.getCurrentRunFilename();
try { try
{
run = new CampaignRun(run).load(); run = new CampaignRun(run).load();
if (!run.isCurrent()) if (!run.isCurrent())
run.setCurrent(); run.setCurrent();
g_CampaignMenu = new CampaignMenu(run); g_CampaignMenu = new CampaignMenu(run);
} catch (err) { }
catch(err)
{
error(sprintf("Error loading campaign run %s: %s.", CampaignRun.getCurrentRunFilename(), err)); error(sprintf("Error loading campaign run %s: %s.", CampaignRun.getCurrentRunFilename(), err));
Engine.SwitchGuiPage("page_pregame.xml", {}); Engine.SwitchGuiPage("page_pregame.xml", {});
} }

View file

@ -47,7 +47,8 @@ class LoadModal extends AutoWatcher
this.selectedRun = -1; this.selectedRun = -1;
this.runSelection = Engine.GetGUIObjectByName("runSelection"); this.runSelection = Engine.GetGUIObjectByName("runSelection");
this.runSelection.onSelectionChange = () => { this.runSelection.onSelectionChange = () =>
{
this.selectedRun = this.runSelection.selected; this.selectedRun = this.runSelection.selected;
if (this.selectedRun === -1) if (this.selectedRun === -1)
Engine.GetGUIObjectByName('runDescription').caption = ""; Engine.GetGUIObjectByName('runDescription').caption = "";
@ -71,7 +72,7 @@ class LoadModal extends AutoWatcher
{ {
out.push(new CampaignRun(name).load()); out.push(new CampaignRun(name).load());
} }
catch (err) catch(err)
{ {
warn(err.toString()); warn(err.toString());
out.push(new BrokenRun(name)); out.push(new BrokenRun(name));

View file

@ -12,7 +12,8 @@ class NewCampaignModal
Engine.GetGUIObjectByName('cancelButton').onPress = closePageCallback; Engine.GetGUIObjectByName('cancelButton').onPress = closePageCallback;
Engine.GetGUIObjectByName('startButton').onPress = () => this.createAndStartCampaign(); Engine.GetGUIObjectByName('startButton').onPress = () => this.createAndStartCampaign();
Engine.GetGUIObjectByName('runDescription').caption = translateWithContext("Campaign Template", this.template.Name); Engine.GetGUIObjectByName('runDescription').caption = translateWithContext("Campaign Template", this.template.Name);
Engine.GetGUIObjectByName('runDescription').onTextEdit = () => { Engine.GetGUIObjectByName('runDescription').onTextEdit = () =>
{
Engine.GetGUIObjectByName('startButton').enabled = Engine.GetGUIObjectByName('runDescription').caption.length > 0; Engine.GetGUIObjectByName('startButton').enabled = Engine.GetGUIObjectByName('runDescription').caption.length > 0;
}; };
Engine.GetGUIObjectByName('runDescription').focus(); Engine.GetGUIObjectByName('runDescription').focus();
@ -38,7 +39,8 @@ var g_NewCampaignModal;
function init(campaign_template_data) function init(campaign_template_data)
{ {
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
g_NewCampaignModal = new NewCampaignModal(campaign_template_data, closePageCallback); g_NewCampaignModal = new NewCampaignModal(campaign_template_data, closePageCallback);
}); });
} }

View file

@ -15,12 +15,14 @@ class CampaignSetupPage extends AutoWatcher
Engine.GetGUIObjectByName("startCampButton").onPress = () => Engine.OpenChildPage("campaigns/new_modal/page.xml", this.selectedTemplate); Engine.GetGUIObjectByName("startCampButton").onPress = () => Engine.OpenChildPage("campaigns/new_modal/page.xml", this.selectedTemplate);
this.campaignSelection = Engine.GetGUIObjectByName("campaignSelection"); this.campaignSelection = Engine.GetGUIObjectByName("campaignSelection");
this.campaignSelection.onMouseLeftDoubleClickItem = () => { this.campaignSelection.onMouseLeftDoubleClickItem = () =>
{
if (this.selectedIndex === -1) if (this.selectedIndex === -1)
return; return;
Engine.OpenChildPage("campaigns/new_modal/page.xml", this.selectedTemplate); Engine.OpenChildPage("campaigns/new_modal/page.xml", this.selectedTemplate);
}; };
this.campaignSelection.onSelectionChange = () => { this.campaignSelection.onSelectionChange = () =>
{
this.selectedIndex = this.campaignSelection.selected; this.selectedIndex = this.campaignSelection.selected;
if (this.selectedIndex !== -1) if (this.selectedIndex !== -1)
this.selectedTemplate = this.templates[this.selectedIndex]; this.selectedTemplate = this.templates[this.selectedIndex];

View file

@ -21,7 +21,8 @@ var ObservableMixin = (Parent) => class Observable extends (() => Parent || Obje
"enumerable": false, "enumerable": false,
}); });
return new Proxy(this, { return new Proxy(this, {
"set": (target, key, value) => { "set": (target, key, value) =>
{
let old; let old;
let hasOld = false; let hasOld = false;
if (Reflect.has(target, key)) if (Reflect.has(target, key))

View file

@ -14,13 +14,15 @@ var ProfilableMixin = (Parent) => class Profilable extends (() => Parent || Obje
{ {
super(); super();
return new Proxy(this, { return new Proxy(this, {
"get": (target, prop, receiver) => { "get": (target, prop, receiver) =>
{
let ret = Reflect.get(target, prop); let ret = Reflect.get(target, prop);
if (typeof ret !== 'function') if (typeof ret !== 'function')
return ret; return ret;
{ {
ret = ret.bind(receiver); ret = ret.bind(receiver);
return (...a) => { return (...a) =>
{
Engine.ProfileStart(target.constructor.name + ":" + prop); Engine.ProfileStart(target.constructor.name + ":" + prop);
const ret2 = ret(...a); const ret2 = ret(...a);
Engine.ProfileStop(); Engine.ProfileStop();

View file

@ -7,10 +7,12 @@
function _watch(object, callback) function _watch(object, callback)
{ {
return new Proxy(object, { return new Proxy(object, {
"get": (obj, key) => { "get": (obj, key) =>
{
return obj[key]; return obj[key];
}, },
"set": (obj, key, value) => { "set": (obj, key, value) =>
{
obj[key] = value; obj[key] = value;
callback(key); callback(key);
return true; return true;

View file

@ -104,7 +104,7 @@ function stringifiedTeamListToPlayerData(stringifiedTeamList)
{ {
teamList = JSON.parse(unescapeText(stringifiedTeamList)); teamList = JSON.parse(unescapeText(stringifiedTeamList));
} }
catch (e) catch(e)
{ {
// Ignore invalid input from remote users // Ignore invalid input from remote users
return []; return [];

View file

@ -153,7 +153,8 @@ function formatPlayerInfo(playerDataArray, playerStates)
// If there are teams, merge "Team N:" + playerDescriptions // If there are teams, merge "Team N:" + playerDescriptions
else else
teamDescription = teams.map(team => { teamDescription = teams.map(team =>
{
const teamCaption = team == -1 ? const teamCaption = team == -1 ?
translate("No Team") : translate("No Team") :

View file

@ -211,7 +211,8 @@ function kickObservers(ban)
*/ */
function sortGUIDsByPlayerID() function sortGUIDsByPlayerID()
{ {
return Object.keys(g_PlayerAssignments).sort((guidA, guidB) => { return Object.keys(g_PlayerAssignments).sort((guidA, guidB) =>
{
const playerIdA = g_PlayerAssignments[guidA].player; const playerIdA = g_PlayerAssignments[guidA].player;
const playerIdB = g_PlayerAssignments[guidB].player; const playerIdB = g_PlayerAssignments[guidB].player;

View file

@ -201,7 +201,8 @@ function loadMapTypes()
function loadBiomes() function loadBiomes()
{ {
return listFiles(g_BiomesDirectory, ".json", true).filter(biomeID => biomeID != "defaultbiome").map(biomeID => { return listFiles(g_BiomesDirectory, ".json", true).filter(biomeID => biomeID != "defaultbiome").map(biomeID =>
{
const description = Engine.ReadJSONFile(g_BiomesDirectory + biomeID + ".json").Description; const description = Engine.ReadJSONFile(g_BiomesDirectory + biomeID + ".json").Description;
return { return {
"Id": biomeID, "Id": biomeID,
@ -221,7 +222,8 @@ function loadVictoryConditions()
{ {
const subdir = "victory_conditions/"; const subdir = "victory_conditions/";
const victoryConditions = listFiles(g_SettingsDirectory + subdir, ".json", false).map(victoryScriptName => { const victoryConditions = listFiles(g_SettingsDirectory + subdir, ".json", false).map(victoryScriptName =>
{
const victoryCondition = loadSettingValuesFile(subdir + victoryScriptName + ".json"); const victoryCondition = loadSettingValuesFile(subdir + victoryScriptName + ".json");
if (victoryCondition) if (victoryCondition)
victoryCondition.Name = victoryScriptName; victoryCondition.Name = victoryScriptName;

View file

@ -90,7 +90,8 @@ function selectNextTab(direction)
function selectPanel(category) function selectPanel(category)
{ {
g_TabCategorySelected = category; g_TabCategorySelected = category;
Engine.GetGUIObjectByName("tabButtons").children.forEach((button, j) => { Engine.GetGUIObjectByName("tabButtons").children.forEach((button, j) =>
{
button.sprite = g_TabHorizontal ? button.sprite = g_TabHorizontal ?
category == j ? category == j ?
"ModernTabHorizontalForeground" : "ModernTabHorizontalForeground" :

View file

@ -57,9 +57,12 @@ function updateTimers()
if (!t) if (!t)
continue; // an earlier timer might have cancelled this one, so skip it continue; // an earlier timer might have cancelled this one, so skip it
try { try
{
t[1](); t[1]();
} catch (e) { }
catch(e)
{
var stack = e.stack.trimRight().replace(/^/mg, ' '); // indent the stack trace var stack = e.stack.trimRight().replace(/^/mg, ' '); // indent the stack trace
error(sprintf("Error in timer: %(error)s", { "error": e }) + "\n" + stack + "\n"); error(sprintf("Error in timer: %(error)s", { "error": e }) + "\n" + stack + "\n");
} }

View file

@ -14,7 +14,8 @@ var g_ShowSecondaryNames = Engine.ConfigDB_GetValue("user", "gui.session.howtosh
function initDisplayedNames() function initDisplayedNames()
{ {
registerConfigChangeHandler(changes => { registerConfigChangeHandler(changes =>
{
if (changes.has("gui.session.howtoshownames")) if (changes.has("gui.session.howtoshownames"))
updateDisplayedNames(); updateDisplayedNames();
}); });
@ -269,7 +270,8 @@ function getStatusEffectsResistanceTooltip(resistanceTypeTemplate)
"label": headerFont(translate("Status Effects:")), "label": headerFont(translate("Status Effects:")),
"details": "details":
Object.keys(resistanceTypeTemplate).map( Object.keys(resistanceTypeTemplate).map(
statusEffect => { statusEffect =>
{
if (resistanceTypeTemplate[statusEffect].blockChance == 1) if (resistanceTypeTemplate[statusEffect].blockChance == 1)
return sprintf(translate("Blocks %(name)s"), { return sprintf(translate("Blocks %(name)s"), {
"name": unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(statusEffect))) "name": unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(statusEffect)))

View file

@ -56,11 +56,13 @@ function init()
g_TabButtonHeight, g_TabButtonHeight,
g_TabButtonDist, g_TabButtonDist,
selectPanel, selectPanel,
category => { category =>
{
Engine.GetGUIObjectByName("creditsText").caption = g_PanelData[category].content; Engine.GetGUIObjectByName("creditsText").caption = g_PanelData[category].content;
}); });
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
Engine.GetGUIObjectByName("closeButton").onPress = closePageCallback; Engine.GetGUIObjectByName("closeButton").onPress = closePageCallback;
}); });
} }

View file

@ -84,7 +84,8 @@ class GameSettingsController
// and particularly could fail with mods that change persistent settings, so this is // and particularly could fail with mods that change persistent settings, so this is
// difficult to fully fix from the gameSettings code. // difficult to fully fix from the gameSettings code.
// Also include hotloaded data because that can also fail and having to restart isn't very useful. // Also include hotloaded data because that can also fail and having to restart isn't very useful.
try { try
{
if (hotloadData) if (hotloadData)
this.parseSettings(hotloadData.initAttributes, false); this.parseSettings(hotloadData.initAttributes, false);
else if (g_IsController && (initData?.gameSettings || this.persistentMatchSettings.enabled)) else if (g_IsController && (initData?.gameSettings || this.persistentMatchSettings.enabled))
@ -96,7 +97,9 @@ class GameSettingsController
if (settings) if (settings)
this.parseSettings(settings, true); this.parseSettings(settings, true);
} }
} catch (err) { }
catch(err)
{
error("There was an error loading game settings. You may need to disable persistent match settings."); error("There was an error loading game settings. You may need to disable persistent match settings.");
warn(err?.toString() ?? uneval(err)); warn(err?.toString() ?? uneval(err));
if (err.stack) if (err.stack)
@ -231,7 +234,8 @@ class GameSettingsController
{ {
if (this.layoutTimer) if (this.layoutTimer)
return; return;
this.layoutTimer = setTimeout(() => { this.layoutTimer = setTimeout(() =>
{
for (const handler of this.updateLayoutHandlers) for (const handler of this.updateLayoutHandlers)
handler(); handler();
delete this.layoutTimer; delete this.layoutTimer;

View file

@ -61,7 +61,8 @@ class GameSettingControlSlider extends GameSettingControl
onValueChangeSuper() onValueChangeSuper()
{ {
if (!this.isInGuiUpdate && !this.timer) if (!this.isInGuiUpdate && !this.timer)
this.timer = setTimeout(() => { this.timer = setTimeout(() =>
{
this.onValueChange(this.slider.value); this.onValueChange(this.slider.value);
delete this.timer; delete this.timer;
}, this.Timeout); }, this.Timeout);

View file

@ -5,7 +5,8 @@ PlayerSettingControls.AIConfigButton = class AIConfigButton extends GameSettingC
super(...args); super(...args);
this.aiConfigButton = Engine.GetGUIObjectByName("aiConfigButton[" + this.playerIndex + "]"); this.aiConfigButton = Engine.GetGUIObjectByName("aiConfigButton[" + this.playerIndex + "]");
this.aiConfigButton.onPress = () => { this.aiConfigButton.onPress = () =>
{
this.setupWindow.pages.AIConfigPage.openPage(this.playerIndex, this.enabled); this.setupWindow.pages.AIConfigPage.openPage(this.playerIndex, this.enabled);
}; };

View file

@ -314,8 +314,8 @@ PlayerSettingControls.PlayerAssignment.prototype.AutocompleteOrder = 100;
}; };
PlayerAssignmentItem.Removed.prototype.Label = PlayerAssignmentItem.Removed.prototype.Label =
translate("Removed"); translate("Removed");
PlayerAssignmentItem.Removed.prototype.Tags = PlayerAssignmentItem.Removed.prototype.Tags =
{ "color": "255 140 140" }; { "color": "255 140 140" };
} }

View file

@ -30,7 +30,8 @@ PlayerSettingControls.PlayerColor = class PlayerColor extends GameSettingControl
this.values = g_GameSettings.playerColor.available; this.values = g_GameSettings.playerColor.available;
this.dropdown.list = this.values.map(color => coloredText(this.ColorIcon, rgbToGuiColor(color))); this.dropdown.list = this.values.map(color => coloredText(this.ColorIcon, rgbToGuiColor(color)));
this.dropdown.list_data = this.values.map((color, i) => i); this.dropdown.list_data = this.values.map((color, i) => i);
this.setSelectedValue(this.values.map((color, i) => { this.setSelectedValue(this.values.map((color, i) =>
{
if (color.r === value.r && color.g === value.g && color.b === value.b) if (color.r === value.r && color.g === value.g && color.b === value.b)
return i; return i;
return undefined; return undefined;

View file

@ -120,7 +120,8 @@ GameSettingControls.MapSelection = class MapSelection extends GameSettingControl
// which takes a few ms, but this could only be done once per frame anyways. // which takes a few ms, but this could only be done once per frame anyways.
// NB: this technically makes it possible to start the game without the change going through // NB: this technically makes it possible to start the game without the change going through
// but it's essentially impossible to trigger accidentally. // but it's essentially impossible to trigger accidentally.
const call = () => { const call = () =>
{
g_GameSettings.map.selectMap(this.values.file[itemIdx]); g_GameSettings.map.selectMap(this.values.file[itemIdx]);
this.gameSettingsController.setNetworkInitAttributes(); this.gameSettingsController.setNetworkInitAttributes();
delete this.reRenderTimeout; delete this.reRenderTimeout;

View file

@ -48,7 +48,8 @@ GameSettingControls.PopulationCap = class PopulationCap extends GameSettingContr
{ {
const popCap = g_GameSettings.population.currentData.Options.List[this.dropdown.hovered]; const popCap = g_GameSettings.population.currentData.Options.List[this.dropdown.hovered];
const nbPlayers = g_GameSettings.playerCount.nbPlayers; const nbPlayers = g_GameSettings.playerCount.nbPlayers;
const nbTeams = g_GameSettings.playerTeam.values.reduce((teamList, team) => { const nbTeams = g_GameSettings.playerTeam.values.reduce((teamList, team) =>
{
if (!teamList.includes(team) || team == -1) if (!teamList.includes(team) || team == -1)
teamList.push(team); teamList.push(team);
return teamList; return teamList;

View file

@ -31,7 +31,8 @@ const cancelTag = Symbol("cancelTag");
*/ */
function cancelOr(costumPromise) function cancelOr(costumPromise)
{ {
return Promise.race([costumPromise, new Promise(resolve => { return Promise.race([costumPromise, new Promise(resolve =>
{
Engine.GetGUIObjectByName("cancelButton").onPress = resolve.bind(undefined, cancelTag); Engine.GetGUIObjectByName("cancelButton").onPress = resolve.bind(undefined, cancelTag);
})]); })]);
} }
@ -42,7 +43,8 @@ async function waitOnEvent(loadSavedGame, joinFromLobby)
{ {
if (!joinFromLobby) if (!joinFromLobby)
{ {
const continueResult = await cancelOr(new Promise(resolve => { const continueResult = await cancelOr(new Promise(resolve =>
{
Engine.GetGUIObjectByName("continueButton").onPress = resolve; Engine.GetGUIObjectByName("continueButton").onPress = resolve;
})); }));
if (continueResult === cancelTag) if (continueResult === cancelTag)
@ -55,7 +57,7 @@ async function waitOnEvent(loadSavedGame, joinFromLobby)
{ {
confirmSetup(loadSavedGame); confirmSetup(loadSavedGame);
} }
catch (e) catch(e)
{ {
if (cancelSetup()) if (cancelSetup())
return; return;
@ -64,7 +66,8 @@ async function waitOnEvent(loadSavedGame, joinFromLobby)
} }
while (true) while (true)
{ {
const tickResult = await cancelOr(new Promise(resolve => { const tickResult = await cancelOr(new Promise(resolve =>
{
Engine.GetGUIObjectByName("multiplayerPages").onTick = resolve; Engine.GetGUIObjectByName("multiplayerPages").onTick = resolve;
})); }));
if (tickResult === cancelTag || await onTick(loadSavedGame)) if (tickResult === cancelTag || await onTick(loadSavedGame))
@ -92,7 +95,8 @@ async function init(attribs)
{ {
g_ServerName = attribs.name; g_ServerName = attribs.name;
switchSetupPage("pagePassword"); switchSetupPage("pagePassword");
const passwordResult = await cancelOr(new Promise(resolve => { const passwordResult = await cancelOr(new Promise(resolve =>
{
Engine.GetGUIObjectByName("confirmPasswordButton").onPress = resolve; Engine.GetGUIObjectByName("confirmPasswordButton").onPress = resolve;
})); }));
if (passwordResult === cancelTag) if (passwordResult === cancelTag)
@ -104,7 +108,7 @@ async function init(attribs)
attribs.hasPassword ? Engine.GetGUIObjectByName("clientPassword").caption : ""); attribs.hasPassword ? Engine.GetGUIObjectByName("clientPassword").caption : "");
switchSetupPage("pageConnecting"); switchSetupPage("pageConnecting");
} }
catch (e) catch(e)
{ {
if (cancelSetup()) if (cancelSetup())
return; return;
@ -439,7 +443,7 @@ function startHost(playername, servername, port, password, loadSavedGame)
Engine.StartNetworkHost(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), port, Engine.StartNetworkHost(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), port,
password, loadSavedGame, true); password, loadSavedGame, true);
} }
catch (e) catch(e)
{ {
messageBox( messageBox(
400, 200, 400, 200,
@ -465,7 +469,7 @@ function startJoin(playername, ip, port)
{ {
Engine.StartNetworkJoin(playername, ip, port, true); Engine.StartNetworkJoin(playername, ip, port, true);
} }
catch (e) catch(e)
{ {
messageBox( messageBox(
400, 200, 400, 200,
@ -507,7 +511,7 @@ function startJoinFromLobby(playername, hostJID, password)
{ {
Engine.StartNetworkJoinLobby(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), hostJID, password); Engine.StartNetworkJoinLobby(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), hostJID, password);
} }
catch (e) catch(e)
{ {
messageBox( messageBox(
400, 200, 400, 200,

View file

@ -48,7 +48,8 @@ class HotkeyMetadata
} }
// Sort categories (JS objects are (in this case) sorted by insertion order). // Sort categories (JS objects are (in this case) sorted by insertion order).
this.categories = {}; this.categories = {};
const keys = Object.keys(categories).sort((a, b) => { const keys = Object.keys(categories).sort((a, b) =>
{
if (a === this.DEFAULT_CATEGORY || b === this.DEFAULT_CATEGORY) if (a === this.DEFAULT_CATEGORY || b === this.DEFAULT_CATEGORY)
return a === this.DEFAULT_CATEGORY ? 1 : -1; return a === this.DEFAULT_CATEGORY ? 1 : -1;
if (categories[a].order === undefined || categories[b].order === undefined) if (categories[a].order === undefined || categories[b].order === undefined)

View file

@ -28,7 +28,8 @@ class HotkeyPicker
this.setupCombinations(); this.setupCombinations();
this.render(); this.render();
Engine.GetGUIObjectByName("hotkeyPickerReset").onPress = () => { Engine.GetGUIObjectByName("hotkeyPickerReset").onPress = () =>
{
// This is a bit "using a bazooka to kill a fly" // This is a bit "using a bazooka to kill a fly"
Engine.ConfigDB_RemoveValueAndSave("user", "hotkey." + this.name); Engine.ConfigDB_RemoveValueAndSave("user", "hotkey." + this.name);
Engine.ReloadHotkeys(); Engine.ReloadHotkeys();
@ -37,10 +38,12 @@ class HotkeyPicker
this.setupCombinations(); this.setupCombinations();
this.render(); this.render();
}; };
Engine.GetGUIObjectByName("hotkeyPickerCancel").onPress = () => { Engine.GetGUIObjectByName("hotkeyPickerCancel").onPress = () =>
{
onClose(this, false); onClose(this, false);
}; };
Engine.GetGUIObjectByName("hotkeyPickerSave").onPress = () => { Engine.GetGUIObjectByName("hotkeyPickerSave").onPress = () =>
{
onClose(this, true); onClose(this, true);
}; };
} }
@ -61,24 +64,28 @@ class HotkeyPicker
const input = Engine.GetGUIObjectByName("combMapping[" + i + "]"); const input = Engine.GetGUIObjectByName("combMapping[" + i + "]");
const picker = Engine.GetGUIObjectByName("picker[" + i + "]"); const picker = Engine.GetGUIObjectByName("picker[" + i + "]");
Engine.GetGUIObjectByName("combMappingBtn[" + i + "]").onPress = () => { Engine.GetGUIObjectByName("combMappingBtn[" + i + "]").onPress = () =>
{
this.enteringInput = i; this.enteringInput = i;
picker.focus(); picker.focus();
this.render(); this.render();
}; };
picker.onKeyChange = keys => { picker.onKeyChange = keys =>
{
input.caption = (keys.length ? input.caption = (keys.length ?
formatHotkeyCombination(keys) + translate(" (hold to register)") : formatHotkeyCombination(keys) + translate(" (hold to register)") :
translate("Enter new Hotkey, hold to register.")); translate("Enter new Hotkey, hold to register."));
}; };
Engine.GetGUIObjectByName("deleteComb[" + i + "]").onPress = (j => () => { Engine.GetGUIObjectByName("deleteComb[" + i + "]").onPress = (j => () =>
{
this.combinations[j] = []; this.combinations[j] = [];
this.render(); this.render();
})(i); })(i);
picker.onCombination = (j => keys => { picker.onCombination = (j => keys =>
{
this.combinations[j] = keys; this.combinations[j] = keys;
this.enteringInput = -1; this.enteringInput = -1;
picker.blur(); picker.blur();

View file

@ -4,7 +4,8 @@ class HotkeysPage
{ {
this.metadata = metadata; this.metadata = metadata;
Engine.GetGUIObjectByName("hotkeyList").onMouseLeftDoubleClickItem = () => { Engine.GetGUIObjectByName("hotkeyList").onMouseLeftDoubleClickItem = () =>
{
const idx = Engine.GetGUIObjectByName("hotkeyList").selected; const idx = Engine.GetGUIObjectByName("hotkeyList").selected;
const picker = new HotkeyPicker( const picker = new HotkeyPicker(
this.metadata, this.metadata,
@ -25,7 +26,8 @@ class HotkeysPage
Engine.GetGUIObjectByName("hotkeyClose").onPress = closePageCallback; Engine.GetGUIObjectByName("hotkeyClose").onPress = closePageCallback;
Engine.GetGUIObjectByName("hotkeyReset").onPress = () => this.resetUserHotkeys(); Engine.GetGUIObjectByName("hotkeyReset").onPress = () => this.resetUserHotkeys();
this.saveButton.onPress = () => { this.saveButton.onPress = () =>
{
this.saveUserHotkeys(); this.saveUserHotkeys();
this.saveButton.enabled = false; this.saveButton.enabled = false;
}; };
@ -55,7 +57,8 @@ class HotkeysPage
categories[this.metadata.DEFAULT_CATEGORY].hotkeys.push(hotkeyName); categories[this.metadata.DEFAULT_CATEGORY].hotkeys.push(hotkeyName);
} }
for (const cat in categories) for (const cat in categories)
categories[cat].hotkeys.sort((a, b) => { categories[cat].hotkeys.sort((a, b) =>
{
if (!this.metadata.hotkeys[a] || !this.metadata.hotkeys[b]) if (!this.metadata.hotkeys[a] || !this.metadata.hotkeys[b])
return !this.metadata.hotkeys[a] ? 1 : -1; return !this.metadata.hotkeys[a] ? 1 : -1;
return this.metadata.hotkeys[a].order - this.metadata.hotkeys[b].order; return this.metadata.hotkeys[a].order - this.metadata.hotkeys[b].order;
@ -89,7 +92,8 @@ class HotkeysPage
hotkeys = this.categories[dropdown.list_data[dropdown.selected]].hotkeys; hotkeys = this.categories[dropdown.list_data[dropdown.selected]].hotkeys;
else else
hotkeys = Object.values(this.categories).map(x => x.hotkeys).flat(); hotkeys = Object.values(this.categories).map(x => x.hotkeys).flat();
hotkeys = hotkeys.filter(x => { hotkeys = hotkeys.filter(x =>
{
return x.indexOf(textFilter) !== -1 || return x.indexOf(textFilter) !== -1 ||
translateWithContext("hotkey metadata", this.metadata.hotkeys[x]?.name || x).toLowerCase().indexOf(textFilter) !== -1; translateWithContext("hotkey metadata", this.metadata.hotkeys[x]?.name || x).toLowerCase().indexOf(textFilter) !== -1;
}); });
@ -151,7 +155,8 @@ class HotkeysPage
return; return;
for (const cat in this.categories) for (const cat in this.categories)
this.categories[cat].hotkeys.forEach((name) => { this.categories[cat].hotkeys.forEach((name) =>
{
Engine.ConfigDB_RemoveValue("user", "hotkey." + name); Engine.ConfigDB_RemoveValue("user", "hotkey." + name);
}); });
Engine.ConfigDB_SaveChanges("user"); Engine.ConfigDB_SaveChanges("user");
@ -181,7 +186,8 @@ class HotkeysPage
function init() function init()
{ {
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
// FIXME: There are proposals to remove init and allowing to specify // FIXME: There are proposals to remove init and allowing to specify
// controller classes in the gui xml, therefore leave it as a class and // controller classes in the gui xml, therefore leave it as a class and
// suppress the warning. // suppress the warning.

View file

@ -23,7 +23,8 @@ class SavegameDeleter
onSelectionChange(gameID, metadata, label) onSelectionChange(gameID, metadata, label)
{ {
this.deleteGameButton.enabled = !!metadata; this.deleteGameButton.enabled = !!metadata;
this.deleteGameButton.onPress = () => { this.deleteGameButton.onPress = () =>
{
this.deleteGame(gameID, label); this.deleteGame(gameID, label);
}; };
} }

View file

@ -35,7 +35,8 @@ class SavegameList
this.gameSelection.onSelectionColumnChange = () => { this.updateSavegameList(); }; this.gameSelection.onSelectionColumnChange = () => { this.updateSavegameList(); };
this.gameSelection.onMouseLeftDoubleClickItem = () => { this.confirmButton.onPress(); }; this.gameSelection.onMouseLeftDoubleClickItem = () => { this.confirmButton.onPress(); };
this.gameSelection.onSelectionChange = () => { this.gameSelection.onSelectionChange = () =>
{
const gameId = this.gameSelection.list_data[this.gameSelection.selected]; const gameId = this.gameSelection.list_data[this.gameSelection.selected];
const metadata = this.savedGamesMetadata[this.gameSelection.selected]; const metadata = this.savedGamesMetadata[this.gameSelection.selected];
const label = this.generateSavegameLabel(metadata, engineInfo); const label = this.generateSavegameLabel(metadata, engineInfo);
@ -74,7 +75,8 @@ class SavegameList
const engineInfo = Engine.GetEngineInfo(); const engineInfo = Engine.GetEngineInfo();
if (this.compatibilityFilter.checked) if (this.compatibilityFilter.checked)
savedGames = savedGames.filter(game => { savedGames = savedGames.filter(game =>
{
return this.isCompatibleSavegame(game.metadata, engineInfo) && return this.isCompatibleSavegame(game.metadata, engineInfo) &&
this.campaignFilter(game.metadata, this.campaignRun); this.campaignFilter(game.metadata, this.campaignRun);
}); });
@ -88,7 +90,8 @@ class SavegameList
const selectedGameId = this.gameSelection.list_data[this.gameSelection.selected]; const selectedGameId = this.gameSelection.list_data[this.gameSelection.selected];
// Save metadata for the detailed view // Save metadata for the detailed view
this.savedGamesMetadata = savedGames.map(game => { this.savedGamesMetadata = savedGames.map(game =>
{
game.metadata.id = game.id; game.metadata.id = game.id;
return game.metadata; return game.metadata;
}); });
@ -96,7 +99,8 @@ class SavegameList
const sortKey = this.gameSelection.selected_column; const sortKey = this.gameSelection.selected_column;
const sortOrder = this.gameSelection.selected_column_order; const sortOrder = this.gameSelection.selected_column_order;
this.savedGamesMetadata = this.savedGamesMetadata.sort((a, b) => { this.savedGamesMetadata = this.savedGamesMetadata.sort((a, b) =>
{
let cmpA, cmpB; let cmpA, cmpB;
switch (sortKey) switch (sortKey)
{ {
@ -128,7 +132,8 @@ class SavegameList
return 0; return 0;
}); });
let list = this.savedGamesMetadata.map(metadata => { let list = this.savedGamesMetadata.map(metadata =>
{
const isCompatible = this.isCompatibleSavegame(metadata, engineInfo) && const isCompatible = this.isCompatibleSavegame(metadata, engineInfo) &&
this.campaignFilter(metadata, this.campaignRun); this.campaignFilter(metadata, this.campaignRun);
// Backwards compatibility for pre-A25 savegames // Backwards compatibility for pre-A25 savegames

View file

@ -14,7 +14,8 @@ class SavegameLoader
onSelectionChange(gameID, metadata, label) onSelectionChange(gameID, metadata, label)
{ {
this.confirmButton.enabled = !!metadata; this.confirmButton.enabled = !!metadata;
this.confirmButton.onPress = () => { this.confirmButton.onPress = () =>
{
this.loadGame(gameID, metadata); this.loadGame(gameID, metadata);
}; };
} }

View file

@ -38,7 +38,8 @@ var g_SavegamePage;
function init(data) function init(data)
{ {
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
g_SavegamePage = new SavegamePage(data, closePageCallback); g_SavegamePage = new SavegamePage(data, closePageCallback);
}); });
} }

View file

@ -9,7 +9,8 @@ class SavegameWriter
this.closePageCallback = closePageCallback; this.closePageCallback = closePageCallback;
this.savedGameData = savedGameData; this.savedGameData = savedGameData;
const saveNew = () => { const saveNew = () =>
{
this.saveGame(); this.saveGame();
}; };
@ -21,7 +22,8 @@ class SavegameWriter
this.saveGameDesc.hidden = false; this.saveGameDesc.hidden = false;
this.saveGameDesc.onPress = saveNew; this.saveGameDesc.onPress = saveNew;
this.descriptionChanged = false; this.descriptionChanged = false;
this.saveGameDesc.onTextEdit = () => { this.saveGameDesc.onTextEdit = () =>
{
this.descriptionChanged = true; this.descriptionChanged = true;
}; };
} }
@ -30,7 +32,8 @@ class SavegameWriter
{ {
if (!this.descriptionChanged && metadata && typeof metadata.description === "string") if (!this.descriptionChanged && metadata && typeof metadata.description === "string")
this.saveGameDesc.caption = metadata.description; this.saveGameDesc.caption = metadata.description;
this.confirmButton.onPress = () => { this.confirmButton.onPress = () =>
{
this.saveGame(gameID, label); this.saveGame(gameID, label);
}; };
} }

View file

@ -12,7 +12,8 @@ var AccountSettingsPage = {
pageElement.hidden = false; pageElement.hidden = false;
pageElement.onTick = updateTimers; pageElement.onTick = updateTimers;
await Promise.race([ await Promise.race([
new Promise(resolve => { new Promise(resolve =>
{
Engine.SetGlobalHotkey("cancel", "Press", resolve); Engine.SetGlobalHotkey("cancel", "Press", resolve);
Engine.GetGUIObjectByName("as_Close").onPress = resolve; Engine.GetGUIObjectByName("as_Close").onPress = resolve;
}), }),
@ -31,7 +32,8 @@ var AccountSettingsPage = {
const changePasswordButton = Engine.GetGUIObjectByName("as_ChangePasswordBtn"); const changePasswordButton = Engine.GetGUIObjectByName("as_ChangePasswordBtn");
while (true) while (true)
{ {
await new Promise(resolve => { await new Promise(resolve =>
{
changePasswordButton.onPress = resolve; changePasswordButton.onPress = resolve;
}); });
try try
@ -56,9 +58,11 @@ var AccountSettingsPage = {
requestResult.caption = translate("Changing password…"); requestResult.caption = translate("Changing password…");
const encryptedPassword = AccountSettingsPage._readAndValidatePassword(SetPasswordError); const encryptedPassword = AccountSettingsPage._readAndValidatePassword(SetPasswordError);
Engine.LobbyChangePassword(encryptedPassword); Engine.LobbyChangePassword(encryptedPassword);
await new Promise((resolve, reject) => { await new Promise((resolve, reject) =>
{
xmppMessages.registerXmppMessageHandler("system", "registered", resolve); xmppMessages.registerXmppMessageHandler("system", "registered", resolve);
xmppMessages.registerXmppMessageHandler("system", "error", message => { xmppMessages.registerXmppMessageHandler("system", "error", message =>
{
reject(new SetPasswordError(message.text)); reject(new SetPasswordError(message.text));
}); });
timeout = setTimeout(reject.bind(null, timeout = setTimeout(reject.bind(null,
@ -70,7 +74,7 @@ var AccountSettingsPage = {
Engine["ConfigDB_" + functionSufix]("user", "lobby.password", encryptedPassword); Engine["ConfigDB_" + functionSufix]("user", "lobby.password", encryptedPassword);
Engine.ConfigDB_SaveChanges("user"); Engine.ConfigDB_SaveChanges("user");
} }
catch (e) catch(e)
{ {
if (e instanceof SetPasswordError) if (e instanceof SetPasswordError)
{ {

View file

@ -47,7 +47,8 @@ class LeaderboardList
const list_rank = []; const list_rank = [];
const list_rating = []; const list_rating = [];
boardList.forEach((entry, i) => { boardList.forEach((entry, i) =>
{
list_name.push(escapeText(entry.name)); list_name.push(escapeText(entry.name));
list_rating.push(entry.rating); list_rating.push(entry.rating);
list_rank.push(i + 1); list_rank.push(i + 1);

View file

@ -86,21 +86,24 @@ ChatCommandHandler.prototype.ChatCommandTags = {
ChatCommandHandler.prototype.ChatCommands = { ChatCommandHandler.prototype.ChatCommands = {
"away": { "away": {
"description": translate("Set your state to 'Away'."), "description": translate("Set your state to 'Away'."),
"handler": function(args) { "handler": function(args)
{
Engine.LobbySetPlayerPresence("away"); Engine.LobbySetPlayerPresence("away");
return true; return true;
} }
}, },
"back": { "back": {
"description": translate("Set your state to 'Online'."), "description": translate("Set your state to 'Online'."),
"handler": function(args) { "handler": function(args)
{
Engine.LobbySetPlayerPresence("available"); Engine.LobbySetPlayerPresence("available");
return true; return true;
} }
}, },
"kick": { "kick": {
"description": translate("Kick a specified user from the lobby. Usage: /kick nick reason"), "description": translate("Kick a specified user from the lobby. Usage: /kick nick reason"),
"handler": function(args) { "handler": function(args)
{
const index = args.indexOf(" "); const index = args.indexOf(" ");
if (index == -1) if (index == -1)
Engine.LobbyKick(args, ""); Engine.LobbyKick(args, "");
@ -112,7 +115,8 @@ ChatCommandHandler.prototype.ChatCommands = {
}, },
"ban": { "ban": {
"description": translate("Ban a specified user from the lobby. Usage: /ban nick reason"), "description": translate("Ban a specified user from the lobby. Usage: /ban nick reason"),
"handler": function(args) { "handler": function(args)
{
const index = args.indexOf(" "); const index = args.indexOf(" ");
if (index == -1) if (index == -1)
Engine.LobbyBan(args, ""); Engine.LobbyBan(args, "");
@ -124,7 +128,8 @@ ChatCommandHandler.prototype.ChatCommands = {
}, },
"help": { "help": {
"description": translate("Show this help."), "description": translate("Show this help."),
"handler": function(args) { "handler": function(args)
{
const isModerator = Engine.LobbyGetPlayerRole(g_Nickname) == "moderator"; const isModerator = Engine.LobbyGetPlayerRole(g_Nickname) == "moderator";
let txt = translate("Chat commands:"); let txt = translate("Chat commands:");
for (const command in this.ChatCommands) for (const command in this.ChatCommands)
@ -145,21 +150,24 @@ ChatCommandHandler.prototype.ChatCommands = {
}, },
"me": { "me": {
"description": translate("Send a chat message about yourself. Example: /me goes swimming."), "description": translate("Send a chat message about yourself. Example: /me goes swimming."),
"handler": function(args) { "handler": function(args)
{
// Translation: Chat command // Translation: Chat command
return this.argumentCount(translate("/me"), args); return this.argumentCount(translate("/me"), args);
} }
}, },
"say": { "say": {
"description": translate("Send text as a chat message (even if it starts with slash). Example: /say /help is a great command."), "description": translate("Send text as a chat message (even if it starts with slash). Example: /say /help is a great command."),
"handler": function(args) { "handler": function(args)
{
// Translation: Chat command // Translation: Chat command
return this.argumentCount(translate("/say"), args); return this.argumentCount(translate("/say"), args);
} }
}, },
"clear": { "clear": {
"description": translate("Clear all chat scrollback."), "description": translate("Clear all chat scrollback."),
"handler": function(args) { "handler": function(args)
{
this.chatMessagesPanel.clearChatMessages(); this.chatMessagesPanel.clearChatMessages();
return true; return true;
} }

View file

@ -104,30 +104,30 @@ ChatMessageEvents.Role = class
}; };
ChatMessageEvents.Role.prototype.RoleStrings = ChatMessageEvents.Role.prototype.RoleStrings =
[ [
{ {
"newrole": "visitor", "newrole": "visitor",
"you": translate("You have been muted."), "you": translate("You have been muted."),
"nick": translate("%(nick)s has been muted.") "nick": translate("%(nick)s has been muted.")
}, },
{ {
"newrole": "moderator", "newrole": "moderator",
"you": translate("You are now a moderator."), "you": translate("You are now a moderator."),
"nick": translate("%(nick)s is now a moderator.") "nick": translate("%(nick)s is now a moderator.")
}, },
{ {
"newrole": "participant", "newrole": "participant",
"oldrole": "visitor", "oldrole": "visitor",
"you": translate("You have been unmuted."), "you": translate("You have been unmuted."),
"nick": translate("%(nick)s has been unmuted.") "nick": translate("%(nick)s has been unmuted.")
}, },
{ {
"newrole": "participant", "newrole": "participant",
"oldrole": "moderator", "oldrole": "moderator",
"you": translate("You are not a moderator anymore."), "you": translate("You are not a moderator anymore."),
"nick": translate("%(nick)s is not a moderator anymore.") "nick": translate("%(nick)s is not a moderator anymore.")
} }
]; ];
ChatMessageEvents.Subject = class ChatMessageEvents.Subject = class
{ {

View file

@ -219,7 +219,7 @@ class Game
{ {
this.mods = JSON.parse(newStanza.mods); this.mods = JSON.parse(newStanza.mods);
} }
catch (e) catch(e)
{ {
this.mods = []; this.mods = [];
} }

View file

@ -125,7 +125,8 @@ class GameList
{ {
Engine.ProfileStart("sortGameList"); Engine.ProfileStart("sortGameList");
const sortOrder = this.gamesBox.selected_column_order; const sortOrder = this.gamesBox.selected_column_order;
this.gameList.sort((game1, game2) => { this.gameList.sort((game1, game2) =>
{
if (game1.sortValue < game2.sortValue) return -sortOrder; if (game1.sortValue < game2.sortValue) return -sortOrder;
if (game1.sortValue > game2.sortValue) return +sortOrder; if (game1.sortValue > game2.sortValue) return +sortOrder;
return 0; return 0;
@ -148,7 +149,8 @@ class GameList
this.list_gameRating.length = length; this.list_gameRating.length = length;
this.list.length = length; this.list.length = length;
this.gameList.forEach((game, i) => { this.gameList.forEach((game, i) =>
{
const displayData = game.displayData; const displayData = game.displayData;
this.list_buddy[i] = displayData.buddy || ""; this.list_buddy[i] = displayData.buddy || "";

View file

@ -145,7 +145,8 @@ class PlayerList
this.nickList.length = length; this.nickList.length = length;
this.ratingList.length = length; this.ratingList.length = length;
playerList.forEach((player, i) => { playerList.forEach((player, i) =>
{
// TODO: COList.cpp columns should support horizontal center align // TODO: COList.cpp columns should support horizontal center align
const rating = player.rating ? (" " + player.rating).substr(-5) : " -"; const rating = player.rating ? (" " + player.rating).substr(-5) : " -";

View file

@ -34,7 +34,8 @@ var g_LobbyHandler;
async function init(attribs) async function init(attribs)
{ {
if (g_Settings) if (g_Settings)
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
g_LobbyHandler = new LobbyHandler(closePageCallback, attribs && attribs.dialog); g_LobbyHandler = new LobbyHandler(closePageCallback, attribs && attribs.dialog);
}); });

View file

@ -3,7 +3,8 @@ function init()
var languageList = Engine.GetGUIObjectByName("languageList"); var languageList = Engine.GetGUIObjectByName("languageList");
const displayLanguages = Engine.GetSupportedLocaleDisplayNames(); const displayLanguages = Engine.GetSupportedLocaleDisplayNames();
const displayLanguagesData = Engine.GetSupportedLocaleBaseNames(); const displayLanguagesData = Engine.GetSupportedLocaleBaseNames();
languageList.list = displayLanguages.map((name, index) => { languageList.list = displayLanguages.map((name, index) =>
{
return `[locale="${displayLanguagesData[index]}"]${name}[/locale]`; return `[locale="${displayLanguagesData[index]}"]${name}[/locale]`;
}); });
languageList.list_data = displayLanguagesData; languageList.list_data = displayLanguagesData;
@ -18,7 +19,8 @@ function init()
var localeText = Engine.GetGUIObjectByName("localeText"); var localeText = Engine.GetGUIObjectByName("localeText");
localeText.caption = currentLocale; localeText.caption = currentLocale;
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
Engine.GetGUIObjectByName("cancelButton").onPress = closePageCallback; Engine.GetGUIObjectByName("cancelButton").onPress = closePageCallback;
}); });
} }

View file

@ -47,9 +47,11 @@ function init(initData)
// fill the script // fill the script
scriptInput.caption = Engine.GetLocaleScript(initData.locale); scriptInput.caption = Engine.GetLocaleScript(initData.locale);
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
Engine.GetGUIObjectByName("cancelButton").onPress = closePageCallback; Engine.GetGUIObjectByName("cancelButton").onPress = closePageCallback;
Engine.GetGUIObjectByName("acceptButton").onPress = () => { Engine.GetGUIObjectByName("acceptButton").onPress = () =>
{
closePageCallback(applySelectedLocale()); closePageCallback(applySelectedLocale());
}; };
}); });

View file

@ -8,7 +8,8 @@ function init()
// Replace anything starting with 'hotkey.' with its hotkey. // Replace anything starting with 'hotkey.' with its hotkey.
mainText.caption = text.replace(/hotkey.([a-z0-9_.]+)/g, (_, k) => formatHotkeyCombinations(hotkeys[k])); mainText.caption = text.replace(/hotkey.([a-z0-9_.]+)/g, (_, k) => formatHotkeyCombinations(hotkeys[k]));
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
Engine.GetGUIObjectByName("closeButton").onPress = closePageCallback; Engine.GetGUIObjectByName("closeButton").onPress = closePageCallback;
}); });
} }

View file

@ -29,7 +29,8 @@ class MapBrowserPageControls
setupButtons() setupButtons()
{ {
this.pickRandom = Engine.GetGUIObjectByName("mapBrowserPagePickRandom"); this.pickRandom = Engine.GetGUIObjectByName("mapBrowserPagePickRandom");
this.pickRandom.onPress = () => { this.pickRandom.onPress = () =>
{
const index = randIntInclusive(0, this.gridBrowser.itemCount - 1); const index = randIntInclusive(0, this.gridBrowser.itemCount - 1);
this.gridBrowser.setSelectedIndex(index); this.gridBrowser.setSelectedIndex(index);
this.gridBrowser.goToPageOfSelected(); this.gridBrowser.goToPageOfSelected();

View file

@ -22,7 +22,8 @@ MapBrowserPageControls.prototype.MapFiltering = class
onOpenPage() onOpenPage()
{ {
// setTimeout avoids having the hotkey key inserted into the input text. // setTimeout avoids having the hotkey key inserted into the input text.
setTimeout(() => { setTimeout(() =>
{
this.searchBox.control.caption = ""; this.searchBox.control.caption = "";
this.searchBox.focus(); this.searchBox.focus();
}, 0); }, 0);

View file

@ -1,4 +1,5 @@
const MatchSort = (function() { const MatchSort = (function()
{
const Highscore = -10E7; const Highscore = -10E7;
return class return class

View file

@ -58,7 +58,8 @@ var g_OptionType = {
"boolean": "boolean":
{ {
"configToValue": config => config == "true", "configToValue": config => config == "true",
"valueToGui": (value, control) => { "valueToGui": (value, control) =>
{
control.checked = value; control.checked = value;
}, },
"guiToValue": control => control.checked, "guiToValue": control => control.checked,
@ -67,7 +68,8 @@ var g_OptionType = {
"string": "string":
{ {
"configToValue": value => value, "configToValue": value => value,
"valueToGui": (value, control) => { "valueToGui": (value, control) =>
{
control.caption = value; control.caption = value;
}, },
"guiToValue": control => control.caption, "guiToValue": control => control.caption,
@ -76,11 +78,14 @@ var g_OptionType = {
"color": "color":
{ {
"configToValue": value => value, "configToValue": value => value,
"valueToGui": (value, control) => { "valueToGui": (value, control) =>
{
control.caption = value; control.caption = value;
}, },
"initGUI": (option, control) => { "initGUI": (option, control) =>
control.children[2].onPress = async() => { {
control.children[2].onPress = async() =>
{
const color = await Engine.OpenChildPage("page_colormixer.xml", control.caption); const color = await Engine.OpenChildPage("page_colormixer.xml", control.caption);
if (color != control.caption) if (color != control.caption)
@ -92,7 +97,8 @@ var g_OptionType = {
}, },
"guiToValue": control => control.caption, "guiToValue": control => control.caption,
"guiSetter": "onTextEdit", "guiSetter": "onTextEdit",
"sanitizeValue": (value, control, option) => { "sanitizeValue": (value, control, option) =>
{
const color = guiToRgbColor(value); const color = guiToRgbColor(value);
const sanitized = rgbToGuiColor(color); const sanitized = rgbToGuiColor(color);
if (control) if (control)
@ -110,12 +116,14 @@ var g_OptionType = {
"number": "number":
{ {
"configToValue": value => value, "configToValue": value => value,
"valueToGui": (value, control) => { "valueToGui": (value, control) =>
{
control.caption = value; control.caption = value;
}, },
"guiToValue": control => control.caption, "guiToValue": control => control.caption,
"guiSetter": "onTextEdit", "guiSetter": "onTextEdit",
"sanitizeValue": (value, control, option) => { "sanitizeValue": (value, control, option) =>
{
const sanitized = const sanitized =
Math.min(option.max !== undefined ? option.max : +Infinity, Math.min(option.max !== undefined ? option.max : +Infinity,
Math.max(option.min !== undefined ? option.min : -Infinity, Math.max(option.min !== undefined ? option.min : -Infinity,
@ -143,15 +151,18 @@ var g_OptionType = {
"dropdown": "dropdown":
{ {
"configToValue": value => value, "configToValue": value => value,
"valueToGui": (value, control) => { "valueToGui": (value, control) =>
{
control.selected = control.list_data.indexOf(value); control.selected = control.list_data.indexOf(value);
}, },
"guiToValue": control => control.list_data[control.selected], "guiToValue": control => control.list_data[control.selected],
"guiSetter": "onSelectionChange", "guiSetter": "onSelectionChange",
"initGUI": (option, control) => { "initGUI": (option, control) =>
{
control.list = option.list.map(e => e.label); control.list = option.list.map(e => e.label);
control.list_data = option.list.map(e => e.value); control.list_data = option.list.map(e => e.value);
control.onHoverChange = () => { control.onHoverChange = () =>
{
const item = option.list[control.hovered]; const item = option.list[control.hovered];
control.tooltip = item && item.tooltip || option.tooltip; control.tooltip = item && item.tooltip || option.tooltip;
}; };
@ -160,20 +171,24 @@ var g_OptionType = {
"dropdownNumber": "dropdownNumber":
{ {
"configToValue": value => +value, "configToValue": value => +value,
"valueToGui": (value, control) => { "valueToGui": (value, control) =>
{
control.selected = control.list_data.indexOf("" + value); control.selected = control.list_data.indexOf("" + value);
}, },
"guiToValue": control => +control.list_data[control.selected], "guiToValue": control => +control.list_data[control.selected],
"guiSetter": "onSelectionChange", "guiSetter": "onSelectionChange",
"initGUI": (option, control) => { "initGUI": (option, control) =>
{
control.list = option.list.map(e => e.label); control.list = option.list.map(e => e.label);
control.list_data = option.list.map(e => e.value); control.list_data = option.list.map(e => e.value);
control.onHoverChange = () => { control.onHoverChange = () =>
{
const item = option.list[control.hovered]; const item = option.list[control.hovered];
control.tooltip = item && item.tooltip || option.tooltip; control.tooltip = item && item.tooltip || option.tooltip;
}; };
}, },
"timeout": async(option, oldValue, hasChanges, newValue) => { "timeout": async(option, oldValue, hasChanges, newValue) =>
{
if (!option.timeout) if (!option.timeout)
return; return;
const buttonIndex = await timedConfirmation( const buttonIndex = await timedConfirmation(
@ -191,12 +206,14 @@ var g_OptionType = {
"slider": "slider":
{ {
"configToValue": value => +value, "configToValue": value => +value,
"valueToGui": (value, control) => { "valueToGui": (value, control) =>
{
control.value = +value; control.value = +value;
}, },
"guiToValue": control => control.value, "guiToValue": control => control.value,
"guiSetter": "onValueChange", "guiSetter": "onValueChange",
"initGUI": (option, control) => { "initGUI": (option, control) =>
{
control.max_value = option.max; control.max_value = option.max;
control.min_value = option.min; control.min_value = option.min;
}, },
@ -282,7 +299,8 @@ function displayOptions()
if (optionType.sanitizeValue) if (optionType.sanitizeValue)
optionType.sanitizeValue(value, control, option); optionType.sanitizeValue(value, control, option);
control[optionType.guiSetter] = function() { control[optionType.guiSetter] = function()
{
const newValue = optionType.guiToValue(control); const newValue = optionType.guiToValue(control);
@ -326,8 +344,10 @@ function displayOptions()
*/ */
function enableButtons() function enableButtons()
{ {
g_Options[g_TabCategorySelected].options.forEach((option, i) => { g_Options[g_TabCategorySelected].options.forEach((option, i) =>
const isDependencyMet = dependency => { {
const isDependencyMet = dependency =>
{
if (typeof dependency === "string") if (typeof dependency === "string")
return Engine.ConfigDB_GetValue("user", dependency) == "true"; return Engine.ConfigDB_GetValue("user", dependency) == "true";
else if (typeof dependency === "object") else if (typeof dependency === "object")
@ -409,8 +429,10 @@ function revertChanges()
async function saveChanges() async function saveChanges()
{ {
const category = Object.keys(g_Options).find(key => { const category = Object.keys(g_Options).find(key =>
return g_Options[key].options.some(option => { {
return g_Options[key].options.some(option =>
{
const optionType = g_OptionType[option.type]; const optionType = g_OptionType[option.type];
if (!optionType.sanitizeValue) if (!optionType.sanitizeValue)
return false; return false;

View file

@ -27,7 +27,8 @@ export class MainMenuItemHandler
setupMenuButtons(buttons, menuItems) setupMenuButtons(buttons, menuItems)
{ {
buttons.forEach((button, i) => { buttons.forEach((button, i) =>
{
const item = menuItems[i]; const item = menuItems[i];
button.hidden = !item; button.hidden = !item;
if (button.hidden) if (button.hidden)
@ -87,7 +88,8 @@ export class MainMenuItemHandler
{ {
const item = menuItems[i]; const item = menuItems[i];
if (item.onPress && item.hotkey) if (item.onPress && item.hotkey)
Engine.SetGlobalHotkey(item.hotkey, "Press", () => { Engine.SetGlobalHotkey(item.hotkey, "Press", () =>
{
this.closeSubmenu(); this.closeSubmenu();
item.onPress(); item.onPress();
}); });

View file

@ -6,14 +6,16 @@ export const mainMenuItems = [
{ {
"caption": translate("Manual"), "caption": translate("Manual"),
"tooltip": translate("Open the 0 A.D. Game Manual."), "tooltip": translate("Open the 0 A.D. Game Manual."),
"onPress": () => { "onPress": () =>
{
Engine.OpenChildPage("page_manual.xml"); Engine.OpenChildPage("page_manual.xml");
} }
}, },
{ {
"caption": translate("Tutorial"), "caption": translate("Tutorial"),
"tooltip": translate("Start the introductory tutorial."), "tooltip": translate("Start the introductory tutorial."),
"onPress": () => { "onPress": () =>
{
Engine.SwitchGuiPage("page_autostart.xml", { Engine.SwitchGuiPage("page_autostart.xml", {
"attribs": { "attribs": {
"mapType": "scenario", "mapType": "scenario",
@ -43,7 +45,8 @@ export const mainMenuItems = [
"caption": translate("Structure Tree"), "caption": translate("Structure Tree"),
"tooltip": colorizeHotkey(translate("%(hotkey)s: View the structure tree of civilizations featured in 0 A.D."), "structree"), "tooltip": colorizeHotkey(translate("%(hotkey)s: View the structure tree of civilizations featured in 0 A.D."), "structree"),
"hotkey": "structree", "hotkey": "structree",
"onPress": () => { "onPress": () =>
{
pageLoop("page_structree.xml"); pageLoop("page_structree.xml");
} }
}, },
@ -51,21 +54,24 @@ export const mainMenuItems = [
"caption": translate("Civilization Overview"), "caption": translate("Civilization Overview"),
"tooltip": colorizeHotkey(translate("%(hotkey)s: Learn about the civilizations featured in 0 A.D."), "civinfo"), "tooltip": colorizeHotkey(translate("%(hotkey)s: Learn about the civilizations featured in 0 A.D."), "civinfo"),
"hotkey": "civinfo", "hotkey": "civinfo",
"onPress": () => { "onPress": () =>
{
pageLoop("page_civinfo.xml"); pageLoop("page_civinfo.xml");
} }
}, },
{ {
"caption": translate("Catafalque Overview"), "caption": translate("Catafalque Overview"),
"tooltip": translate("Compare the bonuses of catafalques featured in 0 A.D."), "tooltip": translate("Compare the bonuses of catafalques featured in 0 A.D."),
"onPress": () => { "onPress": () =>
{
Engine.OpenChildPage("page_catafalque.xml"); Engine.OpenChildPage("page_catafalque.xml");
} }
}, },
{ {
"caption": translate("Map Overview"), "caption": translate("Map Overview"),
"tooltip": translate("View the different maps featured in 0 A.D."), "tooltip": translate("View the different maps featured in 0 A.D."),
"onPress": () => { "onPress": () =>
{
Engine.OpenChildPage("page_mapbrowser.xml"); Engine.OpenChildPage("page_mapbrowser.xml");
} }
} }
@ -74,12 +80,13 @@ export const mainMenuItems = [
{ {
"caption": translate("Continue Campaign"), "caption": translate("Continue Campaign"),
"tooltip": translate("Relive history through historical military campaigns."), "tooltip": translate("Relive history through historical military campaigns."),
"onPress": () => { "onPress": () =>
{
try try
{ {
Engine.SwitchGuiPage(CampaignRun.getCurrentRun().getMenuPath()); Engine.SwitchGuiPage(CampaignRun.getCurrentRun().getMenuPath());
} }
catch (err) catch(err)
{ {
error("Error opening campaign run:"); error("Error opening campaign run:");
error(err.toString()); error(err.toString());
@ -94,14 +101,16 @@ export const mainMenuItems = [
{ {
"caption": translate("Matches"), "caption": translate("Matches"),
"tooltip": translate("Start a new single-player game."), "tooltip": translate("Start a new single-player game."),
"onPress": () => { "onPress": () =>
{
Engine.SwitchGuiPage("page_gamesetup.xml"); Engine.SwitchGuiPage("page_gamesetup.xml");
} }
}, },
{ {
"caption": translate("Load Game"), "caption": translate("Load Game"),
"tooltip": translate("Load a saved game."), "tooltip": translate("Load a saved game."),
"onPress": async() => { "onPress": async() =>
{
const gameId = await Engine.OpenChildPage("page_loadgame.xml"); const gameId = await Engine.OpenChildPage("page_loadgame.xml");
if (!gameId) if (!gameId)
@ -131,12 +140,13 @@ export const mainMenuItems = [
{ {
"caption": translate("Continue Campaign"), "caption": translate("Continue Campaign"),
"tooltip": translate("Relive history through historical military campaigns."), "tooltip": translate("Relive history through historical military campaigns."),
"onPress": () => { "onPress": () =>
{
try try
{ {
Engine.SwitchGuiPage(CampaignRun.getCurrentRun().getMenuPath()); Engine.SwitchGuiPage(CampaignRun.getCurrentRun().getMenuPath());
} }
catch (err) catch(err)
{ {
error("Error opening campaign run:"); error("Error opening campaign run:");
error(err.toString()); error(err.toString());
@ -147,14 +157,16 @@ export const mainMenuItems = [
{ {
"caption": translate("New Campaign"), "caption": translate("New Campaign"),
"tooltip": translate("Relive history through historical military campaigns."), "tooltip": translate("Relive history through historical military campaigns."),
"onPress": () => { "onPress": () =>
{
Engine.SwitchGuiPage("campaigns/setup/page.xml"); Engine.SwitchGuiPage("campaigns/setup/page.xml");
} }
}, },
{ {
"caption": translate("Load Campaign"), "caption": translate("Load Campaign"),
"tooltip": translate("Relive history through historical military campaigns."), "tooltip": translate("Relive history through historical military campaigns."),
"onPress": () => { "onPress": () =>
{
// Switch instead of push, otherwise the 'continue' // Switch instead of push, otherwise the 'continue'
// button might remain enabled. // button might remain enabled.
// TODO: find a better solution. // TODO: find a better solution.
@ -164,7 +176,8 @@ export const mainMenuItems = [
{ {
"caption": translate("Replays"), "caption": translate("Replays"),
"tooltip": translate("Playback previous games."), "tooltip": translate("Playback previous games."),
"onPress": () => { "onPress": () =>
{
Engine.SwitchGuiPage("page_replaymenu.xml", { Engine.SwitchGuiPage("page_replaymenu.xml", {
"replaySelectionData": { "replaySelectionData": {
"filters": { "filters": {
@ -187,7 +200,8 @@ export const mainMenuItems = [
(Engine.StartXmppClient ? "" : translate("Launch the multiplayer lobby. \\[DISABLED BY BUILD]")), (Engine.StartXmppClient ? "" : translate("Launch the multiplayer lobby. \\[DISABLED BY BUILD]")),
"enabled": () => !!Engine.StartXmppClient, "enabled": () => !!Engine.StartXmppClient,
"hotkey": "lobby", "hotkey": "lobby",
"onPress": () => { "onPress": () =>
{
if (Engine.StartXmppClient) if (Engine.StartXmppClient)
Engine.OpenChildPage("page_prelobby_entrance.xml"); Engine.OpenChildPage("page_prelobby_entrance.xml");
} }
@ -219,7 +233,8 @@ export const mainMenuItems = [
{ {
"caption": translate("Replays"), "caption": translate("Replays"),
"tooltip": translate("Playback previous games."), "tooltip": translate("Playback previous games."),
"onPress": () => { "onPress": () =>
{
Engine.SwitchGuiPage("page_replaymenu.xml", { Engine.SwitchGuiPage("page_replaymenu.xml", {
"replaySelectionData": { "replaySelectionData": {
"filters": { "filters": {
@ -238,35 +253,40 @@ export const mainMenuItems = [
{ {
"caption": translate("Options"), "caption": translate("Options"),
"tooltip": translate("Adjust game settings."), "tooltip": translate("Adjust game settings."),
"onPress": async() => { "onPress": async() =>
{
fireConfigChangeHandlers(await Engine.OpenChildPage("page_options.xml")); fireConfigChangeHandlers(await Engine.OpenChildPage("page_options.xml"));
} }
}, },
{ {
"caption": translate("Hotkeys"), "caption": translate("Hotkeys"),
"tooltip": translate("Adjust hotkeys."), "tooltip": translate("Adjust hotkeys."),
"onPress": () => { "onPress": () =>
{
Engine.OpenChildPage("hotkeys/page_hotkeys.xml"); Engine.OpenChildPage("hotkeys/page_hotkeys.xml");
} }
}, },
{ {
"caption": translate("Language"), "caption": translate("Language"),
"tooltip": translate("Choose the language of the game."), "tooltip": translate("Choose the language of the game."),
"onPress": () => { "onPress": () =>
{
Engine.OpenChildPage("page_locale.xml"); Engine.OpenChildPage("page_locale.xml");
} }
}, },
{ {
"caption": translate("Mod Selection"), "caption": translate("Mod Selection"),
"tooltip": translate("Select and download mods for the game."), "tooltip": translate("Select and download mods for the game."),
"onPress": () => { "onPress": () =>
{
Engine.SwitchGuiPage("page_modmod.xml"); Engine.SwitchGuiPage("page_modmod.xml");
} }
}, },
{ {
"caption": translate("Welcome Screen"), "caption": translate("Welcome Screen"),
"tooltip": translate("Show the Welcome Screen again. Useful if you hid it by mistake."), "tooltip": translate("Show the Welcome Screen again. Useful if you hid it by mistake."),
"onPress": () => { "onPress": () =>
{
Engine.OpenChildPage("page_splashscreen.xml"); Engine.OpenChildPage("page_splashscreen.xml");
} }
} }
@ -275,7 +295,8 @@ export const mainMenuItems = [
{ {
"caption": translate("Scenario Editor"), "caption": translate("Scenario Editor"),
"tooltip": translate('Open the Atlas Scenario Editor in a new window. You can run this more reliably by starting the game with the command-line argument "-editor".'), "tooltip": translate('Open the Atlas Scenario Editor in a new window. You can run this more reliably by starting the game with the command-line argument "-editor".'),
"onPress": async(closePageCallback) => { "onPress": async(closePageCallback) =>
{
if (!Engine.AtlasIsAvailable()) if (!Engine.AtlasIsAvailable())
{ {
messageBox( messageBox(
@ -298,14 +319,16 @@ export const mainMenuItems = [
{ {
"caption": translate("Credits"), "caption": translate("Credits"),
"tooltip": translate("Show the 0 A.D. credits."), "tooltip": translate("Show the 0 A.D. credits."),
"onPress": () => { "onPress": () =>
{
Engine.OpenChildPage("page_credits.xml"); Engine.OpenChildPage("page_credits.xml");
} }
}, },
{ {
"caption": translate("Exit"), "caption": translate("Exit"),
"tooltip": translate("Exit the game."), "tooltip": translate("Exit the game."),
"onPress": async(closePageCallback) => { "onPress": async(closePageCallback) =>
{
const buttonIndex = await messageBox( const buttonIndex = await messageBox(
400, 200, 400, 200,
translate("Are you sure you want to quit 0 A.D.?"), translate("Are you sure you want to quit 0 A.D.?"),

View file

@ -19,7 +19,8 @@ function initCommunityButton(communityButtons)
{ {
const buttons = Engine.GetGUIObjectByName("communityButtons").children; const buttons = Engine.GetGUIObjectByName("communityButtons").children;
communityButtons.forEach((buttonInfo, i) => { communityButtons.forEach((buttonInfo, i) =>
{
const button = buttons[i]; const button = buttons[i];
button.hidden = false; button.hidden = false;
for (const propertyName in buttonInfo) for (const propertyName in buttonInfo)

View file

@ -25,7 +25,8 @@ export const communityButtons = [
"caption": translate("Website"), "caption": translate("Website"),
"tooltip": translate("Click to open play0ad.com in your web browser."), "tooltip": translate("Click to open play0ad.com in your web browser."),
"size": "8 100%-148 50%-4 100%-116", "size": "8 100%-148 50%-4 100%-116",
"onPress": () => { "onPress": () =>
{
openURL("https://play0ad.com/"); openURL("https://play0ad.com/");
} }
}, },
@ -33,7 +34,8 @@ export const communityButtons = [
"caption": translate("Chat"), "caption": translate("Chat"),
"tooltip": translate("Click to open the 0 A.D. IRC chat in your browser (#0ad on webchat.quakenet.org). It is run by volunteers who do all sorts of tasks, it may take a while to get your question answered. Alternatively, you can use the forum (see Website)."), "tooltip": translate("Click to open the 0 A.D. IRC chat in your browser (#0ad on webchat.quakenet.org). It is run by volunteers who do all sorts of tasks, it may take a while to get your question answered. Alternatively, you can use the forum (see Website)."),
"size": "50%+4 100%-148 100%-8 100%-116", "size": "50%+4 100%-148 100%-8 100%-116",
"onPress": () => { "onPress": () =>
{
openURL("https://webchat.quakenet.org/?channels=0ad"); openURL("https://webchat.quakenet.org/?channels=0ad");
} }
}, },
@ -41,7 +43,8 @@ export const communityButtons = [
"caption": translate("Report a Bug"), "caption": translate("Report a Bug"),
"tooltip": translate("Click to visit the 0 A.D. issue tracker to report a bug, crash, or error."), "tooltip": translate("Click to visit the 0 A.D. issue tracker to report a bug, crash, or error."),
"size": "8 100%-112 50%-4 100%-80", "size": "8 100%-112 50%-4 100%-80",
"onPress": () => { "onPress": () =>
{
openURL("https://gitea.wildfiregames.com/0ad/0ad/issues"); openURL("https://gitea.wildfiregames.com/0ad/0ad/issues");
} }
}, },
@ -49,7 +52,8 @@ export const communityButtons = [
"caption": translateWithContext("Frequently Asked Questions", "FAQ"), "caption": translateWithContext("Frequently Asked Questions", "FAQ"),
"tooltip": translate("Click to visit the Frequently Asked Questions page in your browser."), "tooltip": translate("Click to visit the Frequently Asked Questions page in your browser."),
"size": "50%+4 100%-112 100%-8 100%-80", "size": "50%+4 100%-112 100%-8 100%-80",
"onPress": () => { "onPress": () =>
{
openURL("https://gitea.wildfiregames.com/0ad/0ad/wiki/FAQ"); openURL("https://gitea.wildfiregames.com/0ad/0ad/wiki/FAQ");
} }
}, },
@ -57,7 +61,8 @@ export const communityButtons = [
"caption": translate("Translate the Game"), "caption": translate("Translate the Game"),
"tooltip": translate("Click to open the 0 A.D. translate page in your browser."), "tooltip": translate("Click to open the 0 A.D. translate page in your browser."),
"size": "8 100%-76 100%-8 100%-44", "size": "8 100%-76 100%-8 100%-44",
"onPress": () => { "onPress": () =>
{
openURL("https://gitea.wildfiregames.com/0ad/0ad/wiki/Localization"); openURL("https://gitea.wildfiregames.com/0ad/0ad/wiki/Localization");
} }
}, },
@ -65,7 +70,8 @@ export const communityButtons = [
"caption": translate("Donate"), "caption": translate("Donate"),
"tooltip": translate("Help with the project expenses by donating."), "tooltip": translate("Help with the project expenses by donating."),
"size": "8 100%-40 100%-8 100%-8", "size": "8 100%-40 100%-8 100%-8",
"onPress": () => { "onPress": () =>
{
openURL("https://play0ad.com/community/donate/"); openURL("https://play0ad.com/community/donate/");
} }
} }

View file

@ -11,7 +11,8 @@ export function init(data, hotloadData)
initUserReport(); initUserReport();
Engine.GetGUIObjectByName("userReport").onTick = updateUserReportStatus; Engine.GetGUIObjectByName("userReport").onTick = updateUserReportStatus;
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
const mainMenuPage = new MainMenuPage( const mainMenuPage = new MainMenuPage(
closePageCallback, closePageCallback,
data, data,

View file

@ -9,7 +9,8 @@ var g_TermsUserReport = {
"configPath": setStringTags(escapeText(Engine.GetUserReportConfigPath()), { "font": "sans-bold-12" }) "configPath": setStringTags(escapeText(Engine.GetUserReportConfigPath()), { "font": "sans-bold-12" })
}, },
"config": "userreport.terms", "config": "userreport.terms",
"callback": data => { "callback": data =>
{
setUserReportEnabled(data.accepted); setUserReportEnabled(data.accepted);
}, },
"accepted": false, "accepted": false,
@ -61,13 +62,15 @@ function updateUserReportButtons()
userReportEnableButton.caption = Engine.IsUserReportEnabled() ? translate("Disable Feedback") : translate("Enable Feedback"); userReportEnableButton.caption = Engine.IsUserReportEnabled() ? translate("Disable Feedback") : translate("Enable Feedback");
userReportEnableButton.enabled = !termsFeedback; userReportEnableButton.enabled = !termsFeedback;
userReportEnableButton.tooltip = termsFeedback; userReportEnableButton.tooltip = termsFeedback;
userReportEnableButton.onPress = () => { userReportEnableButton.onPress = () =>
{
setUserReportEnabled(!Engine.IsUserReportEnabled()); setUserReportEnabled(!Engine.IsUserReportEnabled());
}; };
const userReportTermsButton = Engine.GetGUIObjectByName("userReportTermsButton"); const userReportTermsButton = Engine.GetGUIObjectByName("userReportTermsButton");
userReportTermsButton.caption = g_TermsUserReport.TermsAndConditions.title; userReportTermsButton.caption = g_TermsUserReport.TermsAndConditions.title;
userReportTermsButton.onPress = () => { userReportTermsButton.onPress = () =>
{
openTerms("TermsAndConditions"); openTerms("TermsAndConditions");
}; };
} }

View file

@ -1,10 +1,12 @@
var g_LobbyMessages = { var g_LobbyMessages = {
"error": message => { "error": message =>
{
setFeedback(message.text || setFeedback(message.text ||
translate("Unknown error. This usually occurs because the same IP address is not allowed to register more than one account within one hour.")); translate("Unknown error. This usually occurs because the same IP address is not allowed to register more than one account within one hour."));
Engine.StopXmppClient(); Engine.StopXmppClient();
}, },
"disconnected": message => { "disconnected": message =>
{
setFeedback(message.reason + message.certificate_status); setFeedback(message.reason + message.certificate_status);
Engine.StopXmppClient(); Engine.StopXmppClient();
} }

View file

@ -37,13 +37,15 @@ function initLobbyTerms()
} }
}; };
Object.keys(terms).forEach((page, i) => { Object.keys(terms).forEach((page, i) =>
{
const button = Engine.GetGUIObjectByName("termsButton[" + i + "]"); const button = Engine.GetGUIObjectByName("termsButton[" + i + "]");
button.caption = terms[page].title; button.caption = terms[page].title;
button.onPress = () => { button.onPress = () =>
{
openTerms(page); openTerms(page);
}; };

View file

@ -3,7 +3,8 @@ function init()
if (Engine.ConfigDB_GetValue("user", "lobby.login")) if (Engine.ConfigDB_GetValue("user", "lobby.login"))
loginButton(); loginButton();
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
Engine.GetGUIObjectByName("cancel").onPress = closePageCallback; Engine.GetGUIObjectByName("cancel").onPress = closePageCallback;
}); });
} }

View file

@ -155,7 +155,8 @@ class TemplateLoader
production.units.push(templateName); production.units.push(templateName);
} }
const appendTechnology = (technologyName) => { const appendTechnology = (technologyName) =>
{
const technology = this.loadTechnologyTemplate(technologyName, civCode); const technology = this.loadTechnologyTemplate(technologyName, civCode);
if (DeriveTechnologyRequirements(technology, civCode)) if (DeriveTechnologyRequirements(technology, civCode))
production.techs.push(technologyName); production.techs.push(technologyName);

View file

@ -37,7 +37,8 @@ class TipDisplay
else else
this.tipFilesData = this.tipFilesData =
hotloadData?.tipFilesData || hotloadData?.tipFilesData ||
shuffleArray(Engine.ReadJSONFile(this.TipFilesDataFile).map(category => category.files).flat().map(tip => { shuffleArray(Engine.ReadJSONFile(this.TipFilesDataFile).map(category => category.files).flat().map(tip =>
{
tip.imageFiles = shuffleArray(tip.imageFiles); tip.imageFiles = shuffleArray(tip.imageFiles);
return tip; return tip;
})); }));

View file

@ -2,7 +2,8 @@ var g_TipsPage;
function init(initData, hotloadData) function init(initData, hotloadData)
{ {
return new Promise(closePageCallback => { return new Promise(closePageCallback =>
{
g_TipsPage = new TipsPage(initData, hotloadData, closePageCallback); g_TipsPage = new TipsPage(initData, hotloadData, closePageCallback);
}); });
} }

Some files were not shown because too many files have changed in this diff Show more