import { LitElement, TemplateResult, html } from "lit"; import { customElement, state } from "lit/decorators.js"; import { isInIframe, translateText } from "../../../client/Utils"; import { ColorPalette, Pattern } from "../../../core/CosmeticSchemas"; import { EventBus } from "../../../core/EventBus"; import { GameUpdateType } from "../../../core/game/GameUpdates"; import { GameView } from "../../../core/game/GameView"; import "../../components/PatternButton"; import { fetchCosmetics, handlePurchase, patternRelationship, } from "../../Cosmetics"; import { getUserMe } from "../../jwt"; import { SendWinnerEvent } from "../../Transport"; import { Layer } from "./Layer"; @customElement("win-modal") export class WinModal extends LitElement implements Layer { public game: GameView; public eventBus: EventBus; private hasShownDeathModal = false; @state() isVisible = false; @state() showButtons = false; @state() private isWin = false; @state() private patternContent: TemplateResult | null = null; private _title: string; private rand = Math.random(); // Override to prevent shadow DOM creation createRenderRoot() { return this; } constructor() { super(); } render() { return html`

${this._title || ""}

${this.innerHtml()}
`; } innerHtml() { if (isInIframe() || this.rand < 0.25) { return this.steamWishlist(); } return this.renderPatternButton(); } renderPatternButton() { return html`

${translateText("win_modal.support_openfront")}

${translateText("win_modal.territory_pattern")}

${this.patternContent}
`; } async loadPatternContent() { const me = await getUserMe(); const patterns = await fetchCosmetics(); const purchasablePatterns: { pattern: Pattern; colorPalette: ColorPalette; }[] = []; for (const pattern of Object.values(patterns?.patterns ?? {})) { for (const colorPalette of pattern.colorPalettes ?? []) { if ( patternRelationship( pattern, colorPalette, me !== false ? me : null, null, ) === "purchasable" ) { const palette = patterns?.colorPalettes?.[colorPalette.name]; if (palette) { purchasablePatterns.push({ pattern, colorPalette: palette, }); } } } } if (purchasablePatterns.length === 0) { this.patternContent = html``; return; } // Shuffle the array and take patterns based on screen size const shuffled = [...purchasablePatterns].sort(() => Math.random() - 0.5); const isMobile = window.innerWidth < 768; // md breakpoint const maxPatterns = isMobile ? 1 : 3; const selectedPatterns = shuffled.slice( 0, Math.min(maxPatterns, shuffled.length), ); this.patternContent = html`
${selectedPatterns.map( ({ pattern, colorPalette }) => html` {}} .onPurchase=${(p: Pattern, colorPalette: ColorPalette | null) => handlePurchase(p, colorPalette)} > `, )}
`; } steamWishlist(): TemplateResult { return html`

${translateText("win_modal.wishlist")}

`; } async show() { await this.loadPatternContent(); this.isVisible = true; this.requestUpdate(); setTimeout(() => { this.showButtons = true; this.requestUpdate(); }, 3000); } hide() { this.isVisible = false; this.showButtons = false; this.requestUpdate(); } private _handleExit() { this.hide(); window.location.href = "/"; } init() {} tick() { const myPlayer = this.game.myPlayer(); if ( !this.hasShownDeathModal && myPlayer && !myPlayer.isAlive() && !this.game.inSpawnPhase() && myPlayer.hasSpawned() ) { this.hasShownDeathModal = true; this._title = translateText("win_modal.died"); this.show(); } const updates = this.game.updatesSinceLastTick(); const winUpdates = updates !== null ? updates[GameUpdateType.Win] : []; winUpdates.forEach((wu) => { if (wu.winner === undefined) { // ... } else if (wu.winner[0] === "team") { this.eventBus.emit(new SendWinnerEvent(wu.winner, wu.allPlayersStats)); if (wu.winner[1] === this.game.myPlayer()?.team()) { this._title = translateText("win_modal.your_team"); this.isWin = true; } else { this._title = translateText("win_modal.other_team", { team: wu.winner[1], }); this.isWin = false; } this.show(); } else { const winner = this.game.playerByClientID(wu.winner[1]); if (!winner?.isPlayer()) return; const winnerClient = winner.clientID(); if (winnerClient !== null) { this.eventBus.emit( new SendWinnerEvent(["player", winnerClient], wu.allPlayersStats), ); } if ( winnerClient !== null && winnerClient === this.game.myPlayer()?.clientID() ) { this._title = translateText("win_modal.you_won"); this.isWin = true; } else { this._title = translateText("win_modal.other_won", { player: winner.name(), }); this.isWin = false; } this.show(); } }); } renderLayer(/* context: CanvasRenderingContext2D */) {} shouldTransform(): boolean { return false; } }