diff --git a/www/html/Game/public/js/play.js b/www/html/Game/public/js/play.js index 5d095c1..70ecb40 100644 --- a/www/html/Game/public/js/play.js +++ b/www/html/Game/public/js/play.js @@ -14,6 +14,8 @@ const forceDefaultCharacter = params.get('defaultChar') === '1'; const editorEmbedReturn = params.get('editorEmbed') === '1'; const playMapIdFromQuery = (params.get('map') || '').trim(); + /** mapId จาก join / game-start — ใช้จับฉาก crown เมื่อ URL ไม่มี ?map= */ + let playSessionMapId = playMapIdFromQuery; /** สรุปภารกิจแบบ mock (popup-result ฯลฯ) — ใช้เฉพาะฉากนี้จาก editor (id ใน URL เช่น editor.html?id=mnorwqx1) */ const quizCarryMissionSummaryMapId = 'mnorwqx1'; const quizCarryUseMissionSummaryOverlay = playMapIdFromQuery === quizCarryMissionSummaryMapId; @@ -99,7 +101,7 @@ /** โหลดจาก mapData.gridImageLibrary — ดัชนีตรงกับ gridImageCells[y][x] */ let mapGridImageImgs = []; let mapGridImageHeldImgs = []; - let me = { x: 1, y: 1, direction: 'down', nickname: nick, isWalking: false, playTint: null, gauntletScore: 0, tx: null, ty: null, quizCarryHeld: null }; + let me = { x: 1, y: 1, direction: 'down', nickname: nick, isWalking: false, playTint: null, gauntletScore: 0, gauntletEliminated: false, tx: null, ty: null, quizCarryHeld: null }; const others = new Map(); /** Stack preview HUD: เทอร์มินัลล็อก (cyber UI) */ const STACK_PREVIEW_HUD_LOG_MAX = 8; @@ -2026,7 +2028,10 @@ if (o.botAnswerWander == null) o.botAnswerWander = false; if (o.gauntletJumpTicks == null) o.gauntletJumpTicks = 0; if (o.gauntletJumpVis == null) o.gauntletJumpVis = o.gauntletJumpTicks; - if (o.gauntletScore == null) o.gauntletScore = 0; + if (o.gauntletScore == null) { + o.gauntletScore = (mapData && mapData.gameType === 'gauntlet' && isGauntletCrownHeistMapPlay()) ? 100 : 0; + } + if (o.gauntletEliminated == null) o.gauntletEliminated = false; if (o.botWanderDx == null || o.botWanderDy == null || (o.botWanderDx === 0 && o.botWanderDy === 0)) { const wd = [[0, -1], [0, 1], [-1, 0], [1, 0]][Math.floor(Math.random() * 4)]; o.botWanderDx = wd[0]; @@ -2058,6 +2063,7 @@ const tierRoll = Math.random(); const botTier = tierRoll < 0.28 ? 'sharp' : tierRoll < 0.62 ? 'avg' : 'weak'; const wd = [[0, -1], [0, 1], [-1, 0], [1, 0]][Math.floor(Math.random() * 4)]; + const crownStart = mapData.gameType === 'gauntlet' && isGauntletCrownHeistMapPlay(); others.set(id, { x, y, tx: x, ty: y, direction: ['down', 'up', 'left', 'right'][Math.floor(Math.random() * 4)], @@ -2067,7 +2073,8 @@ botTier, gauntletJumpTicks: 0, gauntletJumpVis: 0, - gauntletScore: 0, + gauntletScore: crownStart ? 100 : 0, + gauntletEliminated: false, quizCannotTrue: false, quizCannotFalse: false, quizCarryHeld: null, @@ -2441,7 +2448,15 @@ function isFrogger() { return mapData && mapData.gameType === 'frogger'; } function isGauntlet() { return mapData && mapData.gameType === 'gauntlet'; } function isGauntletFaceRightMapMno9kb07() { - return !!(isGauntlet() && playMapIdFromQuery === GAUNTLET_FACE_RIGHT_MAP_ID); + return !!(isGauntlet() && playSessionMapId === GAUNTLET_FACE_RIGHT_MAP_ID); + } + /** Crown heist rules + UI (เดียวกับหันขวา — ฉาก mno9kb07) */ + function isGauntletCrownHeistMapPlay() { + return isGauntletFaceRightMapMno9kb07(); + } + let gauntletCrownHowtoVisible = false; + function isGauntletCrownHowtoBlocking() { + return isGauntletCrownHeistMapPlay() && gauntletCrownHowtoVisible; } function isStack() { return mapData && mapData.gameType === 'stack'; } function isJumpSurvive() { return mapData && mapData.gameType === 'jump_survive'; } @@ -5068,6 +5083,7 @@ * — ตอบสนองสิ่งกีดขวางที่ชนเซลล์เดียวกัน + กระโดดล่วงหน้าเมื่อ threat อยู่คอลัมน์ถัดไป */ function maybePreviewBotGauntletJump(o, obstacles, w, h) { + if (isGauntletCrownHeistMapPlay() && o.gauntletEliminated) return; let px = Math.floor(Number(o.x)) || 0; let py = Math.floor(Number(o.y)) || 0; px = Math.max(0, Math.min(w - 1, px)); @@ -5101,12 +5117,14 @@ /** หนึ่ง tick เดียวกับ runGauntletTick ฝั่งเซิร์ฟเวอร์ (เฉพาะ collision + เลื่อน x) */ function applyGauntletPhysicsToPreviewBot(o, obstacles, w, h) { + if (isGauntletCrownHeistMapPlay() && o.gauntletEliminated) return; let px = Math.floor(Number(o.x)) || 0; let py = Math.floor(Number(o.y)) || 0; px = Math.max(0, Math.min(w - 1, px)); py = Math.max(0, Math.min(h - 1, py)); const air = (o.gauntletJumpTicks || 0) > 0; const { ch: gauntletCh2 } = getCharacterFootprintWH(mapData); + const crown = isGauntletCrownHeistMapPlay(); let advanceX = false; let hitBack = false; for (let i = 0; i < obstacles.length; i++) { @@ -5129,9 +5147,21 @@ if (advanceX) { px = Math.min(w - 2, px + 1); o.gauntletJumpTicks = 0; - o.gauntletScore = (o.gauntletScore || 0) + 1; + if (!crown) { + o.gauntletScore = (o.gauntletScore || 0) + 1; + } } else if (hitBack) { - px = Math.max(0, px - 1); + if (crown) { + if (px <= 0) { + o.gauntletEliminated = true; + o.gauntletScore = 0; + } else { + o.gauntletScore = Math.max(0, (o.gauntletScore || 0) - 10); + px = Math.max(0, px - 1); + } + } else { + px = Math.max(0, px - 1); + } } if ((o.gauntletJumpTicks || 0) > 0) o.gauntletJumpTicks--; o.tx = px; @@ -5165,6 +5195,163 @@ socket.emit('gauntlet-preview-rows', { ys: [...ysSet] }); } + /** ซ่อน overlay โหมดอื่นที่ค้างจาก embed / session ก่อน — กัน UI ซ้อนไม่ตรง mock */ + function hideConflictingOverlaysForGauntletCrown() { + hideQuizCarryPregameOverlay(); + quizCarryPregameActive = false; + const hideIds = [ + 'quiz-game-overlay', + 'quiz-carry-mission-overlay', + 'gauntlet-ended-overlay', + 'quiz-battle-mcq-overlay', + 'quiz-carry-embed-countdown', + 'quiz-carry-embed-q-strip', + 'play-quiz-scoreboard', + 'play-quiz-feedback', + ]; + for (let i = 0; i < hideIds.length; i++) { + const el = document.getElementById(hideIds[i]); + if (el) el.classList.add('is-hidden'); + } + const gcm = document.getElementById('gauntlet-crown-mission-overlay'); + if (gcm) gcm.classList.add('is-hidden'); + } + + function gcmRankBadgeUrl(rank) { + const r = Math.floor(Number(rank)) || 99; + if (r === 1) return BASE + '/img/gauntlet-assets/result-1st.png'; + if (r === 2) return BASE + '/img/gauntlet-assets/result-2nd.png'; + if (r === 3) return BASE + '/img/gauntlet-assets/result-3rd.png'; + return BASE + '/img/gauntlet-assets/result-txt-2.png'; + } + + function showGauntletCrownHowtoOverlay() { + if (!isGauntletCrownHeistMapPlay()) return; + hideConflictingOverlaysForGauntletCrown(); + const ov = document.getElementById('gauntlet-crown-howto-overlay'); + if (!ov) return; + gauntletCrownHowtoVisible = true; + ov.classList.remove('is-hidden'); + const btn = document.getElementById('btn-gch-ready'); + if (btn) { + btn.onclick = function () { + ov.classList.add('is-hidden'); + gauntletCrownHowtoVisible = false; + }; + } + } + + function showGauntletCrownMissionOverlay(mission) { + const ov = document.getElementById('gauntlet-crown-mission-overlay'); + const rowEl = document.getElementById('gcm-rank-row'); + const totalEl = document.getElementById('gcm-total'); + const gradeEl = document.getElementById('gcm-grade'); + const bonusEl = document.getElementById('gcm-bonus'); + const btn = document.getElementById('btn-gcm-done'); + if (!ov || !rowEl || !mission || !Array.isArray(mission.ranked)) return; + rowEl.innerHTML = ''; + mission.ranked.forEach((r) => { + const cell = document.createElement('div'); + cell.className = 'gcm-cell'; + const tag = document.createElement('div'); + tag.className = 'gcm-rank-tag'; + const rk = Math.floor(Number(r.rank)) || 0; + if (rk >= 1 && rk <= 3) { + const tagImg = document.createElement('img'); + tagImg.src = gcmRankBadgeUrl(rk); + tagImg.alt = '[' + String(r.rankLabel || rk) + ']'; + tagImg.style.maxWidth = '100%'; + tagImg.style.height = 'auto'; + tag.appendChild(tagImg); + } else { + tag.textContent = '[' + String(r.rankLabel || rk) + ']'; + } + const frame = document.createElement('div'); + frame.className = 'gcm-frame'; + const img = document.createElement('img'); + img.className = 'gcm-av'; + img.alt = ''; + const cid = r.characterId ? String(r.characterId) : ''; + if (cid) { + const im = getCharacterImg(cid, 'down'); + if (im && im.src) img.src = im.src; + } else { + img.src = defaultAvatarImg.src; + } + img.onerror = function () { + this.onerror = null; + this.src = defaultAvatarImg.src; + }; + frame.appendChild(img); + if (r.eliminated) { + const st = document.createElement('img'); + st.className = 'gcm-stamp'; + st.src = BASE + '/img/gauntlet-assets/result-Lose_stamp.png'; + st.alt = 'เสียชีวิต'; + frame.appendChild(st); + } + const nick = document.createElement('div'); + nick.className = 'gcm-nick'; + nick.textContent = r.nickname || '—'; + const sc = document.createElement('div'); + sc.className = 'gcm-sc'; + sc.textContent = String(r.baseScore || 0) + '(+' + String(r.rankBonus || 0) + ')'; + cell.appendChild(tag); + cell.appendChild(frame); + cell.appendChild(nick); + cell.appendChild(sc); + rowEl.appendChild(cell); + }); + if (totalEl) { + const parts = (mission.totalParts || []).map((n) => String(Math.max(0, Number(n) || 0))); + const sum = Math.max(0, Number(mission.totalSum) || 0); + const avg = Math.max(0, Math.floor(Number(mission.averageScore) || 0)); + totalEl.innerHTML = 'คะแนนรวม (' + parts.join('+') + ') = ' + sum + ' · เฉลี่ย ' + avg + ' → เกรด'; + } + if (gradeEl) { + const g = String(mission.grade || 'C').toUpperCase().charAt(0); + gradeEl.textContent = g; + gradeEl.className = 'gcm-grade gcm-grade--' + g.toLowerCase(); + } + if (bonusEl) { + bonusEl.innerHTML = ''; + const row = document.createElement('div'); + row.style.display = 'flex'; + row.style.alignItems = 'center'; + row.style.gap = '8px'; + const chk = document.createElement('img'); + chk.src = BASE + '/img/gauntlet-assets/result-check.png'; + chk.alt = ''; + chk.width = 26; + chk.height = 26; + const sp = document.createElement('span'); + sp.style.color = '#9ece6a'; + sp.style.fontWeight = '700'; + sp.textContent = 'ภารกิจสำเร็จ'; + row.appendChild(chk); + row.appendChild(sp); + bonusEl.appendChild(row); + const rc = mission.rewardCard; + if (rc && rc.th) { + const pl = document.createElement('div'); + pl.className = 'gcm-plaque'; + pl.innerHTML = '' + String(rc.th) + '' + String(rc.en || '') + ''; + bonusEl.appendChild(pl); + } + } + ov.classList.remove('is-hidden'); + function goLobby() { + ov.classList.add('is-hidden'); + window.location.href = 'room-lobby.html?space=' + encodeURIComponent(spaceId) + '&nick=' + encodeURIComponent(nick); + } + if (btn) { + btn.onclick = function () { + if (previewMode && editorEmbedReturn) ov.classList.add('is-hidden'); + else goLobby(); + }; + } + } + function isLobby() { return mapData && mapData.gameType === 'lobby'; } function isQuiz() { return mapData && mapData.gameType === 'quiz'; } function getLane(y) { @@ -7351,6 +7538,9 @@ const prevWasSpaceShooter = mapData && mapData.gameType === 'space_shooter'; const prevWasBalloonBoss = mapData && mapData.gameType === 'balloon_boss'; mapData = gameMapData; + if (res && res.mapId != null && String(res.mapId).trim() !== '') { + playSessionMapId = String(res.mapId).trim(); + } if (res && res.hostId != null) playHostId = res.hostId; if (mapData.gameType !== 'space_shooter') { spaceShooterGameEnded = false; @@ -7426,6 +7616,7 @@ { const sc0 = Number(myPeer && myPeer.gauntletScore); me.gauntletScore = Number.isFinite(sc0) ? Math.max(0, sc0) : 0; + me.gauntletEliminated = !!(myPeer && myPeer.gauntletEliminated); } { const sh0 = Number(myPeer && myPeer.spaceShooterScore); @@ -7465,6 +7656,7 @@ gauntletJumpTicks: typeof p.gauntletJumpTicks === 'number' ? p.gauntletJumpTicks : 0, gauntletJumpVis: typeof p.gauntletJumpTicks === 'number' ? p.gauntletJumpTicks : 0, gauntletScore: (() => { const s = Number(p.gauntletScore); return Number.isFinite(s) ? Math.max(0, s) : 0; })(), + gauntletEliminated: !!p.gauntletEliminated, spaceShooterScore: (() => { const s = Number(p.spaceShooterScore); return Number.isFinite(s) ? Math.max(0, s) : 0; })(), balloonBossScore: (() => { const s = Number(p.balloonBossScore); return Number.isFinite(s) ? Math.max(0, s) : 0; })(), balloonBossBalloons: (() => { @@ -7558,6 +7750,16 @@ else if (isQuizCarry()) setupPlayQuizCarryUi(); else if (isQuizBattle()) setupPlayQuizBattleUi(); else teardownPlayQuizUi(); + if (mapData.gameType === 'gauntlet' && isGauntletCrownHeistMapPlay()) { + hideConflictingOverlaysForGauntletCrown(); + setTimeout(function () { showGauntletCrownHowtoOverlay(); }, 50); + } else { + const hov = document.getElementById('gauntlet-crown-howto-overlay'); + if (hov) { + hov.classList.add('is-hidden'); + gauntletCrownHowtoVisible = false; + } + } resizeCanvas(); draw(); tick(); } @@ -7862,8 +8064,10 @@ if (p.direction) me.direction = p.direction; const jt = Number(p.gauntletJumpTicks); meGauntletJumpTicks = Number.isFinite(jt) ? jt : 0; + meGauntletJumpVis = meGauntletJumpTicks; const sc = Number(p.gauntletScore); me.gauntletScore = Number.isFinite(sc) ? Math.max(0, sc) : 0; + me.gauntletEliminated = !!p.gauntletEliminated; } else { const o = others.get(p.id) ?? others.get(pid); if (o) { @@ -7877,6 +8081,7 @@ if (o.gauntletJumpVis == null) o.gauntletJumpVis = o.gauntletJumpTicks; const sc = Number(p.gauntletScore); o.gauntletScore = Number.isFinite(sc) ? Math.max(0, sc) : 0; + o.gauntletEliminated = !!p.gauntletEliminated; } } }); @@ -7887,13 +8092,20 @@ }); socket.on('gauntlet-ended', (data) => { + gauntletEndsAtMs = null; + const hto = document.getElementById('gauntlet-crown-howto-overlay'); + if (hto) hto.classList.add('is-hidden'); + gauntletCrownHowtoVisible = false; + if (data && data.crownMission) { + showGauntletCrownMissionOverlay(data.crownMission); + return; + } const ov = document.getElementById('gauntlet-ended-overlay'); const msgEl = document.getElementById('gauntlet-ended-message'); const titleEl = document.getElementById('gauntlet-ended-title'); const listEl = document.getElementById('gauntlet-ended-rankings'); const btn = document.getElementById('btn-gauntlet-ended-lobby'); if (!ov || !msgEl || !listEl) return; - gauntletEndsAtMs = null; if (titleEl) { titleEl.textContent = data && data.reason === 'time' ? 'หมดเวลา · Time up' : 'เกมจบ · Game over'; } @@ -7923,6 +8135,9 @@ if (!ev || !ev.mapId) return; const applySnap = (md) => { mapData = md; + if (ev.mapId != null && String(ev.mapId).trim() !== '') { + playSessionMapId = String(ev.mapId).trim(); + } if (mapData.gameType !== 'space_shooter') { spaceShooterGameEnded = false; } @@ -7955,6 +8170,7 @@ meGauntletJumpVis = meGauntletJumpTicks; const sc = Number(p.gauntletScore); me.gauntletScore = Number.isFinite(sc) ? Math.max(0, sc) : 0; + me.gauntletEliminated = !!p.gauntletEliminated; } else { const o = others.get(p.id) ?? others.get(String(p.id)); if (o) { @@ -7968,6 +8184,7 @@ o.gauntletJumpVis = o.gauntletJumpTicks; const sc = Number(p.gauntletScore); o.gauntletScore = Number.isFinite(sc) ? Math.max(0, sc) : 0; + o.gauntletEliminated = !!p.gauntletEliminated; } } }); @@ -7975,10 +8192,12 @@ meGauntletJumpTicks = 0; meGauntletJumpVis = 0; me.gauntletScore = 0; + me.gauntletEliminated = false; others.forEach((o) => { o.gauntletJumpTicks = 0; o.gauntletJumpVis = 0; o.gauntletScore = 0; + o.gauntletEliminated = false; }); } if (mapData.gameType === 'gauntlet') { @@ -7995,8 +8214,18 @@ if (stackMini && isStack()) stackMini.phaseSpeed = playStackSwingHz; }) .catch(() => {}); + if (String(ev.mapId || '') === GAUNTLET_FACE_RIGHT_MAP_ID) { + setTimeout(function () { showGauntletCrownHowtoOverlay(); }, 60); + } else { + const hto2 = document.getElementById('gauntlet-crown-howto-overlay'); + if (hto2) hto2.classList.add('is-hidden'); + gauntletCrownHowtoVisible = false; + } } else { gauntletEndsAtMs = null; + const hto3 = document.getElementById('gauntlet-crown-howto-overlay'); + if (hto3) hto3.classList.add('is-hidden'); + gauntletCrownHowtoVisible = false; } if (mapData.gameType !== 'gauntlet') { me.tx = null; @@ -8004,6 +8233,8 @@ } const gauntletOv = document.getElementById('gauntlet-ended-overlay'); if (gauntletOv) gauntletOv.classList.add('is-hidden'); + const gcmOv = document.getElementById('gauntlet-crown-mission-overlay'); + if (gcmOv) gcmOv.classList.add('is-hidden'); if (mapData.gameType === 'stack') { if (!mapData.stackReleaseArea) mapData.stackReleaseArea = []; if (!mapData.stackLandArea) mapData.stackLandArea = []; @@ -9192,6 +9423,8 @@ : (me.balloonBossEliminated ? 'คุณตกรอบแล้ว — ดูเพื่อนเล่น · You are out — spectate' : 'ยานมีแรงเฉื่อย — A D / arrows / W S เร่งทิศทาง · ปล่อยปุ่มแล้วยังไหล (แรงหน่วง) · Space = ยิง (ดีเลย์) · ลูกโป้งหมด = ตกรอบ'); + } else if (isGauntletCrownHeistMapPlay()) { + hintEl.textContent = 'Space / W / ↑ jump · Start 100 pts · Hit -10 · Fall off left edge = out · Rank bonus at end'; } else { hintEl.textContent = 'Space / W / ↑ jump · Lanes + lasers · Clear = right + score'; } @@ -9221,7 +9454,8 @@ : (isSpaceShooter() ? (me.spaceShooterScore || 0) : (isBalloonBoss() ? (me.balloonBossScore || 0) : 0))), y: safeYv(me.y), - eliminated: !!(isJumpSurvive() && jumpSurviveEliminated) || !!(isBalloonBoss() && me.balloonBossEliminated), + eliminated: !!(isJumpSurvive() && jumpSurviveEliminated) || !!(isBalloonBoss() && me.balloonBossEliminated) + || !!(isGauntletCrownHeistMapPlay() && me.gauntletEliminated), isMe: true, }); others.forEach((o, id) => { @@ -9235,7 +9469,8 @@ : (isBalloonBoss() ? (o.balloonBossScore || 0) : 0))), y: safeYv(o.y), eliminated: !!(isJumpSurvive() && isPreviewBotId(id) && o.jumpSurviveEliminated) - || !!(isBalloonBoss() && o.balloonBossEliminated), + || !!(isBalloonBoss() && o.balloonBossEliminated) + || !!(isGauntletCrownHeistMapPlay() && o.gauntletEliminated), isMe: false, }); }); @@ -9296,7 +9531,7 @@ st.textContent = isQuizCarry() ? '' : (row.eliminated - ? (isBalloonBoss() ? 'OUT' : 'OFFLINE') + ? (isBalloonBoss() ? 'OUT' : (isGauntletCrownHeistMapPlay() ? 'เสียชีวิต' : 'OFFLINE')) : (isBalloonBoss() ? ('♥' + Math.max(0, row.isMe ? (me.balloonBossBalloons | 0) : ((() => { const ox = others.get(row.id); @@ -9987,10 +10222,17 @@ ctx.fillStyle = '#f7768e'; ctx.font = 'bold 14px sans-serif'; ctx.textAlign = 'left'; - ctx.fillText('พรมแดงสุดท้าย | คะแนน: ' + (me.gauntletScore || 0) + ' (ข้าม 1 ชิ้น +1) · สูงสุด 6 คน', 10, 24); - ctx.font = '12px sans-serif'; - ctx.fillStyle = '#c0caf5'; - ctx.fillText('Space / W / ↑ = กระโดด · เลน + เลเซอร์ · ข้ามสำเร็จ → ขวา 1 + คะแนน · ชน → ซ้าย 1', 10, 42); + if (isGauntletCrownHeistMapPlay()) { + ctx.fillText('พรมแดงสุดท้าย | คะแนน ' + (me.gauntletScore || 0) + ' · ชน -10 · ขอบซ้ายตาย · สูงสุด 6 คน', 10, 24); + ctx.font = '12px sans-serif'; + ctx.fillStyle = '#c0caf5'; + ctx.fillText('Space / W / ↑ = กระโดด · เลน + เลเซอร์ · จบเกมมีโบนัสอันดับ + เกรดทีม', 10, 42); + } else { + ctx.fillText('พรมแดงสุดท้าย | คะแนน: ' + (me.gauntletScore || 0) + ' (ข้าม 1 ชิ้น +1) · สูงสุด 6 คน', 10, 24); + ctx.font = '12px sans-serif'; + ctx.fillStyle = '#c0caf5'; + ctx.fillText('Space / W / ↑ = กระโดด · เลน + เลเซอร์ · ข้ามสำเร็จ → ขวา 1 + คะแนน · ชน → ซ้าย 1', 10, 42); + } ctx.fillStyle = '#e0af68'; if (gauntletEndsAtMs != null && Number.isFinite(gauntletEndsAtMs)) { const rem = Math.max(0, Math.ceil((gauntletEndsAtMs - Date.now()) / 1000)); @@ -10082,6 +10324,8 @@ if (isGauntlet() && mapData && !isChatFocused()) { if (e.code === 'Space' || e.code === 'ArrowUp' || e.code === 'KeyW') { e.preventDefault(); + if (isGauntletCrownHowtoBlocking()) return; + if (isGauntletCrownHeistMapPlay() && me.gauntletEliminated) return; const now = Date.now(); if (now - lastGauntletJumpKey < 200) return; lastGauntletJumpKey = now; diff --git a/www/html/Game/public/js/version.js b/www/html/Game/public/js/version.js index a0e87c7..6d696b4 100644 --- a/www/html/Game/public/js/version.js +++ b/www/html/Game/public/js/version.js @@ -1,6 +1,6 @@ // ทุกครั้งที่มีการเพิ่มหรือเปลี่ยน ให้เพิ่ม v +0.0001 // หลังแก้ค่าแล้วต้อง copy ไป path ที่ Nginx ชี้ (หรือรัน copy-frogger-files-only.sh) ถึงจะเห็นบนเว็บ -window.APP_VERSION = '0.0169'; +window.APP_VERSION = '0.0170'; document.addEventListener('DOMContentLoaded', function () { var t = document.querySelector('.version-tag'); if (t) t.textContent = 'v ' + window.APP_VERSION; diff --git a/www/html/Game/public/play.html b/www/html/Game/public/play.html index 1b0dc71..c0b8491 100644 --- a/www/html/Game/public/play.html +++ b/www/html/Game/public/play.html @@ -12,6 +12,17 @@