From 2f15ac301c369627c738f8fb8f9bff52dafe8be8 Mon Sep 17 00:00:00 2001 From: giteaadmin Date: Wed, 17 Jun 2026 05:02:18 +0000 Subject: [PATCH] =?UTF-8?q?=E0=B9=80=E0=B8=9E=E0=B8=B4=E0=B9=88=E0=B8=A1?= =?UTF-8?q?=E0=B9=80=E0=B8=A7=E0=B8=A5=E0=B8=B2=20=E0=B8=97=E0=B8=99?= =?UTF-8?q?=E0=B8=B2=E0=B8=A2=20=E0=B8=95=E0=B8=B3=E0=B8=A3=E0=B8=A7?= =?UTF-8?q?=E0=B8=88=20=E0=B9=83=E0=B8=AA=E0=B9=88=20Design?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- www/html/Admin/admin.js | 38 +++++++++- www/html/Admin/index.html | 12 +++ www/html/Admin/private/store.json | 10 ++- www/html/Game/data/game-timing.json | 2 +- www/html/Game/public/js/play.js | 36 ++++++++- www/html/Game/public/play.html | 2 +- www/html/Game/server.js | 109 +++++++++++++++++++++------- 7 files changed, 174 insertions(+), 35 deletions(-) diff --git a/www/html/Admin/admin.js b/www/html/Admin/admin.js index adc6857..e979fd8 100644 --- a/www/html/Admin/admin.js +++ b/www/html/Admin/admin.js @@ -4136,6 +4136,40 @@ .then(function () { if (btn) btn.disabled = false; }); } + function loadSpecialQuizIconExpirePanel() { + var inp = el('special-quiz-icon-expire-sec'); + if (!inp) return; + gameTimingFetch('GET') + .then(function (data) { + var v = (data && data.specialQuizIconExpireSec != null) ? Math.floor(Number(data.specialQuizIconExpireSec)) : 10; + if (!Number.isFinite(v) || v < 0) v = 10; + inp.value = String(Math.min(120, v)); + setMsg('special-quiz-icon-expire-msg', '', ''); + }) + .catch(function (e) { setMsg('special-quiz-icon-expire-msg', e.message || 'โหลดไม่ได้', 'error'); }); + } + function saveSpecialQuizIconExpirePanel() { + var inp = el('special-quiz-icon-expire-sec'); + if (!inp) return; + var v = Math.floor(Number(inp.value)); + if (!Number.isFinite(v) || v < 0) v = 10; + v = Math.min(120, v); + inp.value = String(v); + var btn = el('btn-special-quiz-icon-expire-save'); + if (btn) btn.disabled = true; + gameTimingFetch('GET') + .then(function (data) { + data.specialQuizIconExpireSec = v; + return gameTimingFetch('PUT', data); + }) + .then(function (res) { + if (res && res.specialQuizIconExpireSec != null) inp.value = String(res.specialQuizIconExpireSec); + setMsg('special-quiz-icon-expire-msg', v > 0 ? ('บันทึกแล้ว — ไอคอนจะหายใน ' + v + ' วินาที (เริ่มเกมใหม่เพื่อเทสต์)') : 'บันทึกแล้ว — ไอคอนจะไม่หาย (อยู่จนจบเกม)', 'ok'); + }) + .catch(function (e) { setMsg('special-quiz-icon-expire-msg', e.message || 'บันทึกไม่ได้', 'error'); }) + .then(function () { if (btn) btn.disabled = false; }); + } + function saveJumpSurviveTimingPanel() { var inp = el('jump-survive-height-mult'); var jumpSurvMult = inp ? parseFloat(String(inp.value)) : 1.5; @@ -4643,7 +4677,7 @@ } }); if (name === 'quiz') loadQuizSettingsPanel(); - if (name === 'special-quiz') loadSpecialQuizPanel(); + if (name === 'special-quiz') { loadSpecialQuizPanel(); loadSpecialQuizIconExpirePanel(); } if (name === 'evidence-cards') loadEvidenceCardsPanel(); if (name === 'case-media') loadCaseMediaPanel(); if (name === 'quiz-carry') loadQuizCarryPanel(); @@ -4884,6 +4918,8 @@ if (specialCardSaveBtn) specialCardSaveBtn.addEventListener('click', saveSpecialCardByMapPanel); var troublesomeForceSaveBtn = el('btn-troublesome-force-save'); if (troublesomeForceSaveBtn) troublesomeForceSaveBtn.addEventListener('click', saveTroublesomeForcePanel); + var sqIconExpireSaveBtn = el('btn-special-quiz-icon-expire-save'); + if (sqIconExpireSaveBtn) sqIconExpireSaveBtn.addEventListener('click', saveSpecialQuizIconExpirePanel); syncTestModeUi(); /* ฟัง storage event — sync เมื่อเปิดหลายแท็บ */ window.addEventListener('storage', function (e) { diff --git a/www/html/Admin/index.html b/www/html/Admin/index.html index d61e198..3c34aff 100644 --- a/www/html/Admin/index.html +++ b/www/html/Admin/index.html @@ -272,6 +272,18 @@

ชุดคำถามพิเศษ — รับการ์ดพิเศษ

มี 15 ชุด = ระดับ (Level 1–5) × คดี (Case 1–3) · แต่ละชุดมีคำถามเป็นของตัวเอง (สุ่มมาเล่นในเกม) และให้ การ์ดพิเศษ 1 ใบ เป็นรางวัล · เก็บที่ specialQuizSets ใน quiz-settings.json · English: 15 sets (Level × Case), multiple-choice (A/B/C/D), each grants one special card.

+
+ เวลาไอคอนอยู่บนฉาก (ทุกชุด) +

ไอคอนคำถามพิเศษตอนขึ้นต้นเกม จะหายไปเองถ้าไม่มีใครเก็บภายในเวลาที่ตั้ง · 0 = ไม่หาย (อยู่จนจบเกม) · เก็บที่ specialQuizIconExpireSec ใน game-timing.json

+ +

+
+
  1. 1 เลือก ระดับ + คดี ที่จะแก้
  2. 2 ตั้ง การ์ดพิเศษ ของชุดนั้น
  3. diff --git a/www/html/Admin/private/store.json b/www/html/Admin/private/store.json index 39ff16c..b8e840d 100644 --- a/www/html/Admin/private/store.json +++ b/www/html/Admin/private/store.json @@ -38,9 +38,9 @@ "providerUserId": "p_1775109142385_wq7wfy1p32j", "notes": "auto: player-coins", "blocked": false, - "coins": 280, + "coins": 330, "createdAt": "2026-04-02T05:52:21+00:00", - "updatedAt": "2026-06-16T14:58:05+00:00", + "updatedAt": "2026-06-17T03:36:39+00:00", "daily": { "anchorMs": 1781197200000, "claimedDays": [ @@ -54,13 +54,15 @@ ], "lockUntilMs": 0 }, - "score": 230, + "score": 280, "scoreByCase": { "1": 10, "10": 70, "8": 110, "11": 20, - "13": 20 + "13": 20, + "14": 20, + "9": 30 }, "lbName": "Q" }, diff --git a/www/html/Game/data/game-timing.json b/www/html/Game/data/game-timing.json index 14297fd..2c0e146 100644 --- a/www/html/Game/data/game-timing.json +++ b/www/html/Game/data/game-timing.json @@ -102,5 +102,5 @@ "mnpz6rkp": 6, "mnq1eml7": 7 }, - "troublesomeForceOffer": true + "troublesomeForceOffer": false } \ No newline at end of file diff --git a/www/html/Game/public/js/play.js b/www/html/Game/public/js/play.js index 6e40535..50da276 100644 --- a/www/html/Game/public/js/play.js +++ b/www/html/Game/public/js/play.js @@ -3126,6 +3126,26 @@ return true; } + /** สุ่มช่องในโซนผีที่ footprint ลงได้ (ใช้คุมบอทผีให้อยู่ในโซน) — คืน {x,y} หรือ null */ + function randomGhostZoneCellPlay() { + const g = quizGhostAreaGridPlay(); + if (!g) return null; + const cells = []; + for (let y = 0; y < g.length; y++) { + const row = g[y] || []; + for (let x = 0; x < row.length; x++) { + if (row[x] === 1 && quizGhostFootprintInsidePlay(x, y)) cells.push({ x: x, y: y }); + } + } + if (!cells.length) { + for (let y = 0; y < g.length; y++) { + const row = g[y] || []; + for (let x = 0; x < row.length; x++) if (row[x] === 1) cells.push({ x: x, y: y }); + } + } + return cells.length ? cells[Math.floor(Math.random() * cells.length)] : null; + } + /** ตรวจว่า peer/me ตอบผิดในแมป mng8a80o แล้ว → คุมผีแทน avatar */ function isQuizWrongGhostActiveForEnt(entId) { if (!isQuizQuestionMissionUiMapPlay()) return false; @@ -19845,6 +19865,11 @@ /* ข้าม path-following → ตกไป wander logic ด้านล่าง */ o.botPath = []; o.botAnswerWander = true; + /* คุมบอทผีให้อยู่ในโซนผี — ถ้าหลุดออกนอกโซน ดึงกลับเข้าช่องในโซน (เหมือน me ที่โดนวาร์ป) */ + if (quizGhostAreaGridPlay() && !quizGhostFootprintInsidePlay(o.x, o.y)) { + const gz = randomGhostZoneCellPlay(); + if (gz) { o.x = gz.x; o.y = gz.y; o.tx = gz.x; o.ty = gz.y; o.botWanderTX = undefined; o.botWanderTY = undefined; } + } } if (inAnswerPhase && o.botPath && o.botPath.length > 0 && !o.botAnswerWander) { stepPreviewBotAlongPath(o, w, h); @@ -19858,8 +19883,15 @@ && Math.hypot(o.botWanderTX - o.x, o.botWanderTY - o.y) < 0.5; const timedOutQ = typeof o.botWanderRetargetAt === 'number' && now >= o.botWanderRetargetAt; if (typeof o.botWanderTX !== 'number' || typeof o.botWanderTY !== 'number' || arrivedQ || timedOutQ) { - o.botWanderTX = 1 + Math.random() * Math.max(1, w - 2); - o.botWanderTY = 1 + Math.random() * Math.max(1, h - 2); + if (ghostWanderBot) { + /* บอทผี: สุ่มเป้าหมายเฉพาะ "ในโซนผี" → ไม่เดินออกนอกเขต */ + const gz = randomGhostZoneCellPlay(); + o.botWanderTX = gz ? gz.x : o.x; + o.botWanderTY = gz ? gz.y : o.y; + } else { + o.botWanderTX = 1 + Math.random() * Math.max(1, w - 2); + o.botWanderTY = 1 + Math.random() * Math.max(1, h - 2); + } o.botWanderRetargetAt = now + 3000 + Math.floor(Math.random() * 4500); o.botWanderPauseUntil = (arrivedQ && Math.random() < 0.4) ? now + 500 + Math.floor(Math.random() * 1500) : 0; } diff --git a/www/html/Game/public/play.html b/www/html/Game/public/play.html index 7392a7d..1d32538 100644 --- a/www/html/Game/public/play.html +++ b/www/html/Game/public/play.html @@ -5180,7 +5180,7 @@ - +
    v —