Index: ps/trunk/binaries/data/mods/public/gui/summary/counters.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/summary/counters.js (revision 19957) +++ ps/trunk/binaries/data/mods/public/gui/summary/counters.js (revision 19958) @@ -1,480 +1,335 @@ var g_TeamHelperData = []; -function resetDataHelpers() -{ - 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 (let type in values) ret += (g_SummaryTypes[type].color ? '[color="' + g_SummaryTypes[type].color + '"]' + values[type] + '[/color]' : values[type]) + g_SummaryTypes[type].postfix; return ret; } -/** - * Remove color tags, whitespace, + and % to read numerical values from the GUI objects. - * Remove \n only when removeLineFeed == true - * TODO: access the data directly instead of this ugly hack. - */ -function cleanGUICaption(team, player, counter, removeLineFeed = true) +function getPlayerValuesPerTeam(team, index, type, counters, headings) +{ + let 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, counters, headings, idGUI, index) { - let caption = Engine.GetGUIObjectByName("valueDataTeam[" + team + "][" + player + "][" + counter + "]").caption; - if (removeLineFeed) - return caption.replace(/\[([\w\' \\\"\/\=]*)\]|\+|\%|\s/g, ""); - else - return caption.replace(/\[([\w\' \\\"\/\=]*)\]|[\t\r \f]/g, ""); + for (let n in counters) + { + let fn = counters[n].fn; + Engine.GetGUIObjectByName(idGUI + "[" + n + "]").caption = + formatSummaryValue(fn && fn(playerState, index, headings[+n + 1].identifier)); + } } -function updateCountersPlayer(playerState, counters, headings, idGUI) +function updateCountersTeam(teamFn, counters, headings, index) { - let index = playerState.sequences.time.length - 1; - for (let w in counters) + for (let team in g_Teams) { - let fn = counters[w].fn; - Engine.GetGUIObjectByName(idGUI + "[" + w + "]").caption = formatSummaryValue(fn && fn(playerState, index, headings[+w+1].identifier)); + if (team == -1) + continue; + + for (let n in counters) + Engine.GetGUIObjectByName("valueDataTeam[" + team + "][" + n + "]").caption = + formatSummaryValue(teamFn(team, index, headings[+n + 1].identifier, counters, headings)); } } /** - * Add two arrays element-wise. So addArray([1, 2], [7, 42]) will result in [8, 44]. + * 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 (let 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} array1 - first summand array. - * @param {Array} array2 - second summand array. - * @returns {Array} the element-wise sum of array1 and array2. + * @param {Array} array - The array to sum up. + * @returns the sum of all elements. */ -function addArray(array1, array2) +function summaryArraySum(array) { - array1 = array1.map((value, index) => value + array2[index]); + return array.reduce((sum, val) => { + if (typeof sum != "object") + return sum + val; + summaryAddObject(sum, val); + return sum; + }); } -// Updates g_TeamHelperData by appending some data from playerState -function calculateTeamCounters(playerState) +function calculateTeamCounterDataHelper() { - if (!g_TeamHelperData[playerState.team]) + for (let i = 0; i < g_PlayerCount; ++i) { - g_TeamHelperData[playerState.team] = {}; - for (let value of ["food", "vegetarianFood", "femaleCitizen", "worker", "enemyUnitsKilled", - "unitsLost", "percentMapControlled", "peakPercentMapControlled", - "percentMapExplored", "totalBought", "totalSold"]) - g_TeamHelperData[playerState.team][value] = new Array(playerState.sequences.time.length).fill(0); - } + let playerState = g_GameData.sim.playerStates[i + 1]; + + if (!g_TeamHelperData[playerState.team]) + { + g_TeamHelperData[playerState.team] = {}; + for (let value of ["food", "vegetarianFood", "femaleCitizen", "worker", "enemyUnitsKilled", + "unitsLost", "mapControl", "mapControlPeak", + "mapExploration", "totalBought", "totalSold"]) + g_TeamHelperData[playerState.team][value] = new Array(playerState.sequences.time.length).fill(0); + } - addArray(g_TeamHelperData[playerState.team].food, playerState.sequences.resourcesGathered.food); - addArray(g_TeamHelperData[playerState.team].vegetarianFood, playerState.sequences.resourcesGathered.vegetarianFood); + summaryAddObject(g_TeamHelperData[playerState.team].food, playerState.sequences.resourcesGathered.food); + summaryAddObject(g_TeamHelperData[playerState.team].vegetarianFood, playerState.sequences.resourcesGathered.vegetarianFood); - addArray(g_TeamHelperData[playerState.team].femaleCitizen, playerState.sequences.unitsTrained.FemaleCitizen); - addArray(g_TeamHelperData[playerState.team].worker, playerState.sequences.unitsTrained.Worker); + summaryAddObject(g_TeamHelperData[playerState.team].femaleCitizen, playerState.sequences.unitsTrained.FemaleCitizen); + summaryAddObject(g_TeamHelperData[playerState.team].worker, playerState.sequences.unitsTrained.Worker); - addArray(g_TeamHelperData[playerState.team].enemyUnitsKilled, playerState.sequences.enemyUnitsKilled.total); - addArray(g_TeamHelperData[playerState.team].unitsLost, playerState.sequences.unitsLost.total); + summaryAddObject(g_TeamHelperData[playerState.team].enemyUnitsKilled, playerState.sequences.enemyUnitsKilled.total); + summaryAddObject(g_TeamHelperData[playerState.team].unitsLost, playerState.sequences.unitsLost.total); - g_TeamHelperData[playerState.team].percentMapControlled = playerState.sequences.teamPercentMapControlled; - g_TeamHelperData[playerState.team].peakPercentMapControlled = playerState.sequences.teamPeakPercentMapControlled; + g_TeamHelperData[playerState.team].mapControl = playerState.sequences.teamPercentMapControlled; + g_TeamHelperData[playerState.team].mapControlPeak = playerState.sequences.teamPeakPercentMapControlled; - g_TeamHelperData[playerState.team].percentMapExplored = playerState.sequences.teamPercentMapExplored; + g_TeamHelperData[playerState.team].mapExploration = playerState.sequences.teamPercentMapExplored; - for (let type in playerState.sequences.resourcesBought) - addArray(g_TeamHelperData[playerState.team].totalBought, playerState.sequences.resourcesBought[type]); + for (let type in playerState.sequences.resourcesBought) + summaryAddObject(g_TeamHelperData[playerState.team].totalBought, playerState.sequences.resourcesBought[type]); - for (let type in playerState.sequences.resourcesSold) - addArray(g_TeamHelperData[playerState.team].totalSold, playerState.sequences.resourcesSold[type]); + for (let type in playerState.sequences.resourcesSold) + summaryAddObject(g_TeamHelperData[playerState.team].totalSold, playerState.sequences.resourcesSold[type]); + } } function calculateEconomyScore(playerState, index) { let total = 0; for (let type of g_ResourceData.GetCodes()) total += playerState.sequences.resourcesGathered[type][index]; // Subtract costs for sheep/goats/pigs to get the net food gain for corralling total -= playerState.sequences.domesticUnitsTrainedValue[index]; total += playerState.sequences.tradeIncome[index]; return Math.round(total / 10); } function calculateMilitaryScore(playerState, index) { return Math.round((playerState.sequences.enemyUnitsKilledValue[index] + playerState.sequences.unitsCapturedValue[index] + playerState.sequences.enemyBuildingsDestroyedValue[index] + playerState.sequences.buildingsCapturedValue[index]) / 10); } function calculateExplorationScore(playerState, index) { return playerState.sequences.percentMapExplored[index] * 10; } function calculateScoreTotal(playerState, index) { return calculateEconomyScore(playerState, index) + calculateMilitaryScore(playerState, index) + calculateExplorationScore(playerState, index); } -function calculateScoreTeam(counters, index) +function calculateScoreTeam(team, index, type, counters, headings) { - for (let t in g_Teams) - { - if (t == -1) - continue; - - let teamTotalScore = 0; - for (let w in counters) - { - let total = 0; + 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); - if (w == 2) // Team exploration score (not additive) - total = g_TeamHelperData[t].percentMapExplored[index] * 10; - else - for (let p = 0; p < g_Teams[t]; ++p) - total += +Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + p + "][" + w + "]").caption; - - if (w < 3) - { - teamTotalScore += total; - Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + w + "]").caption = total; - } - else - Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + w + "]").caption = teamTotalScore; - } - } + 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(counters, index) +function calculateBuildingsTeam(team, index, type, counters, headings) { - for (let t in g_Teams) - { - if (t == -1) - continue; - - for (let w in counters) - { - let total = { - "constructed" : 0, - "destroyed" : 0, - "captured" : 0, - "lost" : 0 - }; - - for (let p = 0; p < g_Teams[t]; ++p) - { - let splitCaption = cleanGUICaption(t, p, w, false).split("\n"); - let first = splitCaption[0].split("/"); - let second = splitCaption[1].split("/"); - - total.constructed += +first[0]; - total.destroyed += +first[1]; - total.captured += +second[0]; - total.lost += +second[1]; - } - - Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + w + "]").caption = - formatSummaryValue(total); - } - } + return summaryArraySum(getPlayerValuesPerTeam(team, index, type, counters, headings)); } -function calculateUnitsTeam(counters, index) +function calculateUnitsTeam(team, index, type, counters, headings) { - for (let t in g_Teams) - { - if (t == -1) - continue; - - for (let w in counters) - { - let total = - { - "trained": 0, - "killed": 0, - "captured" : 0, - "lost": 0 - }; - - for (let p = 0; p < g_Teams[t]; ++p) - { - let splitCaption = cleanGUICaption(t, p, w, false).split("\n"); - let first = splitCaption[0].split("/"); - total.trained += +first[0]; - total.killed += +first[1]; - - if (w == 0 || w == 6) - { - let second = splitCaption[1].split("/"); - total.captured += +second[0]; - total.lost += +second[1]; - } - else - total.lost += +splitCaption[1]; - } - - if (w != 0 && w != 6) - delete total.captured; - - Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + w + "]").caption = formatSummaryValue(total); - } - } + 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 { "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; for (let type of g_ResourceData.GetCodes()) { totalGathered += playerState.sequences.resourcesGathered[type][index]; totalUsed += playerState.sequences.resourcesUsed[type][index] - playerState.sequences.resourcesSold[type][index]; } return { "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 calculateResourcesTeam(counters, index) +function calculateResourcesTeam(team, index, type, counters, headings) { - for (let t in g_Teams) - { - if (t == -1) - continue; - - for (let w in counters) - { - let total = { - "income": 0, - "outcome": 0 - }; - - for (let p = 0; p < g_Teams[t]; ++p) - { - let caption = cleanGUICaption(t, p, w); - - if (w >= 6) - total.income += +caption; - else - { - let splitCaption = caption.split("/"); - - total.income += +splitCaption[0]; - total.outcome += +splitCaption[1]; - } - } - - let teamTotal; - if (w >= 6) - teamTotal = total.income; - else if (w == 5) - teamTotal = { "sent": total.income, "received": total.outcome }; - else - teamTotal = { "gathered": total.income, "used": total.outcome }; - - Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + w + "]").caption = formatSummaryValue(teamTotal); - } - } + 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 (let type in playerState.sequences.resourcesBought) totalBought += playerState.sequences.resourcesBought[type][index]; for (let 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(counters, index) +function calculateMarketTeam(team, index, type, counters, headings) { - for (let t in g_Teams) - { - if (t == -1) - continue; - - for (let w in counters) - { - let total = { - "income": 0, - "outcome": 0 - }; - - for (let p = 0; p < g_Teams[t]; ++p) - { - let caption = cleanGUICaption(t, p, w); - - if (w >= 4) - total.income += +caption; - else - { - let splitCaption = caption.split("/"); - total.income += +splitCaption[0]; - total.outcome += +splitCaption[1]; - } - } - - let teamTotal; - if (w == 4) - teamTotal = calculatePercent(g_TeamHelperData[t].totalBought[index], g_TeamHelperData[t].totalSold[index]); - else if (w > 4) - teamTotal = total.income; - else - teamTotal = total; + if (type == "barterEfficency") + return calculatePercent(g_TeamHelperData[team].totalBought[index], g_TeamHelperData[team].totalSold[index]); - Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + w + "]").caption = formatSummaryValue(teamTotal); - } - } + 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 calculateFeminization(playerState, index) { return calculatePercent( playerState.sequences.unitsTrained.FemaleCitizen[index], playerState.sequences.unitsTrained.Worker[index]); } function calculateKillDeathRatio(playerState, index) { return calculateRatio( playerState.sequences.enemyUnitsKilled.total[index], playerState.sequences.unitsLost.total[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(counters, index) +function calculateMiscellaneousTeam(team, index, type) { - for (let t in g_Teams) - { - if (t == -1) - continue; + if (type == "vegetarianRatio") + return calculatePercent(g_TeamHelperData[team].vegetarianFood[index], g_TeamHelperData[team].food[index]); - for (let w in counters) - { - let teamTotal; + if (type == "feminization") + return calculatePercent(g_TeamHelperData[team].femaleCitizen[index], g_TeamHelperData[team].worker[index]); - if (w == 0) - teamTotal = calculatePercent(g_TeamHelperData[t].vegetarianFood[index], g_TeamHelperData[t].food[index]); - else if (w == 1) - teamTotal = calculatePercent(g_TeamHelperData[t].femaleCitizen[index], g_TeamHelperData[t].worker[index]); - else if (w == 2) - teamTotal = calculateRatio(g_TeamHelperData[t].enemyUnitsKilled[index], g_TeamHelperData[t].unitsLost[index]); - else if (w == 3) - teamTotal = { "percent": g_TeamHelperData[t].percentMapExplored[index] }; - else if (w == 4) - teamTotal = { "percent": g_TeamHelperData[t].peakPercentMapControlled[index] }; - else if (w == 5) - teamTotal = { "percent": g_TeamHelperData[t].percentMapControlled[index] }; + if (type == "killDeath") + return calculateRatio(g_TeamHelperData[team].enemyUnitsKilled[index], g_TeamHelperData[team].unitsLost[index]); - Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + w + "]").caption = formatSummaryValue(teamTotal); - } - } + return { "percent": g_TeamHelperData[team][type][index] }; } Index: ps/trunk/binaries/data/mods/public/gui/summary/layout.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/summary/layout.js (revision 19957) +++ ps/trunk/binaries/data/mods/public/gui/summary/layout.js (revision 19958) @@ -1,365 +1,367 @@ var g_ScorePanelsData = { "score": { "caption": translate("Score"), "headings": [ { "identifier": "playername", "caption": translate("Player name"), "yStart": 26, "width": 200 }, { "identifier": "economyScore", "caption": translate("Economy score"), "yStart": 16, "width": 100 }, { "identifier": "militaryScore", "caption": translate("Military score"), "yStart": 16, "width": 100 }, { "identifier": "explorationScore", "caption": translate("Exploration score"), "yStart": 16, "width": 100 }, { "identifier": "totalScore", "caption": translate("Total score"), "yStart": 16, "width": 100 } ], "titleHeadings": [], "counters": [ { "width": 100, "fn": calculateEconomyScore, "verticalOffset": 12 }, { "width": 100, "fn": calculateMilitaryScore, "verticalOffset": 12 }, { "width": 100, "fn": calculateExplorationScore, "verticalOffset": 12 }, { "width": 100, "fn": calculateScoreTotal, "verticalOffset": 12 } ], "teamCounterFn": calculateScoreTeam }, "buildings": { "caption": translate("Buildings"), "headings": [ { "identifier": "playername", "caption": translate("Player name"), "yStart": 26, "width": 200 }, { "identifier": "total", "caption": translate("Total"), "yStart": 34, "width": 105 }, { "identifier": "House", "caption": translate("Houses"), "yStart": 34, "width": 85 }, { "identifier": "Economic", "caption": translate("Economic"), "yStart": 34, "width": 85 }, { "identifier": "Outpost", "caption": translate("Outposts"), "yStart": 34, "width": 85 }, { "identifier": "Military", "caption": translate("Military"), "yStart": 34, "width": 85 }, { "identifier": "Fortress", "caption": translate("Fortresses"), "yStart": 34, "width": 85 }, { "identifier": "CivCentre", "caption": translate("Civ centers"), "yStart": 34, "width": 85 }, { "identifier": "Wonder", "caption": translate("Wonders"), "yStart": 34, "width": 85 } ], "titleHeadings": [ { "caption": sprintf(translate("Buildings Statistics (%(constructed)s / %(destroyed)s / %(captured)s / %(lost)s)"), { "constructed": getColoredTypeTranslation("constructed"), "destroyed": getColoredTypeTranslation("destroyed"), "captured": getColoredTypeTranslation("captured"), "lost": getColoredTypeTranslation("lost") }), "yStart": 16, "width": 85 * 7 + 105 }, // width = 700 ], "counters": [ { "width": 105, "fn": calculateBuildings, "verticalOffset": 3 }, { "width": 85, "fn": calculateBuildings, "verticalOffset": 3 }, { "width": 85, "fn": calculateBuildings, "verticalOffset": 3 }, { "width": 85, "fn": calculateBuildings, "verticalOffset": 3 }, { "width": 85, "fn": calculateBuildings, "verticalOffset": 3 }, { "width": 85, "fn": calculateBuildings, "verticalOffset": 3 }, { "width": 85, "fn": calculateBuildings, "verticalOffset": 3 }, { "width": 85, "fn": calculateBuildings, "verticalOffset": 3 } ], "teamCounterFn": calculateBuildingsTeam }, "units": { "caption": translate("Units"), "headings": [ { "identifier": "playername", "caption": translate("Player name"), "yStart": 26, "width": 200 }, { "identifier": "total", "caption": translate("Total"), "yStart": 34, "width": 105 }, { "identifier": "Infantry", "caption": translate("Infantry"), "yStart": 34, "width": 85 }, { "identifier": "Worker", "caption": translate("Worker"), "yStart": 34, "width": 85 }, { "identifier": "Cavalry", "caption": translate("Cavalry"), "yStart": 34, "width": 85 }, { "identifier": "Champion", "caption": translate("Champion"), "yStart": 34, "width": 85 }, { "identifier": "Hero", "caption": translate("Heroes"), "yStart": 34, "width": 85 }, { "identifier": "Siege", "caption": translate("Siege"), "yStart": 34, "width": 85 }, { "identifier": "Ship", "caption": translate("Navy"), "yStart": 34, "width": 85 }, { "identifier": "Trader", "caption": translate("Traders"), "yStart": 34, "width": 85 } ], "titleHeadings": [ { "caption": sprintf(translate("Units Statistics (%(trained)s / %(killed)s / %(captured)s / %(lost)s)"), { "trained": getColoredTypeTranslation("trained"), "killed": getColoredTypeTranslation("killed"), "captured": getColoredTypeTranslation("captured"), "lost": getColoredTypeTranslation("lost") }), "yStart": 16, "width": 85 * 8 + 105 }, // width = 785 ], "counters": [ { "width": 105, "fn": calculateUnitsWithCaptured, "verticalOffset": 3 }, { "width": 85, "fn": calculateUnits, "verticalOffset": 3 }, { "width": 85, "fn": calculateUnits, "verticalOffset": 3 }, { "width": 85, "fn": calculateUnits, "verticalOffset": 3 }, { "width": 85, "fn": calculateUnits, "verticalOffset": 3 }, { "width": 85, "fn": calculateUnits, "verticalOffset": 3 }, { "width": 85, "fn": calculateUnitsWithCaptured, "verticalOffset": 3 }, { "width": 85, "fn": calculateUnits, "verticalOffset": 3 }, { "width": 85, "fn": calculateUnits, "verticalOffset": 3 } ], "teamCounterFn": calculateUnitsTeam }, "resources": { "caption": translate("Resources"), "headings": [ { "identifier": "playername", "caption": translate("Player name"), "yStart": 26, "width": 200 }, ...g_ResourceData.GetResources().map(res => ({ "identifier": res.code, "caption": resourceNameFirstWord(res.code), "yStart": 34, "width": 100 })), { "identifier": "total", "caption": translate("Total"), "yStart": 34, "width": 110 }, { "identifier": "tributes", "caption": sprintf(translate("Tributes \n(%(sent)s / %(received)s)"), { "sent": getColoredTypeTranslation("sent"), "received": getColoredTypeTranslation("received") }), "yStart": 16, "width": 121 }, { "identifier": "treasuresCollected", "caption": translate("Treasures collected"), "yStart": 16, "width": 100 }, { "identifier": "loot", "caption": translate("Loot"), "yStart": 16, "width": 100 } ], "titleHeadings": [ { "caption": sprintf(translate("Resource Statistics (%(gathered)s / %(used)s)"), { "gathered": getColoredTypeTranslation("gathered"), "used": getColoredTypeTranslation("used") }), "yStart": 16, "width": 100 * g_ResourceData.GetCodes().length + 110 }, ], "counters": [ ...g_ResourceData.GetCodes().map(code => ({ "fn": calculateResources, "verticalOffset": 12, "width": 100 })), { "width": 110, "fn": calculateTotalResources, "verticalOffset": 12 }, { "width": 121, "fn": calculateTributeSent, "verticalOffset": 12 }, { "width": 100, "fn": calculateTreasureCollected, "verticalOffset": 12 }, { "width": 100, "fn": calculateLootCollected, "verticalOffset": 12 } ], "teamCounterFn": calculateResourcesTeam }, "market": { "caption": translate("Market"), "headings": [ { "identifier": "playername", "caption": translate("Player name"), "yStart": 26, "width": 200 }, ...g_ResourceData.GetResources().map(res => { return { "identifier": res.code, "caption": // Translation: use %(resourceWithinSentence)s if needed sprintf(translate("%(resourceFirstWord)s exchanged"), { "resourceFirstWord": resourceNameFirstWord(res.code), "resourceWithinSentence": resourceNameWithinSentence(res.code) }), "yStart": 16, "width": 100 }; }), { "identifier": "barterEfficency", "caption": translate("Barter efficiency"), "yStart": 16, "width": 100 }, { "identifier": "tradeIncome", "caption": translate("Trade income"), "yStart": 16, "width": 100 } ], "titleHeadings": [], "counters": [ ...g_ResourceData.GetCodes().map(code => ({ "width": 100, "fn": calculateResourceExchanged, "verticalOffset": 12 })), { "width": 100, "fn": calculateBarterEfficiency, "verticalOffset": 12 }, { "width": 100, "fn": calculateTradeIncome, "verticalOffset": 12 } ], "teamCounterFn": calculateMarketTeam }, "misc": { "caption": translate("Miscellaneous"), "headings": [ { "identifier": "playername", "caption": translate("Player name"), "yStart": 26, "width": 200 }, { "identifier": "vegetarianRatio", "caption": translate("Vegetarian ratio"), "yStart": 16, "width": 100 }, { "identifier": "feminization", "caption": translate("Feminization"), "yStart": 16, "width": 100 }, { "identifier": "killDeath", "caption": translate("Kill / Death ratio"), "yStart": 16, "width": 100 }, { "identifier": "mapExploration", "caption": translate("Map exploration"), "yStart": 16, "width": 100 }, { "identifier": "mapControlPeak", "caption": translate("Map control (peak)"), "yStart": 16, "width": 100 }, - { "identifier": "mapControlFinish", "caption": translate("Map control (finish)"), "yStart": 16, "width": 100 } + { "identifier": "mapControl", "caption": translate("Map control (finish)"), "yStart": 16, "width": 100 } ], "titleHeadings": [], "counters": [ { "width": 100, "fn": calculateVegetarianRatio, "verticalOffset": 12 }, { "width": 100, "fn": calculateFeminization, "verticalOffset": 12 }, { "width": 100, "fn": calculateKillDeathRatio, "verticalOffset": 12 }, { "width": 100, "fn": calculateMapExploration, "verticalOffset": 12 }, { "width": 100, "fn": calculateMapPeakControl, "verticalOffset": 12 }, { "width": 100, "fn": calculateMapFinalControl, "verticalOffset": 12 } ], "teamCounterFn": calculateMiscellaneousTeam } }; function getColoredTypeTranslation(type) { return g_SummaryTypes[type].color ? '[color="' + g_SummaryTypes[type].color + '"]' + g_SummaryTypes[type].caption + '[/color]' : g_SummaryTypes[type].caption; } function resetGeneralPanel() { for (let h = 0; h < g_MaxHeadingTitle; ++h) { Engine.GetGUIObjectByName("titleHeading["+ h +"]").hidden = true; Engine.GetGUIObjectByName("Heading[" + h + "]").hidden = true; for (let p = 0; p < g_MaxPlayers; ++p) { Engine.GetGUIObjectByName("valueData[" + p + "][" + h + "]").hidden = true; for (let t = 0; t < g_MaxTeams; ++t) { Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + p + "][" + h + "]").hidden = true; Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + h + "]").hidden = true; } } } } function updateGeneralPanelHeadings(headings) { let left = 50; for (let h in headings) { let headerGUIName = "playerNameHeading"; if (h > 0) headerGUIName = "Heading[" + (h - 1) + "]"; let headerGUI = Engine.GetGUIObjectByName(headerGUIName); headerGUI.caption = headings[h].caption; headerGUI.size = left + " " + headings[h].yStart + " " + (left + headings[h].width) + " 100%"; headerGUI.hidden = false; if (headings[h].width < g_LongHeadingWidth) left += headings[h].width; } } function updateGeneralPanelTitles(titleHeadings) { let left = 250; for (let th in titleHeadings) { if (th >= g_MaxHeadingTitle) break; if (titleHeadings[th].xOffset) left += titleHeadings[th].xOffset; let headerGUI = Engine.GetGUIObjectByName("titleHeading["+ th +"]"); headerGUI.caption = titleHeadings[th].caption; headerGUI.size = left + " " + titleHeadings[th].yStart + " " + (left + titleHeadings[th].width) + " 100%"; headerGUI.hidden = false; if (titleHeadings[th].width < g_LongHeadingWidth) left += titleHeadings[th].width; } } function updateGeneralPanelCounter(counters) { let rowPlayerObjectWidth = 0; let left = 0; for (let p = 0; p < g_MaxPlayers; ++p) { left = 240; let counterObject; for (let w in counters) { counterObject = Engine.GetGUIObjectByName("valueData[" + p + "][" + w + "]"); counterObject.size = left + " " + counters[w].verticalOffset + " " + (left + counters[w].width) + " 100%"; counterObject.hidden = false; left += counters[w].width; } if (rowPlayerObjectWidth == 0) rowPlayerObjectWidth = left; let counterTotalObject; for (let t = 0; t < g_MaxTeams; ++t) { left = 240; for (let w in counters) { counterObject = Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + p + "][" + w + "]"); counterObject.size = left + " " + counters[w].verticalOffset + " " + (left + counters[w].width) + " 100%"; counterObject.hidden = false; if (g_Teams[t]) { - let yStart = 25 + g_Teams[t] * (g_PlayerBoxYSize + g_PlayerBoxGap) + 3 + counters[w].verticalOffset; + let yStart = 25 + g_Teams[t].length * (g_PlayerBoxYSize + g_PlayerBoxGap) + 3 + counters[w].verticalOffset; counterTotalObject = Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + w + "]"); counterTotalObject.size = (left + 20) + " " + yStart + " " + (left + counters[w].width) + " 100%"; counterTotalObject.hidden = false; } left += counters[w].width; } } } return rowPlayerObjectWidth; } function updateGeneralPanelTeams() { - if (!g_Teams || g_WithoutTeam > 0) + let withoutTeam = !g_Teams[-1] ? 0 : g_Teams[-1].length; + + if (!g_Teams || withoutTeam > 0) Engine.GetGUIObjectByName("noTeamsBox").hidden = false; if (!g_Teams) return; - let yStart = g_TeamsBoxYStart + g_WithoutTeam * (g_PlayerBoxYSize + g_PlayerBoxGap); - for (let i = 0; i < g_Teams.length; ++i) + let yStart = g_TeamsBoxYStart + withoutTeam * (g_PlayerBoxYSize + g_PlayerBoxGap) + (withoutTeam ? 30 : 0); + for (let i in g_Teams) { - if (!g_Teams[i]) + if (i == -1) continue; let teamBox = Engine.GetGUIObjectByName("teamBoxt["+i+"]"); teamBox.hidden = false; let teamBoxSize = teamBox.size; teamBoxSize.top = yStart; teamBox.size = teamBoxSize; - yStart += 30 + g_Teams[i] * (g_PlayerBoxYSize + g_PlayerBoxGap) + 32; + yStart += 30 + g_Teams[i].length * (g_PlayerBoxYSize + g_PlayerBoxGap) + 32; - Engine.GetGUIObjectByName("teamNameHeadingt["+i+"]").caption = "Team "+(i+1); + Engine.GetGUIObjectByName("teamNameHeadingt["+i+"]").caption = "Team " + (+i + 1); let teamHeading = Engine.GetGUIObjectByName("teamHeadingt["+i+"]"); - let yStartTotal = 30 + g_Teams[i] * (g_PlayerBoxYSize + g_PlayerBoxGap) + 10; + let yStartTotal = 30 + g_Teams[i].length * (g_PlayerBoxYSize + g_PlayerBoxGap) + 10; teamHeading.size = "50 " + yStartTotal + " 100% " + (yStartTotal + 20); teamHeading.caption = translate("Team total"); } // If there are no players without team, hide "player name" heading - if (!g_WithoutTeam) + if (!withoutTeam) Engine.GetGUIObjectByName("playerNameHeading").caption = ""; } function initPlayerBoxPositions() { for (let h = 0; h < g_MaxPlayers; ++h) { let playerBox = Engine.GetGUIObjectByName("playerBox[" + h + "]"); let boxSize = playerBox.size; boxSize.top += h * (g_PlayerBoxYSize + g_PlayerBoxGap); boxSize.bottom = boxSize.top + g_PlayerBoxYSize; playerBox.size = boxSize; for (let i = 0; i < g_MaxTeams; ++i) { let playerBoxt = Engine.GetGUIObjectByName("playerBoxt[" + i + "][" + h + "]"); boxSize = playerBoxt.size; boxSize.top += h * (g_PlayerBoxYSize + g_PlayerBoxGap); boxSize.bottom = boxSize.top + g_PlayerBoxYSize; playerBoxt.size = boxSize; } } } Index: ps/trunk/binaries/data/mods/public/gui/summary/summary.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/summary/summary.js (revision 19957) +++ ps/trunk/binaries/data/mods/public/gui/summary/summary.js (revision 19958) @@ -1,487 +1,479 @@ const g_MaxHeadingTitle= 9; // const for filtering long collective headings const g_LongHeadingWidth = 250; const g_PlayerBoxYSize = 40; const g_PlayerBoxGap = 2; const g_PlayerBoxAlpha = " 50"; const g_PlayerColorBoxAlpha = " 255"; const g_TeamsBoxYStart = 40; const g_TypeColors = { "blue": "196 198 255", "green": "201 255 200", "red": "255 213 213", "yellow": "255 255 157" } /** * Colors, captions and format used for units, buildings, etc. types */ var g_SummaryTypes = { "percent": { "color": "", "caption": "%", "postfix": "%" }, "trained": { "color": g_TypeColors.green, "caption": translate("Trained"), "postfix": " / " }, "constructed": { "color": g_TypeColors.green, "caption": translate("Constructed"), "postfix": " / " }, "gathered": { "color": g_TypeColors.green, "caption": translate("Gathered"), "postfix": " / " }, "sent": { "color": g_TypeColors.green, "caption": translate("Sent"), "postfix": " / " }, "bought": { "color": g_TypeColors.green, "caption": translate("Bought"), "postfix": " / " }, "income": { "color": g_TypeColors.green, "caption": translate("Income"), "postfix": " / " }, "captured": { "color": g_TypeColors.yellow, "caption": translate("Captured"), "postfix": " / " }, "destroyed": { "color": g_TypeColors.blue, "caption": translate("Destroyed"), "postfix": "\n" }, "killed": { "color": g_TypeColors.blue, "caption": translate("Killed"), "postfix": "\n" }, "lost": { "color": g_TypeColors.red, "caption": translate("Lost"), "postfix": "\n" }, "used": { "color": g_TypeColors.red, "caption": translate("Used"), "postfix": "\n" }, "received": { "color": g_TypeColors.red, "caption": translate("Received"), "postfix": "\n" }, "sold": { "color": g_TypeColors.red, "caption": translate("Sold"), "postfix": "\n" }, "outcome": { "color": g_TypeColors.red, "caption": translate("Outcome"), "postfix": "\n" } }; const g_InfinitySymbol = "\u221E"; var g_CivData = loadCivData(); var g_Teams = []; // TODO set g_PlayerCount as playerCounters.length var g_PlayerCount = 0; -// Count players without team (or all if teams are not displayed) -var g_WithoutTeam = 0; var g_GameData; var g_ResourceData = new Resources(); // Selected chart indexes var g_SelectedChart = { "category": [0, 0], "value": [0, 0], "type": [0, 0] }; function selectPanel(panel) { // TODO: move panel buttons to a custom parent object for (let button of Engine.GetGUIObjectByName("summaryWindow").children) if (button.name.endsWith("PanelButton")) button.sprite = "BackgroundTab"; panel.sprite = "ForegroundTab"; adjustTabDividers(panel.size); let generalPanel = Engine.GetGUIObjectByName("generalPanel"); let chartsPanel = Engine.GetGUIObjectByName("chartsPanel"); let chartsHidden = panel.name != "chartsPanelButton"; generalPanel.hidden = !chartsHidden; chartsPanel.hidden = chartsHidden; if (chartsHidden) updatePanelData(g_ScorePanelsData[panel.name.substr(0, panel.name.length - "PanelButton".length)]); else [0, 1].forEach(updateCategoryDropdown); } function initCharts() { let player_colors = []; for (let i = 1; i <= g_PlayerCount; ++i) { let playerState = g_GameData.sim.playerStates[i]; player_colors.push( Math.floor(playerState.color.r * 255) + " " + Math.floor(playerState.color.g * 255) + " " + Math.floor(playerState.color.b * 255) ); } [0, 1].forEach(i => Engine.GetGUIObjectByName("chart[" + i + "]").series_color = player_colors); let chartLegend = Engine.GetGUIObjectByName("chartLegend"); chartLegend.caption = g_GameData.sim.playerStates.slice(1).map( (state, index) => '[color="' + player_colors[index] + '"]■[/color] ' + state.name ).join(" "); let chart1Part = Engine.GetGUIObjectByName("chart[1]Part"); let chart1PartSize = chart1Part.size; chart1PartSize.rright += 50; chart1PartSize.rleft += 50; chart1PartSize.right -= 5; chart1PartSize.left -= 5; chart1Part.size = chart1PartSize; } function resizeDropdown(dropdown) { let size = dropdown.size; size.bottom = dropdown.size.top + (Engine.GetTextWidth(dropdown.font, dropdown.list[dropdown.selected]) > dropdown.size.right - dropdown.size.left - 32 ? 42 : 27); dropdown.size = size; } function updateCategoryDropdown(number) { let chartCategory = Engine.GetGUIObjectByName("chart[" + number + "]CategorySelection"); chartCategory.list_data = Object.keys(g_ScorePanelsData); chartCategory.list = Object.keys(g_ScorePanelsData).map(panel => g_ScorePanelsData[panel].caption); chartCategory.onSelectionChange = function() { if (!this.list_data[this.selected]) return; if (g_SelectedChart.category[number] != this.selected) { g_SelectedChart.category[number] = this.selected; g_SelectedChart.value[number] = 0; g_SelectedChart.type[number] = 0; } resizeDropdown(this); updateValueDropdown(number, this.list_data[this.selected]); }; chartCategory.selected = g_SelectedChart.category[number]; } function updateValueDropdown(number, category) { let chartValue = Engine.GetGUIObjectByName("chart[" + number + "]ValueSelection"); let list = g_ScorePanelsData[category].headings.map(heading => heading.caption); list.shift(); chartValue.list = list; let list_data = g_ScorePanelsData[category].headings.map(heading => heading.identifier); list_data.shift(); chartValue.list_data = list_data; chartValue.onSelectionChange = function() { if (!this.list_data[this.selected]) return; if (g_SelectedChart.value[number] != this.selected) { g_SelectedChart.value[number] = this.selected; g_SelectedChart.type[number] = 0; } resizeDropdown(this); updateTypeDropdown(number, category, this.list_data[this.selected], this.selected); }; chartValue.selected = g_SelectedChart.value[number]; } function updateTypeDropdown(number, category, item, itemNumber) { let testValue = g_ScorePanelsData[category].counters[itemNumber].fn(g_GameData.sim.playerStates[1], 0, item); let hide = !g_ScorePanelsData[category].counters[itemNumber].fn || typeof testValue != "object" || Object.keys(testValue).length < 2; Engine.GetGUIObjectByName("chart[" + number + "]TypeLabel").hidden = hide; let chartType = Engine.GetGUIObjectByName("chart[" + number + "]TypeSelection"); chartType.hidden = hide; if (hide) { updateChart(number, category, item, itemNumber, Object.keys(testValue)[0] || undefined); return; } chartType.list = Object.keys(testValue).map(type => g_SummaryTypes[type].caption); chartType.list_data = Object.keys(testValue); chartType.onSelectionChange = function() { if (!this.list_data[this.selected]) return; g_SelectedChart.type[number] = this.selected; resizeDropdown(this); updateChart(number, category, item, itemNumber, this.list_data[this.selected]); }; chartType.selected = g_SelectedChart.type[number]; } function updateChart(number, category, item, itemNumber, type) { if (!g_ScorePanelsData[category].counters[itemNumber].fn) return; let chart = Engine.GetGUIObjectByName("chart[" + number + "]"); let series = []; for (let j = 1; j <= g_PlayerCount; ++j) { let playerState = g_GameData.sim.playerStates[j]; let data = []; for (let index in playerState.sequences.time) { let value = g_ScorePanelsData[category].counters[itemNumber].fn(playerState, index, item); if (type) value = value[type]; data.push([playerState.sequences.time[index], value]); } series.push(data); } chart.series = series; } function adjustTabDividers(tabSize) { let leftSpacer = Engine.GetGUIObjectByName("tabDividerLeft"); let rightSpacer = Engine.GetGUIObjectByName("tabDividerRight"); leftSpacer.size = [ 20, leftSpacer.size.top, tabSize.left + 2, leftSpacer.size.bottom ].join(" "); rightSpacer.size = [ tabSize.right - 2, rightSpacer.size.top, "100%-20", rightSpacer.size.bottom ].join(" "); } function updatePanelData(panelInfo) { resetGeneralPanel(); - resetDataHelpers(); updateGeneralPanelHeadings(panelInfo.headings); updateGeneralPanelTitles(panelInfo.titleHeadings); let rowPlayerObjectWidth = updateGeneralPanelCounter(panelInfo.counters); updateGeneralPanelTeams(); - let playerBoxesCounts = [ ]; + let index = g_GameData.sim.playerStates[1].sequences.time.length - 1; + let playerBoxesCounts = []; for (let i = 0; i < g_PlayerCount; ++i) { let playerState = g_GameData.sim.playerStates[i+1]; if (!playerBoxesCounts[playerState.team+1]) playerBoxesCounts[playerState.team+1] = 1; else playerBoxesCounts[playerState.team+1] += 1; let positionObject = playerBoxesCounts[playerState.team+1] - 1; let rowPlayer = "playerBox[" + positionObject + "]"; let playerOutcome = "playerOutcome[" + positionObject + "]"; let playerNameColumn = "playerName[" + positionObject + "]"; let playerCivicBoxColumn = "civIcon[" + positionObject + "]"; let playerCounterValue = "valueData[" + positionObject + "]"; if (playerState.team != -1) { rowPlayer = "playerBoxt[" + playerState.team + "][" + positionObject + "]"; playerOutcome = "playerOutcomet[" + playerState.team + "][" + positionObject + "]"; playerNameColumn = "playerNamet[" + playerState.team + "][" + positionObject + "]"; playerCivicBoxColumn = "civIcont[" + playerState.team + "][" + positionObject + "]"; playerCounterValue = "valueDataTeam[" + playerState.team + "][" + positionObject + "]"; } let colorString = "color: " + Math.floor(playerState.color.r * 255) + " " + Math.floor(playerState.color.g * 255) + " " + Math.floor(playerState.color.b * 255); let rowPlayerObject = Engine.GetGUIObjectByName(rowPlayer); rowPlayerObject.hidden = false; rowPlayerObject.sprite = colorString + g_PlayerBoxAlpha; let boxSize = rowPlayerObject.size; boxSize.right = rowPlayerObjectWidth; rowPlayerObject.size = boxSize; setOutcomeIcon(playerState.state, playerOutcome); Engine.GetGUIObjectByName(playerNameColumn).caption = g_GameData.sim.playerStates[i+1].name; let civIcon = Engine.GetGUIObjectByName(playerCivicBoxColumn); civIcon.sprite = "stretched:" + g_CivData[playerState.civ].Emblem; civIcon.tooltip = g_CivData[playerState.civ].Name; - updateCountersPlayer(playerState, panelInfo.counters, panelInfo.headings, playerCounterValue); - - calculateTeamCounters(playerState); + updateCountersPlayer(playerState, panelInfo.counters, panelInfo.headings, playerCounterValue, index); } let teamCounterFn = panelInfo.teamCounterFn; if (g_Teams && teamCounterFn) - teamCounterFn(panelInfo.counters, g_GameData.sim.playerStates[1].sequences.time.length - 1); + updateCountersTeam(teamCounterFn, panelInfo.counters, panelInfo.headings, index); } function confirmStartReplay() { if (Engine.HasXmppClient()) messageBox( 400, 200, translate("Are you sure you want to quit the lobby?"), translate("Confirmation"), [translate("No"), translate("Yes")], [null, startReplay] ); else startReplay(); } function continueButton() { if (g_GameData.gui.isInGame) Engine.PopGuiPageCB(0); else if (g_GameData.gui.isReplay) Engine.SwitchGuiPage("page_replaymenu.xml", { "replaySelectionData": g_GameData.gui.replaySelectionData }); else if (Engine.HasXmppClient()) Engine.SwitchGuiPage("page_lobby.xml"); else Engine.SwitchGuiPage("page_pregame.xml"); } function startReplay() { if (Engine.HasXmppClient()) Engine.StopXmppClient(); if (!Engine.StartVisualReplay(g_GameData.gui.replayDirectory)) { warn("Replay file not found!"); return; } Engine.SwitchGuiPage("page_loading.xml", { "attribs": Engine.GetReplayAttributes(g_GameData.gui.replayDirectory), "isNetworked": false, "playerAssignments": { "local": { "name": singleplayerName(), "player": -1 } }, "savedGUIData": "", "isReplay": true, "replaySelectionData": g_GameData.gui.replaySelectionData }); } function init(data) { g_GameData = data; let assignedState = g_GameData.sim.playerStates[g_GameData.gui.assignedPlayer || -1]; Engine.GetGUIObjectByName("summaryText").caption = g_GameData.gui.isInGame ? translate("Current Scores") : g_GameData.gui.isReplay ? translate("Scores at the end of the game.") : g_GameData.gui.disconnected ? translate("You have been disconnected.") : !assignedState ? translate("You have left the game.") : assignedState.state == "won" ? translate("You have won the battle!") : assignedState.state == "defeated" ? translate("You have been defeated...") : translate("You have abandoned the game."); initPlayerBoxPositions(); Engine.GetGUIObjectByName("timeElapsed").caption = sprintf( translate("Game time elapsed: %(time)s"), { "time": timeToString(g_GameData.sim.timeElapsed) }); let mapType = g_Settings.MapTypes.find(mapType => mapType.Name == g_GameData.sim.mapSettings.mapType); let mapSize = g_Settings.MapSizes.find(size => size.Tiles == g_GameData.sim.mapSettings.Size || 0); Engine.GetGUIObjectByName("mapName").caption = sprintf( translate("%(mapName)s - %(mapType)s"), { "mapName": translate(g_GameData.sim.mapSettings.Name), "mapType": mapSize ? mapSize.Name : (mapType ? mapType.Title : "") }); Engine.GetGUIObjectByName("replayButton").hidden = g_GameData.gui.isInGame || !g_GameData.gui.replayDirectory; // Panels g_PlayerCount = g_GameData.sim.playerStates.length - 1; if (g_GameData.sim.mapSettings.LockTeams) { // Count teams - for (let t = 0; t < g_PlayerCount; ++t) + for (let player = 1; player <= g_PlayerCount; ++player) { - let playerTeam = g_GameData.sim.playerStates[t+1].team; - g_Teams[playerTeam] = (g_Teams[playerTeam] || 0) + 1; + let playerTeam = g_GameData.sim.playerStates[player].team; + if (!g_Teams[playerTeam]) + g_Teams[playerTeam] = []; + g_Teams[playerTeam].push(player); } - if (g_Teams.length == g_PlayerCount) + if (g_Teams.every(team => team && team.length < 2)) g_Teams = false; // Each player has his own team. Displaying teams makes no sense. } else g_Teams = false; // Erase teams data if teams are not displayed if (!g_Teams) { for (let p = 0; p < g_PlayerCount; ++p) g_GameData.sim.playerStates[p+1].team = -1; } - g_WithoutTeam = g_PlayerCount; - if (g_Teams) - { - // Count players without team (or all if teams are not displayed) - for (let i = 0; i < g_Teams.length; ++i) - g_WithoutTeam -= g_Teams[i] ? g_Teams[i] : 0; - } + calculateTeamCounterDataHelper(); initCharts(); selectPanel(Engine.GetGUIObjectByName("scorePanelButton")); }