diff --git a/binaries/data/mods/public/gamesettings/attributes/Population.js b/binaries/data/mods/public/gamesettings/attributes/Population.js index 2b47dd2928..696fef8053 100644 --- a/binaries/data/mods/public/gamesettings/attributes/Population.js +++ b/binaries/data/mods/public/gamesettings/attributes/Population.js @@ -35,8 +35,9 @@ GameSettings.prototype.Attributes.Population = class Population extends GameSett if (this.getLegacySetting(attribs, "PopulationCapType") !== undefined) this.setPopCapType(this.getLegacySetting(attribs, "PopulationCapType")); - if (this.getLegacySetting(attribs, "PopulationCap") !== undefined) - this.setPopCap(this.getLegacySetting(attribs, "PopulationCap")); + const cap = this.getLegacySetting(attribs, "PopulationCap"); + if (cap !== undefined) + this.setPopCap(cap ?? Infinity); } onMapChange() @@ -64,7 +65,9 @@ GameSettings.prototype.Attributes.Population = class Population extends GameSett setPopCapType(capType) { this.capType = capType; + const oldFactor = this.currentData?.Factor; this.currentData = g_Settings.PopulationCapacities.find(type => type.Name == capType); - this.setPopCap(this.currentData.Options.Default); + this.setPopCap(10 * Math.round( + (this.cap && oldFactor ? (this.cap / oldFactor) : 1) * this.currentData.Factor / 10)); } }; diff --git a/binaries/data/mods/public/gui/common/gamedescription.js b/binaries/data/mods/public/gui/common/gamedescription.js index 8a163baca8..fbc891d714 100644 --- a/binaries/data/mods/public/gui/common/gamedescription.js +++ b/binaries/data/mods/public/gui/common/gamedescription.js @@ -382,9 +382,9 @@ function getGameDescription(initAttributes, mapCache) "value": initAttributes.settings.PlayerData?.some(pData => pData?.PopulationLimit !== undefined) ? translateWithContext("population capacity", "Per Player") : - initAttributes.settings.PopulationCap < 10000 ? - initAttributes.settings.PopulationCap : - translateWithContext("population capacity", "Unlimited") + initAttributes.settings.PopulationCap === Infinity ? + translateWithContext("population capacity", "Unlimited") : + initAttributes.settings.PopulationCap }); titles.push({ diff --git a/binaries/data/mods/public/gui/common/settings.js b/binaries/data/mods/public/gui/common/settings.js index 4ad854f885..112e9946d9 100644 --- a/binaries/data/mods/public/gui/common/settings.js +++ b/binaries/data/mods/public/gui/common/settings.js @@ -358,7 +358,7 @@ function translatePopulationCapacity(popCap, popCapType) if (!popCapTypeData) return translateWithContext("population capacity", "Unknown"); - return popCap >= 10000 ? + return popCap === Infinity ? translateWithContext("population capacity", "Unlimited") : sprintf(translate("%(populationCapacity)s (%(populationCapacityType)s)"), { "populationCapacity": popCap, diff --git a/binaries/data/mods/public/gui/gamesetup/Controllers/GuiData.js b/binaries/data/mods/public/gui/gamesetup/Controllers/GuiData.js index e2c340c214..afa150085b 100644 --- a/binaries/data/mods/public/gui/gamesetup/Controllers/GuiData.js +++ b/binaries/data/mods/public/gui/gamesetup/Controllers/GuiData.js @@ -20,6 +20,7 @@ class GameSettingsGuiData Serialize() { const ret = { + "linearPopulationCapacity": this.linearPopulationCapacity, "mapFilter": this.mapFilter.filter }; if (Object.keys(this.lockSettings).length) @@ -30,6 +31,7 @@ class GameSettingsGuiData Deserialize(data) { this.mapFilter.filter = data.mapFilter; + this.linearPopulationCapacity = data.linearPopulationCapacity; this.lockSettings = data?.lockSettings || {}; } } diff --git a/binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/Single/Dropdowns/PopulationCap.js b/binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/Single/Sliders/PopulationCap.js similarity index 68% rename from binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/Single/Dropdowns/PopulationCap.js rename to binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/Single/Sliders/PopulationCap.js index 51d614a375..149004d278 100644 --- a/binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/Single/Dropdowns/PopulationCap.js +++ b/binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/Single/Sliders/PopulationCap.js @@ -2,7 +2,7 @@ const CAPTYPE_PLAYER_POPULATION = "player"; const CAPTYPE_TEAM_POPULATION = "team"; const CAPTYPE_WORLD_POPULATION = "world"; -GameSettingControls.PopulationCap = class PopulationCap extends GameSettingControlDropdown +GameSettingControls.PopulationCap = class PopulationCap extends GameSettingControlSlider { constructor(...args) { @@ -15,38 +15,52 @@ GameSettingControls.PopulationCap = class PopulationCap extends GameSettingContr this.render(); } + round(value) + { + return Math.round(value / 10) * 10; + } + + linearToLogarythmic(value) + { + return this.round((1 / (1 - value) + 28 * value / (1 + 5 * value)) * + g_GameSettings.population.currentData.Factor / 6); + } + render() { this.setEnabled(g_GameSettings.map.type != "scenario" && !g_GameSettings.population.perPlayer); this.title.caption = g_GameSettings.population.currentData.CapTitle; if (g_GameSettings.population.perPlayer) this.label.caption = this.PerPlayerCaption; - if (!this.enabled) - return; + else + this.setTooltip(0); - this.dropdown.list_data = g_GameSettings.population.currentData.Options.List; - this.dropdown.list = this.dropdown.list_data.map(population => - population < 10000 ? population : translate("Unlimited") - ); - this.setSelectedValue(g_GameSettings.population.cap); + const linear = this.gameSettingsController.guiData.linearPopulationCapacity ?? 0.5; + const display = g_GameSettings.population.cap === Infinity ? translate("Unlimited") : + g_GameSettings.population.cap; + this.setSelectedValue(linear, display); } - - onHoverChange() + onValueChange(value) + { + this.gameSettingsController.guiData.linearPopulationCapacity = value; + const popCap = this.linearToLogarythmic(value); + g_GameSettings.population.setPopCap(popCap); + this.setTooltip(popCap); + this.gameSettingsController.setNetworkInitAttributes(); + } + + setTooltip(popCap) { - if (this.dropdown.hovered == -1) - return; let tooltip = g_GameSettings.population.currentData.CapTooltip; - if (this.canTotalPopExceedRecommendedMax()) + if (this.canTotalPopExceedRecommendedMax(popCap)) tooltip = setStringTags(this.WarningTooltip, this.WarningTags); - this.dropdown.tooltip = tooltip; + this.slider.tooltip = tooltip; } - - canTotalPopExceedRecommendedMax() + canTotalPopExceedRecommendedMax(popCap) { - const popCap = g_GameSettings.population.currentData.Options.List[this.dropdown.hovered]; const nbPlayers = g_GameSettings.playerCount.nbPlayers; const nbTeams = g_GameSettings.playerTeam.values.reduce((teamList, team) => { @@ -86,3 +100,6 @@ GameSettingControls.PopulationCap.prototype.WarningTags = { * It means a 4v4 with 150 population can still run nicely, but more than that might "lag". */ GameSettingControls.PopulationCap.prototype.PopulationCapacityRecommendation = 1200; + +GameSettingControls.PopulationCap.prototype.MinValue = 0; +GameSettingControls.PopulationCap.prototype.MaxValue = 1; diff --git a/binaries/data/mods/public/gui/replaymenu/replay_filters.js b/binaries/data/mods/public/gui/replaymenu/replay_filters.js index 62c0b9c865..daa2c42a51 100644 --- a/binaries/data/mods/public/gui/replaymenu/replay_filters.js +++ b/binaries/data/mods/public/gui/replaymenu/replay_filters.js @@ -95,21 +95,11 @@ function initMapNameFilter(filters) */ function initPopCapFilter(filters) { - var populationFilter = Engine.GetGUIObjectByName("populationFilter"); + const populationFilter = Engine.GetGUIObjectByName("populationFilter"); + const popCapSet = new Set(g_Replays.map(replay => replay.attribs.settings.PopulationCap)); + const popCapOptions = [...popCapSet.values()].sort((a, b) => b - a); - // Merge the pop cap options of all pop cap types into one single list. - const popCapOptions = g_PopulationCapacities.Options - .map(item => item.List) - .flat() - .reduce((list, cap) => - { - if (!list.includes(cap)) - list.push(cap); - return list; - }, []) - .sort((a, b) => a > b); - - populationFilter.list = [translateWithContext("population capacity", "Any")].concat(popCapOptions.map(cap => cap >= 10000 ? "Unlimited" : cap)); + populationFilter.list = [translateWithContext("population capacity", "Any")].concat(popCapOptions.map(cap => cap === Infinity ? "Unlimited" : cap)); populationFilter.list_data = [""].concat(popCapOptions); if (filters?.popCap) diff --git a/binaries/data/mods/public/gui/replaymenu/replay_menu.js b/binaries/data/mods/public/gui/replaymenu/replay_menu.js index 98cd5f558d..62bf1010a3 100644 --- a/binaries/data/mods/public/gui/replaymenu/replay_menu.js +++ b/binaries/data/mods/public/gui/replaymenu/replay_menu.js @@ -174,8 +174,7 @@ function sanitizeInitAttributes(attribs) if (!attribs.settings.PlayerData) attribs.settings.PlayerData = []; - if (!attribs.settings.PopulationCap) - attribs.settings.PopulationCap = 300; + attribs.settings.PopulationCap ??= Infinity; if (!attribs.settings.PopulationCapType) attribs.settings.PopulationCapType = diff --git a/binaries/data/mods/public/gui/session/top_panel/CounterPopulation.js b/binaries/data/mods/public/gui/session/top_panel/CounterPopulation.js index 654693282c..e2cf030d49 100644 --- a/binaries/data/mods/public/gui/session/top_panel/CounterPopulation.js +++ b/binaries/data/mods/public/gui/session/top_panel/CounterPopulation.js @@ -18,7 +18,9 @@ class CounterPopulation rebuild(playerState, getAllyStatTooltip) { - this.count.caption = sprintf(translate(this.CounterCaption), playerState); + const state = Object.fromEntries(Object.entries(playerState).map(([key, value]) => + [key, value === Infinity ? translateWithContext("In other places refered as 'Unlimited', here is to litle space.", "∞") : value])); + this.count.caption = sprintf(translate(this.CounterCaption), state); let total = 0; for (const resCode of g_ResourceData.GetCodes()) total += playerState.resourceGatherers[resCode]; diff --git a/binaries/data/mods/public/simulation/data/settings/population_capacities.json b/binaries/data/mods/public/simulation/data/settings/population_capacities.json index d9e9177ced..0db109e842 100644 --- a/binaries/data/mods/public/simulation/data/settings/population_capacities.json +++ b/binaries/data/mods/public/simulation/data/settings/population_capacities.json @@ -9,10 +9,7 @@ "Tooltip": "Locked population cap for all players.", "CapTooltip": "Choose the player population cap.", "Default": true, - "Options": { - "List": [50, 100, 150, 200, 250, 300, 10000], - "Default": 300 - } + "Factor": 300 }, { "Name": "team", @@ -20,10 +17,7 @@ "CapTitle": "Team Population Cap", "Tooltip": "Distributes a team's total population cap evenly over all its living members. Enables the setting 'Locked teams'.", "CapTooltip": "Choose the team population cap.", - "Options": { - "List": [100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 700, 800, 1000, 10000], - "Default": 400 - } + "Factor": 400 }, { "Name": "world", @@ -31,10 +25,7 @@ "CapTitle": "World Population Cap", "Tooltip": "Distributes the total population cap evenly over all living players.", "CapTooltip": "Choose the world population cap.", - "Options": { - "List": [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1600, 2000, 2400, 10000], - "Default": 600 - } + "Factor": 600 } ] } diff --git a/binaries/data/mods/public/simulation/helpers/InitGame.js b/binaries/data/mods/public/simulation/helpers/InitGame.js index 1af2bd9645..d4c8875665 100644 --- a/binaries/data/mods/public/simulation/helpers/InitGame.js +++ b/binaries/data/mods/public/simulation/helpers/InitGame.js @@ -65,7 +65,7 @@ function InitGame(settings) } { - const popCap = settings.PopulationCap || 300; + const popCap = settings.PopulationCap ?? Infinity; const cmpPopulationCapManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PopulationCapManager); const nonGaiaPlayers = settings.PlayerData.slice(1); if (nonGaiaPlayers.some(player => player.PopulationLimit))