This commit is contained in:
Ryan Barlow
2026-03-01 14:51:35 +00:00
parent 16fedbbd84
commit 401501aa2d
4 changed files with 42 additions and 11 deletions
+12 -5
View File
@@ -32,7 +32,7 @@ interface TeamEntry {
totalWarShips: string;
totalCities: string;
totalScoreSort: number;
crownTicks: number;
crownSeconds: number;
players: PlayerView[];
}
@@ -168,7 +168,11 @@ export class TeamStats extends LitElement implements Layer {
0,
currentTick - this.game.config().numSpawnPhaseTurns(),
);
const elapsedSeconds = Math.floor(elapsedGameTicks / 10);
const maxTimerValue = this.game.config().gameConfig().maxTimerValue;
const elapsedSeconds =
maxTimerValue !== undefined
? Math.min(Math.floor(elapsedGameTicks / 10), maxTimerValue * 60)
: Math.floor(elapsedGameTicks / 10);
const serverCrownTicks = this.game.teamCrownTicks() ?? {};
// Crown holder = team with most tiles (same logic as WinCheckExecution)
let crownHolder: string | null = null;
@@ -237,7 +241,11 @@ export class TeamStats extends LitElement implements Layer {
totalGold: renderNumber(totalGold),
totalMaxTroops: renderTroops(totalMaxTroops),
players: teamPlayers,
crownTicks: normalizedCrownTicks.get(teamStr) ?? 0,
crownSeconds:
this._gameOver && this.game.competitiveScores()
? (this.game.competitiveScores()!.find((s) => s.team === teamStr)
?.crownTimeSeconds ?? 0)
: Math.floor((normalizedCrownTicks.get(teamStr) ?? 0) / 10),
totalLaunchers: renderNumber(totalLaunchers),
totalSAMs: renderNumber(totalSAMs),
@@ -335,8 +343,7 @@ export class TeamStats extends LitElement implements Layer {
return html`
<div class="${rowClass}">
${td(team.teamName)} ${td(team.totalScoreStr)}
${td(team.peakScoreStr)}
${td(secondsToHms(Math.floor(team.crownTicks / 10)))}
${td(team.peakScoreStr)} ${td(secondsToHms(team.crownSeconds))}
</div>
`;
}
+3 -6
View File
@@ -9,7 +9,6 @@ import {
} from "../../../client/Utils";
import { ColorPalette, Pattern } from "../../../core/CosmeticSchemas";
import { EventBus } from "../../../core/EventBus";
import { TeamScoreBreakdown } from "../../../core/game/CompetitiveScoring";
import { RankedType } from "../../../core/game/Game";
import { GameUpdateType } from "../../../core/game/GameUpdates";
import { GameView } from "../../../core/game/GameView";
@@ -46,8 +45,9 @@ export class WinModal extends LitElement implements Layer {
@state()
private patternContent: TemplateResult | null = null;
@state()
private competitiveScores: TeamScoreBreakdown[] | null = null;
private get competitiveScores() {
return this.game.competitiveScores();
}
private _title: string;
@@ -409,9 +409,6 @@ export class WinModal extends LitElement implements Layer {
// ...
} else if (wu.winner[0] === "team") {
this.eventBus.emit(new SendWinnerEvent(wu.winner, wu.allPlayersStats));
if (wu.competitiveScores) {
this.competitiveScores = wu.competitiveScores;
}
if (wu.winner[1] === this.game.myPlayer()?.team()) {
this._title = translateText("win_modal.your_team");
this.isWin = true;
@@ -22,6 +22,14 @@ export class TeamMetricsExecution implements Execution {
if (ticks % 10 !== 0) return;
if (this.mg === null) throw new Error("Not initialized");
// Stop tracking after the game timer expires.
const maxTimerValue = this.mg.config().gameConfig().maxTimerValue;
if (maxTimerValue !== undefined) {
const elapsedSeconds =
(ticks - this.mg.config().numSpawnPhaseTurns()) / 10;
if (elapsedSeconds >= maxTimerValue * 60) return;
}
const teamToTiles = new Map<Team, number>();
for (const player of this.mg.players()) {
const team = player.team();
+19
View File
@@ -6,6 +6,7 @@ import { PatternDecoder } from "../PatternDecoder";
import { ClientID, GameID, Player, PlayerCosmetics } from "../Schemas";
import { createRandomName } from "../Util";
import { WorkerClient } from "../worker/WorkerClient";
import { TeamScoreBreakdown } from "./CompetitiveScoring";
import {
Cell,
EmojiMessage,
@@ -33,6 +34,7 @@ import {
GameUpdateViewData,
PlayerUpdate,
UnitUpdate,
WinUpdate,
} from "./GameUpdates";
import { MotionPlanRecord, unpackMotionPlans } from "./MotionPlans";
import { TerrainMapData } from "./TerrainMapLoader";
@@ -631,6 +633,7 @@ export class GameView implements GameMap {
private trainUnitToEngine = new Map<number, number>();
private toDelete = new Set<number>();
private _competitiveScores: TeamScoreBreakdown[] | null = null;
private _cosmetics: Map<string, PlayerCosmetics> = new Map();
@@ -679,6 +682,11 @@ export class GameView implements GameMap {
return this.lastUpdate?.teamCrownTicks;
}
/** Competitive scores set once at game end (authoritative). */
public competitiveScores(): TeamScoreBreakdown[] | null {
return this._competitiveScores;
}
public motionPlans(): ReadonlyMap<
number,
{
@@ -803,6 +811,17 @@ export class GameView implements GameMap {
}
});
// Capture competitive scores from WinUpdate (once)
if (this._competitiveScores === null && gu.updates) {
const winUpdates = gu.updates[GameUpdateType.Win] as WinUpdate[];
for (const wu of winUpdates) {
if (wu.competitiveScores) {
this._competitiveScores = wu.competitiveScores;
break;
}
}
}
this.advanceMotionPlannedUnits(gu.tick);
this.rebuildMotionPlannedUnitIdsCacheIfDirty();
}