Color incompatible mods and add filter

This helps to see compatible mods in the list, which can get a bit long.
For incompatible mods in disabled section use gray colour.
For incompatible mods in enabled section use red colour (what can happen
when using arguments to start the game or they can be in config file).
Add option to filter compatible mods, this does not affect enabled
section, because if there is incompatible mod, it is error and it needs
to be always visible.
Add function recomputeCompatibility and g_ModsCompatibility to avoid
recomputing aredependenciesmet when coloring mods, because every column
is colored separately.
Disable enable mod button if mod is incompatible.
Remove all dependencies met messages as they are now replaced by this
mechanism.

fix getSelectedModUrl in process

Differential revision: D3687
Fixes: #6053
Tested by: @Freagarach
Comments by: @vladislavbelov
This was SVN commit r25095.
This commit is contained in:
Angen 2021-03-21 10:22:50 +00:00
parent 1c68d9890b
commit 841bf5f2dd
2 changed files with 76 additions and 35 deletions

View file

@ -51,6 +51,11 @@ var g_ModsDisabled = [];
var g_ModsEnabledFiltered = [];
var g_ModsDisabledFiltered = [];
/**
* Cache mod compatibility recomputed when some mod is enbaled/disabled.
*/
var g_ModsCompatibility = [];
/**
* Name of the mods installed by the ModInstaller.
*/
@ -72,6 +77,7 @@ function initMods()
{
loadMods();
loadEnabledMods();
recomputeCompatibility();
validateMods();
initGUIFilters();
}
@ -104,6 +110,7 @@ function validateMods()
function initGUIFilters()
{
Engine.GetGUIObjectByName("negateFilter").checked = false;
Engine.GetGUIObjectByName("modCompatibleFilter").checked = true;
displayModLists();
}
@ -133,11 +140,11 @@ function startMods()
function displayModLists()
{
g_ModsEnabledFiltered = displayModList("modsEnabledList", g_ModsEnabled);
g_ModsDisabledFiltered = displayModList("modsDisabledList", g_ModsDisabled);
g_ModsEnabledFiltered = displayModList("modsEnabledList", g_ModsEnabled, true);
g_ModsDisabledFiltered = displayModList("modsDisabledList", g_ModsDisabled, false);
}
function displayModList(listObjectName, folders)
function displayModList(listObjectName, folders, enabled)
{
let listObject = Engine.GetGUIObjectByName(listObjectName);
@ -150,15 +157,17 @@ function displayModList(listObjectName, folders)
}
folders = folders.filter(filterMod);
if (!enabled && Engine.GetGUIObjectByName("modCompatibleFilter").checked)
folders = folders.filter(folder => g_ModsCompatibility[folder]);
let selected = listObject.selected !== -1 ? listObject.list_name[listObject.selected] : null;
listObject.list_name = folders.map(folder => g_Mods[folder].name).map(name => g_InstalledMods.indexOf(name) == -1 ? name : coloredText(name, "green"));
listObject.list_folder = folders;
listObject.list_label = folders.map(folder => g_Mods[folder].label);
listObject.list_url = folders.map(folder => g_Mods[folder].url || "");
listObject.list_version = folders.map(folder => g_Mods[folder].version);
listObject.list_dependencies = folders.map(folder => g_Mods[folder].dependencies.join(" "));
listObject.list_name = folders.map(folder => colorMod(folder, g_Mods[folder].name, enabled));
listObject.list_folder = folders.map(folder => colorMod(folder, folder, enabled));
listObject.list_label = folders.map(folder => colorMod(folder, g_Mods[folder].label, enabled));
listObject.list_url = folders.map(folder => colorMod(folder, g_Mods[folder].url || ""), enabled);
listObject.list_version = folders.map(folder => colorMod(folder, g_Mods[folder].version, enabled));
listObject.list_dependencies = folders.map(folder => colorMod(folder, g_Mods[folder].dependencies.join(" "), enabled));
listObject.list = folders;
listObject.selected = selected ? listObject.list_name.indexOf(selected) : -1;
@ -166,6 +175,21 @@ function displayModList(listObjectName, folders)
return folders;
}
function getModColor(folder, enabled)
{
if (!g_ModsCompatibility[folder])
return enabled ? g_ColorDependenciesNotMet : "gray";
if (g_InstalledMods.indexOf(g_Mods[folder].name) != -1)
return "green";
return false;
}
function colorMod(folder, text, enabled)
{
let color = getModColor(folder, enabled);
return color ? coloredText(text, color) : text;
}
function reloadDisabledMods()
{
g_ModsDisabled = Object.keys(g_Mods).filter(folder => g_ModsEnabled.indexOf(folder) == -1);
@ -176,11 +200,12 @@ function enableMod()
let modsDisabledList = Engine.GetGUIObjectByName("modsDisabledList");
let pos = modsDisabledList.selected;
if (pos == -1 || !areDependenciesMet(g_ModsDisabledFiltered[pos]))
if (pos == -1 || !g_ModsCompatibility[g_ModsDisabledFiltered[pos]])
return;
g_ModsEnabled.push(g_ModsDisabledFiltered.splice(pos, 1)[0]);
reloadDisabledMods();
recomputeCompatibility();
if (pos >= g_ModsDisabledFiltered.length)
--pos;
@ -214,12 +239,13 @@ function disableMod()
sortEnabledMods();
for (let i = 0; i < g_ModsEnabled.length; ++i)
if (!areDependenciesMet(g_ModsEnabled[i]))
if (!areDependenciesMet(g_ModsEnabled[i], true))
{
g_ModsDisabled.push(g_ModsEnabled.splice(i, 1)[0]);
--i;
}
recomputeCompatibility(true);
displayModLists();
modsEnabledList.selected = Math.min(pos, g_ModsEnabledFiltered.length - 1);
}
@ -280,30 +306,31 @@ function moveCurrItem(objectName, up)
g_ModsEnabled[idx] = g_ModsEnabled[idx2];
g_ModsEnabled[idx2] = tmp;
g_ModsEnabledFiltered = displayModList("modsEnabledList", g_ModsEnabled);
g_ModsEnabledFiltered = displayModList("modsEnabledList", g_ModsEnabled, true);
obj.selected = idx2;
}
function areDependenciesMet(folder)
function areDependenciesMet(folder, disabledAction = false)
{
let guiObject = Engine.GetGUIObjectByName("message");
// If we disabled mod it will not change satus of incompatible mods
if (disabledAction && !g_ModsCompatibility[folder])
return g_ModsCompatibility[folder];
for (let dependency of g_Mods[folder].dependencies)
{
if (isDependencyMet(dependency))
continue;
guiObject.caption = coloredText(
sprintf(translate('Dependency not met: %(dep)s'), { "dep": dependency }),
g_ColorDependenciesNotMet);
return false;
if (!isDependencyMet(dependency))
return false;
}
guiObject.caption = coloredText(translate('All dependencies met'), g_ColorDependenciesMet);
return true;
}
function recomputeCompatibility(disabledAction = false)
{
for (let mod in g_Mods)
g_ModsCompatibility[mod] = areDependenciesMet(mod, disabledAction);
}
/**
* @param dependency is a mod name or a mod version comparison.
*/
@ -364,31 +391,31 @@ function sortEnabledMods()
dependencies[folder1].indexOf(g_Mods[folder2].name) != -1 ? 1 :
dependencies[folder2].indexOf(g_Mods[folder1].name) != -1 ? -1 : 0);
g_ModsEnabledFiltered = displayModList("modsEnabledList", g_ModsEnabled);
g_ModsEnabledFiltered = displayModList("modsEnabledList", g_ModsEnabled, true);
}
function selectedMod(listObjectName)
{
let listObject = Engine.GetGUIObjectByName(listObjectName);
let otherListObject = Engine.GetGUIObjectByName(listObjectName == "modsDisabledList" ?
let isPickedDisabledList = listObjectName == "modsDisabledList";
let otherListObject = Engine.GetGUIObjectByName(isPickedDisabledList ?
"modsEnabledList" : "modsDisabledList");
let toggleModButton = Engine.GetGUIObjectByName("toggleModButton");
let modSelected = listObject.selected != -1;
if (modSelected)
let isModSelected = listObject.selected != -1;
if (isModSelected)
{
otherListObject.selected = -1;
toggleModButton.onPress = listObjectName == "modsDisabledList" ? enableMod : disableMod;
toggleModButton.onPress = isPickedDisabledList ? enableMod : disableMod;
}
Engine.GetGUIObjectByName("visitWebButton").enabled = modSelected && !!getSelectedModUrl();
toggleModButton.caption = listObjectName == "modsDisabledList" ?
Engine.GetGUIObjectByName("visitWebButton").enabled = isModSelected && !!getSelectedModUrl();
toggleModButton.caption = isPickedDisabledList ?
translateWithContext("mod activation", "Enable") :
translateWithContext("mod activation", "Disable");
toggleModButton.enabled = modSelected;
Engine.GetGUIObjectByName("enabledModUp").enabled = modSelected && listObjectName == "modsEnabledList" && !areFilters();
Engine.GetGUIObjectByName("enabledModDown").enabled = modSelected && listObjectName == "modsEnabledList" && !areFilters();
toggleModButton.enabled = isPickedDisabledList ? isModSelected && g_ModsCompatibility[listObject.list[listObject.selected]] : isModSelected;
Engine.GetGUIObjectByName("enabledModUp").enabled = isModSelected && listObjectName == "modsEnabledList" && !areFilters();
Engine.GetGUIObjectByName("enabledModDown").enabled = isModSelected && listObjectName == "modsEnabledList" && !areFilters();
Engine.GetGUIObjectByName("globalModDescription").caption =
listObject.list[listObject.selected] ?
@ -405,7 +432,7 @@ function getSelectedModUrl()
let modsDisabledList = Engine.GetGUIObjectByName("modsDisabledList");
let list = modsEnabledList.selected == -1 ? modsDisabledList : modsEnabledList;
let folder = list.list_folder[list.selected];
let folder = list.list[list.selected];
return folder && g_Mods[folder] && g_Mods[folder].url || undefined;
}

View file

@ -38,6 +38,20 @@
</object>
</object>
<object size = "100%-200 40 100%-20 64">
<object name="modCompatibleFilter"
type="checkbox"
checked="false"
style="ModernTickBox"
size="16 0 36 100%"
>
<action on="Press">displayModLists();</action>
</object>
<object type="text" size="40 0 100% 100%" text_align="left" textcolor="white">
<translatableAttribute id="caption">Filter compatible</translatableAttribute>
</object>
</object>
<object
name="globalModDescription"
type="text"