615 lines
19 KiB
JavaScript
615 lines
19 KiB
JavaScript
/**
|
|
* TeamResultScene.js
|
|
* 3v3 Team match result screen.
|
|
* Shows winner, per-player stats (kills/deaths/assists/base damage),
|
|
* base HP summary, and options to rematch or return to menu.
|
|
*/
|
|
|
|
const {
|
|
SCREEN_WIDTH,
|
|
SCREEN_HEIGHT,
|
|
COLORS,
|
|
SCENE,
|
|
NET_MSG,
|
|
} = require('../base/GameGlobal');
|
|
const { t } = require('../i18n/I18n');
|
|
|
|
// Layout
|
|
const BTN_WIDTH = Math.min(SCREEN_WIDTH * 0.35, 180);
|
|
const BTN_HEIGHT = Math.min(36, SCREEN_HEIGHT * 0.07);
|
|
const BTN_GAP = 14;
|
|
const CENTER_X = SCREEN_WIDTH / 2;
|
|
|
|
// Team colors
|
|
const TEAM_A_COLOR = '#4A90D9';
|
|
const TEAM_B_COLOR = '#E94560';
|
|
|
|
const TeamResultScene = {
|
|
_winner: '',
|
|
_winReason: '',
|
|
_myTeam: '',
|
|
_didWin: false,
|
|
_teamABaseHp: 0,
|
|
_teamBBaseHp: 0,
|
|
_stats: {},
|
|
_players: [],
|
|
_elapsedTime: 0,
|
|
_teamId: '',
|
|
_animTimer: 0,
|
|
_battleMode: '3v3', // '1v1' or '3v3'
|
|
|
|
// Rematch state
|
|
_rematchRequested: false,
|
|
_rematchReadyCount: 0,
|
|
_rematchTotalCount: 0,
|
|
_networkManager: null,
|
|
_unsubscribers: [],
|
|
|
|
// Button rects
|
|
_rematchBtnRect: null,
|
|
_menuBtnRect: null,
|
|
_adDoubleBtnRect: null,
|
|
|
|
// Ad state
|
|
_adWatched: false,
|
|
_goldReward: 0,
|
|
|
|
// Scroll state for player list
|
|
_scrollY: 0,
|
|
|
|
enter(params) {
|
|
this._winner = (params && params.winner) || '';
|
|
this._winReason = (params && params.winReason) || 'base_destroyed';
|
|
this._myTeam = (params && params.myTeam) || 'A';
|
|
this._didWin = (params && params.didWin) || false;
|
|
this._teamABaseHp = (params && params.teamABaseHp) || 0;
|
|
this._teamBBaseHp = (params && params.teamBBaseHp) || 0;
|
|
this._stats = (params && params.stats) || {};
|
|
this._players = (params && params.players) || [];
|
|
this._elapsedTime = (params && params.elapsedTime) || 0;
|
|
this._teamId = (params && params.teamId) || '';
|
|
this._animTimer = 0;
|
|
this._scrollY = 0;
|
|
this._battleMode = (params && params.battleMode) || '3v3';
|
|
this._rematchRequested = false;
|
|
this._rematchReadyCount = 0;
|
|
this._rematchTotalCount = 0;
|
|
this._networkManager = GameGlobal.networkManager;
|
|
this._adWatched = false;
|
|
this._goldReward = 0;
|
|
|
|
// Calculate and award gold
|
|
this._calculateAndAwardGold();
|
|
|
|
this._setupNetworkEvents();
|
|
|
|
const btnY = SCREEN_HEIGHT * 0.88;
|
|
this._rematchBtnRect = {
|
|
x: CENTER_X - BTN_WIDTH - BTN_GAP / 2,
|
|
y: btnY,
|
|
w: BTN_WIDTH,
|
|
h: BTN_HEIGHT,
|
|
};
|
|
this._menuBtnRect = {
|
|
x: CENTER_X + BTN_GAP / 2,
|
|
y: btnY,
|
|
w: BTN_WIDTH,
|
|
h: BTN_HEIGHT,
|
|
};
|
|
|
|
// Double reward ad button (above rematch/menu buttons)
|
|
const adBtnY = btnY - BTN_HEIGHT - BTN_GAP;
|
|
this._adDoubleBtnRect = {
|
|
x: CENTER_X - BTN_WIDTH * 0.75,
|
|
y: adBtnY,
|
|
w: BTN_WIDTH * 1.5,
|
|
h: BTN_HEIGHT,
|
|
};
|
|
},
|
|
|
|
exit() {
|
|
this._cleanupNetworkEvents();
|
|
},
|
|
|
|
_setupNetworkEvents() {
|
|
this._cleanupNetworkEvents();
|
|
const nm = this._networkManager;
|
|
if (!nm) return;
|
|
|
|
const unsubs = [];
|
|
|
|
// Listen for rematch ready updates
|
|
unsubs.push(nm.on(NET_MSG.REMATCH_READY, (data) => {
|
|
console.log('[TeamResultScene] REMATCH_READY received:', JSON.stringify(data));
|
|
this._rematchReadyCount = data.readyCount || 0;
|
|
this._rematchTotalCount = data.totalCount || 0;
|
|
}));
|
|
|
|
// Listen for game start (rematch accepted, new game starting)
|
|
unsubs.push(nm.on(NET_MSG.GAME_START, (data) => {
|
|
console.log('[TeamResultScene] GAME_START received for rematch');
|
|
this._startRematchGame(data);
|
|
}));
|
|
|
|
unsubs.push(nm.on(NET_MSG.TEAM_GAME_START, (data) => {
|
|
console.log('[TeamResultScene] TEAM_GAME_START received for rematch');
|
|
this._startRematchGame(data);
|
|
}));
|
|
|
|
this._unsubscribers = unsubs;
|
|
},
|
|
|
|
_cleanupNetworkEvents() {
|
|
for (const unsub of this._unsubscribers) {
|
|
if (typeof unsub === 'function') unsub();
|
|
}
|
|
this._unsubscribers = [];
|
|
},
|
|
|
|
/**
|
|
* Calculate and award gold for team match.
|
|
* @private
|
|
*/
|
|
_calculateAndAwardGold() {
|
|
let gold = 30; // Base reward (reduced from 50)
|
|
|
|
// Find local player stats
|
|
const localPlayer = this._players.find(p => p.isLocal);
|
|
if (localPlayer) {
|
|
const stats = this._stats[localPlayer.playerId] || {};
|
|
gold += (stats.kills || 0) * 5;
|
|
gold += (stats.assists || 0) * 3;
|
|
}
|
|
|
|
// Victory bonus (reduced from 50)
|
|
if (this._didWin) {
|
|
gold += 30;
|
|
}
|
|
|
|
this._goldReward = gold;
|
|
|
|
// Award gold
|
|
if (gold > 0 && GameGlobal.currencyManager) {
|
|
GameGlobal.currencyManager.addGold(gold);
|
|
}
|
|
},
|
|
|
|
_startRematchGame(data) {
|
|
const sm = GameGlobal.sceneManager;
|
|
if (!sm._scenes.has(SCENE.TEAM_GAME)) {
|
|
const TeamGameScene = require('./TeamGameScene');
|
|
sm.register(SCENE.TEAM_GAME, TeamGameScene);
|
|
}
|
|
|
|
const myPlayerId = this._networkManager ? this._networkManager.playerId : 'local';
|
|
|
|
sm.switchTo(SCENE.TEAM_GAME, {
|
|
teamId: data.roomId || this._teamId,
|
|
roomId: data.roomId || this._teamId,
|
|
mapId: data.mapId || null,
|
|
teamA: data.teamA || [],
|
|
teamB: data.teamB || [],
|
|
teamABaseHp: data.teamABaseHp,
|
|
teamBBaseHp: data.teamBBaseHp,
|
|
myPlayerId,
|
|
battleMode: data.battleMode || this._battleMode,
|
|
});
|
|
},
|
|
|
|
update(dt) {
|
|
this._animTimer += dt;
|
|
},
|
|
|
|
render(ctx) {
|
|
// Background
|
|
ctx.fillStyle = COLORS.MENU_BG;
|
|
ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
|
|
// Top accent bar
|
|
const gradient = ctx.createLinearGradient(0, 0, SCREEN_WIDTH, 0);
|
|
gradient.addColorStop(0, '#0f3460');
|
|
gradient.addColorStop(0.5, '#e94560');
|
|
gradient.addColorStop(1, '#0f3460');
|
|
ctx.fillStyle = gradient;
|
|
ctx.fillRect(0, 0, SCREEN_WIDTH, 4);
|
|
|
|
// Title
|
|
ctx.font = 'bold 16px Arial';
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'middle';
|
|
ctx.fillStyle = '#AAAAAA';
|
|
ctx.fillText(t('teamResult.title'), CENTER_X, SCREEN_HEIGHT * 0.05);
|
|
|
|
// Winner announcement with pulsing effect
|
|
let resultText, resultColor;
|
|
if (this._didWin) {
|
|
resultText = t('teamResult.victory');
|
|
resultColor = '#00FF00';
|
|
} else {
|
|
resultText = t('teamResult.defeat');
|
|
resultColor = '#FF4444';
|
|
}
|
|
|
|
const scale = 1 + Math.sin(this._animTimer * 3) * 0.05;
|
|
ctx.save();
|
|
ctx.translate(CENTER_X, SCREEN_HEIGHT * 0.13);
|
|
ctx.scale(scale, scale);
|
|
ctx.fillStyle = resultColor;
|
|
ctx.font = 'bold 28px Arial';
|
|
ctx.fillText(resultText, 0, 0);
|
|
ctx.restore();
|
|
|
|
// Base HP summary
|
|
const hpY = SCREEN_HEIGHT * 0.2;
|
|
ctx.font = 'bold 12px Arial';
|
|
ctx.textAlign = 'center';
|
|
|
|
ctx.fillStyle = TEAM_A_COLOR;
|
|
ctx.fillText(t('teamResult.teamAHp', { hp: this._teamABaseHp }), CENTER_X - 70, hpY);
|
|
|
|
ctx.fillStyle = '#AAAAAA';
|
|
ctx.fillText('vs', CENTER_X, hpY);
|
|
|
|
ctx.fillStyle = TEAM_B_COLOR;
|
|
ctx.fillText(t('teamResult.teamBHp', { hp: this._teamBBaseHp }), CENTER_X + 70, hpY);
|
|
|
|
// Win reason
|
|
let reasonText = t('teamResult.baseDestroyed');
|
|
if (this._winReason === 'disconnected') {
|
|
reasonText = t('teamResult.disconnectedReason');
|
|
}
|
|
ctx.fillStyle = '#888888';
|
|
ctx.font = '10px Arial';
|
|
ctx.fillText(reasonText, CENTER_X, hpY + 16);
|
|
|
|
// Player stats table
|
|
this._renderStatsTable(ctx);
|
|
|
|
// Double reward ad button
|
|
if (!this._adWatched) {
|
|
this._drawButton(ctx, this._adDoubleBtnRect, t('result.adDouble') || '📺 Double Rewards');
|
|
}
|
|
|
|
// Gold reward display
|
|
if (this._goldReward > 0) {
|
|
const goldY = this._adDoubleBtnRect ? this._adDoubleBtnRect.y - 20 : SCREEN_HEIGHT * 0.82;
|
|
ctx.fillStyle = '#FFD700';
|
|
ctx.font = 'bold 14px Arial';
|
|
ctx.textAlign = 'center';
|
|
const goldLabel = this._adWatched
|
|
? `🪙 +${this._goldReward} (${t('result.doubled') || '2x!'})`
|
|
: `🪙 +${this._goldReward}`;
|
|
ctx.fillText(goldLabel, CENTER_X, goldY);
|
|
}
|
|
|
|
// Buttons
|
|
if (this._rematchRequested) {
|
|
// Show waiting state on rematch button
|
|
const dots = '.'.repeat(Math.floor(this._animTimer * 3) % 4);
|
|
this._drawButton(ctx, this._rematchBtnRect,
|
|
t('teamResult.rematchWaiting', { ready: this._rematchReadyCount, total: this._rematchTotalCount }) + dots,
|
|
true);
|
|
} else {
|
|
this._drawButton(ctx, this._rematchBtnRect, t('teamResult.rematch'));
|
|
}
|
|
this._drawButton(ctx, this._menuBtnRect, t('teamResult.backMenu'));
|
|
},
|
|
|
|
_renderStatsTable(ctx) {
|
|
const tableY = SCREEN_HEIGHT * 0.28;
|
|
const tableW = Math.min(SCREEN_WIDTH * 0.92, 400);
|
|
const tableX = CENTER_X - tableW / 2;
|
|
const rowH = 18;
|
|
const headerH = 22;
|
|
|
|
// Sort players: Team A first, then Team B; within team sort by kills desc
|
|
const teamAPlayers = this._players.filter(p => p.team === 'A');
|
|
const teamBPlayers = this._players.filter(p => p.team === 'B');
|
|
|
|
const sortByKills = (a, b) => {
|
|
const sa = this._stats[a.playerId] || {};
|
|
const sb = this._stats[b.playerId] || {};
|
|
return (sb.kills || 0) - (sa.kills || 0);
|
|
};
|
|
teamAPlayers.sort(sortByKills);
|
|
teamBPlayers.sort(sortByKills);
|
|
|
|
// Column positions
|
|
const cols = {
|
|
name: tableX + tableW * 0.22,
|
|
kills: tableX + tableW * 0.48,
|
|
deaths: tableX + tableW * 0.60,
|
|
assists: tableX + tableW * 0.72,
|
|
baseDmg: tableX + tableW * 0.88,
|
|
};
|
|
|
|
// Render Team A section
|
|
let y = tableY;
|
|
|
|
// Team A header
|
|
ctx.fillStyle = 'rgba(74, 144, 217, 0.15)';
|
|
ctx.fillRect(tableX, y, tableW, headerH);
|
|
ctx.fillStyle = TEAM_A_COLOR;
|
|
ctx.font = 'bold 11px Arial';
|
|
ctx.textAlign = 'left';
|
|
ctx.textBaseline = 'middle';
|
|
ctx.fillText(t('teamResult.teamAHeader') + (this._myTeam === 'A' ? t('teamResult.myTeamSuffix') : ''), tableX + 6, y + headerH / 2);
|
|
|
|
// Column headers
|
|
ctx.fillStyle = '#AAAAAA';
|
|
ctx.font = '9px Arial';
|
|
ctx.textAlign = 'center';
|
|
ctx.fillText(t('teamResult.player'), cols.name, y + headerH / 2);
|
|
ctx.fillText(t('teamResult.k'), cols.kills, y + headerH / 2);
|
|
ctx.fillText(t('teamResult.d'), cols.deaths, y + headerH / 2);
|
|
ctx.fillText(t('teamResult.a'), cols.assists, y + headerH / 2);
|
|
ctx.fillText(t('teamResult.dmg'), cols.baseDmg, y + headerH / 2);
|
|
y += headerH;
|
|
|
|
// Team A players
|
|
for (const player of teamAPlayers) {
|
|
const stats = this._stats[player.playerId] || {};
|
|
const isLocal = player.isLocal;
|
|
|
|
ctx.fillStyle = isLocal ? 'rgba(255, 215, 0, 0.1)' : 'rgba(255,255,255,0.02)';
|
|
ctx.fillRect(tableX, y, tableW, rowH);
|
|
|
|
// Player name
|
|
ctx.fillStyle = isLocal ? '#FFD700' : '#CCCCCC';
|
|
ctx.font = isLocal ? 'bold 10px Arial' : '10px Arial';
|
|
ctx.textAlign = 'center';
|
|
const name = player.isBot ? t('teamResult.bot') : this._getDisplayName(player);
|
|
ctx.fillText(name + (isLocal ? ' ★' : ''), cols.name, y + rowH / 2);
|
|
|
|
// Stats
|
|
ctx.fillStyle = '#FFFFFF';
|
|
ctx.font = '10px Arial';
|
|
ctx.fillText(String(stats.kills || 0), cols.kills, y + rowH / 2);
|
|
ctx.fillText(String(stats.deaths || 0), cols.deaths, y + rowH / 2);
|
|
ctx.fillText(String(stats.assists || 0), cols.assists, y + rowH / 2);
|
|
ctx.fillText(String(stats.baseDamage || 0), cols.baseDmg, y + rowH / 2);
|
|
|
|
y += rowH;
|
|
}
|
|
|
|
// Separator
|
|
y += 4;
|
|
|
|
// Team B header
|
|
ctx.fillStyle = 'rgba(233, 69, 96, 0.15)';
|
|
ctx.fillRect(tableX, y, tableW, headerH);
|
|
ctx.fillStyle = TEAM_B_COLOR;
|
|
ctx.font = 'bold 11px Arial';
|
|
ctx.textAlign = 'left';
|
|
ctx.fillText(t('teamResult.teamBHeader') + (this._myTeam === 'B' ? t('teamResult.myTeamSuffix') : ''), tableX + 6, y + headerH / 2);
|
|
|
|
// Column headers
|
|
ctx.fillStyle = '#AAAAAA';
|
|
ctx.font = '9px Arial';
|
|
ctx.textAlign = 'center';
|
|
ctx.fillText(t('teamResult.player'), cols.name, y + headerH / 2);
|
|
ctx.fillText(t('teamResult.k'), cols.kills, y + headerH / 2);
|
|
ctx.fillText(t('teamResult.d'), cols.deaths, y + headerH / 2);
|
|
ctx.fillText(t('teamResult.a'), cols.assists, y + headerH / 2);
|
|
ctx.fillText(t('teamResult.dmg'), cols.baseDmg, y + headerH / 2);
|
|
y += headerH;
|
|
|
|
// Team B players
|
|
for (const player of teamBPlayers) {
|
|
const stats = this._stats[player.playerId] || {};
|
|
const isLocal = player.isLocal;
|
|
|
|
ctx.fillStyle = isLocal ? 'rgba(255, 215, 0, 0.1)' : 'rgba(255,255,255,0.02)';
|
|
ctx.fillRect(tableX, y, tableW, rowH);
|
|
|
|
// Player name
|
|
ctx.fillStyle = isLocal ? '#FFD700' : '#CCCCCC';
|
|
ctx.font = isLocal ? 'bold 10px Arial' : '10px Arial';
|
|
ctx.textAlign = 'center';
|
|
const name = player.isBot ? t('teamResult.bot') : this._getDisplayName(player);
|
|
ctx.fillText(name + (isLocal ? ' ★' : ''), cols.name, y + rowH / 2);
|
|
|
|
// Stats
|
|
ctx.fillStyle = '#FFFFFF';
|
|
ctx.font = '10px Arial';
|
|
ctx.fillText(String(stats.kills || 0), cols.kills, y + rowH / 2);
|
|
ctx.fillText(String(stats.deaths || 0), cols.deaths, y + rowH / 2);
|
|
ctx.fillText(String(stats.assists || 0), cols.assists, y + rowH / 2);
|
|
ctx.fillText(String(stats.baseDamage || 0), cols.baseDmg, y + rowH / 2);
|
|
|
|
y += rowH;
|
|
}
|
|
|
|
// Elapsed time display
|
|
if (this._elapsedTime > 0) {
|
|
y += 8;
|
|
const minutes = Math.floor(this._elapsedTime / 60);
|
|
const seconds = this._elapsedTime % 60;
|
|
ctx.fillStyle = '#666666';
|
|
ctx.font = '10px Arial';
|
|
ctx.textAlign = 'center';
|
|
ctx.fillText(
|
|
t('teamResult.duration', { time: `${minutes}:${seconds.toString().padStart(2, '0')}` }),
|
|
CENTER_X,
|
|
y
|
|
);
|
|
}
|
|
|
|
// MVP highlight (player with most kills)
|
|
const allPlayers = [...teamAPlayers, ...teamBPlayers];
|
|
let mvp = null;
|
|
let maxKills = 0;
|
|
for (const p of allPlayers) {
|
|
const s = this._stats[p.playerId] || {};
|
|
if ((s.kills || 0) > maxKills) {
|
|
maxKills = s.kills || 0;
|
|
mvp = p;
|
|
}
|
|
}
|
|
if (mvp && maxKills > 0) {
|
|
y += 16;
|
|
ctx.fillStyle = '#FFD700';
|
|
ctx.font = 'bold 11px Arial';
|
|
ctx.textAlign = 'center';
|
|
const mvpName = mvp.isBot ? t('teamResult.bot').replace('🤖 ', '') : this._getDisplayName(mvp);
|
|
ctx.fillText(t('teamResult.mvp', { name: mvpName, kills: maxKills }), CENTER_X, y);
|
|
}
|
|
|
|
// Rank points change
|
|
y += 18;
|
|
const basePoints = 20;
|
|
const mvpBonus = 5;
|
|
if (this._didWin) {
|
|
const isMvp = mvp && mvp.isLocal;
|
|
const points = basePoints + (isMvp ? mvpBonus : 0);
|
|
ctx.fillStyle = '#00FF00';
|
|
ctx.font = 'bold 11px Arial';
|
|
ctx.textAlign = 'center';
|
|
ctx.fillText(t('teamResult.rankUp', { points }) + (isMvp ? t('teamResult.mvpBonus') : ''), CENTER_X, y);
|
|
} else {
|
|
ctx.fillStyle = '#FF6347';
|
|
ctx.font = 'bold 11px Arial';
|
|
ctx.textAlign = 'center';
|
|
ctx.fillText(t('teamResult.rankDown', { points: basePoints }), CENTER_X, y);
|
|
}
|
|
},
|
|
|
|
_drawButton(ctx, rect, label) {
|
|
if (!rect) return;
|
|
|
|
ctx.fillStyle = COLORS.MENU_BTN;
|
|
ctx.strokeStyle = COLORS.MENU_BTN_BORDER;
|
|
ctx.lineWidth = 2;
|
|
|
|
const r = 6;
|
|
ctx.beginPath();
|
|
ctx.moveTo(rect.x + r, rect.y);
|
|
ctx.lineTo(rect.x + rect.w - r, rect.y);
|
|
ctx.arcTo(rect.x + rect.w, rect.y, rect.x + rect.w, rect.y + r, r);
|
|
ctx.lineTo(rect.x + rect.w, rect.y + rect.h - r);
|
|
ctx.arcTo(rect.x + rect.w, rect.y + rect.h, rect.x + rect.w - r, rect.y + rect.h, r);
|
|
ctx.lineTo(rect.x + r, rect.y + rect.h);
|
|
ctx.arcTo(rect.x, rect.y + rect.h, rect.x, rect.y + rect.h - r, r);
|
|
ctx.lineTo(rect.x, rect.y + r);
|
|
ctx.arcTo(rect.x, rect.y, rect.x + r, rect.y, r);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = COLORS.MENU_BTN_TEXT;
|
|
ctx.font = 'bold 14px Arial';
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'middle';
|
|
ctx.fillText(label, rect.x + rect.w / 2, rect.y + rect.h / 2);
|
|
},
|
|
|
|
_hitTest(tx, ty, rect) {
|
|
if (!rect) return false;
|
|
return tx >= rect.x && tx <= rect.x + rect.w && ty >= rect.y && ty <= rect.y + rect.h;
|
|
},
|
|
|
|
handleTouch(eventType, e) {
|
|
if (eventType !== 'touchstart') return;
|
|
|
|
const touch = e.touches[0];
|
|
const tx = touch.clientX;
|
|
const ty = touch.clientY;
|
|
|
|
// Double reward ad button
|
|
if (!this._adWatched && this._hitTest(tx, ty, this._adDoubleBtnRect)) {
|
|
const AdManager = require('../managers/AdManager');
|
|
if (GameGlobal.adManager &&
|
|
GameGlobal.adManager.canShowScene(AdManager.AD_SCENE.DOUBLE_REWARD)) {
|
|
GameGlobal.adManager.showRewardedVideoForScene(
|
|
AdManager.AD_SCENE.DOUBLE_REWARD,
|
|
(completed) => {
|
|
if (completed) {
|
|
this._adWatched = true;
|
|
// Award bonus gold (double the original reward)
|
|
if (this._goldReward > 0 && GameGlobal.currencyManager) {
|
|
GameGlobal.currencyManager.addGold(this._goldReward);
|
|
this._goldReward *= 2; // Update display
|
|
}
|
|
console.log('[TeamResultScene] Double reward ad completed');
|
|
}
|
|
}
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Rematch button -> send rematch request to server (reuse room)
|
|
if (this._hitTest(tx, ty, this._rematchBtnRect)) {
|
|
if (!this._rematchRequested) {
|
|
this._rematchRequested = true;
|
|
const nm = this._networkManager;
|
|
console.log(`[TeamResultScene] Rematch clicked. nm=${!!nm}, connected=${nm ? nm.connected : 'N/A'}, teamId=${this._teamId}`);
|
|
if (nm && nm.connected) {
|
|
nm.send(NET_MSG.REMATCH, { teamId: this._teamId });
|
|
console.log('[TeamResultScene] Rematch request sent');
|
|
} else {
|
|
// Not connected, fall back to creating a new room
|
|
this._rematchRequested = false;
|
|
const sm = GameGlobal.sceneManager;
|
|
if (this._battleMode === '1v1') {
|
|
if (!sm._scenes.has(SCENE.PVP_ROOM)) {
|
|
const RoomScene = require('./RoomScene');
|
|
sm.register(SCENE.PVP_ROOM, RoomScene);
|
|
}
|
|
sm.switchTo(SCENE.PVP_ROOM);
|
|
} else {
|
|
if (!sm._scenes.has(SCENE.TEAM_ROOM)) {
|
|
const TeamRoomScene = require('./TeamRoomScene');
|
|
sm.register(SCENE.TEAM_ROOM, TeamRoomScene);
|
|
}
|
|
sm.switchTo(SCENE.TEAM_ROOM);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Menu button -> disconnect and go to menu
|
|
if (this._hitTest(tx, ty, this._menuBtnRect)) {
|
|
// Show interstitial ad when leaving
|
|
if (GameGlobal.adManager) {
|
|
GameGlobal.adManager.showInterstitial();
|
|
}
|
|
if (GameGlobal.networkManager && GameGlobal.networkManager.connected) {
|
|
GameGlobal.networkManager.disconnect();
|
|
}
|
|
const sm = GameGlobal.sceneManager;
|
|
sm.switchTo(SCENE.MENU);
|
|
return;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Compute a display name for the results table (≤ 4 CJK chars).
|
|
* @private
|
|
*/
|
|
_getDisplayName(player) {
|
|
if (!player) return '';
|
|
const profile = GameGlobal.playerProfile;
|
|
let raw = '';
|
|
if (player.isLocal && profile && profile.nickname) {
|
|
raw = profile.nickname;
|
|
} else {
|
|
raw = player.nickname || '';
|
|
}
|
|
if (!raw) {
|
|
if (profile && typeof profile.getDisplayName === 'function') {
|
|
raw = profile.getDisplayName(player.playerId);
|
|
} else {
|
|
raw = player.playerId || '';
|
|
}
|
|
}
|
|
if (profile && typeof profile.truncate === 'function') {
|
|
return profile.truncate(raw, 4);
|
|
}
|
|
return raw.length > 10 ? raw.substring(0, 10) + '..' : raw;
|
|
},
|
|
};
|
|
|
|
module.exports = TeamResultScene;
|