mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-20 07:13:56 -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
376 lines
12 KiB
JavaScript
376 lines
12 KiB
JavaScript
var g_TeamHelperData = [];
|
|
|
|
function calculatePercent(divident, divisor)
|
|
{
|
|
return { "percent": divisor ? Math.floor(100 * divident / divisor) : 0 };
|
|
}
|
|
|
|
function calculateRatio(divident, divisor)
|
|
{
|
|
return divident ? +((divident / divisor).toFixed(2)) : 0;
|
|
}
|
|
|
|
function formatSummaryValue(values)
|
|
{
|
|
if (typeof values !== "object")
|
|
return values === Infinity ? g_InfinitySymbol : values;
|
|
|
|
let ret = "";
|
|
for (const type in values)
|
|
if (!g_SummaryTypes[type].hideInSummary)
|
|
ret += (g_SummaryTypes[type].color ?
|
|
coloredText(values[type], g_SummaryTypes[type].color) :
|
|
values[type]) + g_SummaryTypes[type].postfix;
|
|
return ret;
|
|
}
|
|
|
|
function getPlayerValuesPerTeam(team, index, type, counters, headings)
|
|
{
|
|
const fn = counters[headings.map(heading => heading.identifier).indexOf(type) - 1].fn;
|
|
return g_Teams[team].map(player => fn(g_GameData.sim.playerStates[player], index, type));
|
|
}
|
|
|
|
function updateCountersPlayer(playerState, allCounters, allHeadings, idGUI, index)
|
|
{
|
|
const counters = allCounters.filter(counter => !counter.hideInSummary);
|
|
const headings = allHeadings.filter(heading => !heading.hideInSummary);
|
|
for (const n in counters)
|
|
{
|
|
const fn = counters[n].fn;
|
|
Engine.GetGUIObjectByName(idGUI + "[" + n + "]").caption =
|
|
formatSummaryValue(fn && fn(playerState, index, headings[+n + 1].identifier));
|
|
}
|
|
}
|
|
|
|
function updateCountersTeam(teamFn, allCounters, allHeadings, index)
|
|
{
|
|
const counters = allCounters.filter(counter => !counter.hideInSummary);
|
|
const headings = allHeadings.filter(heading => !heading.hideInSummary);
|
|
for (const team in g_Teams)
|
|
{
|
|
if (team == -1)
|
|
continue;
|
|
|
|
for (const n in counters)
|
|
Engine.GetGUIObjectByName("valueDataTeam[" + team + "][" + n + "]").caption =
|
|
formatSummaryValue(teamFn(team, index, headings[+n + 1].identifier, counters, headings));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add two objects property-wise and writes the result to obj1.
|
|
* So summaryAddObject([1, 2], [7, 42]) will result in [8, 44] and
|
|
* summaryAddObject({ "f": 3, "o", 5 }, { "f": -1, "o", 42 }) will result in { "f": 2, "o", 47 }.
|
|
*
|
|
* @param {Object} obj1 - First summand object. This will be set to the sum of both.
|
|
* @param {Object} obj2 - Second summand object.
|
|
*/
|
|
function summaryAddObject(obj1, obj2)
|
|
{
|
|
for (const p in obj1)
|
|
obj1[p] += obj2[p];
|
|
}
|
|
|
|
/**
|
|
* The sum of all elements of an array. So summaryArraySum([1, 2]) will be 3 and
|
|
* summaryArraySum([{ "f": 3, "o", 5 }, { "f": -1, "o", 42 }]) will be { "f": 2, "o", 47 }.
|
|
*
|
|
* @param {Array} array - The array to sum up.
|
|
* @returns the sum of all elements.
|
|
*/
|
|
function summaryArraySum(array)
|
|
{
|
|
return array.reduce((sum, val) =>
|
|
{
|
|
if (typeof sum !== "object")
|
|
return sum + val;
|
|
summaryAddObject(sum, val);
|
|
return sum;
|
|
});
|
|
}
|
|
|
|
function calculateTeamCounterDataHelper()
|
|
{
|
|
for (let i = 0; i < g_PlayerCount; ++i)
|
|
{
|
|
const playerState = g_GameData.sim.playerStates[i + 1];
|
|
|
|
if (!g_TeamHelperData[playerState.team])
|
|
{
|
|
g_TeamHelperData[playerState.team] = {};
|
|
for (const value of ["food", "vegetarianFood", "civilian", "worker", "enemyUnitsKilled",
|
|
"unitsLost", "mapControl", "mapControlPeak",
|
|
"mapExploration", "totalBought", "totalSold"])
|
|
g_TeamHelperData[playerState.team][value] = new Array(playerState.sequences.time.length).fill(0);
|
|
}
|
|
|
|
summaryAddObject(g_TeamHelperData[playerState.team].food, playerState.sequences.resourcesGathered.food);
|
|
summaryAddObject(g_TeamHelperData[playerState.team].vegetarianFood, playerState.sequences.resourcesGathered.vegetarianFood);
|
|
|
|
summaryAddObject(g_TeamHelperData[playerState.team].civilian, playerState.sequences.unitsTrained.Civilian);
|
|
summaryAddObject(g_TeamHelperData[playerState.team].worker, playerState.sequences.unitsTrained.Worker);
|
|
|
|
summaryAddObject(g_TeamHelperData[playerState.team].enemyUnitsKilled, playerState.sequences.enemyUnitsKilled.Unit);
|
|
summaryAddObject(g_TeamHelperData[playerState.team].unitsLost, playerState.sequences.unitsLost.Unit);
|
|
|
|
g_TeamHelperData[playerState.team].mapControl = playerState.sequences.teamPercentMapControlled;
|
|
g_TeamHelperData[playerState.team].mapControlPeak = playerState.sequences.teamPeakPercentMapControlled;
|
|
|
|
g_TeamHelperData[playerState.team].mapExploration = playerState.sequences.teamPercentMapExplored;
|
|
|
|
for (const type in playerState.sequences.resourcesBought)
|
|
summaryAddObject(g_TeamHelperData[playerState.team].totalBought, playerState.sequences.resourcesBought[type]);
|
|
|
|
for (const type in playerState.sequences.resourcesSold)
|
|
summaryAddObject(g_TeamHelperData[playerState.team].totalSold, playerState.sequences.resourcesSold[type]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Keep this in sync with the score computation in session/ for the lobby rating reports!
|
|
*/
|
|
function calculateEconomyScore(playerState, index)
|
|
{
|
|
let total = 0;
|
|
|
|
// Notice that this skips the vegetarianFood property of resourcesGathered
|
|
for (const type of g_ResourceData.GetCodes())
|
|
total += playerState.sequences.resourcesGathered[type][index];
|
|
|
|
total += playerState.sequences.tradeIncome[index];
|
|
return Math.round(total / 10);
|
|
}
|
|
|
|
/**
|
|
* Keep this in sync with the score computation in session/ for the lobby rating reports!
|
|
*/
|
|
function calculateMilitaryScore(playerState, index)
|
|
{
|
|
return Math.round((playerState.sequences.enemyUnitsKilledValue[index] +
|
|
playerState.sequences.unitsCapturedValue[index] +
|
|
playerState.sequences.enemyBuildingsDestroyedValue[index] +
|
|
playerState.sequences.buildingsCapturedValue[index]) / 10);
|
|
}
|
|
|
|
/**
|
|
* Keep this in sync with the score computation in session/ for the lobby rating reports!
|
|
*/
|
|
function calculateExplorationScore(playerState, index)
|
|
{
|
|
return playerState.sequences.percentMapExplored[index] * 10;
|
|
}
|
|
|
|
/**
|
|
* Keep this in sync with the score computation in session/ for the lobby rating reports!
|
|
*/
|
|
function calculateScoreTotal(playerState, index)
|
|
{
|
|
return calculateEconomyScore(playerState, index) +
|
|
calculateMilitaryScore(playerState, index) +
|
|
calculateExplorationScore(playerState, index);
|
|
}
|
|
|
|
function calculateScoreTeam(team, index, type, counters, headings)
|
|
{
|
|
if (type == "explorationScore")
|
|
return g_TeamHelperData[team].mapExploration[index] * 10;
|
|
if (type == "totalScore")
|
|
return ["economyScore", "militaryScore", "explorationScore"].map(
|
|
t => calculateScoreTeam(team, index, t, counters, headings)).reduce(
|
|
(sum, value) => sum + value);
|
|
|
|
return summaryArraySum(getPlayerValuesPerTeam(team, index, type, counters, headings));
|
|
}
|
|
|
|
function calculateBuildings(playerState, index, type)
|
|
{
|
|
return {
|
|
"constructed": playerState.sequences.buildingsConstructed[type][index],
|
|
"destroyed": playerState.sequences.enemyBuildingsDestroyed[type][index],
|
|
"captured": playerState.sequences.buildingsCaptured[type][index],
|
|
"lost": playerState.sequences.buildingsLost[type][index]
|
|
};
|
|
}
|
|
|
|
function calculateBuildingsTeam(team, index, type, counters, headings)
|
|
{
|
|
return summaryArraySum(getPlayerValuesPerTeam(team, index, type, counters, headings));
|
|
}
|
|
|
|
function calculateUnitsTeam(team, index, type, counters, headings)
|
|
{
|
|
return summaryArraySum(getPlayerValuesPerTeam(team, index, type, counters, headings));
|
|
}
|
|
|
|
function calculateUnitsWithCaptured(playerState, index, type)
|
|
{
|
|
return {
|
|
"trained": playerState.sequences.unitsTrained[type][index],
|
|
"killed": playerState.sequences.enemyUnitsKilled[type][index],
|
|
"captured": playerState.sequences.unitsCaptured[type][index],
|
|
"lost": playerState.sequences.unitsLost[type][index]
|
|
};
|
|
}
|
|
|
|
function calculateUnits(playerState, index, type)
|
|
{
|
|
return {
|
|
"trained": playerState.sequences.unitsTrained[type][index],
|
|
"killed": playerState.sequences.enemyUnitsKilled[type][index],
|
|
"lost": playerState.sequences.unitsLost[type][index]
|
|
};
|
|
}
|
|
|
|
function calculateResources(playerState, index, type)
|
|
{
|
|
return {
|
|
"count": playerState.sequences.resourcesCount[type][index],
|
|
"gathered": playerState.sequences.resourcesGathered[type][index],
|
|
"used": playerState.sequences.resourcesUsed[type][index] - playerState.sequences.resourcesSold[type][index]
|
|
};
|
|
}
|
|
|
|
function calculateTotalResources(playerState, index)
|
|
{
|
|
let totalGathered = 0;
|
|
let totalUsed = 0;
|
|
let totalCount = 0;
|
|
|
|
for (const type of g_ResourceData.GetCodes())
|
|
{
|
|
totalCount += playerState.sequences.resourcesCount[type][index];
|
|
totalGathered += playerState.sequences.resourcesGathered[type][index];
|
|
totalUsed += playerState.sequences.resourcesUsed[type][index] - playerState.sequences.resourcesSold[type][index];
|
|
}
|
|
|
|
return { "count": totalCount, "gathered": totalGathered, "used": totalUsed };
|
|
}
|
|
|
|
function calculateTreasureCollected(playerState, index)
|
|
{
|
|
return playerState.sequences.treasuresCollected[index];
|
|
}
|
|
|
|
function calculateLootCollected(playerState, index)
|
|
{
|
|
return playerState.sequences.lootCollected[index];
|
|
}
|
|
|
|
function calculateTributeSent(playerState, index)
|
|
{
|
|
return {
|
|
"sent": playerState.sequences.tributesSent[index],
|
|
"received": playerState.sequences.tributesReceived[index]
|
|
};
|
|
}
|
|
|
|
function calculateLivestockTrained(playerState, index)
|
|
{
|
|
return playerState.sequences.unitsTrained.Domestic[index];
|
|
}
|
|
|
|
function calculateResourcesTeam(team, index, type, counters, headings)
|
|
{
|
|
return summaryArraySum(getPlayerValuesPerTeam(team, index, type, counters, headings));
|
|
}
|
|
|
|
function calculateResourceExchanged(playerState, index, type)
|
|
{
|
|
return {
|
|
"bought": playerState.sequences.resourcesBought[type][index],
|
|
"sold": playerState.sequences.resourcesSold[type][index]
|
|
};
|
|
}
|
|
|
|
function calculateBarterEfficiency(playerState, index)
|
|
{
|
|
let totalBought = 0;
|
|
let totalSold = 0;
|
|
|
|
for (const type in playerState.sequences.resourcesBought)
|
|
totalBought += playerState.sequences.resourcesBought[type][index];
|
|
|
|
for (const type in playerState.sequences.resourcesSold)
|
|
totalSold += playerState.sequences.resourcesSold[type][index];
|
|
|
|
return calculatePercent(totalBought, totalSold);
|
|
}
|
|
|
|
function calculateTradeIncome(playerState, index)
|
|
{
|
|
return playerState.sequences.tradeIncome[index];
|
|
}
|
|
|
|
function calculateMarketTeam(team, index, type, counters, headings)
|
|
{
|
|
if (type == "barterEfficency")
|
|
return calculatePercent(g_TeamHelperData[team].totalBought[index], g_TeamHelperData[team].totalSold[index]);
|
|
|
|
return summaryArraySum(getPlayerValuesPerTeam(team, index, type, counters, headings));
|
|
}
|
|
|
|
function calculateVegetarianRatio(playerState, index)
|
|
{
|
|
return calculatePercent(
|
|
playerState.sequences.resourcesGathered.vegetarianFood[index],
|
|
playerState.sequences.resourcesGathered.food[index]);
|
|
}
|
|
|
|
function calculateCivilianization(playerState, index)
|
|
{
|
|
return calculatePercent(
|
|
playerState.sequences.unitsTrained.Civilian[index],
|
|
playerState.sequences.unitsTrained.Worker[index]);
|
|
}
|
|
|
|
function calculateKillDeathRatio(playerState, index)
|
|
{
|
|
return calculateRatio(
|
|
playerState.sequences.enemyUnitsKilled.Unit[index],
|
|
playerState.sequences.unitsLost.Unit[index]);
|
|
}
|
|
|
|
function calculatePopulationCount(playerState, index)
|
|
{
|
|
return { "population": playerState.sequences.populationCount[index] };
|
|
}
|
|
|
|
function calculateMapExploration(playerState, index)
|
|
{
|
|
return { "percent": playerState.sequences.percentMapExplored[index] };
|
|
}
|
|
|
|
function calculateMapFinalControl(playerState, index)
|
|
{
|
|
return { "percent": playerState.sequences.percentMapControlled[index] };
|
|
}
|
|
|
|
function calculateMapPeakControl(playerState, index)
|
|
{
|
|
return { "percent": playerState.sequences.peakPercentMapControlled[index] };
|
|
}
|
|
|
|
function calculateMiscellaneousTeam(team, index, type, counters, headings)
|
|
{
|
|
if (type == "vegetarianRatio")
|
|
return calculatePercent(g_TeamHelperData[team].vegetarianFood[index], g_TeamHelperData[team].food[index]);
|
|
|
|
if (type == "civilianization")
|
|
return calculatePercent(g_TeamHelperData[team].civilian[index], g_TeamHelperData[team].worker[index]);
|
|
|
|
if (type == "killDeath")
|
|
return calculateRatio(g_TeamHelperData[team].enemyUnitsKilled[index], g_TeamHelperData[team].unitsLost[index]);
|
|
|
|
if (type == "bribes" || type == "population")
|
|
return summaryArraySum(getPlayerValuesPerTeam(team, index, type, counters, headings));
|
|
|
|
return { "percent": g_TeamHelperData[team][type][index] };
|
|
}
|
|
|
|
function calculateBribes(playerState, index, type)
|
|
{
|
|
return {
|
|
"succeeded": playerState.sequences.successfulBribes[index],
|
|
"failed": playerState.sequences.failedBribes[index]
|
|
};
|
|
}
|