diff --git a/www/html/Game/public/js/play.js b/www/html/Game/public/js/play.js index 75f082f..7f14c76 100644 --- a/www/html/Game/public/js/play.js +++ b/www/html/Game/public/js/play.js @@ -17,6 +17,8 @@ /** สรุปภารกิจแบบ mock (popup-result ฯลฯ) — ใช้เฉพาะฉากนี้จาก editor (id ใน URL เช่น editor.html?id=mnorwqx1) */ const quizCarryMissionSummaryMapId = 'mnorwqx1'; const quizCarryUseMissionSummaryOverlay = playMapIdFromQuery === quizCarryMissionSummaryMapId; + /** Gauntlet พรมแดง — ฉากนี้จาก editor (?map=mno9kb07): วาดตัวหันขวา + ใช้รูป lane/laser จาก game-timing */ + const GAUNTLET_FACE_RIGHT_MAP_ID = 'mno9kb07'; /** จนกว่าโหลด /api/characters — placeholder ชั่วคราวก่อน join */ const LEGACY_PLACEHOLDER_CHARACTER_ID = 'Chatest'; let firstCharacterDefaultResolved = null; @@ -699,8 +701,23 @@ let gauntletLaserLineWidthPx = 2; const gauntletAssetImageCache = new Map(); + /** แปลง URL จาก Admin/game-timing ให้โหลดได้ (nginx เสิร์ฟจาก /Game/...) */ + function normalizeGauntletAssetUrlForPlay(u) { + if (typeof u !== 'string') return ''; + const t = u.trim(); + if (!t) return ''; + if (/^https?:\/\//i.test(t)) return t; + const qIdx = t.indexOf('?'); + const base = (qIdx >= 0 ? t.slice(0, qIdx) : t).trim(); + const qs = qIdx >= 0 ? t.slice(qIdx) : ''; + if (!base) return ''; + if (base.startsWith('/')) return base + qs; + if (/^Game\//i.test(base)) return '/' + base.replace(/^\/+/, '') + qs; + return base + qs; + } + function ensureGauntletAssetImage(url) { - const u = typeof url === 'string' ? url.trim() : ''; + const u = normalizeGauntletAssetUrlForPlay(typeof url === 'string' ? url : ''); if (!u) return null; let rec = gauntletAssetImageCache.get(u); if (rec) return rec; @@ -2423,6 +2440,9 @@ function isFrogger() { return mapData && mapData.gameType === 'frogger'; } function isGauntlet() { return mapData && mapData.gameType === 'gauntlet'; } + function isGauntletFaceRightMapMno9kb07() { + return !!(isGauntlet() && playMapIdFromQuery === GAUNTLET_FACE_RIGHT_MAP_ID); + } function isStack() { return mapData && mapData.gameType === 'stack'; } function isJumpSurvive() { return mapData && mapData.gameType === 'jump_survive'; } function isSpaceShooter() { return mapData && mapData.gameType === 'space_shooter'; } @@ -4873,19 +4893,23 @@ } } if (Object.prototype.hasOwnProperty.call(payload, 'gauntletLaneImageUrls') && Array.isArray(payload.gauntletLaneImageUrls)) { - gauntletLaneImageUrls = payload.gauntletLaneImageUrls.filter((x) => typeof x === 'string').slice(0, 24); + gauntletLaneImageUrls = payload.gauntletLaneImageUrls + .filter((x) => typeof x === 'string') + .map((x) => normalizeGauntletAssetUrlForPlay(x)) + .filter((x) => x) + .slice(0, 24); gauntletLaneImageUrls.forEach((x) => ensureGauntletAssetImage(x)); } if (Object.prototype.hasOwnProperty.call(payload, 'gauntletLaserTopUrl')) { - gauntletLaserTopUrl = typeof payload.gauntletLaserTopUrl === 'string' ? payload.gauntletLaserTopUrl : ''; + gauntletLaserTopUrl = normalizeGauntletAssetUrlForPlay(typeof payload.gauntletLaserTopUrl === 'string' ? payload.gauntletLaserTopUrl : ''); ensureGauntletAssetImage(gauntletLaserTopUrl); } if (Object.prototype.hasOwnProperty.call(payload, 'gauntletLaserBottomUrl')) { - gauntletLaserBottomUrl = typeof payload.gauntletLaserBottomUrl === 'string' ? payload.gauntletLaserBottomUrl : ''; + gauntletLaserBottomUrl = normalizeGauntletAssetUrlForPlay(typeof payload.gauntletLaserBottomUrl === 'string' ? payload.gauntletLaserBottomUrl : ''); ensureGauntletAssetImage(gauntletLaserBottomUrl); } if (Object.prototype.hasOwnProperty.call(payload, 'gauntletLaserLineUrl')) { - gauntletLaserLineUrl = typeof payload.gauntletLaserLineUrl === 'string' ? payload.gauntletLaserLineUrl : ''; + gauntletLaserLineUrl = normalizeGauntletAssetUrlForPlay(typeof payload.gauntletLaserLineUrl === 'string' ? payload.gauntletLaserLineUrl : ''); ensureGauntletAssetImage(gauntletLaserLineUrl); } if (Object.prototype.hasOwnProperty.call(payload, 'gauntletLaserFillColor')) { @@ -9069,7 +9093,7 @@ if (portrait) { const cid = me.characterId || getPlayCharacterId(); - const dir = me.direction || 'down'; + const dir = (isGauntletFaceRightMapMno9kb07() ? 'right' : (me.direction || 'down')); const nowT = Date.now(); const walk = !!me.isWalking; const rawImg = getAvatarImg(cid, dir, nowT, walk); @@ -9665,17 +9689,9 @@ ctx.fillStyle = '#f7768e'; ctx.fillRect(sx + 2, sy + 2, size - 4, size - 4); } - ctx.strokeStyle = '#ff9ebc'; - ctx.lineWidth = 2; - ctx.strokeRect(sx + 2, sy + 2, size - 4, size - 4); - ctx.lineWidth = 1; } else { ctx.fillStyle = '#f7768e'; ctx.fillRect(sx + 2, sy + 2, size - 4, size - 4); - ctx.strokeStyle = '#ff9ebc'; - ctx.lineWidth = 2; - ctx.strokeRect(sx + 2, sy + 2, size - 4, size - 4); - ctx.lineWidth = 1; } } else if (o.kind === 'laser' && typeof o.drawX === 'number') { if (o.drawX < stx - 2 || o.drawX > enx + 2) continue; @@ -9882,16 +9898,18 @@ ? !!o.botIsWalking : !!((o.tx != null && Math.abs((o.tx || o.x) - o.x) > 0.02) || (o.ty != null && Math.abs((o.ty || o.y) - o.y) > 0.02))); const ot = o.playTint || playTintFromPeerId(id); + const faceDirOther = isGauntletFaceRightMapMno9kb07() ? 'right' : o.direction; const botOut = isJumpSurvive() && isPreviewBotId(id) && o.jumpSurviveEliminated; const peerName = botOut ? (o.nickname + ' (ตกรอบ)') : o.nickname; if (botOut) ctx.save(); if (botOut) ctx.globalAlpha = 0.4; - drawAvatar(safeX(o.x) + off.ax, safeY(o.y) + off.ay, false, peerName, o.characterId, o.direction, otherWalk, ot, (o.gauntletJumpVis != null ? o.gauntletJumpVis : o.gauntletJumpTicks) || 0, o.gauntletScore || 0, quizCarrySignForEntity(o)); + drawAvatar(safeX(o.x) + off.ax, safeY(o.y) + off.ay, false, peerName, o.characterId, faceDirOther, otherWalk, ot, (o.gauntletJumpVis != null ? o.gauntletJumpVis : o.gauntletJumpTicks) || 0, o.gauntletScore || 0, quizCarrySignForEntity(o)); if (botOut) ctx.restore(); } else { if (isJumpSurvive() && jumpSurviveEliminated) ctx.save(); if (isJumpSurvive() && jumpSurviveEliminated) ctx.globalAlpha = 0.4; - drawAvatar(safeX(me.x), safeY(me.y), true, me.nickname + meTag, me.characterId, me.direction, meWalking, mt, meGauntletJumpVis, me.gauntletScore || 0, quizCarrySignForEntity(me)); + const faceDirMe = isGauntletFaceRightMapMno9kb07() ? 'right' : me.direction; + drawAvatar(safeX(me.x), safeY(me.y), true, me.nickname + meTag, me.characterId, faceDirMe, meWalking, mt, meGauntletJumpVis, me.gauntletScore || 0, quizCarrySignForEntity(me)); if (isJumpSurvive() && jumpSurviveEliminated) ctx.restore(); } }); diff --git a/www/html/Game/public/play.html b/www/html/Game/public/play.html index f6a53f6..3d22225 100644 --- a/www/html/Game/public/play.html +++ b/www/html/Game/public/play.html @@ -1462,7 +1462,7 @@ - +