import { LitElement, html } from "lit"; import { customElement, property } from "lit/decorators.js"; import { EventBus } from "../../../core/EventBus"; import { GameMode, Team, UnitType } from "../../../core/game/Game"; import { GameView, PlayerView } from "../../../core/game/GameView"; import { formatPercentage, renderNumber, renderTroops, translateText, } from "../../Utils"; import { Layer } from "./Layer"; interface TeamEntry { teamName: string; isMyTeam: boolean; totalScoreStr: string; totalGold: string; totalMaxTroops: string; totalSAMs: string; totalLaunchers: string; totalWarShips: string; totalCities: string; totalScoreSort: number; players: PlayerView[]; } @customElement("team-stats") export class TeamStats extends LitElement implements Layer { public game: GameView; public eventBus: EventBus; @property({ type: Boolean }) visible = false; teams: TeamEntry[] = []; private _shownOnInit = false; private showUnits = false; private _myTeam: Team | null = null; createRenderRoot() { return this; // use light DOM for Tailwind } init() {} getTickIntervalMs() { return 1000; } tick() { if (this.game.config().gameConfig().gameMode !== GameMode.Team) return; if (!this._shownOnInit && !this.game.inSpawnPhase()) { this._shownOnInit = true; this.updateTeamStats(); } if (!this.visible) return; this.updateTeamStats(); } private updateTeamStats() { const players = this.game.playerViews(); const grouped: Record = {}; if (this._myTeam === null) { const myPlayer = this.game.myPlayer(); this._myTeam = myPlayer?.team() ?? null; } for (const player of players) { const team = player.team(); if (team === null) continue; grouped[team] ??= []; grouped[team].push(player); } this.teams = Object.entries(grouped) .map(([teamStr, teamPlayers]) => { let totalGold = 0n; let totalMaxTroops = 0; let totalScoreSort = 0; let totalSAMs = 0; let totalLaunchers = 0; let totalWarShips = 0; let totalCities = 0; for (const p of teamPlayers) { if (p.isAlive()) { totalMaxTroops += this.game.config().maxTroops(p); totalGold += p.gold(); totalScoreSort += p.numTilesOwned(); totalLaunchers += p.totalUnitLevels(UnitType.MissileSilo); totalSAMs += p.totalUnitLevels(UnitType.SAMLauncher); totalWarShips += p.totalUnitLevels(UnitType.Warship); totalCities += p.totalUnitLevels(UnitType.City); } } const numTilesWithoutFallout = this.game.numLandTiles() - this.game.numTilesWithFallout(); const totalScorePercent = totalScoreSort / numTilesWithoutFallout; return { teamName: teamStr, isMyTeam: teamStr === this._myTeam, totalScoreStr: formatPercentage(totalScorePercent), totalScoreSort, totalGold: renderNumber(totalGold), totalMaxTroops: renderTroops(totalMaxTroops), players: teamPlayers, totalLaunchers: renderNumber(totalLaunchers), totalSAMs: renderNumber(totalSAMs), totalWarShips: renderNumber(totalWarShips), totalCities: renderNumber(totalCities), }; }) .sort((a, b) => b.totalScoreSort - a.totalScoreSort); this.requestUpdate(); } renderLayer(context: CanvasRenderingContext2D) {} shouldTransform(): boolean { return false; } render() { if (!this.visible) return html``; return html`
e.preventDefault()} >
${translateText("leaderboard.team")}
${this.showUnits ? html`
${translateText("leaderboard.launchers")}
${translateText("leaderboard.sams")}
${translateText("leaderboard.warships")}
${translateText("leaderboard.cities")}
` : html`
${translateText("leaderboard.owned")}
${translateText("leaderboard.gold")}
${translateText("leaderboard.maxtroops")}
`}
${this.teams.map((team) => this.showUnits ? html`
${team.teamName}
${team.totalLaunchers}
${team.totalSAMs}
${team.totalWarShips}
${team.totalCities}
` : html`
${team.teamName}
${team.totalScoreStr}
${team.totalGold}
${team.totalMaxTroops}
`, )}
`; } }