From 0466eeac134c70a3dc4ef0ef28b4c991f7682d0b Mon Sep 17 00:00:00 2001 From: DevelopingTom Date: Thu, 15 Jan 2026 21:24:35 +0100 Subject: [PATCH] Add train gold to game info ranking (#2901) ## Description: The game info panel was missing the gold generated with trains, which was recently added into the recorded stats. This PR adds the gold train ranking, grouped with the naval trade. Visually the game info panel is not matching the new visual identity, but this PR only focuses on the missing data. image ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: IngloriousTom --- .../baseComponents/ranking/GameInfoRanking.ts | 12 +++- .../baseComponents/ranking/PlayerRow.ts | 68 +++++++++++++++---- .../baseComponents/ranking/RankingControls.ts | 11 ++- .../baseComponents/ranking/RankingHeader.ts | 23 ++++--- tests/GameInfoRanking.test.ts | 15 ++-- 5 files changed, 100 insertions(+), 29 deletions(-) diff --git a/src/client/components/baseComponents/ranking/GameInfoRanking.ts b/src/client/components/baseComponents/ranking/GameInfoRanking.ts index 015d6ae40..fa78d36f0 100644 --- a/src/client/components/baseComponents/ranking/GameInfoRanking.ts +++ b/src/client/components/baseComponents/ranking/GameInfoRanking.ts @@ -2,6 +2,8 @@ import { AnalyticsRecord, PlayerRecord } from "../../../../core/Schemas"; import { GOLD_INDEX_STEAL, GOLD_INDEX_TRADE, + GOLD_INDEX_TRAIN_OTHER, + GOLD_INDEX_TRAIN_SELF, GOLD_INDEX_WAR, } from "../../../../core/StatsSchemas"; @@ -12,7 +14,8 @@ export enum RankType { MIRV = "MIRV", TotalGold = "TotalGold", StolenGold = "StolenGold", - TradedGold = "TradedGold", + NavalTrade = "NavalTrade", + TrainTrade = "TrainTrade", ConqueredGold = "ConqueredGold", Lifetime = "Lifetime", } @@ -134,10 +137,15 @@ export class Ranking { return Number(player.gold.reduce((sum, gold) => sum + gold, 0n)); case RankType.StolenGold: return Number(player.gold[GOLD_INDEX_STEAL] ?? 0n); - case RankType.TradedGold: + case RankType.NavalTrade: return Number(player.gold[GOLD_INDEX_TRADE] ?? 0n); case RankType.ConqueredGold: return Number(player.gold[GOLD_INDEX_WAR] ?? 0n); + case RankType.TrainTrade: { + const ownTrains = player.gold[GOLD_INDEX_TRAIN_SELF] ?? 0n; + const otherTrains = player.gold[GOLD_INDEX_TRAIN_OTHER] ?? 0n; + return Number(ownTrains + otherTrains); + } } } diff --git a/src/client/components/baseComponents/ranking/PlayerRow.ts b/src/client/components/baseComponents/ranking/PlayerRow.ts index 2ebe635ed..9989962a9 100644 --- a/src/client/components/baseComponents/ranking/PlayerRow.ts +++ b/src/client/components/baseComponents/ranking/PlayerRow.ts @@ -1,5 +1,10 @@ import { LitElement, html } from "lit"; import { customElement, property } from "lit/decorators.js"; +import { + GOLD_INDEX_TRADE, + GOLD_INDEX_TRAIN_OTHER, + GOLD_INDEX_TRAIN_SELF, +} from "src/core/StatsSchemas"; import { renderNumber } from "../../../Utils"; import { PlayerInfo, RankType } from "./GameInfoRanking"; @@ -67,10 +72,12 @@ export class PlayerRow extends LitElement { case RankType.MIRV: return this.renderBombScore(); case RankType.TotalGold: - case RankType.TradedGold: case RankType.ConqueredGold: case RankType.StolenGold: return this.renderGoldScore(); + case RankType.NavalTrade: + case RankType.TrainTrade: + return this.renderTradeScore(); default: return html``; } @@ -109,14 +116,15 @@ export class PlayerRow extends LitElement { `; } - private renderBombType(value: number, highlight: boolean) { + + private renderMultiScoreType(value: number, highlight: boolean) { return html`
- ${value} + ${renderNumber(value)}
`; } @@ -124,17 +132,17 @@ export class PlayerRow extends LitElement { private renderAllBombs() { return html`
- ${this.renderBombType( + ${this.renderMultiScoreType( this.player.atoms, this.rankType === RankType.Atoms, )} / - ${this.renderBombType( + ${this.renderMultiScoreType( this.player.hydros, this.rankType === RankType.Hydros, )} / - ${this.renderBombType( + ${this.renderMultiScoreType( this.player.mirv, this.rankType === RankType.MIRV, )} @@ -142,9 +150,28 @@ export class PlayerRow extends LitElement { `; } + private renderAllTrades() { + const navalTrade = this.player.gold[GOLD_INDEX_TRADE] ?? 0n; + const ownTrainTrade = this.player.gold[GOLD_INDEX_TRAIN_SELF] ?? 0n; + const otherTrainTrade = this.player.gold[GOLD_INDEX_TRAIN_OTHER] ?? 0n; + return html` +
+ ${this.renderMultiScoreType( + Number(navalTrade), + this.rankType === RankType.NavalTrade, + )} + / + ${this.renderMultiScoreType( + Number(ownTrainTrade + otherTrainTrade), + this.rankType === RankType.TrainTrade, + )} +
+ `; + } + private renderBombScore() { return html` -
+
${this.renderPlayerIcon()}
${this.renderPlayerName()} ${this.renderAllBombs()} @@ -157,13 +184,12 @@ export class PlayerRow extends LitElement { return html`
${this.renderPlayerIcon()} -
- ${this.renderPlayerName()} -
+
${this.renderPlayerName()}
+
${renderNumber(this.score)}
@@ -172,6 +198,24 @@ export class PlayerRow extends LitElement { `; } + private renderTradeScore() { + return html` +
+ ${this.renderPlayerIcon()} +
${this.renderPlayerName()}
+
+ +
+
+ ${this.renderAllTrades()} +
+ +
+ `; + } + private renderPlayerName() { return html`
diff --git a/src/client/components/baseComponents/ranking/RankingControls.ts b/src/client/components/baseComponents/ranking/RankingControls.ts index 59e3ea76c..25321d8aa 100644 --- a/src/client/components/baseComponents/ranking/RankingControls.ts +++ b/src/client/components/baseComponents/ranking/RankingControls.ts @@ -7,8 +7,10 @@ const economyRankings = new Set([ RankType.TotalGold, RankType.StolenGold, RankType.ConqueredGold, - RankType.TradedGold, + RankType.NavalTrade, + RankType.TrainTrade, ]); +const tradeRankings = new Set([RankType.NavalTrade, RankType.TrainTrade]); const bombRankings = new Set([RankType.Atoms, RankType.Hydros, RankType.MIRV]); const warRankings = new Set([ RankType.Conquests, @@ -18,6 +20,7 @@ const warRankings = new Set([ ]); const isEconomyRanking = (t: RankType) => economyRankings.has(t); +const isTradeRanking = (t: RankType) => tradeRankings.has(t); const isBombRanking = (t: RankType) => bombRankings.has(t); const isWarRanking = (t: RankType) => warRankings.has(t); @@ -87,7 +90,6 @@ export class RankingControls extends LitElement { if (!isEconomyRanking(this.rankType)) return ""; const econButtons = [ - [RankType.TradedGold, "game_info_modal.trade"], [RankType.StolenGold, "game_info_modal.pirate"], [RankType.ConqueredGold, "game_info_modal.conquered"], [RankType.TotalGold, "game_info_modal.total_gold"], @@ -95,6 +97,11 @@ export class RankingControls extends LitElement { return html`
+ ${this.renderSubButton( + RankType.NavalTrade, + isTradeRanking(this.rankType), + "game_info_modal.trade", + )} ${econButtons.map(([type, label]) => this.renderSubButton(type as RankType, this.rankType === type, label), )} diff --git a/src/client/components/baseComponents/ranking/RankingHeader.ts b/src/client/components/baseComponents/ranking/RankingHeader.ts index 881de1101..6869b9526 100644 --- a/src/client/components/baseComponents/ranking/RankingHeader.ts +++ b/src/client/components/baseComponents/ranking/RankingHeader.ts @@ -36,17 +36,17 @@ export class RankingHeader extends LitElement { case RankType.MIRV: return html`
- ${this.renderBombHeaderButton( + ${this.renderMultipleChoiceHeaderButton( translateText("game_info_modal.atoms"), RankType.Atoms, )} / - ${this.renderBombHeaderButton( + ${this.renderMultipleChoiceHeaderButton( translateText("game_info_modal.hydros"), RankType.Hydros, )} / - ${this.renderBombHeaderButton( + ${this.renderMultipleChoiceHeaderButton( translateText("game_info_modal.mirv"), RankType.MIRV, )} @@ -56,10 +56,15 @@ export class RankingHeader extends LitElement { return html`
${translateText("game_info_modal.all_gold")}
`; - case RankType.TradedGold: - return html`
- ${translateText("game_info_modal.trade")} -
`; + case RankType.NavalTrade: + case RankType.TrainTrade: + return html` +
+ ${this.renderMultipleChoiceHeaderButton("🚂", RankType.TrainTrade)} + / + ${this.renderMultipleChoiceHeaderButton("🚢", RankType.NavalTrade)} +
+ `; case RankType.ConqueredGold: return html`
${translateText("game_info_modal.conquest_gold")} @@ -74,13 +79,13 @@ export class RankingHeader extends LitElement { } } - private renderBombHeaderButton(label: string, type: RankType) { + private renderMultipleChoiceHeaderButton(label: string, type: RankType) { return html` diff --git a/tests/GameInfoRanking.test.ts b/tests/GameInfoRanking.test.ts index 7955fb807..1e523ae93 100644 --- a/tests/GameInfoRanking.test.ts +++ b/tests/GameInfoRanking.test.ts @@ -13,6 +13,8 @@ import { AnalyticsRecord } from "../src/core/Schemas"; import { GOLD_INDEX_STEAL, GOLD_INDEX_TRADE, + GOLD_INDEX_TRAIN_OTHER, + GOLD_INDEX_TRAIN_SELF, GOLD_INDEX_WAR, } from "../src/core/StatsSchemas"; @@ -55,7 +57,7 @@ describe("Ranking class", () => { stats: { units: { port: [2n, 0n, 0n, 2n] }, conquests: 5n, - gold: [0n, 100n, 20n, 0n], // total 120 + gold: [0n, 100n, 20n, 0n, 15n, 5n], // total 140 bombs: { abomb: [1n], hbomb: [1n], @@ -70,7 +72,7 @@ describe("Ranking class", () => { stats: { units: { city: [2n, 0n, 0n, 2n] }, conquests: 8n, - gold: [0n, 50n, 10n, 5n], // total 65 + gold: [0n, 50n, 10n, 5n], // total 65, no train trade bombs: { abomb: [0n], hbomb: [2n], @@ -86,7 +88,7 @@ describe("Ranking class", () => { // no units, but has conquests/killedAt to count as played conquests: 8n, killedAt: BigInt(600), - gold: [0n, 10n, 2n, 10n], // total 22 + gold: [0n, 10n, 2n, 10n, 0n, 5n], // total 27 bombs: {}, }, persistentID: null, @@ -178,9 +180,14 @@ describe("Ranking class", () => { expect(r.score(p1, RankType.StolenGold)).toBe( Number(p1.gold[GOLD_INDEX_STEAL] ?? 0n), ); - expect(r.score(p1, RankType.TradedGold)).toBe( + expect(r.score(p1, RankType.NavalTrade)).toBe( Number(p1.gold[GOLD_INDEX_TRADE] ?? 0n), ); + const ownTrain = p1.gold[GOLD_INDEX_TRAIN_SELF] ?? 0n; + const otherTrain = p1.gold[GOLD_INDEX_TRAIN_OTHER] ?? 0n; + expect(r.score(p1, RankType.TrainTrade)).toBe( + Number(ownTrain + otherTrain), + ); expect(r.score(p1, RankType.ConqueredGold)).toBe( Number(p1.gold[GOLD_INDEX_WAR] ?? 0n), );