forked from mirrors/0ad
Allow world population capacity.
This allows to specify a world population capacity that is divided evenly amongst living players. Differential Revision: D2426 Reviewed by: @Angen This was SVN commit r23873.
This commit is contained in:
@@ -377,6 +377,15 @@ function getGameDescription(mapCache)
|
||||
g_GameAttributes.settings.PopulationCap)]
|
||||
});
|
||||
|
||||
if (g_GameAttributes.settings.WorldPopulationCap !== undefined)
|
||||
titles.push({
|
||||
"label": translate("World Population Cap"),
|
||||
"value":
|
||||
g_WorldPopulationCapacities.Title[
|
||||
g_WorldPopulationCapacities.Population.indexOf(
|
||||
g_GameAttributes.settings.WorldPopulationCap)]
|
||||
});
|
||||
|
||||
titles.push({
|
||||
"label": translate("Treasures"),
|
||||
"value": g_GameAttributes.settings.DisableTreasures ?
|
||||
|
||||
@@ -44,6 +44,7 @@ function loadSettingsValues()
|
||||
"Biomes": loadBiomes(),
|
||||
"PlayerDefaults": loadPlayerDefaults(),
|
||||
"PopulationCapacities": loadPopulationCapacities(),
|
||||
"WorldPopulationCapacities": loadWorldPopulationCapacities(),
|
||||
"StartingResources": loadSettingValuesFile("starting_resources.json"),
|
||||
"VictoryConditions": loadVictoryConditions(),
|
||||
"TriggerDifficulties": loadSettingValuesFile("trigger_difficulties.json")
|
||||
@@ -268,6 +269,29 @@ function loadPopulationCapacities()
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -364,11 +388,19 @@ function translateMapSize(tiles)
|
||||
/**
|
||||
* Returns title or placeholder.
|
||||
*
|
||||
* @param {Number} population - for example 300
|
||||
* @param {Number} population
|
||||
* @param {boolean} world - Whether the entry has world population enabled.
|
||||
* @returns {string}
|
||||
*/
|
||||
function translatePopulationCapacity(population)
|
||||
function translatePopulationCapacity(population, world)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
let popCap = g_Settings.PopulationCapacities.find(p => p.Population == population);
|
||||
return popCap ? popCap.Title : translateWithContext("population capacity", "Unknown");
|
||||
}
|
||||
|
||||
+2
@@ -26,7 +26,9 @@ var g_GameSettingsLayout = [
|
||||
"label": translateWithContext("Match settings tab name", "Player"),
|
||||
"settings": [
|
||||
"PlayerCount",
|
||||
"WorldPopulation",
|
||||
"PopulationCap",
|
||||
"WorldPopulationCap",
|
||||
"StartingResources",
|
||||
"Spies",
|
||||
"Cheats"
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
GameSettingControls.WorldPopulation = class extends GameSettingControlCheckbox
|
||||
{
|
||||
onMapChange(mapData)
|
||||
{
|
||||
let mapValue =
|
||||
mapData &&
|
||||
mapData.settings &&
|
||||
mapData.settings.WorldPopulation || undefined;
|
||||
|
||||
if (mapValue !== undefined && mapValue != g_GameAttributes.settings.WorldPopulation)
|
||||
{
|
||||
g_GameAttributes.settings.WorldPopulation = mapValue;
|
||||
this.gameSettingsControl.updateGameAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
onGameAttributesChange()
|
||||
{
|
||||
if (!g_GameAttributes.mapType)
|
||||
return;
|
||||
|
||||
if (g_GameAttributes.settings.WorldPopulation !== undefined)
|
||||
return;
|
||||
|
||||
g_GameAttributes.settings.WorldPopulation = false;
|
||||
this.gameSettingsControl.updateGameAttributes();
|
||||
}
|
||||
|
||||
onGameAttributesBatchChange()
|
||||
{
|
||||
if (!g_GameAttributes.mapType)
|
||||
return;
|
||||
|
||||
this.setChecked(g_GameAttributes.settings.WorldPopulation);
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
g_GameAttributes.settings.WorldPopulation = checked;
|
||||
this.gameSettingsControl.updateGameAttributes();
|
||||
this.gameSettingsControl.setNetworkGameAttributes();
|
||||
}
|
||||
};
|
||||
|
||||
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.");
|
||||
+12
-3
@@ -40,10 +40,19 @@ GameSettingControls.PopulationCap = class extends GameSettingControlDropdown
|
||||
|
||||
onGameAttributesChange()
|
||||
{
|
||||
if (g_GameAttributes.settings.PopulationCap === undefined)
|
||||
if (g_GameAttributes.settings.WorldPopulation)
|
||||
{
|
||||
g_GameAttributes.settings.PopulationCap = g_PopulationCapacities.Population[g_PopulationCapacities.Default];
|
||||
this.gameSettingsControl.updateGameAttributes();
|
||||
this.setHidden(true);
|
||||
g_GameAttributes.settings.PopulationCap = undefined;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setHidden(false);
|
||||
if (g_GameAttributes.settings.PopulationCap === undefined)
|
||||
{
|
||||
g_GameAttributes.settings.PopulationCap = g_PopulationCapacities.Population[g_PopulationCapacities.Default];
|
||||
this.gameSettingsControl.updateGameAttributes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
GameSettingControls.WorldPopulationCap = class extends GameSettingControlDropdown
|
||||
{
|
||||
constructor(...args)
|
||||
{
|
||||
super(...args);
|
||||
|
||||
this.dropdown.list = g_WorldPopulationCapacities.Title;
|
||||
this.dropdown.list_data = g_WorldPopulationCapacities.Population;
|
||||
|
||||
this.sprintfArgs = {};
|
||||
}
|
||||
|
||||
onMapChange(mapData)
|
||||
{
|
||||
let mapValue =
|
||||
mapData &&
|
||||
mapData.settings &&
|
||||
mapData.settings.WorldPopulationCap || undefined;
|
||||
|
||||
if (mapValue !== undefined && mapValue != g_GameAttributes.settings.WorldPopulationCap)
|
||||
{
|
||||
g_GameAttributes.settings.WorldPopulationCap = mapValue;
|
||||
this.gameSettingsControl.updateGameAttributes();
|
||||
}
|
||||
|
||||
this.setEnabled(g_GameAttributes.mapType != "scenario");
|
||||
}
|
||||
|
||||
onGameAttributesChange()
|
||||
{
|
||||
if (g_GameAttributes.settings.WorldPopulation)
|
||||
{
|
||||
this.setHidden(false);
|
||||
if (g_GameAttributes.settings.WorldPopulationCap === undefined)
|
||||
{
|
||||
g_GameAttributes.settings.WorldPopulationCap = g_WorldPopulationCapacities.Population[g_WorldPopulationCapacities.Default];
|
||||
this.gameSettingsControl.updateGameAttributes();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setHidden(true);
|
||||
g_GameAttributes.settings.WorldPopulationCap = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
onGameAttributesBatchChange()
|
||||
{
|
||||
this.setSelectedValue(g_GameAttributes.settings.WorldPopulationCap);
|
||||
}
|
||||
|
||||
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_GameAttributes.settings.WorldPopulationCap = g_WorldPopulationCapacities.Population[itemIdx];
|
||||
this.gameSettingsControl.updateGameAttributes();
|
||||
this.gameSettingsControl.setNetworkGameAttributes();
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -2,6 +2,7 @@
|
||||
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,6 +16,7 @@ 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
|
||||
|
||||
@@ -226,7 +226,7 @@ function displayReplayList()
|
||||
return {
|
||||
"directories": replay.directory,
|
||||
"months": compatibilityColor(getReplayDateTime(replay), works),
|
||||
"popCaps": compatibilityColor(translatePopulationCapacity(replay.attribs.settings.PopulationCap), works),
|
||||
"popCaps": compatibilityColor(translatePopulationCapacity(replay.attribs.settings.PopulationCap, !!replay.attribs.settings.WorldPopulation), works),
|
||||
"mapNames": compatibilityColor(getReplayMapName(replay), works),
|
||||
"mapSizes": compatibilityColor(translateMapSize(replay.attribs.settings.Size), works),
|
||||
"durations": compatibilityColor(getReplayDuration(replay), works),
|
||||
|
||||
@@ -5,6 +5,7 @@ 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;
|
||||
|
||||
|
||||
@@ -58,7 +58,8 @@ GuiInterface.prototype.GetSimulationState = function()
|
||||
"players": []
|
||||
};
|
||||
|
||||
let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
|
||||
let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
let numPlayers = cmpPlayerManager.GetNumPlayers();
|
||||
for (let i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
let cmpPlayer = QueryPlayerIDInterface(i);
|
||||
@@ -154,6 +155,8 @@ GuiInterface.prototype.GetSimulationState = function()
|
||||
ret.victoryConditions = cmpEndGameManager.GetVictoryConditions();
|
||||
ret.alliedVictory = cmpEndGameManager.GetAlliedVictory();
|
||||
|
||||
ret.maxWorldPopulation = cmpPlayerManager.GetMaxWorldPopulation();
|
||||
|
||||
for (let i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
let cmpPlayerStatisticsTracker = QueryPlayerIDInterface(i, IID_StatisticsTracker);
|
||||
|
||||
@@ -5,7 +5,11 @@ PlayerManager.prototype.Schema =
|
||||
|
||||
PlayerManager.prototype.Init = function()
|
||||
{
|
||||
this.playerEntities = []; // list of player entity IDs
|
||||
// List of player entity IDs.
|
||||
this.playerEntities = [];
|
||||
|
||||
// Maximum world population (if applicable will be distributed amongst living players).
|
||||
this.maxWorldPopulation = undefined;
|
||||
};
|
||||
|
||||
PlayerManager.prototype.AddPlayer = function(ent)
|
||||
@@ -165,4 +169,35 @@ 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()
|
||||
{
|
||||
let worldPopulation = this.GetMaxWorldPopulation();
|
||||
if (!worldPopulation)
|
||||
return;
|
||||
|
||||
let activePlayers = this.GetActivePlayers();
|
||||
if (!activePlayers.length)
|
||||
return;
|
||||
|
||||
let newMaxPopulation = worldPopulation / activePlayers.length;
|
||||
for (let playerID of activePlayers)
|
||||
QueryPlayerIDInterface(playerID).SetMaxPopulation(newMaxPopulation);
|
||||
};
|
||||
|
||||
PlayerManager.prototype.OnGlobalPlayerDefeated = function(msg)
|
||||
{
|
||||
this.RedistributeWorldPopulation();
|
||||
};
|
||||
|
||||
Engine.RegisterSystemComponentType(IID_PlayerManager, "PlayerManager", PlayerManager);
|
||||
|
||||
@@ -74,7 +74,8 @@ AddMock(SYSTEM_ENTITY, IID_EndGameManager, {
|
||||
|
||||
AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
|
||||
"GetNumPlayers": function() { return 2; },
|
||||
"GetPlayerByID": function(id) { TS_ASSERT(id === 0 || id === 1); return 100 + id; }
|
||||
"GetPlayerByID": function(id) { TS_ASSERT(id === 0 || id === 1); return 100 + id; },
|
||||
"GetMaxWorldPopulation": function() {}
|
||||
});
|
||||
|
||||
AddMock(SYSTEM_ENTITY, IID_RangeManager, {
|
||||
@@ -369,7 +370,8 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
|
||||
"circularMap": false,
|
||||
"timeElapsed": 0,
|
||||
"victoryConditions": ["conquest", "wonder"],
|
||||
"alliedVictory": false
|
||||
"alliedVictory": false,
|
||||
"maxWorldPopulation": undefined
|
||||
});
|
||||
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
||||
@@ -522,7 +524,8 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
||||
"circularMap": false,
|
||||
"timeElapsed": 0,
|
||||
"victoryConditions": ["conquest", "wonder"],
|
||||
"alliedVictory": false
|
||||
"alliedVictory": false,
|
||||
"maxWorldPopulation": undefined
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"WorldPopulationCapacities": [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 63000],
|
||||
"Default": 600
|
||||
}
|
||||
@@ -24,11 +24,16 @@ function Cheat(input)
|
||||
cmpRangeManager.SetLosRevealAll(-1, true);
|
||||
return;
|
||||
case "maxpopulation":
|
||||
cmpPlayer.SetPopulationBonuses(500);
|
||||
cmpPlayer.SetPopulationBonuses((cmpPlayerManager.GetMaxWorldPopulation() || cmpPlayer.GetMaxPopulation()) + 500);
|
||||
return;
|
||||
case "changemaxpopulation":
|
||||
cmpPlayer.SetMaxPopulation(500);
|
||||
{
|
||||
let cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager);
|
||||
cmpModifiersManager.AddModifiers("cheat/maxpopulation", {
|
||||
"Player/MaxPopulation": [{ "affects": ["Player"], "add": 500 }],
|
||||
}, playerEnt);
|
||||
return;
|
||||
}
|
||||
case "convertunit":
|
||||
for (let ent of input.selected)
|
||||
{
|
||||
@@ -69,6 +74,7 @@ function Cheat(input)
|
||||
cmpProductionQueue.SpawnUnits(input.templates[i % input.templates.length], 1, null);
|
||||
return;
|
||||
case "fastactions":
|
||||
{
|
||||
let cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager);
|
||||
if (cmpModifiersManager.HasAnyModifier("cheat/fastactions", playerEnt))
|
||||
cmpModifiersManager.RemoveAllModifiers("cheat/fastactions", playerEnt);
|
||||
@@ -81,6 +87,7 @@ function Cheat(input)
|
||||
"ProductionQueue/TechCostMultiplier/time": [{ "affects": [["Structure"], ["Unit"]], "multiply": 0.01 }]
|
||||
}, playerEnt);
|
||||
return;
|
||||
}
|
||||
case "changephase":
|
||||
var cmpTechnologyManager = Engine.QueryInterface(playerEnt, IID_TechnologyManager);
|
||||
if (!cmpTechnologyManager)
|
||||
|
||||
@@ -65,8 +65,14 @@ function InitGame(settings)
|
||||
"Cost/BuildTime": [{ "affects": ["Unit", "Structure"], "multiply": time[AIDiff] }],
|
||||
}, cmpPlayer.entity);
|
||||
}
|
||||
|
||||
if (settings.PopulationCap)
|
||||
cmpPlayer.SetMaxPopulation(settings.PopulationCap);
|
||||
}
|
||||
// Map or player data (handicap...) dependent initialisations of components (i.e. garrisoned units)
|
||||
if (settings.WorldPopulationCap)
|
||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).SetMaxWorldPopulation(settings.WorldPopulationCap);
|
||||
|
||||
// Map or player data (handicap...) dependent initialisations of components (i.e. garrisoned units).
|
||||
Engine.BroadcastMessage(MT_InitGame, {});
|
||||
|
||||
cmpAIManager.TryLoadSharedComponent();
|
||||
|
||||
Reference in New Issue
Block a user