diff --git a/binaries/data/mods/mod/gui/modmod/modmod.js b/binaries/data/mods/mod/gui/modmod/modmod.js
index 424a29c0ae..fcddc84e00 100644
--- a/binaries/data/mods/mod/gui/modmod/modmod.js
+++ b/binaries/data/mods/mod/gui/modmod/modmod.js
@@ -1,270 +1,211 @@
-/*
-Example contents of g_mods:
-{
- "foldername1": { // this is the content of the json file in a specific mod
- name: "unique_shortname", // eg "0ad", "rote"
- version: "0.0.16",
- label: "Nice Mod Name", // eg "0 A.D. - Empires Ascendant"
- type: "content|functionality|mixed/mod-pack",
- url: "http://wildfregames.com/",
- description: "",
- dependencies: [] // (name({<,<=,==,>=,>}version)?)+
- },
- "foldername2": {
- name: "mod2",
- label: "Mod 2",
- version: "1.1",
- type: "content|functionality|mixed/mod-pack", // optional
- url: "http://play0ad.wfg.com/", //optional
- description: "",
- dependencies: []
- }
-}
-*/
-
-
-var g_mods = {}; // Contains all JSONs as explained in the structure above
-var g_modsEnabled = []; // folder names
-var g_modsAvailable = []; // folder names
-
-const g_sortByOptions = [translate("Name"), translate("Folder"), translate("Label"), translate("Version")];
-const SORT_BY_NAME = 0;
-const SORT_BY_FOLDER = 1;
-const SORT_BY_LABEL = 2;
-const SORT_BY_VERSION = 3;
-
-var g_modTypes = [translate("Type: Any")];
+/**
+ * Contains JS objects defined by the mod JSON files available.
+ * @example
+ *{
+ * "public":
+ * {
+ * "name": "0ad",
+ * "version": "0.0.16",
+ * "label": "0 A.D. - Empires Ascendant",
+ * "type": "content|functionality|mixed/mod-pack",
+ * "url": "http://wildfregames.com/",
+ * "description": "A free, open-source, historical RTS game.",
+ * "dependencies": []
+ * },
+ * "foldername2": {
+ * "name": "mod2",
+ * "label": "Mod 2",
+ * "version": "1.1",
+ * "description": "",
+ * "dependencies": ["0ad<=0.0.16", "rote"]
+ * }
+ *}
+ */
+var g_Mods = {};
/**
- * Fetches the mod lists in JSON from the Engine.
- * Initiates a first creation of the GUI lists.
- * Enabled mods are read from the Configuration and checked if still available.
+ * Every mod needs to define these properties.
*/
+var g_RequiredProperties = ["name", "label", "description", "dependencies", "version"];
+
+/**
+ * Version checks in mod dependencies can use these operators.
+ */
+var g_CompareVersion = /(<=|>=|<|>|=)/;
+
+/**
+ * Folder names of all mods that are or can be launched.
+ */
+var g_ModsEnabled = [];
+var g_ModsDisabled = [];
+
+var g_ColorNoModSelected = "255 255 100";
+var g_ColorDependenciesMet = "100 255 100";
+var g_ColorDependenciesNotMet = "255 100 100";
+
+/**
+ * Dropdown choices to sort the available mods.
+ */
+var g_SortOptions = [
+ {
+ "id": "name",
+ "title": translate("Name"),
+ "value": folder => g_Mods[folder].name.toLowerCase(),
+ "default": true
+ },
+ {
+ "id": "folder",
+ "title": translate("Folder"),
+ "value": folder => folder.toLowerCase()
+ },
+ {
+ "id": "label",
+ "title": translate("Label"),
+ "value": folder => g_Mods[folder].label.toLowerCase()
+ },
+ {
+ "id": "version",
+ "title": translate("Version"),
+ "value": folder => g_Mods[folder].version
+ }
+];
+
function init()
+{
+ loadMods();
+ initGUIFilters();
+}
+
+function loadMods()
{
let mods = Engine.GetAvailableMods();
- let keys = ["name", "label", "description", "dependencies", "version"];
- Object.keys(mods).forEach(function(k) {
- for (let i = 0; i < keys.length; ++i)
- if (!keys[i] in mods[k])
- {
- log("Skipping mod '"+k+"'. Missing property '"+keys[i]+"'.");
- return;
- }
- g_mods[k] = mods[k];
- });
+ for (let folder in mods)
+ if (g_RequiredProperties.every(prop => mods[folder][prop] !== undefined))
+ g_Mods[folder] = mods[folder];
+ else
+ warn("Skipping mod '" + mod + "' which does not define '" + property + "'.");
- g_modsEnabled = getExistingModsFromConfig();
- g_modsAvailable = Object.keys(g_mods).filter(function(i) { return g_modsEnabled.indexOf(i) === -1; });
+ deepfreeze(g_Mods);
+ g_ModsEnabled = Engine.ConfigDB_GetValue("user", "mod.enabledmods").split(/\s+/).filter(folder => !!g_Mods[folder]);
+ g_ModsDisabled = Object.keys(g_Mods).filter(folder => g_ModsEnabled.indexOf(folder) == -1);
+}
+
+function initGUIFilters()
+{
Engine.GetGUIObjectByName("negateFilter").checked = false;
Engine.GetGUIObjectByName("modGenericFilter").caption = translate("Filter");
Engine.GetGUIObjectByName("modTypeFilter").selected = 0;
- var sortBy = Engine.GetGUIObjectByName("sortBy");
- sortBy.list = g_sortByOptions;
- sortBy.selected = SORT_BY_NAME;
+ let sortBy = Engine.GetGUIObjectByName("sortBy");
+ sortBy.list = g_SortOptions.map(option => option.title);
+ sortBy.selected = g_SortOptions.findIndex(option => option.default);
- // sort ascending by default
Engine.GetGUIObjectByName("isOrderDescending").checked = false;
- generateModsLists();
-
- Engine.GetGUIObjectByName("message").caption = translate("Message: Mods Loaded.");
-}
-
-/**
- * Recreating both the available and enabled mods lists.
- */
-function generateModsLists()
-{
- generateModsList('modsAvailableList', g_modsAvailable);
- generateModsList('modsEnabledList', g_modsEnabled);
+ displayModLists();
}
function saveMods()
{
- // always sort mods before saving
- sortMods();
- Engine.ConfigDB_CreateValue("user", "mod.enabledmods", ["mod"].concat(g_modsEnabled).join(" "));
+ sortEnabledMods();
+ Engine.ConfigDB_CreateValue("user", "mod.enabledmods", ["mod"].concat(g_ModsEnabled).join(" "));
Engine.ConfigDB_WriteFile("user", "config/user.cfg");
}
function startMods()
{
- // always sort mods before starting
- sortMods();
- Engine.SetMods(["mod"].concat(g_modsEnabled));
+ sortEnabledMods();
+ Engine.SetMods(["mod"].concat(g_ModsEnabled));
Engine.RestartEngine();
}
-function getExistingModsFromConfig()
+function displayModLists()
{
- var existingMods = [];
-
- var mods = [];
- var cfgMods = Engine.ConfigDB_GetValue("user", "mod.enabledmods");
- if (cfgMods.length > 0)
- mods = cfgMods.split(/\s+/);
-
- mods.forEach(function(mod) {
- if (mod in g_mods)
- existingMods.push(mod);
- });
-
- return existingMods;
+ displayModList("modsEnabledList", g_ModsEnabled);
+ displayModList("modsDisabledList", g_ModsDisabled);
}
-/**
- * (Re-)Generate List of all mods.
- * @param listObjectName The GUI object's name (e.g. "modsEnabledList", "modsAvailableList")
- */
-function generateModsList(listObjectName, mods)
+function displayModList(listObjectName, folders)
{
- var sortBy = Engine.GetGUIObjectByName("sortBy");
- var orderDescending = Engine.GetGUIObjectByName("isOrderDescending");
- var isDescending = orderDescending && orderDescending.checked;
+ updateModTypes();
- // TODO: Sorting mods by dependencies would be nice
- if (listObjectName != "modsEnabledList")
+ let sortOption = g_SortOptions[Engine.GetGUIObjectByName("sortBy").selected];
+ if (sortOption && listObjectName == "modsDisabledList")
{
- var idx = -1;
- if (sortBy)
- idx = sortBy.selected;
-
- switch (idx)
- {
- default:
- warn("generateModsList: invalid index '"+idx+"'"); // fall through
- // sort by unique name alphanumerically by default:
- case -1:
- case SORT_BY_NAME:
- mods.sort(function(a, b)
- {
- var ret = compare(g_mods[a].name.toLowerCase(), g_mods[b].name.toLowerCase());
- return ret * (isDescending ? -1 : 1);
- });
- break;
- case SORT_BY_FOLDER:
- mods.sort(function(a, b)
- {
- return compare(a.toLowerCase(), b.toLowerCase()) * (isDescending ? -1 : 1);
- });
- break;
- case SORT_BY_LABEL:
- mods.sort(function(a, b)
- {
- var ret = compare(g_mods[a].label.toLowerCase(), g_mods[b].label.toLowerCase());
- return ret * (isDescending ? -1 : 1);
- });
- break;
- case SORT_BY_VERSION:
- mods.sort(function(a, b)
- {
- // TODO reuse actual logic
- var ret = compare(g_mods[a].version, g_mods[b].version);
- return ret * (isDescending ? -1 : 1);
- });
- break;
- }
+ folders.sort((version1, version2) => sortOption.value(version1).localeCompare(sortOption.value(version2)));
+ if (Engine.GetGUIObjectByName("isOrderDescending").checked)
+ folders.reverse();
}
- var [keys, names, folders, labels, types, urls, versions, dependencies] = [[],[],[],[],[],[],[],[]];
- mods.forEach(function(foldername)
- {
- var mod = g_mods[foldername];
- if (mod.type && g_modTypes.indexOf(mod.type) == -1)
- g_modTypes.push(mod.type);
+ folders = folders.filter(filterMod);
- if (filterMod(foldername))
- return;
-
- keys.push(foldername);
- names.push(mod.name);
- folders.push('[color="255 255 255"](' + foldername + ')[/color]');
-
- labels.push(mod.label || "");
- types.push(mod.type || "");
- urls.push(mod.url || "");
- versions.push(mod.version || "");
- dependencies.push((mod.dependencies || []).join(" "));
- });
-
- // Update the list
- var obj = Engine.GetGUIObjectByName(listObjectName);
- obj.list_name = names;
- obj.list_modFolderName = folders;
- obj.list_modLabel = labels;
- obj.list_modType = types;
- obj.list_modURL = urls;
- obj.list_modVersion = versions;
- obj.list_modDependencies = dependencies;
-
- obj.list = keys;
-
- var modTypeFilter = Engine.GetGUIObjectByName("modTypeFilter");
- modTypeFilter.list = g_modTypes;
+ let listObject = Engine.GetGUIObjectByName(listObjectName);
+ listObject.list_name = folders.map(folder => g_Mods[folder].name);
+ listObject.list_modFolderName = folders;
+ listObject.list_modLabel = folders.map(folder => g_Mods[folder].label);
+ listObject.list_modType = folders.map(folder => g_Mods[folder].type || "");
+ listObject.list_modURL = folders.map(folder => g_Mods[folder].url || "");
+ listObject.list_modVersion = folders.map(folder => g_Mods[folder].version);
+ listObject.list_modDependencies = folders.map(folder => g_Mods[folder].dependencies.join(" "));
+ listObject.list = folders;
}
-function compare(a, b)
+function updateModTypes()
{
- return ( (a > b) ? 1 : (b > a) ? -1 : 0 );
+ let types = [translate("Type: Any")];
+ for (let folder in g_Mods)
+ {
+ if (g_Mods[folder].type && types.indexOf(g_Mods[folder].type) == -1)
+ types.push(g_Mods[folder].type);
+ }
+ Engine.GetGUIObjectByName("modTypeFilter").list = types;
}
function enableMod()
{
- var obj = Engine.GetGUIObjectByName("modsAvailableList");
- var pos = obj.selected;
- if (pos === -1)
+ let modsDisabledList = Engine.GetGUIObjectByName("modsDisabledList");
+ let pos = modsDisabledList.selected;
+
+ if (pos == -1 || !areDependenciesMet(g_ModsDisabled[pos]))
return;
- var mod = g_modsAvailable[pos];
+ g_ModsEnabled.push(g_ModsDisabled.splice(pos, 1)[0]);
- // Move it to the other table
- // check dependencies, warn about not satisfied dependencies and abort if so:
- if (!areDependenciesMet(mod))
- return;
+ if (pos >= g_ModsDisabled.length)
+ --pos;
- g_modsEnabled.push(g_modsAvailable.splice(pos, 1)[0]);
+ modsDisabledList.selected = pos;
- if (pos >= g_modsAvailable.length)
- pos--;
- obj.selected = pos;
-
- generateModsLists();
+ displayModLists();
}
function disableMod()
{
- var obj = Engine.GetGUIObjectByName("modsEnabledList");
- var pos = obj.selected;
- if (pos === -1)
+ let modsEnabledList = Engine.GetGUIObjectByName("modsEnabledList");
+ let pos = modsEnabledList.selected;
+ if (pos == -1)
return;
- var mod = g_modsEnabled[pos];
-
- g_modsAvailable.push(g_modsEnabled.splice(pos, 1)[0]);
+ g_ModsDisabled.push(g_ModsEnabled.splice(pos, 1)[0]);
// Remove mods that required the removed mod and cascade
// Sort them, so we know which ones can depend on the removed mod
// TODO: Find position where the removed mod would have fit (for now assume idx 0)
- sortMods();
- for (var i = 0; i < g_modsEnabled.length; ++i)
- {
- if (!areDependenciesMet(g_modsEnabled[i]))
+
+ sortEnabledMods();
+
+ for (let i = 0; i < g_ModsEnabled.length; ++i)
+ if (!areDependenciesMet(g_ModsEnabled[i]))
{
- g_modsAvailable.push(g_modsEnabled.splice(i, 1)[0]);
+ g_ModsDisabled.push(g_ModsEnabled.splice(i, 1)[0]);
--i;
}
- }
- // select the last element even if more than 1 mod has been removed:
- if (pos > g_modsEnabled.length - 1)
- pos = g_modsEnabled.length - 1;
- obj.selected = pos;
+ modsEnabledList.selected = Math.min(pos, g_ModsEnabled.length - 1);
- generateModsLists();
+ displayModLists();
}
function resetFilters()
@@ -272,69 +213,55 @@ function resetFilters()
Engine.GetGUIObjectByName("modGenericFilter").caption = "";
Engine.GetGUIObjectByName("negateFilter").checked = false;
- // NOTE: Calling generateModsLists() is not needed as the selection changes and that calls applyFilters()
+ // Calling displayModLists is not needed as the selection changes and that calls applyFilters
Engine.GetGUIObjectByName("modTypeFilter").selected = 0;
}
function applyFilters()
{
// Save selected rows
- let modsAvailableList = Engine.GetGUIObjectByName("modsAvailableList");
+ let modsDisabledList = Engine.GetGUIObjectByName("modsDisabledList");
let modsEnabledList = Engine.GetGUIObjectByName("modsEnabledList");
- let selectedModAvailableFolder = modsAvailableList.list_modFolderName[modsAvailableList.selected];
+ let selectedModAvailableFolder = modsDisabledList.list_modFolderName[modsDisabledList.selected];
let selectedModEnabledFolder = modsEnabledList.list_modFolderName[modsEnabledList.selected];
// Remove selected rows to prevent a link to a non existing item
- modsAvailableList.selected = -1;
+ modsDisabledList.selected = -1;
modsEnabledList.selected = -1;
- generateModsLists();
+ displayModLists();
// Restore previously selected rows
- modsAvailableList.selected = modsAvailableList.list_modFolderName.indexOf(selectedModAvailableFolder);
+ modsDisabledList.selected = modsDisabledList.list_modFolderName.indexOf(selectedModAvailableFolder);
modsEnabledList.selected = modsEnabledList.list_modFolderName.indexOf(selectedModEnabledFolder);
Engine.GetGUIObjectByName("globalModDescription").caption = "";
}
-/**
- * Filter a mod based on the status of the filters.
- *
- * @param modFolder Mod to be tested.
- * @return True if mod should not be displayed.
- */
-function filterMod(modFolder)
+function filterMod(folder)
{
- var mod = g_mods[modFolder];
+ let mod = g_Mods[folder];
- var modTypeFilter = Engine.GetGUIObjectByName("modTypeFilter");
- var genericFilter = Engine.GetGUIObjectByName("modGenericFilter");
- var negateFilter = Engine.GetGUIObjectByName("negateFilter");
+ let modTypeFilter = Engine.GetGUIObjectByName("modTypeFilter");
+ let negateFilter = Engine.GetGUIObjectByName("negateFilter").checked;
- // TODO: and result of filters together (type && generic)
+ if (modTypeFilter.selected > 0 && (mod.type || "") != modTypeFilter.list[modTypeFilter.selected])
+ return negateFilter;
- // We assume index 0 means display all for any given filter.
- if (modTypeFilter.selected > 0
- && (mod.type || "") != modTypeFilter.list[modTypeFilter.selected])
- return !negateFilter.checked;
+ let searchText = Engine.GetGUIObjectByName("modGenericFilter").caption;
+ if (searchText &&
+ searchText != translate("Filter") &&
+ folder.indexOf(searchText) == -1 &&
+ mod.name.indexOf(searchText) == -1 &&
+ mod.label.indexOf(searchText) == -1 &&
+ (mod.type || "").indexOf(searchText) == -1 &&
+ (mod.url || "").indexOf(searchText) == -1 &&
+ mod.version.indexOf(searchText) == -1 &&
+ mod.description.indexOf(searchText) == -1 &&
+ mod.dependencies.indexOf(searchText) == -1)
+ return negateFilter;
- if (genericFilter && genericFilter.caption && genericFilter.caption != "" && genericFilter.caption != translate("Filter"))
- {
- var t = genericFilter.caption;
- if (modFolder.indexOf(t) === -1
- && mod.name.indexOf(t) === -1
- && mod.label.indexOf(t) === -1
- && (mod.type || "").indexOf(t) === -1
- && (mod.url || "").indexOf(t) === -1
- && mod.version.indexOf(t) === -1
- && mod.description.indexOf(t) === -1
- && mod.dependencies.indexOf(t) === -1)
- {
- return !negateFilter.checked;
- }
- }
-
- return negateFilter.checked;
+ return !negateFilter;
}
function closePage()
@@ -343,176 +270,126 @@ function closePage()
}
/**
- * Moves an item in the list @p objectName up or down depending on the value of @p up.
+ * Moves an item in the list up or down.
*/
function moveCurrItem(objectName, up)
{
- var obj = Engine.GetGUIObjectByName(objectName);
- if (!obj)
+ let obj = Engine.GetGUIObjectByName(objectName);
+ let idx = obj.selected;
+ if (idx == -1)
return;
- var idx = obj.selected;
- if (idx === -1)
- return;
-
- var num = obj.list.length;
- var idx2 = idx + (up ? -1 : 1);
+ let num = obj.list.length;
+ let idx2 = idx + (up ? -1 : 1);
if (idx2 < 0 || idx2 >= num)
return;
- var tmp = g_modsEnabled[idx];
- g_modsEnabled[idx] = g_modsEnabled[idx2];
- g_modsEnabled[idx2] = tmp;
+ let tmp = g_ModsEnabled[idx];
+ g_ModsEnabled[idx] = g_ModsEnabled[idx2];
+ g_ModsEnabled[idx2] = tmp;
- // Selected object reached the new position.
- obj.list = g_modsEnabled;
+ obj.list = g_ModsEnabled;
obj.selected = idx2;
- generateModsList('modsEnabledList', g_modsEnabled);
+
+ displayModList("modsEnabledList", g_ModsEnabled);
}
-function areDependenciesMet(mod)
+function areDependenciesMet(folder)
{
- var guiObject = Engine.GetGUIObjectByName("message");
- for (var dependency of g_mods[mod].dependencies)
+ let guiObject = Engine.GetGUIObjectByName("message");
+
+ for (let dependency of g_Mods[folder].dependencies)
{
if (isDependencyMet(dependency))
continue;
- guiObject.caption = '[color="255 100 100"]' + translate(sprintf('Dependency not met: %(dep)s', { "dep": dependency })) +'[/color]';
+
+ guiObject.caption =
+ '[color="' + g_ColorDependenciesNotMet + '"]' +
+ sprintf(translate('Dependency not met: %(dep)s'), { "dep": dependency }) +
+ '[/color]';
+
return false;
}
- guiObject.caption = '[color="100 255 100"]' + translate('All dependencies met') + '[/color]';
+ guiObject.caption =
+ '[color="' + g_ColorDependenciesMet + '"]' +
+ translate('All dependencies met') +
+ '[/color]';
return true;
}
/**
- * @param dependency: Either id (unique modJson.name) and version or only the unique mod name.
- * Concatenated by either "=", ">", "<", ">=", "<=".
+ * @param dependency is a mod name or a mod version comparison.
*/
-function isDependencyMet(dependency_idAndVersion, modsEnabled = null)
+function isDependencyMet(dependency)
{
- if (!modsEnabled)
- modsEnabled = g_modsEnabled;
+ let operator = dependency.match(g_CompareVersion);
+ let [name, version] = operator ? dependency.split(operator[0]) : [dependency, undefined];
- // Split on {=,<,<=,>,>=} and use the second part as the version number
- // and whatever we split on as a way to handle that version.
- var op = dependency_idAndVersion.match(/(<=|>=|<|>|=)/);
- // Did the dependency contain a version number?
- if (op)
- {
- op = op[0];
- var dependency_parts = dependency_idAndVersion.split(op);
- var dependency_version = dependency_parts[1];
- var dependency_id = dependency_parts[0];
- }
- else
- var dependency_id = dependency_idAndVersion;
-
- // modsEnabled_key currently is the mod folder name.
- for (var modsEnabled_key of modsEnabled)
- {
- var modJson = g_mods[modsEnabled_key];
- if (modJson.name != dependency_id)
- continue;
-
- // There could be another mod with a satisfying version
- if (!op || versionSatisfied(modJson.version, op, dependency_version))
- return true;
- }
- return false;
+ return g_ModsEnabled.some(folder =>
+ g_Mods[folder].name == name &&
+ (!operator || versionSatisfied(g_Mods[folder].version, operator, version)));
}
/**
- * Returns true if @p version satisfies @p op (<,<=,=,>=,>) @p requirement.
- * @note @p version and @p requirement are split on '.' and everything after
+ * Compares the given versions using the given operator.
* '-' or '_' is ignored. Only numbers are supported.
* @note "5.3" < "5.3.0"
*/
-function versionSatisfied(version, op, requirement)
+function versionSatisfied(version1, operator, version2)
{
- var reqList = requirement.split(/[-_]/)[0].split(/\./g);
- var avList = version.split(/[-_]/)[0].split(/\./g);
+ let versionList1 = version1.split(/[-_]/)[0].split(/\./g);
+ let versionList2 = version2.split(/[-_]/)[0].split(/\./g);
- var eq = op.indexOf("=") !== -1;
- var lt = op.indexOf("<") !== -1;
- var gt = op.indexOf(">") !== -1;
- if (!(eq || lt || gt))
+ let eq = operator.indexOf("=") != -1;
+ let lt = operator.indexOf("<") != -1;
+ let gt = operator.indexOf(">") != -1;
+
+ for (let i = 0; i < Math.min(versionList1.length, versionList2.length); ++i)
{
- warn("No valid compare op");
- return false;
- }
+ let diff = +versionList1[i] - +versionList2[i];
+ if (isNaN(diff))
+ continue;
- var l = Math.min(reqList.length, avList.length);
- for (var i = 0; i < l; ++i)
- {
- // TODO: Handle NaN
- var diff = +avList[i] - +reqList[i];
-
- // Early success
- if (gt && diff > 0)
- return true;
- if (lt && diff < 0)
+ if (gt && diff > 0 || lt && diff < 0)
return true;
- // Early failure
- if (gt && diff < 0)
- return false;
- if (lt && diff > 0)
- return false;
- if (eq && diff !== 0)
+ if (gt && diff < 0 || lt && diff > 0 || eq && diff)
return false;
}
+
// common prefix matches
- var ldiff = avList.length - reqList.length;
- if (ldiff === 0)
+ let ldiff = versionList1.length - versionList2.length;
+ if (!ldiff)
return eq;
+
// NB: 2.3 != 2.3.0
if (ldiff < 0)
return lt;
- if (ldiff > 0)
- return gt;
- // Can't be reached
- error("version checking code broken");
- return false;
+ return gt;
}
-function sortMods()
+function sortEnabledMods()
{
- // store the list of dependencies per mod, but strip the version numbers
- var deps = {};
- for (var mod of g_modsEnabled)
- {
- deps[mod] = [];
- if (!g_mods[mod].dependencies)
- continue;
- deps[mod] = g_mods[mod].dependencies.map(function(d) { return d.split(/(<=|>=|<|>|=)/)[0]; });
- }
- var sortFunction = function(mod1, mod2)
- {
- var name1 = g_mods[mod1].name;
- var name2 = g_mods[mod2].name;
- if (deps[mod1].indexOf(name2) != -1)
- return 1;
- if (deps[mod2].indexOf(name1) != -1)
- return -1;
- return 0;
- }
- g_modsEnabled.sort(sortFunction);
- generateModsList("modsEnabledList", g_modsEnabled);
+ let dependencies = {};
+ for (let folder of g_ModsEnabled)
+ dependencies[folder] = g_Mods[folder].dependencies.map(d => d.split()[0]);
+
+ g_ModsEnabled.sort((folder1, folder2) =>
+ dependencies[folder1].indexOf(g_Mods[folder2].name) != -1 ? 1 :
+ dependencies[folder2].indexOf(g_Mods[folder1].name) != -1 ? -1 : 0);
+
+ displayModList("modsEnabledList", g_ModsEnabled);
}
function showModDescription(listObjectName)
{
- var listObject = Engine.GetGUIObjectByName(listObjectName);
- if (listObject.selected == -1)
- var desc = '[color="255 255 100"]' + translate("No mod has been selected.") + '[/color]';
- else
- {
- let key = listObject.list[listObject.selected];
- var desc = g_mods[key].description;
- }
+ let listObject = Engine.GetGUIObjectByName(listObjectName);
- Engine.GetGUIObjectByName("globalModDescription").caption = desc;
+ Engine.GetGUIObjectByName("globalModDescription").caption =
+ listObject.list[listObject.selected] ?
+ g_Mods[listObject.list[listObject.selected]].description :
+ '[color="' + g_ColorNoModSelected + '"]' + translate("No mod has been selected.") + '[/color]';
}
diff --git a/binaries/data/mods/mod/gui/modmod/modmod.xml b/binaries/data/mods/mod/gui/modmod/modmod.xml
index c6f839005f..959e53815d 100644
--- a/binaries/data/mods/mod/gui/modmod/modmod.xml
+++ b/binaries/data/mods/mod/gui/modmod/modmod.xml
@@ -5,7 +5,8 @@
-