0ad/binaries/data/mods/public/simulation/components/PopulationCapManager.js
Dunedan 93ce94655d
Use @stylistic/brace-style for eslint
Up to now `eslint-plugin-brace-rules` was used to enforce a common brace
style for JavaScript code. This plugin was however updated the last time
over 9 years ago and will be incompatible with ESLint v10, as that
[removes `context.getSourceCode()`][1], the plugin relies on.

To keep the eslint config working with ESLint v10, this replaces
`eslint-plugin-brace-rules` with the [`@stylistic/brace-style`][2] rule
from `@stylistic/eslint-plugin`, a package we already use.

While `@stylistic/brace-style` doesn't offer an option to format braces
in exactly the same way as before, the "allman" style seems to be the
one closest to the existing code.

[1]: https://eslint.org/blog/2025/11/eslint-v10.0.0-alpha.0-released/#removed-deprecated-rule-context-members
[2]: https://eslint.style/rules/brace-style
2026-01-12 21:33:52 +01:00

191 lines
5.3 KiB
JavaScript

function PopulationCapManager() {}
PopulationCapManager.prototype.CAPTYPE_PLAYER_POPULATION = "player";
PopulationCapManager.prototype.CAPTYPE_TEAM_POPULATION = "team";
PopulationCapManager.prototype.CAPTYPE_WORLD_POPULATION = "world";
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 (![this.CAPTYPE_PLAYER_POPULATION, this.CAPTYPE_TEAM_POPULATION, this.CAPTYPE_WORLD_POPULATION].includes(type))
error("Invalid population cap type specified: " + type);
this.popCapType = type;
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();
};
PopulationCapManager.prototype.SetPerPlayerPopulationCaps = function(playerCaps)
{
this.perPlayerPopCaps = playerCaps;
this.popCapType = this.CAPTYPE_PLAYER_POPULATION;
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 this.CAPTYPE_PLAYER_POPULATION:
this.InitializePlayerPopCaps();
break;
case this.CAPTYPE_TEAM_POPULATION:
this.InitializeTeamPopCaps();
break;
case this.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).GetNonGaiaPlayers();
for (const i in players)
QueryPlayerIDInterface(players[i], IID_Player)
.SetMaxPopulation(this.perPlayerPopCaps ? this.perPlayerPopCaps[i] : 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();
const 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 this.CAPTYPE_TEAM_POPULATION:
{
const team = QueryPlayerIDInterface(msg.playerId, IID_Diplomacy).GetTeam();
if (team !== -1)
this.RedistributeTeamPopCap(team);
break;
}
case this.CAPTYPE_WORLD_POPULATION:
this.RedistributeWorldPopCap();
break;
case this.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 !== this.CAPTYPE_TEAM_POPULATION)
return;
this.RedistributeTeamPopCap(msg.oldTeam);
this.RedistributeTeamPopCap(msg.newTeam);
};
Engine.RegisterSystemComponentType(IID_PopulationCapManager, "PopulationCapManager", PopulationCapManager);