mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
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
147 lines
4 KiB
JavaScript
147 lines
4 KiB
JavaScript
/**
|
|
* Stores in-game names for all players.
|
|
*
|
|
* NB: the regular gamesetup has a particular handling of this setting.
|
|
* The names are loaded from the map, but the GUI also show playernames.
|
|
* Force these at the start of the match.
|
|
*/
|
|
GameSettings.prototype.Attributes.PlayerName = class PlayerName extends GameSetting
|
|
{
|
|
init()
|
|
{
|
|
// NB: watchers aren't auto-triggered when modifying array elements.
|
|
this.values = [];
|
|
this.settings.playerCount.watch(() => this.maybeUpdate(), ["nbPlayers"]);
|
|
this.settings.map.watch(() => this.onMapChange(), ["map"]);
|
|
}
|
|
|
|
toInitAttributes(attribs)
|
|
{
|
|
if (!attribs.settings.PlayerData)
|
|
attribs.settings.PlayerData = [];
|
|
while (attribs.settings.PlayerData.length < this.values.length)
|
|
attribs.settings.PlayerData.push({});
|
|
|
|
for (const i in this.values)
|
|
if (this.values[i])
|
|
attribs.settings.PlayerData[i].Name = this.values[i];
|
|
}
|
|
|
|
fromInitAttributes(attribs, fromPersistentSettings)
|
|
{
|
|
if (fromPersistentSettings || !this.getLegacySetting(attribs, "PlayerData"))
|
|
return;
|
|
const pData = this.getLegacySetting(attribs, "PlayerData");
|
|
for (let i = 0; i < this.values.length; ++i)
|
|
if (pData[i] && pData[i].Name !== undefined)
|
|
{
|
|
this.values[i] = pData[i].Name;
|
|
this.trigger("values");
|
|
}
|
|
}
|
|
|
|
_resize(nb)
|
|
{
|
|
while (this.values.length > nb)
|
|
this.values.pop();
|
|
while (this.values.length < nb)
|
|
this.values.push(undefined);
|
|
}
|
|
|
|
onMapChange()
|
|
{
|
|
// Reset.
|
|
this._resize(0);
|
|
this.maybeUpdate();
|
|
}
|
|
|
|
maybeUpdate()
|
|
{
|
|
this._resize(this.settings.playerCount.nbPlayers);
|
|
this.values.forEach((_, i) => this._set(i));
|
|
this.trigger("values");
|
|
}
|
|
|
|
/**
|
|
* Pick AI names.
|
|
*/
|
|
pickRandomItems()
|
|
{
|
|
const AIPlayerNamesList = [];
|
|
let picked = false;
|
|
for (const i in this.values)
|
|
{
|
|
if (!!this.values[i] &&
|
|
this.values[i] !== g_Settings.PlayerDefaults[+i + 1].Name)
|
|
continue;
|
|
|
|
const ai = this.settings.playerAI.values[i];
|
|
if (!ai)
|
|
continue;
|
|
|
|
const civ = this.settings.playerCiv.values[i];
|
|
if (!civ || civ == "random")
|
|
continue;
|
|
|
|
picked = true;
|
|
|
|
const names = this.settings.civData[civ].AINames;
|
|
const remainingNames = names.filter(name => !AIPlayerNamesList.includes(name));
|
|
const chosenName = pickRandom(remainingNames.length ? remainingNames : names);
|
|
|
|
// Avoid translating AI names if the game is networked, so all players see and refer to
|
|
// English names instead of names in the language of the host.
|
|
const translatedCountLabel = this.settings.isNetworked ? this.CountLabel : translate(this.CountLabel);
|
|
const translatedChosenName = this.settings.isNetworked ? chosenName : translate(chosenName);
|
|
|
|
const duplicateNameCount = AIPlayerNamesList.reduce((count, name) =>
|
|
{
|
|
if (name == chosenName)
|
|
count++;
|
|
return count;
|
|
}, 0);
|
|
|
|
AIPlayerNamesList.push(chosenName);
|
|
|
|
this.values[i] = !duplicateNameCount ? translatedChosenName :
|
|
sprintf(translatedCountLabel, {
|
|
"playerName": translatedChosenName,
|
|
"nameCount": duplicateNameCount + 1
|
|
});
|
|
}
|
|
if (picked)
|
|
{
|
|
this.trigger("values");
|
|
}
|
|
return picked;
|
|
}
|
|
|
|
onFinalizeAttributes(attribs, playerAssignments)
|
|
{
|
|
// Replace client player names with the real players.
|
|
for (const guid in playerAssignments)
|
|
if (playerAssignments[guid].player !== -1)
|
|
attribs.settings.PlayerData[playerAssignments[guid].player -1].Name = playerAssignments[guid].name;
|
|
}
|
|
|
|
_getMapData(i)
|
|
{
|
|
const data = this.settings.map.data;
|
|
if (!data || !data.settings || !data.settings.PlayerData)
|
|
return undefined;
|
|
if (data.settings.PlayerData.length <= i)
|
|
return undefined;
|
|
return data.settings.PlayerData[i].Name;
|
|
}
|
|
|
|
_set(playerIndex)
|
|
{
|
|
this.values[playerIndex] = this._getMapData(playerIndex) || g_Settings && g_Settings.PlayerDefaults[playerIndex + 1].Name || "";
|
|
}
|
|
};
|
|
|
|
/** Translation: This is a template (sprintf format specifier) for the name of
|
|
* an AI-controlled player and a unique number for each of the players with
|
|
* that same name. Example: Perseus (2)
|
|
*/
|
|
GameSettings.prototype.Attributes.PlayerName.prototype.CountLabel = markForTranslation("%(playerName)s (%(nameCount)i)");
|