mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Add a 'team population' gamesetting
Remove the world population setting from the game setup. Add a dropdown for choosing the "Population Cap Type". (-> containing Player Population, World Population, Team Population) Use a single "Population Cap" dropdown adapting to the pop cap types. Move all population data into a single .json file. New system component "PopulationCapManager" for distributing pop caps. Resolves: #6918
This commit is contained in:
parent
c448973398
commit
5741f77c6e
28 changed files with 531 additions and 308 deletions
|
|
@ -5,6 +5,7 @@ GameSettings.prototype.Attributes.LockedTeams = class LockedTeams extends GameSe
|
|||
this.enabled = false;
|
||||
this.settings.map.watch(() => this.onMapChange(), ["map"]);
|
||||
this.settings.rating.watch(() => this.onRatingChange(), ["enabled"]);
|
||||
this.settings.population.watch(() => this.onPopCapTypeChange(), ["capType"]);
|
||||
this.onRatingChange();
|
||||
}
|
||||
|
||||
|
|
@ -20,20 +21,25 @@ GameSettings.prototype.Attributes.LockedTeams = class LockedTeams extends GameSe
|
|||
|
||||
onMapChange()
|
||||
{
|
||||
if (this.settings.map.type != "scenario")
|
||||
return;
|
||||
this.setAvailable(this.settings.map.type != "scenario");
|
||||
this.setEnabled(!!this.getMapSetting("LockTeams"));
|
||||
}
|
||||
|
||||
onRatingChange()
|
||||
{
|
||||
if (this.settings.rating.enabled)
|
||||
{
|
||||
this.available = false;
|
||||
this.setEnabled(true);
|
||||
}
|
||||
else
|
||||
this.available = true;
|
||||
this.setAvailable(!this.settings.rating.enabled);
|
||||
this.setEnabled(this.settings.rating.enabled);
|
||||
}
|
||||
|
||||
onPopCapTypeChange()
|
||||
{
|
||||
this.setAvailable(this.settings.population.capType != "team");
|
||||
this.setEnabled(this.settings.population.capType == "team");
|
||||
}
|
||||
|
||||
setAvailable(available)
|
||||
{
|
||||
this.available = available;
|
||||
}
|
||||
|
||||
setEnabled(enabled)
|
||||
|
|
|
|||
|
|
@ -1,23 +1,21 @@
|
|||
/**
|
||||
* Combines the worldPopulation and regular population cap.
|
||||
* At the moment those are incompatible so this makes sense.
|
||||
* Manages the maximum population capacity.
|
||||
* This includes the cap value itself and its type (determining how to distribute the set cap among players).
|
||||
* TODO: Should there be a dialog allowing per-player pop limits?
|
||||
*/
|
||||
GameSettings.prototype.Attributes.Population = class Population extends GameSetting
|
||||
{
|
||||
init()
|
||||
{
|
||||
this.popDefault = this.getDefaultValue("PopulationCapacities", "Population") || 200;
|
||||
this.worldPopDefault = this.getDefaultValue("WorldPopulationCapacities", "Population") || 800;
|
||||
|
||||
this.perPlayer = false;
|
||||
this.useWorldPop = false;
|
||||
this.cap = this.popDefault;
|
||||
this.perPlayer = null;
|
||||
this.capTypeDefault = this.getDefaultValue("PopulationCapacities", "Name");
|
||||
this.setPopCapType(this.capTypeDefault);
|
||||
this.settings.map.watch(() => this.onMapChange(), ["map"]);
|
||||
}
|
||||
|
||||
toInitAttributes(attribs)
|
||||
{
|
||||
attribs.settings.PopulationCapType = this.capType;
|
||||
if (this.perPlayer)
|
||||
{
|
||||
if (!attribs.settings.PlayerData)
|
||||
|
|
@ -28,48 +26,45 @@ GameSettings.prototype.Attributes.Population = class Population extends GameSett
|
|||
if (this.perPlayer[i])
|
||||
attribs.settings.PlayerData[i].PopulationLimit = this.perPlayer[i];
|
||||
}
|
||||
if (this.useWorldPop)
|
||||
{
|
||||
attribs.settings.WorldPopulation = true;
|
||||
attribs.settings.WorldPopulationCap = this.cap;
|
||||
}
|
||||
else
|
||||
attribs.settings.PopulationCap = this.cap;
|
||||
}
|
||||
|
||||
fromInitAttributes(attribs)
|
||||
{
|
||||
if (!!this.getLegacySetting(attribs, "WorldPopulation"))
|
||||
this.setPopCap(true, this.getLegacySetting(attribs, "WorldPopulationCap"));
|
||||
else if (!!this.getLegacySetting(attribs, "PopulationCap"))
|
||||
this.setPopCap(false, this.getLegacySetting(attribs, "PopulationCap"));
|
||||
if (this.getLegacySetting(attribs, "PopulationCapType") !== undefined)
|
||||
this.setPopCapType(this.getLegacySetting(attribs, "PopulationCapType"));
|
||||
|
||||
if (this.getLegacySetting(attribs, "PopulationCap") !== undefined)
|
||||
this.setPopCap(this.getLegacySetting(attribs, "PopulationCap"));
|
||||
}
|
||||
|
||||
onMapChange()
|
||||
{
|
||||
this.perPlayer = undefined;
|
||||
this.perPlayer = null;
|
||||
if (this.settings.map.type != "scenario")
|
||||
return;
|
||||
|
||||
if (this.getMapSetting("PlayerData")?.some(data => data.PopulationLimit))
|
||||
{
|
||||
this.perPlayer = this.getMapSetting("PlayerData").map(data => data.PopulationLimit || undefined);
|
||||
else if (this.getMapSetting("WorldPopulation"))
|
||||
this.setPopCap(true, +this.getMapSetting("WorldPopulationCap"));
|
||||
else
|
||||
this.setPopCap(false, +this.getMapSetting("PopulationCap"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.setPopCapType(this.getMapSetting("PopulationCapType") || this.capTypeDefault);
|
||||
if (this.getMapSetting("PopulationCap"))
|
||||
this.setPopCap(this.getMapSetting("PopulationCap"));
|
||||
}
|
||||
|
||||
setPopCap(worldPop, cap = undefined)
|
||||
setPopCap(cap)
|
||||
{
|
||||
if (worldPop != this.useWorldPop)
|
||||
this.cap = undefined;
|
||||
this.cap = cap;
|
||||
}
|
||||
|
||||
this.useWorldPop = worldPop;
|
||||
|
||||
if (!!cap)
|
||||
this.cap = cap;
|
||||
else if (!this.cap && !this.useWorldPop)
|
||||
this.cap = this.popDefault;
|
||||
else if (!this.cap && this.useWorldPop)
|
||||
this.cap = this.worldPopDefault;
|
||||
setPopCapType(capType)
|
||||
{
|
||||
this.capType = capType;
|
||||
this.currentData = g_Settings.PopulationCapacities.find(type => type.Name == capType);
|
||||
this.setPopCap(this.currentData.Options.Default);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -360,25 +360,21 @@ function getGameDescription(initAttributes, mapCache)
|
|||
})
|
||||
});
|
||||
|
||||
if (initAttributes.settings.PopulationCap !== undefined)
|
||||
if (initAttributes.settings.PopulationCapType !== undefined)
|
||||
titles.push({
|
||||
"label": translate("Population Limit"),
|
||||
"value":
|
||||
initAttributes.settings.PlayerData &&
|
||||
initAttributes.settings.PlayerData.some(pData => pData && pData.PopulationLimit !== undefined) ?
|
||||
translateWithContext("population limit", "Per Player") :
|
||||
g_PopulationCapacities.Title[
|
||||
g_PopulationCapacities.Population.indexOf(
|
||||
initAttributes.settings.PopulationCap)]
|
||||
"label": translate("Population Cap Type"),
|
||||
"value": translate(g_PopulationCapacities.Title[g_PopulationCapacities.Name.indexOf(initAttributes.settings.PopulationCapType)])
|
||||
});
|
||||
|
||||
if (initAttributes.settings.WorldPopulationCap !== undefined)
|
||||
if (initAttributes.settings.PopulationCap !== undefined)
|
||||
titles.push({
|
||||
"label": translate("World Population Cap"),
|
||||
"label": translate(g_PopulationCapacities.CapTitle[g_PopulationCapacities.Name.indexOf(initAttributes.settings.PopulationCapType)]),
|
||||
"value":
|
||||
g_WorldPopulationCapacities.Title[
|
||||
g_WorldPopulationCapacities.Population.indexOf(
|
||||
initAttributes.settings.WorldPopulationCap)]
|
||||
initAttributes.settings.PlayerData?.some(pData => pData?.PopulationLimit !== undefined) ?
|
||||
translateWithContext("population capacity", "Per Player") :
|
||||
initAttributes.settings.PopulationCap < 10000 ?
|
||||
initAttributes.settings.PopulationCap :
|
||||
translateWithContext("population capacity", "Unlimited")
|
||||
});
|
||||
|
||||
titles.push({
|
||||
|
|
|
|||
|
|
@ -43,8 +43,7 @@ function loadSettingsValues()
|
|||
"MapSizes": loadSettingValuesFile("map_sizes.json"),
|
||||
"Biomes": loadBiomes(),
|
||||
"PlayerDefaults": loadPlayerDefaults(),
|
||||
"PopulationCapacities": loadPopulationCapacities(),
|
||||
"WorldPopulationCapacities": loadWorldPopulationCapacities(),
|
||||
"PopulationCapacities": loadSettingValuesFile("population_capacities.json"),
|
||||
"StartingResources": loadSettingValuesFile("starting_resources.json"),
|
||||
"VictoryConditions": loadVictoryConditions(),
|
||||
"TriggerDifficulties": loadSettingValuesFile("trigger_difficulties.json")
|
||||
|
|
@ -250,51 +249,6 @@ function loadPlayerDefaults()
|
|||
return json.PlayerData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads available population capacities.
|
||||
*
|
||||
* @returns {Array|undefined}
|
||||
*/
|
||||
function loadPopulationCapacities()
|
||||
{
|
||||
var json = Engine.ReadJSONFile(g_SettingsDirectory + "population_capacities.json");
|
||||
|
||||
if (!json || json.Default === undefined || !json.PopulationCapacities || !Array.isArray(json.PopulationCapacities))
|
||||
{
|
||||
error("Could not load population_capacities.json");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return json.PopulationCapacities.map(population => ({
|
||||
"Population": population,
|
||||
"Default": population == json.Default,
|
||||
"Title": population < 10000 ? population : translate("Unlimited")
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads available world population capacities.
|
||||
*
|
||||
* @returns {Object[]|undefined} - An array of the world population capacities in the form:
|
||||
* { "Population": number, "Default": number, "Title": number|String }.
|
||||
*/
|
||||
function loadWorldPopulationCapacities()
|
||||
{
|
||||
let json = Engine.ReadJSONFile(g_SettingsDirectory + "world_population_capacities.json");
|
||||
|
||||
if (!json || json.Default === undefined || !json.WorldPopulationCapacities || !Array.isArray(json.WorldPopulationCapacities))
|
||||
{
|
||||
error("Could not load population_capacities.json");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return json.WorldPopulationCapacities.map(population => ({
|
||||
"Population": population,
|
||||
"Default": population == json.Default,
|
||||
"Title": population < 10000 ? population : translate("Unlimited")
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object with all values of that property of the given setting and
|
||||
* finds the index of the default value.
|
||||
|
|
@ -391,21 +345,22 @@ function translateMapSize(tiles)
|
|||
/**
|
||||
* Returns title or placeholder.
|
||||
*
|
||||
* @param {number} population
|
||||
* @param {boolean} world - Whether the entry has world population enabled.
|
||||
* @param {number} popCap
|
||||
* @param {string} popCapType - "player", "team", or "world"
|
||||
* @returns {string}
|
||||
*/
|
||||
function translatePopulationCapacity(population, world)
|
||||
function translatePopulationCapacity(popCap, popCapType)
|
||||
{
|
||||
if (world)
|
||||
{
|
||||
let popCap = g_Settings.WorldPopulationCapacities.find(p => p.Population == population);
|
||||
return popCap ? popCap.Title + " " + translateWithContext("population capacity addendum", "(world)") :
|
||||
translateWithContext("population capacity", "Unknown");
|
||||
}
|
||||
const popCapTypeData = g_Settings.PopulationCapacities.find(type => type.Name == popCapType);
|
||||
if (!popCapTypeData)
|
||||
return translateWithContext("population capacity", "Unknown");
|
||||
|
||||
let popCap = g_Settings.PopulationCapacities.find(p => p.Population == population);
|
||||
return popCap ? popCap.Title : translateWithContext("population capacity", "Unknown");
|
||||
return popCap >= 10000 ?
|
||||
translateWithContext("population capacity", "Unlimited") :
|
||||
sprintf(translate("%(populationCapacity)s (%(populationCapacityType)s)"), {
|
||||
"populationCapacity": popCap,
|
||||
"populationCapacityType": popCapType
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,9 +29,8 @@ var g_GameSettingsLayout = [
|
|||
"label": translateWithContext("Match settings tab name", "Player"),
|
||||
"settings": [
|
||||
"PlayerCount",
|
||||
"WorldPopulation",
|
||||
"PopulationCapType",
|
||||
"PopulationCap",
|
||||
"WorldPopulationCap",
|
||||
"StartingResources",
|
||||
"Spies",
|
||||
"Cheats"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ GameSettingControls.LockedTeams = class LockedTeams extends GameSettingControlCh
|
|||
super(...args);
|
||||
g_GameSettings.map.watch(() => this.render(), ["type"]);
|
||||
g_GameSettings.lockedTeams.watch(() => this.render(), ["available", "enabled"]);
|
||||
g_GameSettings.population.watch(() => this.render(), ["capType"]);
|
||||
g_GameSettings.rating.watch(() => this.render(), ["enabled"]);
|
||||
this.render();
|
||||
}
|
||||
|
||||
|
|
@ -15,7 +17,7 @@ GameSettingControls.LockedTeams = class LockedTeams extends GameSettingControlCh
|
|||
|
||||
render()
|
||||
{
|
||||
this.setEnabled(g_GameSettings.map.type != "scenario" && g_GameSettings.lockedTeams.available);
|
||||
this.setEnabled(g_GameSettings.lockedTeams.available);
|
||||
this.setChecked(g_GameSettings.lockedTeams.enabled);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
GameSettingControls.WorldPopulation = class WorldPopulation extends GameSettingControlCheckbox
|
||||
{
|
||||
constructor(...args)
|
||||
{
|
||||
super(...args);
|
||||
g_GameSettings.population.watch(() => this.render(), ["useWorldPop"]);
|
||||
g_GameSettings.map.watch(() => this.render(), ["type"]);
|
||||
this.render();
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
this.setEnabled(g_GameSettings.map.type != "scenario");
|
||||
this.setChecked(g_GameSettings.population.useWorldPop);
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
g_GameSettings.population.setPopCap(checked);
|
||||
this.gameSettingsController.setNetworkInitAttributes();
|
||||
}
|
||||
};
|
||||
|
||||
GameSettingControls.WorldPopulation.prototype.TitleCaption =
|
||||
translate("World Population");
|
||||
|
||||
GameSettingControls.WorldPopulation.prototype.Tooltip =
|
||||
translate("When checked the Population Cap will be evenly distributed over all living players.");
|
||||
|
|
@ -1,66 +1,82 @@
|
|||
const CAPTYPE_PLAYER_POPULATION = "player";
|
||||
const CAPTYPE_TEAM_POPULATION = "team";
|
||||
const CAPTYPE_WORLD_POPULATION = "world";
|
||||
|
||||
GameSettingControls.PopulationCap = class PopulationCap extends GameSettingControlDropdown
|
||||
{
|
||||
constructor(...args)
|
||||
{
|
||||
super(...args);
|
||||
|
||||
this.dropdown.list = g_PopulationCapacities.Title;
|
||||
this.dropdown.list_data = g_PopulationCapacities.Population;
|
||||
|
||||
this.sprintfArgs = {};
|
||||
|
||||
g_GameSettings.population.watch(() => this.render(), ["useWorldPop", "cap", "perPlayer"]);
|
||||
g_GameSettings.population.watch(() => this.render(), ["cap", "perPlayer"]);
|
||||
g_GameSettings.map.watch(() => this.render(), ["type"]);
|
||||
this.render();
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
this.setHidden(g_GameSettings.population.useWorldPop);
|
||||
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;
|
||||
else
|
||||
this.setSelectedValue(g_GameSettings.population.cap);
|
||||
if (!this.enabled)
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
onHoverChange()
|
||||
{
|
||||
let tooltip = this.Tooltip;
|
||||
if (this.dropdown.hovered != -1)
|
||||
{
|
||||
let popCap = g_PopulationCapacities.Population[this.dropdown.hovered];
|
||||
let players = g_GameSettings.playerCount.nbPlayers;
|
||||
if (popCap * players >= this.PopulationCapacityRecommendation)
|
||||
{
|
||||
this.sprintfArgs.players = players;
|
||||
this.sprintfArgs.popCap = popCap;
|
||||
tooltip = setStringTags(sprintf(this.HoverTooltip, this.sprintfArgs), this.HoverTags);
|
||||
}
|
||||
}
|
||||
if (this.dropdown.hovered == -1)
|
||||
return;
|
||||
let tooltip = g_GameSettings.population.currentData.CapTooltip;
|
||||
if (this.canTotalPopExceedRecommendedMax())
|
||||
tooltip = setStringTags(this.WarningTooltip, this.WarningTags);
|
||||
|
||||
this.dropdown.tooltip = tooltip;
|
||||
}
|
||||
|
||||
|
||||
canTotalPopExceedRecommendedMax()
|
||||
{
|
||||
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) => {
|
||||
if (!teamList.includes(team) || team == -1)
|
||||
teamList.push(team);
|
||||
return teamList;
|
||||
}, []).length;
|
||||
|
||||
switch (g_GameSettings.population.capType)
|
||||
{
|
||||
case CAPTYPE_PLAYER_POPULATION: return nbPlayers * popCap > this.PopulationCapacityRecommendation;
|
||||
case CAPTYPE_TEAM_POPULATION: return nbTeams * popCap > this.PopulationCapacityRecommendation;
|
||||
case CAPTYPE_WORLD_POPULATION: return popCap > this.PopulationCapacityRecommendation;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
onSelectionChange(itemIdx)
|
||||
{
|
||||
g_GameSettings.population.setPopCap(false, g_PopulationCapacities.Population[itemIdx]);
|
||||
g_GameSettings.population.setPopCap(g_GameSettings.population.currentData.Options.List[itemIdx]);
|
||||
this.gameSettingsController.setNetworkInitAttributes();
|
||||
}
|
||||
};
|
||||
|
||||
GameSettingControls.PopulationCap.prototype.TitleCaption =
|
||||
translate("Population Cap");
|
||||
|
||||
GameSettingControls.PopulationCap.prototype.Tooltip =
|
||||
translate("Select population limit.");
|
||||
|
||||
GameSettingControls.PopulationCap.prototype.PerPlayerCaption =
|
||||
translateWithContext("population limit", "Per Player");
|
||||
|
||||
GameSettingControls.PopulationCap.prototype.HoverTooltip =
|
||||
translate("Warning: There might be performance issues if all %(players)s players reach %(popCap)s population.");
|
||||
GameSettingControls.PopulationCap.prototype.WarningTooltip =
|
||||
translate("Warning: These settings can result in significant lag when all players reach their maximum population capacity.");
|
||||
|
||||
GameSettingControls.PopulationCap.prototype.HoverTags = {
|
||||
GameSettingControls.PopulationCap.prototype.WarningTags = {
|
||||
"color": "orange"
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
GameSettingControls.PopulationCapType = class PopulationCapType extends GameSettingControlDropdown
|
||||
{
|
||||
constructor(...args)
|
||||
{
|
||||
super(...args);
|
||||
|
||||
this.dropdown.list = g_PopulationCapacities.Title;
|
||||
this.dropdown.list_data = g_PopulationCapacities.Name;
|
||||
|
||||
g_GameSettings.population.watch(() => this.render(), ["capType"]);
|
||||
g_GameSettings.map.watch(() => this.render(), ["type"]);
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
this.setSelectedValue(g_GameSettings.population.capType);
|
||||
this.setEnabled(g_GameSettings.map.type != "scenario");
|
||||
}
|
||||
|
||||
onHoverChange()
|
||||
{
|
||||
this.dropdown.tooltip = g_PopulationCapacities.Tooltip[this.dropdown.hovered] || this.Tooltip;
|
||||
}
|
||||
|
||||
onSelectionChange(itemIdx)
|
||||
{
|
||||
g_GameSettings.population.setPopCapType(g_PopulationCapacities.Name[itemIdx]);
|
||||
this.gameSettingsController.setNetworkInitAttributes();
|
||||
}
|
||||
};
|
||||
|
||||
GameSettingControls.PopulationCapType.prototype.TitleCaption =
|
||||
translate("Population Cap Type");
|
||||
|
||||
GameSettingControls.PopulationCapType.prototype.Tooltip =
|
||||
translate("Select a population capacity type.");
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
GameSettingControls.WorldPopulationCap = class WorldPopulationCap extends GameSettingControlDropdown
|
||||
{
|
||||
constructor(...args)
|
||||
{
|
||||
super(...args);
|
||||
|
||||
this.dropdown.list = g_WorldPopulationCapacities.Title;
|
||||
this.dropdown.list_data = g_WorldPopulationCapacities.Population;
|
||||
|
||||
this.sprintfArgs = {};
|
||||
|
||||
g_GameSettings.population.watch(() => this.render(), ["useWorldPop", "cap"]);
|
||||
g_GameSettings.map.watch(() => this.render(), ["type"]);
|
||||
this.render();
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
this.setEnabled(g_GameSettings.map.type != "scenario");
|
||||
this.setHidden(!g_GameSettings.population.useWorldPop);
|
||||
this.setSelectedValue(g_GameSettings.population.cap);
|
||||
}
|
||||
|
||||
onHoverChange()
|
||||
{
|
||||
let tooltip = this.Tooltip;
|
||||
if (this.dropdown.hovered != -1)
|
||||
{
|
||||
let popCap = g_WorldPopulationCapacities.Population[this.dropdown.hovered];
|
||||
if (popCap >= this.WorldPopulationCapacityRecommendation)
|
||||
{
|
||||
this.sprintfArgs.popCap = popCap;
|
||||
tooltip = setStringTags(sprintf(this.HoverTooltip, this.sprintfArgs), this.HoverTags);
|
||||
}
|
||||
}
|
||||
this.dropdown.tooltip = tooltip;
|
||||
}
|
||||
|
||||
onSelectionChange(itemIdx)
|
||||
{
|
||||
g_GameSettings.population.setPopCap(true, g_WorldPopulationCapacities.Population[itemIdx]);
|
||||
this.gameSettingsController.setNetworkInitAttributes();
|
||||
}
|
||||
};
|
||||
|
||||
GameSettingControls.WorldPopulationCap.prototype.TitleCaption =
|
||||
translate("World Population Cap");
|
||||
|
||||
GameSettingControls.WorldPopulationCap.prototype.Tooltip =
|
||||
translate("Select world population limit.");
|
||||
|
||||
GameSettingControls.WorldPopulationCap.prototype.HoverTooltip =
|
||||
translate("Warning: There might be performance issues if %(popCap)s population is reached.");
|
||||
|
||||
GameSettingControls.WorldPopulationCap.prototype.HoverTags = {
|
||||
"color": "orange"
|
||||
};
|
||||
|
||||
/**
|
||||
* Total number of units that the engine can run with smoothly.
|
||||
*/
|
||||
GameSettingControls.WorldPopulationCap.prototype.WorldPopulationCapacityRecommendation = 1200;
|
||||
|
|
@ -25,7 +25,7 @@ class GameDescription
|
|||
g_GameSettings.mapExploration.watch(update, ["revealed"]);
|
||||
g_GameSettings.mapExploration.watch(update, ["allied"]);
|
||||
g_GameSettings.nomad.watch(update, ["enabled"]);
|
||||
g_GameSettings.population.watch(update, ["perPlayer", "cap", "useWorldPop"]);
|
||||
g_GameSettings.population.watch(update, ["perPlayer", "cap", "capType"]);
|
||||
g_GameSettings.rating.watch(update, ["enabled"]);
|
||||
g_GameSettings.regicideGarrison.watch(update, ["enabled"]);
|
||||
g_GameSettings.relic.watch(update, ["count", "duration"]);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
const g_MapSizes = prepareForDropdown(g_Settings && g_Settings.MapSizes);
|
||||
const g_MapTypes = prepareForDropdown(g_Settings && g_Settings.MapTypes);
|
||||
const g_PopulationCapacities = prepareForDropdown(g_Settings && g_Settings.PopulationCapacities);
|
||||
const g_WorldPopulationCapacities = prepareForDropdown(g_Settings && g_Settings.WorldPopulationCapacities);
|
||||
const g_StartingResources = prepareForDropdown(g_Settings && g_Settings.StartingResources);
|
||||
const g_VictoryConditions = g_Settings && g_Settings.VictoryConditions;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ var g_DurationFilterIntervals = [
|
|||
* Allow to filter by population capacity.
|
||||
*/
|
||||
const g_PopulationCapacities = prepareForDropdown(g_Settings && g_Settings.PopulationCapacities);
|
||||
const g_WorldPopulationCapacities = prepareForDropdown(g_Settings && g_Settings.WorldPopulationCapacities);
|
||||
|
||||
/**
|
||||
* Reloads the selectable values in the filters. The filters depend on g_Settings and g_Replays
|
||||
|
|
@ -97,10 +96,22 @@ function initMapNameFilter(filters)
|
|||
function initPopCapFilter(filters)
|
||||
{
|
||||
var populationFilter = Engine.GetGUIObjectByName("populationFilter");
|
||||
populationFilter.list = [translateWithContext("population capacity", "Any")].concat(g_PopulationCapacities.Title);
|
||||
populationFilter.list_data = [""].concat(g_PopulationCapacities.Population);
|
||||
|
||||
if (filters && filters.popCap)
|
||||
// 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_data = [""].concat(popCapOptions);
|
||||
|
||||
if (filters?.popCap)
|
||||
populationFilter.selected = populationFilter.list_data.indexOf(filters.popCap);
|
||||
|
||||
if (populationFilter.selected == -1 || populationFilter.selected >= populationFilter.list.length)
|
||||
|
|
@ -191,7 +202,7 @@ function filterReplays()
|
|||
let sortOrder = Engine.GetGUIObjectByName("replaySelection").selected_column_order;
|
||||
|
||||
g_ReplaysFiltered = g_Replays.filter(replay => filterReplay(replay)).sort((a, b) => {
|
||||
let cmpA, cmpB;
|
||||
let cmpA, cmpB, cmpA_secondary, cmpB_secondary;
|
||||
switch (sortKey)
|
||||
{
|
||||
case 'months':
|
||||
|
|
@ -217,6 +228,8 @@ function filterReplays()
|
|||
case 'popCapacity':
|
||||
cmpA = +a.attribs.settings.PopulationCap;
|
||||
cmpB = +b.attribs.settings.PopulationCap;
|
||||
cmpA_secondary = g_PopulationCapacities.Name.indexOf(a.attribs.settings.PopulationCapType);
|
||||
cmpB_secondary = g_PopulationCapacities.Name.indexOf(b.attribs.settings.PopulationCapType);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -225,6 +238,12 @@ function filterReplays()
|
|||
else if (cmpA > cmpB)
|
||||
return +sortOrder;
|
||||
|
||||
else if(cmpA_secondary && cmpB_secondary)
|
||||
if (cmpA_secondary < cmpB_secondary)
|
||||
return -sortOrder;
|
||||
else if(cmpA_secondary > cmpB_secondary)
|
||||
return +sortOrder;
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,6 +177,12 @@ function sanitizeInitAttributes(attribs)
|
|||
if (!attribs.settings.PopulationCap)
|
||||
attribs.settings.PopulationCap = 300;
|
||||
|
||||
if (!attribs.settings.PopulationCapType)
|
||||
attribs.settings.PopulationCapType =
|
||||
attribs.settings.WorldPopulation ?
|
||||
"world" :
|
||||
"player";
|
||||
|
||||
if (!attribs.mapType)
|
||||
attribs.mapType = "skirmish";
|
||||
|
||||
|
|
@ -228,7 +234,7 @@ function displayReplayList()
|
|||
return {
|
||||
"directories": replay.directory,
|
||||
"months": compatibilityColor(getReplayDateTime(replay), works),
|
||||
"popCaps": compatibilityColor(translatePopulationCapacity(replay.attribs.settings.PopulationCap, !!replay.attribs.settings.WorldPopulation), works),
|
||||
"popCaps": compatibilityColor(translatePopulationCapacity(replay.attribs.settings.PopulationCap, replay.attribs.settings.PopulationCapType), works),
|
||||
"mapNames": compatibilityColor(getReplayMapName(replay), works),
|
||||
"mapSizes": compatibilityColor(translateMapSize(replay.attribs.settings.Size), works),
|
||||
"durations": compatibilityColor(getReplayDuration(replay), works),
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ const g_CivData = loadCivData(false, true);
|
|||
const g_MapSizes = prepareForDropdown(g_Settings && g_Settings.MapSizes);
|
||||
const g_MapTypes = prepareForDropdown(g_Settings && g_Settings.MapTypes);
|
||||
const g_PopulationCapacities = prepareForDropdown(g_Settings && g_Settings.PopulationCapacities);
|
||||
const g_WorldPopulationCapacities = prepareForDropdown(g_Settings && g_Settings.WorldPopulationCapacities);
|
||||
const g_StartingResources = prepareForDropdown(g_Settings && g_Settings.StartingResources);
|
||||
const g_VictoryConditions = g_Settings && g_Settings.VictoryConditions;
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ Diplomacy.prototype.ChangeTeam = function(team)
|
|||
if (this.team !== -1)
|
||||
warn("A change in teams is requested while the player already had a team, previous alliances are maintained.");
|
||||
|
||||
const oldTeam = this.team;
|
||||
this.team = team;
|
||||
|
||||
if (this.team !== -1)
|
||||
|
|
@ -97,9 +98,10 @@ Diplomacy.prototype.ChangeTeam = function(team)
|
|||
}
|
||||
}
|
||||
|
||||
Engine.BroadcastMessage(MT_DiplomacyChanged, {
|
||||
Engine.BroadcastMessage(MT_TeamChanged, {
|
||||
"player": playerID,
|
||||
"otherPlayer": null
|
||||
"oldTeam": oldTeam,
|
||||
"newTeam": team
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,9 @@ GuiInterface.prototype.GetSimulationState = function()
|
|||
ret.victoryConditions = cmpEndGameManager.GetVictoryConditions();
|
||||
ret.alliedVictory = cmpEndGameManager.GetAlliedVictory();
|
||||
|
||||
ret.maxWorldPopulation = cmpPlayerManager.GetMaxWorldPopulation();
|
||||
let cmpPopulationCapManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PopulationCapManager);
|
||||
ret.populationCapType = cmpPopulationCapManager.GetPopulationCapType();
|
||||
ret.populationCap = cmpPopulationCapManager.GetPopulationCap();
|
||||
|
||||
for (let i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -152,35 +152,4 @@ PlayerManager.prototype.RemoveLastPlayer = function()
|
|||
Engine.DestroyEntity(lastId);
|
||||
};
|
||||
|
||||
PlayerManager.prototype.SetMaxWorldPopulation = function(max)
|
||||
{
|
||||
this.maxWorldPopulation = max;
|
||||
this.RedistributeWorldPopulation();
|
||||
};
|
||||
|
||||
PlayerManager.prototype.GetMaxWorldPopulation = function()
|
||||
{
|
||||
return this.maxWorldPopulation;
|
||||
};
|
||||
|
||||
PlayerManager.prototype.RedistributeWorldPopulation = function()
|
||||
{
|
||||
const worldPopulation = this.GetMaxWorldPopulation();
|
||||
if (!worldPopulation)
|
||||
return;
|
||||
|
||||
const activePlayers = this.GetActivePlayers();
|
||||
if (!activePlayers.length)
|
||||
return;
|
||||
|
||||
const newMaxPopulation = worldPopulation / activePlayers.length;
|
||||
for (const playerID of activePlayers)
|
||||
Engine.QueryInterface(this.GetPlayerByID(playerID), IID_Player).SetMaxPopulation(newMaxPopulation);
|
||||
};
|
||||
|
||||
PlayerManager.prototype.OnGlobalPlayerDefeated = function(msg)
|
||||
{
|
||||
this.RedistributeWorldPopulation();
|
||||
};
|
||||
|
||||
Engine.RegisterSystemComponentType(IID_PlayerManager, "PlayerManager", PlayerManager);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,184 @@
|
|||
const CAPTYPE_PLAYER_POPULATION = "player";
|
||||
const CAPTYPE_TEAM_POPULATION = "team";
|
||||
const CAPTYPE_WORLD_POPULATION = "world";
|
||||
|
||||
function PopulationCapManager() {}
|
||||
|
||||
PopulationCapManager.prototype.Schema =
|
||||
"<a:component type='system'/><empty/>";
|
||||
|
||||
PopulationCapManager.prototype.Init = function()
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the pop cap type and, if possible, initialize the first distribution.
|
||||
* @param {string} type
|
||||
*/
|
||||
PopulationCapManager.prototype.SetPopulationCapType = function(type)
|
||||
{
|
||||
if ([CAPTYPE_PLAYER_POPULATION, CAPTYPE_TEAM_POPULATION, CAPTYPE_WORLD_POPULATION].includes(type))
|
||||
this.popCapType = type;
|
||||
else
|
||||
{
|
||||
warn(`Attempted to set an unknown population capacity type: '${type}'. Continuing with type 'Player Population'...`);
|
||||
this.popCapType = CAPTYPE_PLAYER_POPULATION;
|
||||
}
|
||||
if (this.popCap)
|
||||
this.InitializePopCaps();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current pop cap type.
|
||||
* @returns {string}
|
||||
*/
|
||||
PopulationCapManager.prototype.GetPopulationCapType = function()
|
||||
{
|
||||
return this.popCapType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the pop cap and, if possible, initialize the first distribution.
|
||||
* @param {number} cap
|
||||
*/
|
||||
PopulationCapManager.prototype.SetPopulationCap = function(cap)
|
||||
{
|
||||
this.popCap = cap;
|
||||
if (this.popCapType)
|
||||
this.InitializePopCaps();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current pop cap.
|
||||
* @returns {number}
|
||||
*/
|
||||
PopulationCapManager.prototype.GetPopulationCap = function()
|
||||
{
|
||||
return this.popCap;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate and distribute the pop caps for the first time. Called as soon as cap and cap type are set.
|
||||
*/
|
||||
PopulationCapManager.prototype.InitializePopCaps = function()
|
||||
{
|
||||
switch(this.popCapType)
|
||||
{
|
||||
case CAPTYPE_PLAYER_POPULATION:
|
||||
this.InitializePlayerPopCaps();
|
||||
break;
|
||||
|
||||
case CAPTYPE_TEAM_POPULATION:
|
||||
this.InitializeTeamPopCaps();
|
||||
break;
|
||||
|
||||
case CAPTYPE_WORLD_POPULATION:
|
||||
this.RedistributeWorldPopCap();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign all players the same, fixed pop cap.
|
||||
*/
|
||||
PopulationCapManager.prototype.InitializePlayerPopCaps = function()
|
||||
{
|
||||
const players = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetActivePlayers();
|
||||
for (const player of players)
|
||||
QueryPlayerIDInterface(player, IID_Player)
|
||||
.SetMaxPopulation(this.popCap);
|
||||
};
|
||||
|
||||
/**
|
||||
* Loop through all teams and distribute the fixed pop cap among their living members.
|
||||
*/
|
||||
PopulationCapManager.prototype.InitializeTeamPopCaps = function()
|
||||
{
|
||||
const players = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetActivePlayers();
|
||||
let processedTeams = [];
|
||||
for (const player of players)
|
||||
{
|
||||
const team = QueryPlayerIDInterface(player, IID_Diplomacy).GetTeam();
|
||||
if (processedTeams.includes(team))
|
||||
continue;
|
||||
processedTeams.push(team);
|
||||
this.RedistributeTeamPopCap(team);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Recalculate and update a single team's members' pop caps.
|
||||
* @param {number} team - ID specifying the team.
|
||||
*/
|
||||
PopulationCapManager.prototype.RedistributeTeamPopCap = function(team)
|
||||
{
|
||||
const activePlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetActivePlayers();
|
||||
const teamMembers = activePlayers.reduce((list, player) => {
|
||||
if (QueryPlayerIDInterface(player, IID_Diplomacy).GetTeam() === team)
|
||||
list.push(player);
|
||||
return list;
|
||||
}, []);
|
||||
|
||||
// Players of team -1 aren't part of any team and need to be assigned the full team pop cap.
|
||||
const newPopulationCap = team === -1 ? this.popCap : Math.round(this.popCap / teamMembers.length);
|
||||
for (const teamMember of teamMembers)
|
||||
QueryPlayerIDInterface(teamMember, IID_Player)
|
||||
.SetMaxPopulation(newPopulationCap);
|
||||
};
|
||||
|
||||
/**
|
||||
* Recalculate the players' new pop cap and assign it to all of them.
|
||||
*/
|
||||
PopulationCapManager.prototype.RedistributeWorldPopCap = function()
|
||||
{
|
||||
const activePlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetActivePlayers();
|
||||
if (!activePlayers.length)
|
||||
return;
|
||||
|
||||
const newPopulationCap = Math.round(this.popCap / activePlayers.length);
|
||||
for (const player of activePlayers)
|
||||
QueryPlayerIDInterface(player, IID_Player).SetMaxPopulation(newPopulationCap);
|
||||
};
|
||||
|
||||
/**
|
||||
* Redistribute the pop caps depending on the pop cap type.
|
||||
* @param {number} msg.playerId - the defeated player's ID.
|
||||
*/
|
||||
PopulationCapManager.prototype.OnGlobalPlayerDefeated = function(msg)
|
||||
{
|
||||
switch(this.popCapType)
|
||||
{
|
||||
case CAPTYPE_TEAM_POPULATION:
|
||||
const team = QueryPlayerIDInterface(msg.playerId, IID_Diplomacy).GetTeam();
|
||||
if (team != -1)
|
||||
this.RedistributeTeamPopCap(team);
|
||||
break;
|
||||
|
||||
case CAPTYPE_WORLD_POPULATION:
|
||||
this.RedistributeWorldPopCap();
|
||||
break;
|
||||
|
||||
case CAPTYPE_PLAYER_POPULATION:
|
||||
default: break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Redistribute pop caps when a player is moved from one team to another.
|
||||
* @param {number} msg.player - the ID of the player.
|
||||
* @param {number} msg.oldTeam - the ID of the team the player was previously part of.
|
||||
* @param {number} msg.newTeam - the ID of the team the player is moved to.
|
||||
*/
|
||||
PopulationCapManager.prototype.OnTeamChanged = function(msg)
|
||||
{
|
||||
if (this.popCapType != CAPTYPE_TEAM_POPULATION)
|
||||
return;
|
||||
|
||||
this.RedistributeTeamPopCap(msg.oldTeam);
|
||||
this.RedistributeTeamPopCap(msg.newTeam);
|
||||
};
|
||||
|
||||
Engine.RegisterSystemComponentType(IID_PopulationCapManager, "PopulationCapManager", PopulationCapManager);
|
||||
|
|
@ -5,3 +5,9 @@ Engine.RegisterInterface("Diplomacy");
|
|||
* sent from Diplomacy component when diplomacy changed for one player or between two players.
|
||||
*/
|
||||
Engine.RegisterMessageType("DiplomacyChanged");
|
||||
|
||||
/**
|
||||
* Message of the form { "player": number, "oldTeam": number, "newTeam", number }
|
||||
* sent from the Diplomacy component when a player switches teams.
|
||||
*/
|
||||
Engine.RegisterMessageType("TeamChanged");
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Engine.RegisterInterface("PopulationCapManager");
|
||||
|
|
@ -22,6 +22,7 @@ Engine.LoadComponentScript("interfaces/Loot.js");
|
|||
Engine.LoadComponentScript("interfaces/Market.js");
|
||||
Engine.LoadComponentScript("interfaces/Pack.js");
|
||||
Engine.LoadComponentScript("interfaces/Population.js");
|
||||
Engine.LoadComponentScript("interfaces/PopulationCapManager.js");
|
||||
Engine.LoadComponentScript("interfaces/ProductionQueue.js");
|
||||
Engine.LoadComponentScript("interfaces/Promotion.js");
|
||||
Engine.LoadComponentScript("interfaces/Repairable.js");
|
||||
|
|
@ -95,6 +96,11 @@ AddMock(SYSTEM_ENTITY, IID_TemplateManager, {
|
|||
"GetTemplate": function(name) { return ""; }
|
||||
});
|
||||
|
||||
AddMock(SYSTEM_ENTITY, IID_PopulationCapManager, {
|
||||
"GetPopulationCapType": function() { return "player"; },
|
||||
"GetPopulationCap": function() { return 200; }
|
||||
});
|
||||
|
||||
AddMock(SYSTEM_ENTITY, IID_Timer, {
|
||||
"GetTime": function() { return 0; },
|
||||
"SetTimeout": function(ent, iid, funcname, time, data) { return 0; }
|
||||
|
|
@ -404,7 +410,8 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
|
|||
"timeElapsed": 0,
|
||||
"victoryConditions": ["conquest", "wonder"],
|
||||
"alliedVictory": false,
|
||||
"maxWorldPopulation": undefined
|
||||
"populationCapType": "player",
|
||||
"populationCap": 200
|
||||
});
|
||||
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
||||
|
|
@ -562,7 +569,8 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
|||
"timeElapsed": 0,
|
||||
"victoryConditions": ["conquest", "wonder"],
|
||||
"alliedVictory": false,
|
||||
"maxWorldPopulation": undefined
|
||||
"populationCapType": "player",
|
||||
"populationCap": 200
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
Engine.LoadHelperScript("Player.js");
|
||||
Engine.LoadComponentScript("interfaces/PlayerManager.js");
|
||||
Engine.LoadComponentScript("interfaces/Diplomacy.js");
|
||||
Engine.LoadComponentScript("interfaces/PopulationCapManager.js");
|
||||
Engine.LoadComponentScript("PopulationCapManager.js");
|
||||
|
||||
const CAPTYPE_PLAYER_POPULATION = "player";
|
||||
const CAPTYPE_TEAM_POPULATION = "team";
|
||||
const CAPTYPE_WORLD_POPULATION = "world";
|
||||
|
||||
const cmpPopulationCapManager = ConstructComponent(SYSTEM_ENTITY, "PopulationCapManager");
|
||||
const playerData = [
|
||||
{
|
||||
"team": -1,
|
||||
"state": "active"
|
||||
},
|
||||
{
|
||||
"team": -1,
|
||||
"state": "active"
|
||||
},
|
||||
{
|
||||
"team": -1,
|
||||
"state": "active"
|
||||
},
|
||||
{
|
||||
"team": 0,
|
||||
"state": "active"
|
||||
},
|
||||
{
|
||||
"team": 1,
|
||||
"state": "active"
|
||||
},
|
||||
{
|
||||
"team": 1,
|
||||
"state": "active"
|
||||
},
|
||||
{
|
||||
"team": 1,
|
||||
"state": "active"
|
||||
},
|
||||
{
|
||||
"team": 2,
|
||||
"state": "active"
|
||||
},
|
||||
{
|
||||
"team": 2,
|
||||
"state": "active"
|
||||
}
|
||||
];
|
||||
|
||||
let currentPopCaps = [];
|
||||
|
||||
AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
|
||||
"GetNonGaiaPlayers": () => { return Object.keys(playerData).slice(1); },
|
||||
"GetActivePlayers": () => { return Object.keys(playerData.filter(player => player.state == "active")).slice(1); },
|
||||
"GetPlayerByID": (id) => id
|
||||
});
|
||||
|
||||
for (const playerID in Object.keys(playerData))
|
||||
{
|
||||
AddMock(playerID, IID_Player, {
|
||||
"SetMaxPopulation": (val) => { currentPopCaps[playerID] = Math.round(val); }
|
||||
});
|
||||
AddMock(playerID, IID_Diplomacy, {
|
||||
"GetTeam": () => { return playerData[playerID].team; }
|
||||
});
|
||||
}
|
||||
|
||||
cmpPopulationCapManager.SetPopulationCap(400);
|
||||
cmpPopulationCapManager.SetPopulationCapType(CAPTYPE_PLAYER_POPULATION);
|
||||
TS_ASSERT_UNEVAL_EQUALS(currentPopCaps, [, 400, 400, 400, 400, 400, 400, 400, 400]);
|
||||
|
||||
cmpPopulationCapManager.SetPopulationCapType(CAPTYPE_TEAM_POPULATION);
|
||||
TS_ASSERT_UNEVAL_EQUALS(currentPopCaps, [, 400, 400, 400, 133, 133, 133, 200, 200]);
|
||||
|
||||
playerData[6].team = 2;
|
||||
cmpPopulationCapManager.OnTeamChanged({ "player": 6, "oldTeam": 1, "newTeam": 2 });
|
||||
TS_ASSERT_UNEVAL_EQUALS(currentPopCaps, [, 400, 400, 400, 200, 200, 133, 133, 133]);
|
||||
|
||||
playerData[8].state = "defeated";
|
||||
currentPopCaps.pop();
|
||||
cmpPopulationCapManager.OnGlobalPlayerDefeated({ "playerId": 8 });
|
||||
TS_ASSERT_UNEVAL_EQUALS(currentPopCaps, [, 400, 400, 400, 200, 200, 200, 200]);
|
||||
|
||||
cmpPopulationCapManager.SetPopulationCapType(CAPTYPE_WORLD_POPULATION);
|
||||
TS_ASSERT_UNEVAL_EQUALS(currentPopCaps, [, 57, 57, 57, 57, 57, 57, 57]);
|
||||
|
||||
playerData[7].state = "defeated";
|
||||
currentPopCaps.pop();
|
||||
cmpPopulationCapManager.OnGlobalPlayerDefeated({ "playerId": 7 });
|
||||
TS_ASSERT_UNEVAL_EQUALS(currentPopCaps, [, 67, 67, 67, 67, 67, 67]);
|
||||
|
|
@ -1,4 +1,43 @@
|
|||
{
|
||||
"PopulationCapacities": [50, 100, 150, 200, 250, 300, 10000],
|
||||
"Default": 300
|
||||
"TranslatedKeys": ["Title", "Tooltip", "CapTitle", "CapTooltip", "Appendage"],
|
||||
"Data":
|
||||
[
|
||||
{
|
||||
"Name": "player",
|
||||
"Title": "Player Population",
|
||||
"CapTitle": "Player Population Cap",
|
||||
"Tooltip": "Locked population cap for all players.",
|
||||
"CapTooltip": "Choose the player population cap.",
|
||||
"Appendage": "per player",
|
||||
"Default": true,
|
||||
"Options": {
|
||||
"List": [50, 100, 150, 200, 250, 300, 10000],
|
||||
"Default": 300
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "team",
|
||||
"Title": "Team Population",
|
||||
"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.",
|
||||
"Appendage": "per team",
|
||||
"Options": {
|
||||
"List": [100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 700, 800, 1000, 10000],
|
||||
"Default": 400
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "world",
|
||||
"Title": "World Population",
|
||||
"CapTitle": "World Population Cap",
|
||||
"Tooltip": "Distributes the total population cap evenly over all living players.",
|
||||
"CapTooltip": "Choose the world population cap.",
|
||||
"Appendage": "globally",
|
||||
"Options": {
|
||||
"List": [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1600, 2000, 2400, 10000],
|
||||
"Default": 600
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"WorldPopulationCapacities": [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1600, 2000, 2400, 63000],
|
||||
"Default": 600
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ function Cheat(input)
|
|||
return;
|
||||
|
||||
const cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
||||
const cmpPopulationManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PopulationCapManager);
|
||||
|
||||
switch(input.action)
|
||||
{
|
||||
|
|
@ -24,7 +25,7 @@ function Cheat(input)
|
|||
Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).SetLosRevealAll(-1, true);
|
||||
return;
|
||||
case "maxpopulation":
|
||||
cmpPlayer.SetPopulationBonuses((cmpPlayerManager.GetMaxWorldPopulation() || cmpPlayer.GetMaxPopulation()) + 500);
|
||||
cmpPlayer.SetPopulationBonuses(cmpPopulationManager.GetPopulationCap() + 500);
|
||||
return;
|
||||
case "changemaxpopulation":
|
||||
{
|
||||
|
|
|
|||
|
|
@ -53,14 +53,13 @@ function InitGame(settings)
|
|||
cmpPlayer.SetAI(true);
|
||||
}
|
||||
|
||||
if (settings.PopulationCap)
|
||||
cmpPlayer.SetMaxPopulation(settings.PopulationCap);
|
||||
|
||||
if (settings.AllyView)
|
||||
Engine.QueryInterface(cmpPlayer.entity, IID_TechnologyManager)?.ResearchTechnology(Engine.QueryInterface(cmpPlayer.entity, IID_Diplomacy).template.SharedLosTech);
|
||||
}
|
||||
if (settings.WorldPopulationCap)
|
||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).SetMaxWorldPopulation(settings.WorldPopulationCap);
|
||||
|
||||
const cmpPopulationCapManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PopulationCapManager);
|
||||
cmpPopulationCapManager.SetPopulationCapType(settings.PopulationCapType);
|
||||
cmpPopulationCapManager.SetPopulationCap(settings.PopulationCap);
|
||||
|
||||
// Update the grid with all entities created for the map init.
|
||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_Pathfinder).UpdateGrid();
|
||||
|
|
|
|||
|
|
@ -69,21 +69,6 @@ function LoadPlayerSettings(settings, newPlayers)
|
|||
if (i == 0)
|
||||
continue;
|
||||
|
||||
// PopulationLimit
|
||||
{
|
||||
const maxPopulation =
|
||||
settings.PlayerData[i].PopulationLimit !== undefined ?
|
||||
settings.PlayerData[i].PopulationLimit :
|
||||
settings.PopulationCap !== undefined ?
|
||||
settings.PopulationCap :
|
||||
playerDefaults[i].PopulationLimit !== undefined ?
|
||||
playerDefaults[i].PopulationLimit :
|
||||
undefined;
|
||||
|
||||
if (maxPopulation !== undefined)
|
||||
cmpPlayer.SetMaxPopulation(maxPopulation);
|
||||
}
|
||||
|
||||
// StartingResources
|
||||
if (settings.PlayerData[i].Resources !== undefined)
|
||||
cmpPlayer.SetResourceCounts(settings.PlayerData[i].Resources);
|
||||
|
|
|
|||
Loading…
Reference in a new issue