sound and game4

This commit is contained in:
2026-07-02 04:25:42 +00:00
parent 82a34b2d53
commit 061ebe7170
86 changed files with 152061 additions and 1181 deletions
+51 -11
View File
@@ -51,9 +51,9 @@
"providerUserId": "p_1775109142385_wq7wfy1p32j",
"notes": "auto: player-coins",
"blocked": false,
"coins": 2860,
"coins": 2890,
"createdAt": "2026-04-02T05:52:21+00:00",
"updatedAt": "2026-07-01T14:37:22+00:00",
"updatedAt": "2026-07-02T03:30:08+00:00",
"daily": {
"anchorMs": 1781197200000,
"claimedDays": [
@@ -67,11 +67,11 @@
],
"lockUntilMs": 0
},
"score": 786,
"score": 816,
"scoreByCase": {
"1": 26,
"10": 914,
"8": 296,
"10": 924,
"8": 306,
"11": 20,
"13": 364,
"14": 30,
@@ -83,7 +83,7 @@
"7": 14,
"3": 150,
"6": 44,
"2": 224
"2": 234
},
"lbName": "บอท7",
"achievements": {
@@ -1072,15 +1072,15 @@
"providerUserId": "p_1782802776912_g9ua6h1w5dj",
"notes": "auto: achievements",
"blocked": false,
"coins": 40,
"coins": 56,
"achievements": {
"d1_minigame_solver": 4
"d1_minigame_solver": 6
},
"createdAt": "2026-07-01T06:43:44+00:00",
"updatedAt": "2026-07-01T06:48:17+00:00",
"score": 40,
"updatedAt": "2026-07-01T16:08:23+00:00",
"score": 56,
"scoreByCase": {
"1": 40
"1": 56
},
"lbName": "DevTester"
},
@@ -1121,6 +1121,46 @@
],
"lockUntilMs": 1782925200000
}
},
{
"id": "998017fcbe328e93ad04b2bd",
"email": "",
"displayName": "MONE",
"loginType": "guest",
"providerUserId": "p_1782921490642_wkx6gl2hwtn",
"notes": "auto: game-award",
"blocked": false,
"coins": 24,
"score": 24,
"scoreByCase": {
"1": 24
},
"lbName": "MONE",
"createdAt": "2026-07-01T16:01:03+00:00",
"updatedAt": "2026-07-01T16:08:23+00:00",
"achievements": {
"d1_minigame_solver": 3
}
},
{
"id": "cc3c865981aa4d36998c8645",
"email": "",
"displayName": "ผู้เล่น",
"loginType": "guest",
"providerUserId": "p_1782921488461_e17kxhzmrl8",
"notes": "auto: game-award",
"blocked": false,
"coins": 18,
"score": 18,
"scoreByCase": {
"1": 18
},
"lbName": "ผู้เล่น",
"createdAt": "2026-07-01T16:01:03+00:00",
"updatedAt": "2026-07-01T16:08:23+00:00",
"achievements": {
"d1_minigame_solver": 1
}
}
]
}
+1 -1
View File
@@ -97,7 +97,7 @@
"balloonBossPlayerBalloonFallbackUrl": "/Game/img/MegaVirus/Artboard%209.png",
"balloonBossBalloonsPerPlayer": 3,
"forcedMinigameKeys": [
"gauntlet",
"quiz_carry",
"quiz",
"balloon_boss"
],
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+37 -1
View File
@@ -4136,6 +4136,7 @@
function spaceShooterSpawnAsteroidExplosion(worldX, worldY, r) {
const urls = playSpaceShooterAsteroidSpriteUrls;
if (!urls || urls.length < 2) return;
if (window.jdSound) { try { window.jdSound.playSfx('bomb', 'mg6'); } catch (e) { /* ignore */ } }
spaceShooterAsteroidExplosions.push({
x: worldX,
y: worldY,
@@ -4296,6 +4297,7 @@
}
}
if (!mine) return;
if (window.jdSound) { try { window.jdSound.playSfx(mine.right ? 'correct' : 'wrong', 'mg1'); } catch (e) { /* ignore */ } }
el.classList.remove('is-hidden');
const botExtra = playBotsEnabled() && (botRight + botWrong > 0)
? ' · บอท ถูก ' + botRight + ' / ผิด ' + botWrong + ' (Bots: ' + botRight + ' right / ' + botWrong + ' wrong)'
@@ -4455,6 +4457,7 @@
const scoreEl = document.getElementById('quiz-map-q-feedback-score');
if (!panel || !icon || panel.classList.contains('is-hidden')) return;
clearQuizMapQuestionCarryFeedback();
if (window.jdSound) { try { window.jdSound.playSfx(isCorrect ? 'correct' : 'wrong', 'mg4'); } catch (e) { /* ignore */ } }
icon.src = isCorrect ? QUIZ_CARRY_MAP_FEEDBACK_IMG.correct : QUIZ_CARRY_MAP_FEEDBACK_IMG.incorrect;
icon.classList.remove('is-hidden');
if (isCorrect && scoreWrap && scoreEl) {
@@ -4905,6 +4908,8 @@
function setCountdown321QuestionAssetGraphic(numEl, n) {
if (!numEl) return;
const d = Math.max(1, Math.min(3, n));
/* เสียงนับถอยหลัง (เล่นครั้งเดียวต่อเลข กัน re-render ยิงซ้ำ) */
if (window.jdSound && window.__jdLastCountN !== d) { window.__jdLastCountN = d; try { window.jdSound.playSfx('time'); } catch (e) { /* ignore */ } }
if (String(numEl.tagName || '').toUpperCase() === 'IMG') {
numEl.src = COUNTDOWN_321_IMG_BASE + d + '.png';
numEl.alt = String(d);
@@ -6500,6 +6505,24 @@
}
function isFrogger() { return mapData && mapData.gameType === 'frogger'; }
/* ===== Sound (jdSound) — scene + end-sfx helpers ===== */
var JD_SCENE_MAP = { quiz: 'mg1', gauntlet: 'mg2', stack: 'mg3', quiz_carry: 'mg4', jump_survive: 'mg5', space_shooter: 'mg6', balloon_boss: 'mg7' };
function jdPlayScene() { var gt = mapData && mapData.gameType; return (gt && JD_SCENE_MAP[gt]) || 'mg1'; }
/* เล่นเสียงจบเกมจากชื่อไฟล์แฟลชผล (complete/victory=ชนะ · timeup=หมดเวลา · gameover=แพ้) + หยุด BGM */
function jdEndSfxFromFile(f) {
if (!window.jdSound) return;
f = String(f || ''); var s = jdPlayScene();
if (f.indexOf('victory') >= 0 || f.indexOf('complete') >= 0) window.jdSound.playSfx('win', s);
else if (f.indexOf('timeup') >= 0) window.jdSound.playSfx('timeup', s);
else if (f.indexOf('gameover') >= 0) window.jdSound.playSfx('lose', s);
try { window.jdSound.stopBgm(); } catch (e) { /* ignore */ }
}
/* เสียงคลิกปุ่ม (เฉพาะ element ที่เป็นปุ่มจริง) */
document.addEventListener('click', function (e) {
if (!window.jdSound) return;
var t = (e.target && e.target.closest) ? e.target.closest('button, .btn, [role="button"], [class*="btn-"]') : null;
if (t) { try { window.jdSound.playSfx('button', jdPlayScene()); } catch (err) { /* ignore */ } }
}, true);
function isGauntlet() { return mapData && mapData.gameType === 'gauntlet'; }
function isGauntletFaceRightMapMno9kb07() {
if (!isGauntlet()) return false;
@@ -7306,6 +7329,7 @@
if (!mission || !ov || !imgEl) { showGauntletCrownMissionOverlay(mission); return; }
const finishToGcm = function () { hideStackTowerResultFlashDomOnlyPlay(); showGauntletCrownMissionOverlay(mission); };
imgEl.onerror = function () { imgEl.onerror = null; finishToGcm(); };
jdEndSfxFromFile(file);
imgEl.src = gcmMissionMockAssetUrl(mission, file);
ov.classList.remove('is-hidden');
ov.setAttribute('aria-hidden', 'false');
@@ -7339,6 +7363,7 @@
imgEl.onerror = null;
finishToGcm();
};
jdEndSfxFromFile(file);
imgEl.src = url;
ov.classList.remove('is-hidden');
ov.setAttribute('aria-hidden', 'false');
@@ -7381,6 +7406,7 @@
imgEl.onerror = null;
onDone();
};
jdEndSfxFromFile(file);
imgEl.src = jumperAssetUrl(file);
ov.classList.remove('is-hidden');
ov.setAttribute('aria-hidden', 'false');
@@ -7425,6 +7451,7 @@
imgEl.onerror = null;
onDone();
};
jdEndSfxFromFile(file);
imgEl.src = violentCrimeAssetUrl(file);
ov.classList.remove('is-hidden');
ov.setAttribute('aria-hidden', 'false');
@@ -7468,12 +7495,14 @@
};
const showOneFlash = function (url, onDone) {
imgEl.onerror = function () { imgEl.onerror = null; onDone(); };
jdEndSfxFromFile(url);
imgEl.src = url;
ov.classList.remove('is-hidden');
ov.setAttribute('aria-hidden', 'false');
stackTowerResultFlashTimer = setTimeout(function () { stackTowerResultFlashTimer = null; onDone(); }, STACK_TOWER_RESULT_FLASH_MS);
};
if (endReason === 'victory') {
if (window.jdSound) { try { window.jdSound.playSfx('boss-elim', 'mg7'); } catch (e) { /* ignore */ } }
/* ฆ่าบอส HP=0 → end-victory-2.png (MegaVirus) */
showOneFlash(megaVirusAssetUrl('end-victory-2.png'), finishToGcm);
} else if (endReason === 'time') {
@@ -11293,6 +11322,7 @@
if ((meGauntletJumpTicks || 0) > 0 || isMeGauntletJumpAnimActivePlay()) return false;
lastGauntletJumpKey = now;
socket.emit('gauntlet-jump');
if (window.jdSound) window.jdSound.playSfx('jump', 'mg2');
/* local (instant feedback) server (jumpTicks×tickMs)
เพอใเหนโคงข-ลงเต แม server จะต jumpTicks=0 กลางคนตอนขามสำเร */
meGauntletJumpAnimDur = Math.max(360, (gauntletRuntimeJumpTicks || 6) * (gauntletRuntimeTickMs || 220));
@@ -12511,6 +12541,7 @@
const m = stackMini;
const actorSeat = m.pendingDropSeat != null ? m.pendingDropSeat : getStackDropActorSeat();
const actorHeavy = !!m.pendingDropHeavy;
if (window.jdSound) { try { window.jdSound.playSfx(hit.miss ? 'drop-fail' : (actorHeavy ? 'drop-hard' : 'drop-clear'), 'mg3'); } catch (e) { /* ignore */ } }
const actorTheme = m.pendingDropTheme || null; /* remote drop = สีจาก host; local = null (resolve เอง) */
const tw = m.widthTiles * tileSize * getStackTowerBlockWorldScalePlay();
/* release = server (landOffsetTiles) "" ( server-time sync teleport )
@@ -17323,6 +17354,7 @@
/* broadcast กระสุนให้ทุกคนเห็นตรงกัน */
try {
if (socket && myId != null) socket.emit('space-shooter-shot', { x: shotX, y: shotY, vy: -580, ownerId: myId, t0: serverNow() });
if (window.jdSound) window.jdSound.playSfx('laser', 'mg6');
} catch (eS) { /* ignore */ }
}
@@ -18408,6 +18440,7 @@
try {
if (socket && myId != null) {
socket.emit('balloon-boss-shot', { sx: shotSx, sy: shotSy, vx, vy, ownerId: myId, t0: serverNow() });
if (window.jdSound) window.jdSound.playSfx('laser', 'mg7');
}
} catch (eS) { /* ignore */ }
/* สเปก MG7: ยิง 1 ครั้ง = −5 คะแนน (ต่ำสุด 0 ไม่ติดลบ) */
@@ -19694,6 +19727,7 @@
const jq = jumpSurviveJumpQueued;
jumpSurviveJumpQueued = false;
if (jq && jumpSurviveOnGround && window.jdSound) { try { window.jdSound.playSfx('jump', 'mg5'); } catch (e) { /* ignore */ } }
/* virtual joystick (touch) — แกน x ป้อนซ้าย/ขวาเหมือนคีย์ A/D (deadzone จัดการในตัว update แล้ว) */
const joyX = isJumpSurviveMissionHudActivePlay() ? (Number(quizQuestionMissionJoyVecX) || 0) : 0;
@@ -21848,7 +21882,7 @@
voiceAnalyser.getByteFrequencyData(dataArray);
var sum = 0; for (var i = 0; i < dataArray.length; i++) sum += dataArray[i];
var level = Math.min(1, (sum / dataArray.length) / 60);
if (level > 0.08 && Date.now() - lastEmit > 80) { lastEmit = Date.now(); socket.emit('voice-activity', { level: level }); }
if (level > 0.08 && Date.now() - lastEmit > 80) { lastEmit = Date.now(); socket.emit('voice-activity', { level: level }); if (window.jdSound) window.jdSound.notifySpeaking(); }
}, 100);
} catch (e) { /* ignore */ }
}
@@ -26452,6 +26486,8 @@
}
function tick() {
if (!mapData) { playTickLastTs = 0; requestAnimationFrame(tick); return; }
/* BGM ต่อมินิเกม (idempotent — playBgm return เร็วถ้า scene เดิม) */
if (window.jdSound) { try { window.jdSound.playBgm(jdPlayScene()); } catch (e) { /* ignore */ } }
/* dt frame (วินาที) → playDtMul = dt*60 (clamp 0.05s = step ≤0.45 tile กัน tunneling) ใช้ทำ movement time-based */
{
const _pnow = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now();
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+15
View File
@@ -200,6 +200,13 @@
btn.setAttribute('data-on', on ? 'true' : 'false');
var img = btn.querySelector('img');
if (img) img.src = on ? asset('btn-on.png') : asset('btn-off.png');
/* ประสานกับ SoundManager (localStorage · มีผลทุกหน้า) */
if (window.jdSound) {
try {
if (btn === refs.musicBtn) window.jdSound.setMusic(on);
else if (btn === refs.sfxBtn) window.jdSound.setSfx(on);
} catch (e) { /* ignore */ }
}
}
function setProfileData(data) {
@@ -478,6 +485,14 @@
createMarkupIfNeeded();
bindRefs();
bindEvents();
/* ตั้งค่าปุ่ม Music/SFX เริ่มจากสถานะ SoundManager (localStorage) + เริ่ม BGM ล็อบบี้ */
if (window.jdSound) {
try {
if (refs.musicBtn) { var mOn = window.jdSound.isMusicOn(); refs.musicBtn.setAttribute('data-on', mOn ? 'true' : 'false'); var mi = refs.musicBtn.querySelector('img'); if (mi) mi.src = asset(mOn ? 'btn-on.png' : 'btn-off.png'); }
if (refs.sfxBtn) { var sOn = window.jdSound.isSfxOn(); refs.sfxBtn.setAttribute('data-on', sOn ? 'true' : 'false'); var si = refs.sfxBtn.querySelector('img'); if (si) si.src = asset(sOn ? 'btn-on.png' : 'btn-off.png'); }
window.jdSound.playBgm('lobby');
} catch (e) { /* ignore */ }
}
buildLinkUi();
syncProfileScale();
setGroup(1);
@@ -0,0 +1,496 @@
(function () {
'use strict';
var script = document.currentScript;
var triggerSelector = (script && script.getAttribute('data-profile-trigger')) || '#btn-myprofile,#btn-profile-set';
var assetBase = (script && script.getAttribute('data-profile-asset-base')) || 'img/03-6-Profile';
var DISPLAY_NAME_KEY = 'roomLobbyDisplayName';
var overlayId = 'room-lobby-profile-overlay';
if (typeof window !== 'undefined') window.__USE_SHARED_PROFILE_POPUP = true;
function resolveAssetBase(raw) {
var base = String(raw || 'img/03-6-Profile').replace(/\/$/, '');
if (/^\/(Game|img)\//i.test(base)) {
return typeof window.appPath === 'function' ? window.appPath(base) : base;
}
try {
return new URL(base + '/', window.location.href).pathname.replace(/\/$/, '');
} catch (e) {
return base;
}
}
var resolvedAssetBase = resolveAssetBase(assetBase);
function asset(name) {
return resolvedAssetBase + '/' + name;
}
function appRel(path) {
if (typeof window.appPath === 'function') return window.appPath(path);
return path;
}
function readName() {
try { return (localStorage.getItem(DISPLAY_NAME_KEY) || localStorage.getItem('playerName') || 'MONE').trim() || 'MONE'; } catch (e) { return 'MONE'; }
}
function readAgentId() {
try { return (localStorage.getItem('agentDisplayId') || '001998').trim() || '001998'; } catch (e) { return '001998'; }
}
function readCoins() {
try { return String(Math.max(0, parseInt(localStorage.getItem('jdCoins') || '0', 10) || 0)); } catch (e) { return '0'; }
}
function readAgentIdRaw() {
try { return (localStorage.getItem('agentDisplayId') || '').trim(); } catch (e) { return ''; }
}
/** key ผู้เล่น (เดียวกับ lobby.js) — สร้างถ้ายังไม่มี เพื่อให้ระบบรหัส sync ใช้ได้ */
function ensurePlayerKey() {
var k = '';
try { k = (localStorage.getItem('jdPlayerKey') || '').trim(); } catch (e) { k = ''; }
if (!k || k.length < 8) {
k = 'p_' + Date.now() + '_' + Math.random().toString(36).slice(2, 14);
try { localStorage.setItem('jdPlayerKey', k); } catch (e2) { /* ignore */ }
}
return k;
}
var refs = {
overlay: null,
backdrop: null,
dialog: null,
closeBtn: null,
avatarEl: null,
nameEl: null,
agentEl: null,
coinsEl: null,
musicBtn: null,
sfxBtn: null,
groupBtns: [],
archivListEl: null,
archivScrollEl: null,
archivScrollBarEl: null,
editBtn: null,
logoutBtn: null
};
function createMarkupIfNeeded() {
if (document.getElementById(overlayId)) return;
var overlay = document.createElement('div');
overlay.id = overlayId;
overlay.className = 'room-lobby-profile-overlay is-hidden';
overlay.setAttribute('aria-hidden', 'true');
overlay.innerHTML = '' +
'<div class="room-lobby-profile-backdrop" id="room-lobby-profile-backdrop" aria-hidden="true"></div>' +
'<div class="room-lobby-profile-dialog" role="dialog" aria-modal="true" aria-label="โปรไฟล์ผู้เล่น">' +
' <button type="button" class="room-lobby-profile-close" id="room-lobby-profile-close" aria-label="ปิดโปรไฟล์">×</button>' +
' <div class="room-lobby-profile-content">' +
' <section class="room-lobby-profile-left-pane">' +
' <div class="room-lobby-profile-inner-frame">' +
' <p class="room-lobby-profile-coins">' +
' <img src="' + asset('profile-pop-coin.png') + '" alt="My Coins" class="room-lobby-profile-coins-label" decoding="async">' +
' <strong id="room-lobby-profile-coins-val">150</strong>' +
' </p>' +
' <div class="room-lobby-profile-char-card">' +
' <img id="room-lobby-profile-overlay-avatar" src="" alt="ตัวละครผู้เล่น" decoding="async">' +
' <div class="room-lobby-profile-overlay-name-row">' +
' <div class="room-lobby-profile-overlay-name" id="room-lobby-profile-overlay-name">PLAYER</div>' +
' <button type="button" class="room-lobby-profile-edit-btn" id="room-lobby-profile-edit-btn" title="แก้ไขชื่อผู้เล่น" aria-label="แก้ไขชื่อผู้เล่น">' +
' <img src="' + asset('btn-edit.png') + '" alt="" decoding="async">' +
' </button>' +
' </div>' +
' <img src="' + asset('profile-char-frame-2.png') + '" alt="" class="room-lobby-profile-name-sep" decoding="async">' +
' <div class="room-lobby-profile-overlay-agent" id="room-lobby-profile-overlay-agent">AGENT ID : 001998</div>' +
' </div>' +
' </div>' +
' <button type="button" class="room-lobby-profile-logout" id="room-lobby-profile-logout" aria-label="ออกจากระบบ">' +
' <img src="' + asset('btn-ex.png') + '" alt="ออกจากระบบ" decoding="async">' +
' </button>' +
' </section>' +
' <section class="room-lobby-profile-right-pane">' +
' <div class="room-lobby-profile-archiv-groups" id="room-lobby-profile-archiv-groups">' +
' <button type="button" class="room-lobby-profile-archiv-group-btn is-active" data-group="1"><img src="' + asset('archiv-group-01-a.png') + '" alt=""></button>' +
' <button type="button" class="room-lobby-profile-archiv-group-btn" data-group="2"><img src="' + asset('archiv-group-02.png') + '" alt=""></button>' +
' <button type="button" class="room-lobby-profile-archiv-group-btn" data-group="3"><img src="' + asset('archiv-group-03.png') + '" alt=""></button>' +
' <button type="button" class="room-lobby-profile-archiv-group-btn" data-group="4"><img src="' + asset('archiv-group-04.png') + '" alt=""></button>' +
' <button type="button" class="room-lobby-profile-archiv-group-btn" data-group="5"><img src="' + asset('archiv-group-05.png') + '" alt=""></button>' +
' </div>' +
' <div class="room-lobby-profile-archiv-frame">' +
' <ul class="room-lobby-profile-achievements-list" id="room-lobby-profile-achievements-list">' +
' <li class="room-lobby-profile-archiv-item"><img class="room-lobby-profile-archiv-icon-bg" src="' + asset('archiv-icon-bg.png') + '" alt=""><div class="room-lobby-profile-archiv-main"><div class="room-lobby-profile-archiv-title-row"><img class="room-lobby-profile-archiv-name" src="' + asset('archiv-name-1.png') + '" alt=""><strong class="room-lobby-profile-archiv-count">1/1</strong></div><div class="room-lobby-profile-archiv-progress-wrap"><img class="room-lobby-profile-archiv-progress-bg" src="' + asset('archiv-progress-bg.png') + '" alt=""><img class="room-lobby-profile-archiv-progress" src="' + asset('archiv-progress.png') + '" alt="" style="--archiv-progress:100%"></div><img class="room-lobby-profile-archiv-line" src="' + asset('archiv-line.png') + '" alt=""></div></li>' +
' <li class="room-lobby-profile-archiv-item"><img class="room-lobby-profile-archiv-icon-bg" src="' + asset('archiv-icon-bg.png') + '" alt=""><div class="room-lobby-profile-archiv-main"><div class="room-lobby-profile-archiv-title-row"><img class="room-lobby-profile-archiv-name" src="' + asset('archiv-name-2.png') + '" alt=""><strong class="room-lobby-profile-archiv-count">2/5</strong></div><div class="room-lobby-profile-archiv-progress-wrap"><img class="room-lobby-profile-archiv-progress-bg" src="' + asset('archiv-progress-bg.png') + '" alt=""><img class="room-lobby-profile-archiv-progress" src="' + asset('archiv-progress.png') + '" alt="" style="--archiv-progress:40%"></div><img class="room-lobby-profile-archiv-line" src="' + asset('archiv-line.png') + '" alt=""></div></li>' +
' <li class="room-lobby-profile-archiv-item"><img class="room-lobby-profile-archiv-icon-bg" src="' + asset('archiv-icon-bg.png') + '" alt=""><div class="room-lobby-profile-archiv-main"><div class="room-lobby-profile-archiv-title-row"><img class="room-lobby-profile-archiv-name" src="' + asset('archiv-name-3.png') + '" alt=""><strong class="room-lobby-profile-archiv-count">3/10</strong></div><div class="room-lobby-profile-archiv-progress-wrap"><img class="room-lobby-profile-archiv-progress-bg" src="' + asset('archiv-progress-bg.png') + '" alt=""><img class="room-lobby-profile-archiv-progress" src="' + asset('archiv-progress.png') + '" alt="" style="--archiv-progress:30%"></div><img class="room-lobby-profile-archiv-line" src="' + asset('archiv-line.png') + '" alt=""></div></li>' +
' <li class="room-lobby-profile-archiv-item"><img class="room-lobby-profile-archiv-icon-bg" src="' + asset('archiv-icon-bg.png') + '" alt=""><div class="room-lobby-profile-archiv-main"><div class="room-lobby-profile-archiv-title-row"><img class="room-lobby-profile-archiv-name" src="' + asset('archiv-name-1.png') + '" alt=""><strong class="room-lobby-profile-archiv-count">4/10</strong></div><div class="room-lobby-profile-archiv-progress-wrap"><img class="room-lobby-profile-archiv-progress-bg" src="' + asset('archiv-progress-bg.png') + '" alt=""><img class="room-lobby-profile-archiv-progress" src="' + asset('archiv-progress.png') + '" alt="" style="--archiv-progress:40%"></div><img class="room-lobby-profile-archiv-line" src="' + asset('archiv-line.png') + '" alt=""></div></li>' +
' <li class="room-lobby-profile-archiv-item"><img class="room-lobby-profile-archiv-icon-bg" src="' + asset('archiv-icon-bg.png') + '" alt=""><div class="room-lobby-profile-archiv-main"><div class="room-lobby-profile-archiv-title-row"><img class="room-lobby-profile-archiv-name" src="' + asset('archiv-name-2.png') + '" alt=""><strong class="room-lobby-profile-archiv-count">5/10</strong></div><div class="room-lobby-profile-archiv-progress-wrap"><img class="room-lobby-profile-archiv-progress-bg" src="' + asset('archiv-progress-bg.png') + '" alt=""><img class="room-lobby-profile-archiv-progress" src="' + asset('archiv-progress.png') + '" alt="" style="--archiv-progress:50%"></div><img class="room-lobby-profile-archiv-line" src="' + asset('archiv-line.png') + '" alt=""></div></li>' +
' </ul>' +
' <div class="room-lobby-profile-archiv-scroll is-hidden"><div class="room-lobby-profile-archiv-scroll-bg"></div><div class="room-lobby-profile-archiv-scroll-bar"></div></div>' +
' </div>' +
' <div class="room-lobby-profile-settings"><img class="room-lobby-profile-settings-frame" src="' + asset('setting-frame.png') + '" alt=""><div class="room-lobby-profile-settings-row">' +
' <div class="room-lobby-profile-setting-item"><img class="room-lobby-profile-setting-label" src="' + asset('setting-txt-1.png') + '" alt="Music"><button type="button" class="room-lobby-profile-toggle" id="room-lobby-profile-music" data-on="true"><img src="' + asset('btn-on.png') + '" alt=""></button></div>' +
' <div class="room-lobby-profile-setting-item"><img class="room-lobby-profile-setting-label" src="' + asset('setting-txt-2.png') + '" alt="SFX"><button type="button" class="room-lobby-profile-toggle" id="room-lobby-profile-sfx" data-on="false"><img src="' + asset('btn-off.png') + '" alt=""></button></div>' +
' </div></div>' +
' </section>' +
' </div>' +
'</div>';
document.body.appendChild(overlay);
}
function bindRefs() {
refs.overlay = document.getElementById(overlayId);
refs.backdrop = document.getElementById('room-lobby-profile-backdrop');
refs.dialog = refs.overlay ? refs.overlay.querySelector('.room-lobby-profile-dialog') : null;
refs.closeBtn = document.getElementById('room-lobby-profile-close');
refs.avatarEl = document.getElementById('room-lobby-profile-overlay-avatar');
refs.nameEl = document.getElementById('room-lobby-profile-overlay-name');
refs.agentEl = document.getElementById('room-lobby-profile-overlay-agent');
refs.coinsEl = document.getElementById('room-lobby-profile-coins-val');
refs.musicBtn = document.getElementById('room-lobby-profile-music');
refs.sfxBtn = document.getElementById('room-lobby-profile-sfx');
refs.groupBtns = Array.prototype.slice.call(document.querySelectorAll('.room-lobby-profile-archiv-group-btn'));
refs.archivListEl = document.getElementById('room-lobby-profile-achievements-list');
refs.archivScrollEl = document.querySelector('.room-lobby-profile-archiv-scroll');
refs.archivScrollBarEl = document.querySelector('.room-lobby-profile-archiv-scroll-bar');
refs.editBtn = document.getElementById('room-lobby-profile-edit-btn');
refs.logoutBtn = document.getElementById('room-lobby-profile-logout');
}
function syncArchivScroll() {
if (!refs.archivListEl || !refs.archivScrollEl || !refs.archivScrollBarEl) return;
var total = refs.archivListEl.scrollHeight || 0;
var visible = refs.archivListEl.clientHeight || 0;
var overflow = total > visible + 1;
refs.archivScrollEl.classList.toggle('is-hidden', !overflow);
if (!overflow) return;
var max = Math.max(1, total - visible);
var ratio = Math.max(0, Math.min(1, refs.archivListEl.scrollTop / max));
var barPct = Math.max(18, Math.min(42, (visible / Math.max(1, total)) * 100));
refs.archivScrollBarEl.style.height = barPct.toFixed(2) + '%';
refs.archivScrollBarEl.style.top = ((100 - barPct) * ratio).toFixed(2) + '%';
}
function syncProfileScale() {
if (!refs.dialog) return;
var rect = refs.dialog.getBoundingClientRect();
if (!rect.width || !rect.height) return;
var scaleW = rect.width / 1701;
var scaleH = rect.height / 951;
var scale = Math.max(0.35, Math.min(1, Math.min(scaleW, scaleH)));
refs.dialog.style.setProperty('--rp-scale', String(scale.toFixed(4)));
}
function setGroup(index) {
refs.groupBtns.forEach(function (btn) {
var id = parseInt(btn.getAttribute('data-group'), 10) || 1;
var active = id === index;
btn.classList.toggle('is-active', active);
var img = btn.querySelector('img');
if (img) img.src = active ? asset('archiv-group-0' + id + '-a.png') : asset('archiv-group-0' + id + '.png');
});
if (window.jdAchievements && refs.archivListEl) {
window.jdAchievements.renderGroup(refs.archivListEl, index);
}
syncArchivScroll();
}
function toggleChip(btn) {
if (!btn) return;
var on = String(btn.getAttribute('data-on') || '').toLowerCase() === 'true';
on = !on;
btn.setAttribute('data-on', on ? 'true' : 'false');
var img = btn.querySelector('img');
if (img) img.src = on ? asset('btn-on.png') : asset('btn-off.png');
}
function setProfileData(data) {
var payload = data || {};
var lobbyAvatar = document.getElementById('lobby-profile-avatar');
var roomAvatar = document.getElementById('room-lobby-profile-avatar');
var src = payload.avatarSrc || (lobbyAvatar && lobbyAvatar.getAttribute('src')) || (roomAvatar && roomAvatar.getAttribute('src')) || '';
if (refs.avatarEl && src) refs.avatarEl.src = src;
if (refs.nameEl) refs.nameEl.textContent = (payload.displayName || readName()).toUpperCase();
if (refs.agentEl) refs.agentEl.textContent = payload.agentIdLabel || ('AGENT ID : ' + readAgentId());
if (refs.coinsEl) refs.coinsEl.textContent = String(payload.coins != null ? payload.coins : readCoins());
}
function openPopup(data) {
if (!refs.overlay) return;
if (window.jdAchievements) window.jdAchievements.load();
setProfileData(data);
refs.overlay.classList.remove('is-hidden');
refs.overlay.setAttribute('aria-hidden', 'false');
syncProfileScale();
syncArchivScroll();
if (refs.closeBtn) refs.closeBtn.focus();
}
function closePopup() {
if (!refs.overlay) return;
refs.overlay.classList.add('is-hidden');
refs.overlay.setAttribute('aria-hidden', 'true');
}
function bindEvents() {
if (refs.backdrop) refs.backdrop.addEventListener('click', closePopup);
if (refs.closeBtn) refs.closeBtn.addEventListener('click', closePopup);
if (refs.musicBtn) refs.musicBtn.addEventListener('click', function () { toggleChip(refs.musicBtn); });
if (refs.sfxBtn) refs.sfxBtn.addEventListener('click', function () { toggleChip(refs.sfxBtn); });
refs.groupBtns.forEach(function (btn) {
btn.addEventListener('click', function () { setGroup(parseInt(btn.getAttribute('data-group'), 10) || 1); });
});
if (refs.archivListEl) refs.archivListEl.addEventListener('scroll', syncArchivScroll, { passive: true });
if (refs.editBtn) refs.editBtn.addEventListener('click', function () {
var runApply = function (draft) {
if (draft == null) return;
var applyFn = typeof window.jdApplyDisplayNameChange === 'function'
? window.jdApplyDisplayNameChange
: null;
if (applyFn) {
var result = applyFn(draft, { socket: window.__jdGameSocket || null });
if (!result.ok) return;
if (refs.nameEl) refs.nameEl.textContent = result.displayName.toUpperCase();
return;
}
try {
localStorage.setItem(DISPLAY_NAME_KEY, draft);
localStorage.setItem('playerName', draft);
} catch (e) { /* ignore */ }
if (refs.nameEl) refs.nameEl.textContent = draft.toUpperCase();
var headerName = document.getElementById('lobby-profile-name');
if (headerName) headerName.textContent = draft.toUpperCase();
};
if (window.jdDisplayName && typeof window.jdDisplayName.openEditor === 'function') {
window.jdDisplayName.openEditor({
initialValue: typeof window.jdReadDisplayName === 'function' ? window.jdReadDisplayName() : readName()
}).then(runApply);
return;
}
if (typeof window.jdPromptAndApplyDisplayName === 'function') {
window.jdPromptAndApplyDisplayName({ socket: window.__jdGameSocket || null }).then(function (result) {
if (result && result.ok && refs.nameEl) refs.nameEl.textContent = result.displayName.toUpperCase();
});
return;
}
var draft = window.prompt('แก้ไขชื่อผู้เล่น', readName() || '');
runApply(draft == null ? null : String(draft).trim() || null);
});
if (refs.logoutBtn) refs.logoutBtn.addEventListener('click', function () {
if (document.getElementById('btn-back')) {
window.location.href = appRel('/Login/');
return;
}
window.location.href = appRel('/Create%20Room/');
});
document.addEventListener('keydown', function (e) {
if (e.key !== 'Escape') return;
var nameEditor = document.getElementById('jd-display-name-editor-overlay');
if (nameEditor && !nameEditor.classList.contains('is-hidden')) return;
if (refs.overlay && !refs.overlay.classList.contains('is-hidden')) closePopup();
});
window.addEventListener('resize', function () {
syncProfileScale();
syncArchivScroll();
});
document.querySelectorAll(triggerSelector).forEach(function (el) {
el.addEventListener('click', function (e) {
e.preventDefault();
openPopup();
});
});
}
/* ===== ระบบรหัสผู้เล่น — sync โปรไฟล์ (สี/COINS/ชื่อ) ข้าม browser/เครื่อง ===== */
var linkRefs = { overlay: null, codeEl: null, input: null, msgEl: null };
function linkApiUrl() {
return appRel('/Admin/api/player-link.php');
}
function buildLinkUi() {
if (document.getElementById('jd-link-overlay')) return;
var st = document.createElement('style');
st.id = 'jd-link-style';
st.textContent = '' +
'.jd-link-trigger{position:absolute;top:14px;left:16px;z-index:6;display:inline-flex;align-items:center;gap:6px;padding:8px 14px;border-radius:999px;border:2px solid rgba(56,232,255,.85);background:rgba(8,24,44,.9);color:#dffaff;font:600 14px/1 Kanit,Segoe UI,sans-serif;cursor:pointer;box-shadow:0 0 14px rgba(56,232,255,.3);}' +
'.jd-link-trigger:hover{background:rgba(20,50,80,.95);}' +
'.jd-link-overlay{position:fixed;inset:0;z-index:10090;display:flex;align-items:center;justify-content:center;padding:16px;}' +
'.jd-link-overlay.is-hidden{display:none!important;}' +
'.jd-link-backdrop{position:absolute;inset:0;background:rgba(0,0,0,.74);}' +
'.jd-link-dialog{position:relative;z-index:1;width:min(440px,calc(100vw - 32px));padding:24px 22px 20px;border-radius:16px;background:linear-gradient(180deg,#0d2848 0%,#061528 100%);border:2px solid rgba(56,232,255,.85);box-shadow:0 0 30px rgba(56,232,255,.35);color:#eaf8ff;font-family:Kanit,Segoe UI,sans-serif;}' +
'.jd-link-close{position:absolute;top:8px;right:12px;background:none;border:none;color:#9fd8ff;font-size:1.7rem;line-height:1;cursor:pointer;}' +
'.jd-link-title{margin:0 0 4px;font-size:1.2rem;font-weight:700;text-align:center;}' +
'.jd-link-sub{margin:0 0 14px;font-size:.82rem;opacity:.75;text-align:center;}' +
'.jd-link-codebox{display:flex;align-items:center;gap:10px;justify-content:center;background:rgba(0,20,40,.85);border:2px solid rgba(56,232,255,.45);border-radius:12px;padding:12px;margin-bottom:6px;}' +
'.jd-link-code{font-size:1.7rem;font-weight:700;letter-spacing:.14em;color:#5ce9ff;}' +
'.jd-link-copy{padding:8px 12px;border-radius:8px;border:2px solid rgba(56,232,255,.55);background:rgba(20,50,80,.7);color:#dffaff;font:600 .85rem Kanit,sans-serif;cursor:pointer;}' +
'.jd-link-hr{height:1px;background:rgba(120,200,255,.25);margin:16px 0;}' +
'.jd-link-label{font-size:.92rem;margin:0 0 8px;font-weight:600;}' +
'.jd-link-row{display:flex;gap:8px;}' +
'.jd-link-input{flex:1;box-sizing:border-box;padding:11px 12px;border-radius:10px;border:2px solid rgba(56,232,255,.55);background:rgba(0,20,40,.85);color:#fff;font:600 1.05rem Kanit,sans-serif;letter-spacing:.1em;text-transform:uppercase;outline:none;}' +
'.jd-link-input:focus{border-color:#5ce9ff;box-shadow:0 0 0 3px rgba(92,233,255,.25);}' +
'.jd-link-go{padding:11px 18px;border-radius:10px;border:2px solid #7df4ff;background:linear-gradient(180deg,#2ee6ff,#0ea5c9);color:#042033;font:700 1rem Kanit,sans-serif;cursor:pointer;}' +
'.jd-link-warn{margin:10px 0 0;font-size:.78rem;color:#ffd27d;text-align:center;}' +
'.jd-link-msg{margin:10px 0 0;font-size:.85rem;text-align:center;min-height:1.1em;}' +
'.jd-link-msg.is-err{color:#ff8a8a;}.jd-link-msg.is-ok{color:#8effa6;}';
document.head.appendChild(st);
var ov = document.createElement('div');
ov.id = 'jd-link-overlay';
ov.className = 'jd-link-overlay is-hidden';
ov.setAttribute('aria-hidden', 'true');
ov.innerHTML = '' +
'<div class="jd-link-backdrop" id="jd-link-backdrop"></div>' +
'<div class="jd-link-dialog" role="dialog" aria-modal="true" aria-label="ซิงก์โปรไฟล์ข้ามเครื่อง">' +
' <button type="button" class="jd-link-close" id="jd-link-close" aria-label="ปิด">×</button>' +
' <h2 class="jd-link-title">ซิงก์โปรไฟล์ข้ามเครื่อง</h2>' +
' <p class="jd-link-sub">ใช้รหัสนี้เพื่อดึงสี / COINS / ชื่อ ไปยังเครื่องหรือ browser อื่น</p>' +
' <p class="jd-link-label">รหัสผู้เล่นของฉัน</p>' +
' <div class="jd-link-codebox"><span class="jd-link-code" id="jd-link-code">····-····</span><button type="button" class="jd-link-copy" id="jd-link-copy">คัดลอก</button></div>' +
' <p class="jd-link-sub" style="margin-top:6px">รหัสจะหมดอายุถ้าไม่ได้ใช้เกิน 30 วัน</p>' +
' <div class="jd-link-hr"></div>' +
' <p class="jd-link-label">มีรหัสจากเครื่องอื่น? กรอกที่นี่</p>' +
' <div class="jd-link-row"><input type="text" class="jd-link-input" id="jd-link-input" maxlength="9" placeholder="XXXX-XXXX" autocomplete="off" inputmode="latin"><button type="button" class="jd-link-go" id="jd-link-go">ดึงข้อมูล</button></div>' +
' <p class="jd-link-warn">การดึงข้อมูลจะแทนที่โปรไฟล์ในเครื่องนี้ (สี/COINS/ชื่อ)</p>' +
' <p class="jd-link-msg" id="jd-link-msg" role="alert"></p>' +
'</div>';
document.body.appendChild(ov);
linkRefs.overlay = ov;
linkRefs.codeEl = document.getElementById('jd-link-code');
linkRefs.input = document.getElementById('jd-link-input');
linkRefs.msgEl = document.getElementById('jd-link-msg');
document.getElementById('jd-link-backdrop').addEventListener('click', closeLinkModal);
document.getElementById('jd-link-close').addEventListener('click', closeLinkModal);
document.getElementById('jd-link-copy').addEventListener('click', copyMyCode);
document.getElementById('jd-link-go').addEventListener('click', redeemEnteredCode);
linkRefs.input.addEventListener('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); redeemEnteredCode(); } });
// ปุ่มเปิด — ฝังในกล่องโปรไฟล์ (absolute, ไม่กระทบ layout เดิม)
if (refs.dialog && !document.getElementById('jd-link-trigger')) {
var btn = document.createElement('button');
btn.type = 'button';
btn.id = 'jd-link-trigger';
btn.className = 'jd-link-trigger';
btn.textContent = '🔗 ซิงก์เครื่อง';
btn.addEventListener('click', openLinkModal);
refs.dialog.appendChild(btn);
}
}
function setLinkMsg(text, kind) {
if (!linkRefs.msgEl) return;
linkRefs.msgEl.textContent = text || '';
linkRefs.msgEl.className = 'jd-link-msg' + (kind ? ' is-' + kind : '');
}
function openLinkModal() {
if (!linkRefs.overlay) return;
setLinkMsg('', '');
if (linkRefs.input) linkRefs.input.value = '';
if (linkRefs.codeEl) linkRefs.codeEl.textContent = '····-····';
linkRefs.overlay.classList.remove('is-hidden');
linkRefs.overlay.setAttribute('aria-hidden', 'false');
fetchMyCode();
}
function closeLinkModal() {
if (!linkRefs.overlay) return;
linkRefs.overlay.classList.add('is-hidden');
linkRefs.overlay.setAttribute('aria-hidden', 'true');
}
function fetchMyCode() {
var key = ensurePlayerKey();
var url = linkApiUrl() + '?action=code&playerKey=' + encodeURIComponent(key) +
'&displayName=' + encodeURIComponent(readName()) +
'&agentId=' + encodeURIComponent(readAgentIdRaw());
fetch(url, { credentials: 'omit', cache: 'no-store' })
.then(function (r) { return r.json(); })
.then(function (d) {
if (d && d.ok && d.codeDisplay && linkRefs.codeEl) linkRefs.codeEl.textContent = d.codeDisplay;
else setLinkMsg('โหลดรหัสไม่สำเร็จ ลองใหม่อีกครั้ง', 'err');
})
.catch(function () { setLinkMsg('ออฟไลน์ — โหลดรหัสไม่ได้', 'err'); });
}
function copyMyCode() {
var txt = linkRefs.codeEl ? linkRefs.codeEl.textContent : '';
if (!txt || txt.indexOf('·') >= 0) return;
function done() { setLinkMsg('คัดลอกรหัสแล้ว', 'ok'); }
try {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(txt).then(done, function () { done(); });
return;
}
} catch (e) { /* ignore */ }
done();
}
function redeemEnteredCode() {
var raw = (linkRefs.input && linkRefs.input.value || '').toUpperCase().replace(/[^A-Z0-9]/g, '');
if (raw.length !== 8) { setLinkMsg('กรุณากรอกรหัส 8 ตัว', 'err'); return; }
setLinkMsg('กำลังดึงข้อมูล…', '');
fetch(linkApiUrl(), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'omit',
body: JSON.stringify({ action: 'redeem', code: raw })
})
.then(function (r) { return r.json().then(function (j) { return { status: r.status, j: j }; }); })
.then(function (res) {
var d = res.j || {};
if (!d.ok || !d.playerKey) {
setLinkMsg(d.error || 'ไม่พบรหัสนี้', 'err');
return;
}
applyRedeemedProfile(d);
})
.catch(function () { setLinkMsg('ออฟไลน์ — ดึงข้อมูลไม่ได้', 'err'); });
}
function applyRedeemedProfile(p) {
try {
localStorage.setItem('jdPlayerKey', String(p.playerKey));
if (p.displayName) { localStorage.setItem(DISPLAY_NAME_KEY, p.displayName); localStorage.setItem('playerName', p.displayName); }
if (p.agentId) localStorage.setItem('agentDisplayId', String(p.agentId));
if (p.colorThemeIndex) localStorage.setItem('lobbyThemeColor', String(p.colorThemeIndex));
if (p.skinToneIndex) localStorage.setItem('lobbySkinTone', String(p.skinToneIndex));
if (p.coins != null) localStorage.setItem('jdCoins', String(p.coins));
// ลบ avatar ที่ bake สีไว้ของเครื่องนี้ — บังคับ recompute จากสีที่ดึงมา
Object.keys(localStorage).forEach(function (k) {
if (k.indexOf('jdCharLobbyIdleDown:') === 0) localStorage.removeItem(k);
});
} catch (e) { /* ignore */ }
setLinkMsg('สำเร็จ! กำลังโหลดโปรไฟล์ใหม่…', 'ok');
setTimeout(function () { window.location.reload(); }, 500);
}
function isRoomLobbyPage() {
return /room-lobby\.html$/i.test(String(window.location.pathname || ''));
}
function init() {
if (isRoomLobbyPage()) {
return;
}
createMarkupIfNeeded();
bindRefs();
bindEvents();
buildLinkUi();
syncProfileScale();
setGroup(1);
if (window.jdAchievements) window.jdAchievements.load();
window.openProfilePopup = openPopup;
window.closeProfilePopup = closePopup;
window.roomLobbyProfileOverlay = { open: openPopup, close: closePopup };
window.mainLobbyProfileOverlay = { open: openPopup, close: closePopup };
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init, { once: true });
} else {
init();
}
})();
+73 -7
View File
@@ -239,6 +239,14 @@
const roomPlayersHud = document.getElementById('room-players-hud');
const peersList = document.getElementById('peers-list');
const readyCheck = document.getElementById('ready-check');
/* LobbyA: host กำลังเปิด wizard เลือกระดับ/คดี → ล็อกไม่ให้ client toggle พร้อม/ไม่พร้อม (server เป็น authority ด้วย) */
let preplayLockActive = false;
/* เสียงคลิกปุ่ม (เฉพาะปุ่มจริง) ในล็อบบี้ */
document.addEventListener('click', function (e) {
if (!window.jdSound) return;
var t = (e.target && e.target.closest) ? e.target.closest('button, .btn, [role="button"], [class*="btn-"]') : null;
if (t) { try { window.jdSound.playSfx('button', 'lobby'); } catch (err) { /* ignore */ } }
}, true);
const btnStart = document.getElementById('btn-start');
const hostOnly = document.getElementById('host-only');
const nonHostMsg = document.getElementById('non-host-msg');
@@ -277,6 +285,10 @@
let lobbyBPresentCount = 0;
let lobbyBTotalCount = 0;
let lobbyBAllHere = true;
/** TC156: ทุกคนอ่าน story (cutscene) ครบหรือยัง — gate เลือกผู้ต้องสงสัยรอบแรก */
let storyReadPresentCount = 0;
let storyReadTotalCount = 0;
let storyReadAllDone = true;
/** มินิเกม 3 แบบที่สุ่มแล้ว — ล็อกกับการ์ด 0–2 จนกว่าสร้างห้องใหม่ */
let suspectCardMinigames = [];
/** หลักฐาน (ติกถูก) ที่เก็บได้ต่อผู้ต้องสงสัย 0–2 (เล่นมินิเกมจบ +1 ต่อช่อง สูงสุด 3) */
@@ -1352,9 +1364,9 @@
const readyLabelImg = document.getElementById('ready-label-img');
const readyLabelEl = document.getElementById('ready-label');
/** พร้อม/ไม่พร้อม ใช้ได้ทุกจำนวนคนในห้อง — ไม่ล็อกตาม peers.size */
/** พร้อม/ไม่พร้อม ใช้ได้ทุกจำนวนคนในห้อง — ไม่ล็อกตาม peers.size · ยกเว้นตอน host เปิด wizard เลือกคดี (preplayLockActive) */
function ensureReadyControlEnabled() {
if (readyCheck) readyCheck.disabled = false;
if (readyCheck) readyCheck.disabled = !!preplayLockActive;
}
function updateReadyLabelVisual() {
@@ -1446,6 +1458,8 @@
function drawLobbyMap() {
if (!canvas || !mapData) return;
/* BGM ล็อบบี้ (ยืมเพลงมินิเกม · idempotent) */
if (window.jdSound) { try { window.jdSound.playBgm('lobby'); } catch (e) { /* ignore */ } }
const ctx = canvas.getContext('2d');
const w = mapData.width || 20;
const h = mapData.height || 15;
@@ -2197,6 +2211,8 @@
delete preplayOverlay.dataset.preplayLevel;
if (preplayCaseDetailOverlay) preplayCaseDetailOverlay.classList.add('is-hidden');
preplayOverlay.querySelectorAll('.lobby-level-card.is-selected').forEach(function (el) { el.classList.remove('is-selected'); });
/* host ปิด wizard → ปลดล็อกพร้อมให้ทุกคน (client อื่นรับผ่าน relay) */
try { if (hostId === socket.id) socket.emit('lobby-preplay-open', { open: false }); } catch (e) { /* ignore */ }
}
function openLobbyPreplayWizard() {
@@ -2212,6 +2228,8 @@
if (preplayStepLevel) preplayStepLevel.classList.remove('is-hidden');
if (preplayStepCase) preplayStepCase.classList.add('is-hidden');
if (preplayCaseDetailOverlay) preplayCaseDetailOverlay.classList.add('is-hidden');
/* host เปิด wizard เลือกคดี → ล็อกไม่ให้ client toggle พร้อม/ไม่พร้อม (client อื่นรับผ่าน relay) */
try { if (hostId === socket.id) socket.emit('lobby-preplay-open', { open: true }); } catch (e) { /* ignore */ }
}
function syncPreplayCaseStepScale() {
@@ -2369,7 +2387,12 @@
var media = getCaseMedia(cid);
var imgs = (media.story || []).filter(function (s) { return typeof s === 'string' && s; });
var finished = false;
var done = function () { if (finished) return; finished = true; if (typeof onDone === 'function') onDone(); };
var done = function () {
if (finished) return; finished = true;
/* TC156: แจ้ง server ว่าคนนี้อ่าน story จบ → host เลือกผู้ต้องสงสัยได้เมื่อครบทุกคน */
try { socket.emit('story-read-done'); } catch (e) { /* ignore */ }
if (typeof onDone === 'function') onDone();
};
if (!imgs.length) { done(); return; }
var idx = 0;
var ov = document.getElementById('case-cutscene-overlay');
@@ -3029,8 +3052,9 @@
this._bindEvents();
this._initProfileFrameScaleObserver();
this._syncProfileFrameScale();
this._applySwitchVisual(this.musicBtn, true);
this._applySwitchVisual(this.sfxBtn, false);
/* ตั้งค่าเริ่มจากสถานะ SoundManager (localStorage) แทน hardcode */
this._applySwitchVisual(this.musicBtn, window.jdSound ? window.jdSound.isMusicOn() : true);
this._applySwitchVisual(this.sfxBtn, window.jdSound ? window.jdSound.isSfxOn() : true);
this._setArchivGroup(1);
this._syncCoinsFromServer();
if (window.jdAchievements) window.jdAchievements.load();
@@ -3093,7 +3117,15 @@
_toggleChip(btn) {
if (!btn) return;
const current = String(btn.getAttribute('data-on') || '').toLowerCase() === 'true';
this._applySwitchVisual(btn, !current);
const next = !current;
this._applySwitchVisual(btn, next);
/* ประสานกับ SoundManager (จำใน localStorage · มีผลทุกหน้า) */
if (window.jdSound) {
try {
if (btn === this.musicBtn) window.jdSound.setMusic(next);
else if (btn === this.sfxBtn) window.jdSound.setSfx(next);
} catch (e) { /* ignore */ }
}
}
_applySwitchVisual(btn, isOn) {
@@ -3669,6 +3701,19 @@
ensureReadyControlEnabled();
});
/* LobbyA: host เปิด/ปิด wizard เลือกระดับ/คดี → server relay ให้ทุกคน → ล็อก/ปลดล็อกปุ่มพร้อม */
socket.on('lobby-preplay-open', (d) => {
const open = !!(d && d.open);
if (open === preplayLockActive) return;
preplayLockActive = open;
ensureReadyControlEnabled();
if (open) {
if (hostId !== socket.id) appendLobbySystemChat('— Host กำลังเลือกระดับ/คดี… รอสักครู่');
} else if (hostId !== socket.id) {
appendLobbySystemChat('— Host เลือกเสร็จแล้ว กดพร้อม/ไม่พร้อมได้');
}
});
socket.on('user-move', (data) => {
const p = peers.get(data.id);
if (p) {
@@ -4085,6 +4130,7 @@
if (level > 0.08 && Date.now() - lastEmit > 80) {
lastEmit = Date.now();
socket.emit('voice-activity', { level: level });
if (window.jdSound) window.jdSound.notifySpeaking();
var me = peers.get(socket.id);
if (me) {
me.speakingUntil = Date.now() + 400;
@@ -6798,7 +6844,9 @@
const hint = document.getElementById('suspect-pick-hint');
/* ต้องรอผู้เล่นทุกคนกลับเข้า LobbyB ครบก่อน host ถึงเริ่มได้ (กันคนยังโหลดไม่เสร็จหลุดรอบ) */
const waitingForPlayers = !lobbyBAllHere;
const canStartInvestigation = isHost && canInvestigateSuspect(suspectSelectedIndex) && !waitingForPlayers;
/* TC156: รอบแรก — ต้องรอทุกคนอ่าน story (cutscene) ครบก่อน */
const waitingForStory = !storyReadAllDone && !allSuspectsInvestigated();
const canStartInvestigation = isHost && canInvestigateSuspect(suspectSelectedIndex) && !waitingForPlayers && !waitingForStory;
if (startBtn) {
startBtn.disabled = !canStartInvestigation;
startBtn.classList.toggle('suspect-btn-start--disabled', !canStartInvestigation);
@@ -6807,6 +6855,8 @@
if (hint) {
if (!isHost) {
hint.textContent = 'รอ Host เลือกการ์ดและกดเริ่มสืบสวน';
} else if (waitingForStory) {
hint.textContent = 'รอผู้เล่นอ่านเนื้อเรื่องให้ครบก่อน (' + storyReadPresentCount + '/' + storyReadTotalCount + ') แล้วจึงเริ่มได้';
} else if (waitingForPlayers) {
hint.textContent = 'รอผู้เล่นกลับเข้าห้องให้ครบก่อน (' + lobbyBPresentCount + '/' + lobbyBTotalCount + ') แล้วจึงเริ่มได้';
} else if (!canInvestigateSuspect(suspectSelectedIndex)) {
@@ -6945,6 +6995,15 @@
if (suspectPickOverlayOpen) updateSuspectHostUi();
});
/* TC156: อัปเดตจำนวนคนที่อ่าน story จบ → host เลือกผู้ต้องสงสัยรอบแรกได้เมื่อครบ */
socket.on('detective-story-read-presence', (data) => {
if (!data) return;
storyReadPresentCount = Number(data.present) || 0;
storyReadTotalCount = Number(data.total) || 0;
storyReadAllDone = (data.allRead !== false);
if (suspectPickOverlayOpen) updateSuspectHostUi();
});
// ===== ห้องสรุปหลักฐาน (ไต่สวน) =====
socket.on('testimony-open', (data) => { openTestimony(data || {}); });
socket.on('testimony-status', (data) => { testimonyStatusUpdate(data || {}); });
@@ -7831,6 +7890,13 @@
ensureReadyControlEnabled();
updateReadyLabelVisual();
readyCheck.addEventListener('change', () => {
/* ล็อกระหว่าง host เลือกคดี — คืนค่าเดิม ไม่ส่ง set-ready (server ก็ปฏิเสธด้วย) */
if (preplayLockActive) {
const meNow = peers.get(socket.id);
readyCheck.checked = !!(meNow && meNow.ready);
updateReadyLabelVisual();
return;
}
const ready = readyCheck.checked;
const me = peers.get(socket.id);
if (me) me.ready = ready;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+174
View File
@@ -0,0 +1,174 @@
/* Justice — Sound Manager (BGM + SFX) · โหลดร่วมทุกหน้า (Main-Menu / room-lobby / play)
window.jdSound = { playBgm(scene), stopBgm(), playSfx(id[,scene]), setMusic(on), setSfx(on),
isMusicOn(), isSfxOn(), notifySpeaking(), duck(ms) }
- ประสาน UI ปุ่ม Music/SFX (profile popup) ผ่าน localStorage (jd_music_on / jd_sfx_on)
- ไม่ยุ่งกับ mic/WebRTC เลย — BGM/SFX เป็น HTMLAudio แยกจากเสียงพูด
- duck: หรี่ BGM อัตโนมัติตอนมีคนพูด (notifySpeaking) → เสียงคนไม่โดนกลบ
- volume master/music/sfx ปรับใน Admin ได้ (GET /Game/api/sound-settings) */
(function () {
'use strict';
if (window.jdSound) return;
var scriptBase = (function () {
try {
var s = (document.currentScript && document.currentScript.src) || '';
if (s) return s.replace(/\/js\/sound\.js.*$/, '');
} catch (e) { /* ignore */ }
/* fallback: หา <script src=".../js/sound.js"> */
try {
var els = document.getElementsByTagName('script');
for (var i = 0; i < els.length; i++) {
var src = els[i].src || '';
if (src.indexOf('/js/sound.js') >= 0) return src.replace(/\/js\/sound\.js.*$/, '');
}
} catch (e2) { /* ignore */ }
return '';
})();
function aurl(p) { return scriptBase + '/audio/' + p; }
var LS_MUSIC = 'jd_music_on', LS_SFX = 'jd_sfx_on';
function readBool(k, def) { try { var v = localStorage.getItem(k); return v == null ? def : (v === '1'); } catch (e) { return def; } }
function writeBool(k, v) { try { localStorage.setItem(k, v ? '1' : '0'); } catch (e) { /* ignore */ } }
var state = {
musicOn: readBool(LS_MUSIC, true),
sfxOn: readBool(LS_SFX, true),
masterVol: 1.0,
musicVol: 0.35,
sfxVol: 0.75,
curScene: null,
duckUntil: 0,
unlocked: false
};
/* ไฟล์ที่มีจริงต่อฉาก (กัน 404 — playSfx no-op ถ้าไม่มี) */
var MANIFEST = {
lobby: { bgm: 1 },
mg1: { bgm: 1, button: 1, correct: 1, endgame: 1, time: 1, wrong: 1 },
mg2: { bgm: 1, button: 1, gameover: 1, jump: 1, time: 1, winner: 1 },
mg3: { bgm: 1, button: 1, 'drop-clear': 1, 'drop-fail': 1, 'drop-hard': 1, endgame: 1, gameover: 1, time: 1, timeup: 1 },
mg4: { bgm: 1, button: 1, correct: 1, endgame: 1, gameover: 1, time: 1, timeup: 1, wrong: 1 },
mg5: { bgm: 1, button: 1, endgame: 1, gameover: 1, jump: 1, time: 1, timeup: 1 },
mg6: { bgm: 1, bomb: 1, button: 1, crash: 1, endgame: 1, gameover: 1, laser: 1, time: 1, timeup: 1 },
mg7: { bgm: 1, 'boss-elim': 1, button: 1, endgame: 1, gameover: 1, laser: 1, time: 1 }
};
var EXT = { button: 'wav' }; /* ที่เหลือ .mp3 */
function fileFor(scene, id) {
var ext = EXT[id] || 'mp3';
return scene + '/' + id + '.' + ext;
}
/* alias สำหรับ win/lose ให้เลือกไฟล์ที่มีในฉากนั้น */
function resolveSfx(scene, id) {
var m = MANIFEST[scene] || {};
if (id === 'win') { id = m.winner ? 'winner' : (m.endgame ? 'endgame' : null); }
else if (id === 'lose') { id = m.gameover ? 'gameover' : null; }
if (!id) return null;
if (m[id]) return fileFor(scene, id);
/* button ใช้ตัวกลางที่ audio root ถ้าฉากไม่มี */
if (id === 'button') return 'button.wav';
return null;
}
/* ===== BGM ===== */
var bgm = null;
function ensureBgm() {
if (!bgm) { bgm = new Audio(); bgm.loop = true; bgm.preload = 'auto'; bgm.setAttribute('playsinline', ''); }
return bgm;
}
function effBgmVol() {
var v = state.masterVol * state.musicVol;
if (Date.now() < state.duckUntil) v *= 0.22; /* หรี่ตอนมีคนพูด */
return Math.max(0, Math.min(1, v));
}
function applyBgmVol() { if (bgm) bgm.volume = state.musicOn ? effBgmVol() : 0; }
function playBgm(scene) {
if (!scene) return;
var man = MANIFEST[scene];
if (!man || !man.bgm) { state.curScene = scene; return; } /* ฉากไม่มี bgm (แต่จำ scene ไว้ให้ sfx) */
var a = ensureBgm();
var want = aurl(scene + '/bgm.mp3');
if (state.curScene !== scene || (a.src && a.src.indexOf(scene + '/bgm.mp3') < 0)) {
try { a.pause(); } catch (e) { /* ignore */ }
a.src = want;
try { a.currentTime = 0; } catch (e) { /* ignore */ }
}
state.curScene = scene;
applyBgmVol();
if (state.musicOn) { var p = a.play(); if (p && p.catch) p.catch(function () { /* รอ gesture ปลดล็อก */ }); }
}
function stopBgm() { if (bgm) { try { bgm.pause(); } catch (e) { /* ignore */ } } }
/* ===== SFX (pool กัน overlap) ===== */
var pool = [];
function grab() {
for (var i = 0; i < pool.length; i++) { if (pool[i].ended || pool[i].paused) return pool[i]; }
if (pool.length < 12) { var a = new Audio(); a.preload = 'auto'; a.setAttribute('playsinline', ''); pool.push(a); return a; }
return pool[0];
}
function playSfx(id, scene) {
if (!state.sfxOn || !id) return;
scene = scene || state.curScene || 'lobby';
var rel = resolveSfx(scene, id);
if (!rel) return;
try {
var a = grab();
a.src = aurl(rel);
a.volume = Math.max(0, Math.min(1, state.masterVol * state.sfxVol));
a.currentTime = 0;
var p = a.play(); if (p && p.catch) p.catch(function () { /* ignore */ });
} catch (e) { /* ignore */ }
}
/* ===== toggles ===== */
function setMusic(on) {
state.musicOn = !!on; writeBool(LS_MUSIC, state.musicOn);
if (!state.musicOn) { stopBgm(); }
else { applyBgmVol(); if (state.curScene) playBgm(state.curScene); }
return state.musicOn;
}
function setSfx(on) { state.sfxOn = !!on; writeBool(LS_SFX, state.sfxOn); return state.sfxOn; }
/* ===== duck (เสียงพูด) ===== */
function duck(ms) { state.duckUntil = Date.now() + (ms || 600); applyBgmVol(); }
function notifySpeaking() { duck(700); }
setInterval(applyBgmVol, 220); /* คลาย duck อัตโนมัติ */
/* ===== unlock audio ครั้งแรกที่ user gesture (autoplay policy) ===== */
function unlock() {
if (state.unlocked) return;
state.unlocked = true;
if (state.musicOn && state.curScene) playBgm(state.curScene);
}
['pointerdown', 'keydown', 'touchstart', 'click'].forEach(function (ev) {
window.addEventListener(ev, unlock, { once: false, passive: true });
});
/* ===== config จาก Admin (ไม่มีก็ใช้ default) ===== */
(function loadSettings() {
try {
fetch(scriptBase + '/api/sound-settings', { cache: 'no-store' })
.then(function (r) { return r.ok ? r.json() : null; })
.then(function (d) {
if (!d) return;
if (typeof d.masterVol === 'number') state.masterVol = Math.max(0, Math.min(1, d.masterVol));
if (typeof d.musicVol === 'number') state.musicVol = Math.max(0, Math.min(1, d.musicVol));
if (typeof d.sfxVol === 'number') state.sfxVol = Math.max(0, Math.min(1, d.sfxVol));
applyBgmVol();
}).catch(function () { /* ignore */ });
} catch (e) { /* ignore */ }
})();
window.jdSound = {
playBgm: playBgm,
stopBgm: stopBgm,
playSfx: playSfx,
setMusic: setMusic,
setSfx: setSfx,
isMusicOn: function () { return state.musicOn; },
isSfxOn: function () { return state.sfxOn; },
notifySpeaking: notifySpeaking,
duck: duck,
_state: state
};
})();
+2 -1
View File
@@ -5438,7 +5438,8 @@
<script src="/app-base.js?v=2"></script>
<script src="/Game/socket.io/socket.io.js"></script>
<script src="js/version.js?v=0.0306"></script>
<script src="js/play.js?v=0.006301060"></script>
<script src="js/sound.js?v=1"></script>
<script src="js/play.js?v=0.006301062"></script>
<div class="version-tag">v —</div>
<style id="qc-howto-mg2-fix">
/* HOW TO PLAY ของ quiz_carry (Minigame-4) -> ให้เหมือน Minigame-2 (gch-mg2-mock)
+2 -1
View File
@@ -1648,7 +1648,8 @@
<script src="js/version.js?v=0.0122"></script>
<script src="js/customize-popup.js?v=40" data-customize-triggers="" data-customize-asset-base="img/03-5-Customize"></script>
<script src="js/achievements.js?v=0.002" data-asset-base="img/03-6-Profile"></script>
<script src="js/room-lobby.js?v=0.0339"></script>
<script src="js/sound.js?v=1"></script>
<script src="js/room-lobby.js?v=0.0342"></script>
<div class="version-tag">v —</div>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+161 -7
View File
@@ -352,6 +352,25 @@ const QUIZ_SETTINGS_MIRROR_PATH = process.env.GAME_QUIZ_SETTINGS_MIRROR_PATH
? path.resolve(String(process.env.GAME_QUIZ_SETTINGS_MIRROR_PATH).trim())
: '';
const GAME_TIMING_PATH = path.join(__dirname, 'data', 'game-timing.json');
const SOUND_SETTINGS_PATH = path.join(__dirname, 'data', 'sound-settings.json');
const SOUND_SETTINGS_DEFAULT = { masterVol: 1.0, musicVol: 0.35, sfxVol: 0.75 };
function loadSoundSettings() {
try {
if (fs.existsSync(SOUND_SETTINGS_PATH)) {
const j = JSON.parse(fs.readFileSync(SOUND_SETTINGS_PATH, 'utf8'));
const clamp = (v, d) => { const n = Number(v); return Number.isFinite(n) ? Math.max(0, Math.min(1, n)) : d; };
return {
masterVol: clamp(j.masterVol, SOUND_SETTINGS_DEFAULT.masterVol),
musicVol: clamp(j.musicVol, SOUND_SETTINGS_DEFAULT.musicVol),
sfxVol: clamp(j.sfxVol, SOUND_SETTINGS_DEFAULT.sfxVol),
};
}
} catch (e) { console.error('loadSoundSettings', e.message); }
return Object.assign({}, SOUND_SETTINGS_DEFAULT);
}
function saveSoundSettings(s) {
try { fs.writeFileSync(SOUND_SETTINGS_PATH, JSON.stringify(s, null, 2)); } catch (e) { console.error('saveSoundSettings', e.message); }
}
/* ===== Quiz Battle global leaderboard (เก็บคะแนนสูงสุดต่อ room/หมวด ข้ามเซสชัน) ===== */
const QB_LEADERBOARD_PATH = path.join(__dirname, 'data', 'quiz-battle-leaderboard.json');
@@ -3601,6 +3620,30 @@ function emitDetectiveLobbyBPresence(sid, space) {
});
}
/* TC156 story-gate: " story (cutscene) "
allRead = roster-nick present ได story-read-done แล (คนท left ไม presence gate มแยก) */
function detectiveStoryReadStatus(space) {
const roster = space && space.caseParticipantNicknames;
if (!roster || roster.size === 0) return { present: 0, total: 0, allRead: true };
const read = space.storyReadNicks || new Set();
const presentRosterNicks = new Set();
space.peers.forEach((p) => {
if (!p || !p.nickname) return;
const n = normalizeLobbyNickname(p.nickname);
if (roster.has(n)) presentRosterNicks.add(n);
});
let readCount = 0;
presentRosterNicks.forEach((n) => { if (read.has(n)) readCount++; });
const allRead = !!space.storyReadComplete || (presentRosterNicks.size > 0 && readCount >= presentRosterNicks.size);
return { present: readCount, total: presentRosterNicks.size, allRead };
}
function emitDetectiveStoryReadPresence(sid, space) {
if (!sid || !space) return;
if (!serverMapIsPostCaseLobbyB(space)) return;
const st = detectiveStoryReadStatus(space);
io.to(sid).emit('detective-story-read-presence', { present: st.present, total: st.total, allRead: st.allRead });
}
function assignDetectiveSuspectCardMinigames(space) {
const available = DETECTIVE_MINIGAME_POOL.filter((e) => maps.has(e.mapId));
/** โหมดเทสต์ (admin game-timing): เลือกเกมต่อการ์ด 3 ใบ — ช่องที่ตั้ง key = เจาะจง, ช่องว่าง = สุ่ม */
@@ -5340,11 +5383,11 @@ function stepQuizCarryBots(sid, space, dt, now) {
const answering = s.phase === 'answer';
const choiceCount = s.current ? (s.current.choices || []).length : 0;
/* (x,y) : ( objects) + hub + submit (interactive)
บอทไมเดนทะล "โต๊ะตรงกลาง" (เดมเชคแค hub+objects ทำใหทะล interactive ไมไดอยใน objects) */
const canStepTo = (x, y) => quizTileWalkableServer(md, x, y)
&& !quizCarryFootprintOverlapsHubServer(md, x, y)
&& !quizCarryFootprintOverlapsInteractiveServer(md, x, y);
/* (x,y) : " footprint" (canStand = / hub/ interactive)
เดมเชคแค quizTileWalkableServer "ช่อง anchor จุดเดียว" ทำให footprint ขอบวเลอนครอมกำแพงได
ตกไปชองท reachability-BFS (footprint-aware) อว "ออกไม่ได้" โดน push-out teleport tick = อาการ "บอทว๊าป".
ใช canStand ใหตรงก pathfind (วางเสนบน canStand อยแล) บอทไมเดนเขาชองทจะถกดนออก */
const canStepTo = (x, y) => quizCarryEntityCanStandServer(md, Math.floor(x), Math.floor(y));
const followPath = (b) => {
if (!b.botPath || !b.botPath.length) return false;
@@ -5390,10 +5433,16 @@ function stepQuizCarryBots(sid, space, dt, now) {
};
s.bots.forEach((b, bid) => {
/* ทับ hub / โต๊ะ submit กลาง (interactive) / หรือ "ติดในคอนโซลกลาง" (ยืนได้แต่เดินออกไม่ได้) → ดันออกไปช่องว่างที่ถึงได้ */
/* ทับ hub / โต submit กลาง (interactive) / หร "ติดในคอนโซลกลาง" (นไดแตเดนออกไมได) นออกไปชองวางทงได
หมายเหต: หลงแก canStepTo canStand แล บอทไมควรเดนเขาชองแบบนเอง teleport งเป safety-net (ควรยงนอยมาก)
diag: glog กครงท teleport จร เพอยนยนว "ว๊าป" ลดลง (ถอด log ออกเมอยนยนแล) */
if (quizCarryFootprintOverlapsHubServer(md, b.x, b.y) || quizCarryFootprintOverlapsInteractiveServer(md, b.x, b.y) || !quizCarryTileReachableServer(md, b.x, b.y)) {
const tiles = quizCarrySpawnTilesServer(md);
if (tiles.length) { const t = tiles[(b.x | 0) % tiles.length]; b.x = t.x + 0.5; b.y = t.y + 0.5; b.botPath = []; }
if (tiles.length) {
const fromX = b.x, fromY = b.y;
const t = tiles[(b.x | 0) % tiles.length]; b.x = t.x + 0.5; b.y = t.y + 0.5; b.botPath = [];
try { glog(sid, space, 'mg4-warp', '[TC158] push-out teleport ' + bid + ' (' + fromX.toFixed(2) + ',' + fromY.toFixed(2) + ')->(' + b.x.toFixed(2) + ',' + b.y.toFixed(2) + ') — event นี้ = ยังว๊าป (fail); ไม่มี event ตลอดเกม = pass'); } catch (e) { /* ignore */ }
}
}
/* ยังไม่มีเส้นทาง → ลองหยิบ/ส่งที่จุดยืนก่อน */
if (!b.botPath || !b.botPath.length) quizCarryServerTryInteract(sid, space, bid, true);
@@ -7201,6 +7250,35 @@ const server = http.createServer((req, res) => {
});
return;
}
/* เสียง: volume master/music/sfx — GET เปิดสาธารณะ (sound.js ทุก client อ่าน) · PUT เฉพาะแอดมิน */
if (url === BASE_PATH + '/api/sound-settings' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
res.end(JSON.stringify(loadSoundSettings()));
return;
}
if (url === BASE_PATH + '/api/sound-settings' && req.method === 'PUT') {
const token = getAdminToken(req.headers.cookie);
if (!token) return res.writeHead(401), res.end(JSON.stringify({ error: 'ต้องล็อกอินก่อน' }));
let body = '';
req.on('data', c => body += c);
req.on('end', () => {
res.setHeader('Content-Type', 'application/json');
try {
const d = JSON.parse(body || '{}');
const s = loadSoundSettings();
const clamp = (v, cur) => { const n = Number(v); return Number.isFinite(n) ? Math.max(0, Math.min(1, n)) : cur; };
if (d.masterVol !== undefined) s.masterVol = clamp(d.masterVol, s.masterVol);
if (d.musicVol !== undefined) s.musicVol = clamp(d.musicVol, s.musicVol);
if (d.sfxVol !== undefined) s.sfxVol = clamp(d.sfxVol, s.sfxVol);
saveSoundSettings(s);
res.writeHead(200);
res.end(JSON.stringify({ ok: true, settings: s }));
} catch (e) {
res.writeHead(400), res.end(JSON.stringify({ ok: false, error: e.message }));
}
});
return;
}
if (url === BASE_PATH + '/api/ai-chat' && req.method === 'POST') {
let body = '';
req.on('data', c => body += c);
@@ -11291,6 +11369,7 @@ io.on('connection', (socket) => {
(เด: หลงจบเกม client บางคนยงโหลด LobbyB ไมเสร แต host กดเรมไดเลย คนนนหลดรอบ) */
const waitInfo = detectiveLobbyBMissingParticipants(space);
if (waitInfo.missing > 0) {
try { const hp = space.peers.get(socket.id); glog(sid, space, 'lobbyb-gate', '[TC144] BLOCK เริ่มสืบสวน — รอผู้เล่นกลับเข้า LobbyB ครบ (' + waitInfo.present + '/' + waitInfo.total + ') — gate ทำงาน (pass)', (hp && hp.nickname) || 'host'); } catch (e) { /* ignore */ }
return reply({
ok: false,
waitingPlayers: true,
@@ -11299,6 +11378,15 @@ io.on('connection', (socket) => {
error: 'รอผู้เล่นกลับเข้าห้องให้ครบก่อน (' + waitInfo.present + '/' + waitInfo.total + ')',
});
}
/* TC156: gate จนกว่าทุกคนอ่าน story (cutscene) ครบ — เฉพาะรอบแรก (storyReadComplete เป็น true หลังครบ/รอบถัดไป) */
if (!space.storyReadComplete) {
const stRead = detectiveStoryReadStatus(space);
if (!stRead.allRead) {
try { const hp = space.peers.get(socket.id); glog(sid, space, 'story-gate', '[TC156] BLOCK เริ่มสืบสวน — รอทุกคนอ่าน story ครบ (' + stRead.present + '/' + stRead.total + ') — gate ทำงาน (pass)', (hp && hp.nickname) || 'host'); } catch (e) { /* ignore */ }
return reply({ ok: false, waitingStory: true, present: stRead.present, total: stRead.total, error: 'รอผู้เล่นอ่านเนื้อเรื่องให้ครบก่อน (' + stRead.present + '/' + stRead.total + ')' });
}
space.storyReadComplete = true;
}
if (!space.suspectCardMinigames || space.suspectCardMinigames.length < 3) {
assignDetectiveSuspectCardMinigames(space);
}
@@ -11323,6 +11411,7 @@ io.on('connection', (socket) => {
if (pend && !space.pickVote) {
pend.consumed = true;
io.to(sid).emit('special-card-applied', { card: specialCardClientPayload(pend.card), context: 'ban' });
try { const hp = space.peers.get(socket.id); glog(sid, space, 'vote-gate', '[TC157] เริ่ม vote ban (ผู้เล่นเข้า LobbyB ครบ ' + waitInfo.present + '/' + waitInfo.total + ') — มินิเกมจะเริ่มหลังโหวตจบเท่านั้น (pass)', (hp && hp.nickname) || 'host'); } catch (e) { /* ignore */ }
startPlayerPickVote(sid, space, 'ban', (targetId) => {
const sp = spaces.get(sid);
if (!sp) return;
@@ -11335,6 +11424,7 @@ io.on('connection', (socket) => {
return reply({ ok: true, banVote: true });
}
const started = beginDetectiveSuspectMinigame(sid, space, cardEntry, selectedIndex);
try { const hp = space.peers.get(socket.id); glog(sid, space, 'lobbyb-gate', '[TC144] เริ่มสืบสวน OK — ผู้เล่นครบ ' + waitInfo.total + ' คน · ผู้ต้องสงสัย #' + (selectedIndex + 1), (hp && hp.nickname) || 'host'); } catch (e) { /* ignore */ }
reply(started);
});
@@ -11440,6 +11530,12 @@ io.on('connection', (socket) => {
if (space.hostId !== socket.id) return reply({ ok: false, error: 'เฉพาะ host เปิดพิจารณาคดีได้' });
const prog = playerSuspectProgressFromEvidence(space, socket.id);
if (![0, 1, 2].every((i) => (prog[i] || 0) >= 1)) return reply({ ok: false, error: 'ต้องสืบครบทั้ง 3 ผู้ต้องสงสัยก่อน (เก็บหลักฐานอย่างน้อย 1 ใบต่อคน)' });
/* ชี้ตัวคนร้าย = เข้าพิจารณาคดี → ต้องรอผู้เล่นในคดีกลับเข้า LobbyB ครบก่อน (กันคนตกรอบโหวต) */
const accuseWait = detectiveLobbyBMissingParticipants(space);
if (accuseWait.missing > 0) {
try { const hp = space.peers.get(socket.id); glog(sid, space, 'lobbyb-gate', '[TC144] BLOCK ชี้ตัวคนร้าย — รอผู้เล่นเข้า LobbyB ครบ (' + accuseWait.present + '/' + accuseWait.total + ') — gate ทำงาน (pass)', (hp && hp.nickname) || 'host'); } catch (e) { /* ignore */ }
return reply({ ok: false, waitingPlayers: true, present: accuseWait.present, total: accuseWait.total, error: 'รอผู้เล่นกลับเข้าห้องให้ครบก่อน (' + accuseWait.present + '/' + accuseWait.total + ')' });
}
if (typeof space.culpritIndex !== 'number') space.culpritIndex = Math.floor(Math.random() * 3);
space.suspectPhaseActive = false;
// เริ่ม "ห้องสรุปหลักฐาน" (ไต่สวน 3 ปากคำ) ก่อนเข้าโหวต
@@ -11640,6 +11736,13 @@ io.on('connection', (socket) => {
socket.on('set-ready', ({ ready }) => {
for (const [sid, space] of spaces) {
if (space.peers.has(socket.id)) {
/* ล็อก: host กำลังเปิด wizard เลือกระดับ/คดี → ปฏิเสธ set-ready (กัน client หลุด flow ตอน host เลือกอยู่) */
if (space.preplayOpen && space.hostId !== socket.id) {
const p = space.peers.get(socket.id);
io.to(socket.id).emit('peer-ready', { id: socket.id, ready: !!(p && p.ready) }); /* ย้ำสถานะเดิมกลับให้ผู้ส่ง */
try { glog(sid, space, 'preplay-lock', '[TC154] REJECT set-ready ระหว่าง host เลือกคดี — feature ทำงาน (pass): client ยกเลิกพร้อมไม่ได้', (p && p.nickname) || String(socket.id).slice(0, 6)); } catch (e) { /* ignore */ }
break;
}
const p = space.peers.get(socket.id);
if (p) p.ready = !!ready;
io.to(sid).emit('peer-ready', { id: socket.id, ready: !!ready });
@@ -11648,10 +11751,46 @@ io.on('connection', (socket) => {
}
});
/* LobbyA: host เปิด/ปิด wizard เลือกระดับ/คดี → เก็บ state ที่ server + relay ทั้งห้อง (ล็อกปุ่มพร้อมฝั่ง client) */
socket.on('lobby-preplay-open', ({ open } = {}) => {
for (const [sid, space] of spaces) {
if (space.peers.has(socket.id) && space.hostId === socket.id) {
space.preplayOpen = !!open;
io.to(sid).emit('lobby-preplay-open', { open: !!open });
try { const hp = space.peers.get(socket.id); glog(sid, space, 'preplay-lock', '[TC154] ' + (open ? 'host เปิด wizard เลือกคดี → ล็อก set-ready ทั้งห้อง' : 'host ปิด wizard → ปลดล็อก set-ready') + ' (' + space.peers.size + ' คนในห้อง)', (hp && hp.nickname) || 'host'); } catch (e) { /* ignore */ }
break;
}
}
});
/* TC156: client อ่าน story (cutscene) จบ → บันทึกว่าคนนี้พร้อม · ครบทุกคน → ปลดล็อกเลือกผู้ต้องสงสัย */
socket.on('story-read-done', () => {
for (const [sid, space] of spaces) {
if (!space.peers.has(socket.id)) continue;
if (!serverMapIsPostCaseLobbyB(space)) break;
const p = space.peers.get(socket.id);
const nick = p && p.nickname ? normalizeLobbyNickname(p.nickname) : '';
if (!nick) break;
if (!space.storyReadNicks) space.storyReadNicks = new Set();
const already = space.storyReadNicks.has(nick);
space.storyReadNicks.add(nick);
const st = detectiveStoryReadStatus(space);
if (!already) { try { glog(sid, space, 'story-gate', '[TC156] อ่าน story จบ ' + st.present + '/' + st.total, nick); } catch (e) { /* ignore */ } }
if (st.allRead && !space.storyReadComplete) {
space.storyReadComplete = true;
if (space.storyReadTimer) { clearTimeout(space.storyReadTimer); space.storyReadTimer = null; }
try { glog(sid, space, 'story-gate', '[TC156] ทุกคนอ่าน story ครบ (' + st.total + ') → ปลดล็อกเลือกผู้ต้องสงสัย (pass)'); } catch (e) { /* ignore */ }
}
emitDetectiveStoryReadPresence(sid, space);
break;
}
});
socket.on('start-game', (data, cb) => {
const reply = typeof cb === 'function' ? cb : () => {};
for (const [sid, space] of spaces) {
if (space.peers.has(socket.id) && space.hostId === socket.id) {
space.preplayOpen = false; /* host เริ่มเกมแล้ว → ปลดล็อก (client เปลี่ยนฉากอยู่แล้ว แต่เคลียร์ state กัน stuck) */
let lobbyLevel = (data && data.lobbyLevel != null) ? String(data.lobbyLevel).trim() : '';
let caseId = (data && data.caseId != null) ? String(data.caseId).trim() : '';
if (lobbyLevel && !/^[1-5]$/.test(lobbyLevel)) lobbyLevel = '';
@@ -11698,6 +11837,19 @@ io.on('connection', (socket) => {
caseNickWl.add(normalizeLobbyNickname(p.nickname));
});
space.caseParticipantNicknames = caseNickWl;
/* TC156: gate story (cutscene) reset initial LobbyALobbyB
(รอบ investigate ดไปไม cutscene storyReadComplete คงเป true) · safety timer deadlock client ไม emit */
space.storyReadNicks = new Set();
space.storyReadComplete = false;
if (space.storyReadTimer) clearTimeout(space.storyReadTimer);
space.storyReadTimer = setTimeout(() => {
const sp = spaces.get(sid);
if (sp && !sp.storyReadComplete) {
sp.storyReadComplete = true;
try { glog(sid, sp, 'story-gate', '[TC156] safety-timeout 90s → force ปลดล็อก (client บางคนไม่ส่ง story-read-done)'); } catch (e) { /* ignore */ }
try { emitDetectiveStoryReadPresence(sid, sp); } catch (e) { /* ignore */ }
}
}, 90000);
space.joinLocked = true;
space.troublesomeOfferSent = false;
space.troublesomeTargetId = null;
@@ -12078,6 +12230,8 @@ io.on('connection', (socket) => {
spaces.delete(sid);
} else {
if (wasHost) {
/* host หลุดกลางเปิด wizard เลือกคดี → ปลดล็อกปุ่มพร้อมให้คนที่เหลือ (กัน stuck lock) */
if (space.preplayOpen) { space.preplayOpen = false; io.to(sid).emit('lobby-preplay-open', { open: false }); try { glog(sid, space, 'preplay-lock', '[TC154] host หลุดกลางเปิด wizard → auto-ปลดล็อก set-ready (กัน stuck)', leftNick); } catch (e) { /* ignore */ } }
const firstPeer = pickNextHostPeer(space); /* คนอยู่นานสุด (spawnJoinOrder ต่ำสุด) — แทน Map-first */
if (firstPeer) {
space.hostId = firstPeer.id; /* ย้าย pointer host ชั่วคราวให้คนที่เหลือ (liveness) */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+10 -1
View File
@@ -230,7 +230,16 @@
<script src="daily-popup.js?v=26" data-daily-trigger="#btn-daily" data-daily-asset-base="IMAGE/Daily" data-daily-test-reset-seconds="0"></script>
<script src="../Game/js/customize-popup.js?v=38" data-customize-triggers="#btn-cloth" data-customize-asset-base="/Game/img/03-5-Customize"></script>
<script src="../Game/js/achievements.js?v=0.002" data-asset-base="/Game/img/03-6-Profile"></script>
<script src="../Game/js/profile-popup.js?v=8" data-profile-trigger="#btn-myprofile" data-profile-asset-base="/Game/img/03-6-Profile"></script>
<script src="../Game/js/sound.js?v=1"></script>
<script src="../Game/js/profile-popup.js?v=9" data-profile-trigger="#btn-myprofile" data-profile-asset-base="/Game/img/03-6-Profile"></script>
<script src="lobby.js?v=0.0194"></script>
<script>
/* เสียงคลิกปุ่มใน Main-Lobby (เฉพาะปุ่มจริง) */
document.addEventListener('click', function (e) {
if (!window.jdSound) return;
var t = (e.target && e.target.closest) ? e.target.closest('button, .btn, [role="button"], [class*="btn-"]') : null;
if (t) { try { window.jdSound.playSfx('button', 'lobby'); } catch (err) { /* ignore */ } }
}, true);
</script>
</body>
</html>
+508
View File
@@ -3808,3 +3808,511 @@
{"t":1782916711791,"cat":"LobbyB","room":"a-1782916565382","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:24.0,16.4->18.2,13.9 b1:13.6,5.2->15.7,13.5 b2:12.0,13.4->14.6,10.8] [+58532ms]","src":"client"}
{"t":1782916715835,"cat":"LobbyB","room":"a-1782916565382","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:24.0,16.4->11.8,16.3 b1:13.6,5.2->15.3,13.5 b2:12.0,13.4->14.6,9.1] [+62575ms]","src":"client"}
{"t":1782916719874,"cat":"LobbyB","room":"a-1782916565382","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:24.0,16.4->10.9,16.8 b1:13.6,5.2->20.4,16.9 b2:12.0,13.4->19.3,10.6] [+66616ms]","src":"client"}
{"t":1782919071786,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"lobby-open","detail":"space=a-1782919068596 [+0ms]","src":"client"}
{"t":1782919071833,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"suspect-gate","detail":"postCase=false howtoOk=true micOk=true sent=false [+20ms]","src":"client"}
{"t":1782919071852,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"preload-start","detail":" [+22ms]","src":"client"}
{"t":1782919071902,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"manifest-done","detail":" [+113ms]","src":"client"}
{"t":1782919071911,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"colors-resolved","detail":" [+114ms]","src":"client"}
{"t":1782919071942,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"socket-connect","detail":" [+153ms]","src":"client"}
{"t":1782919071945,"cat":"LobbyA","room":"a","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782919072616,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"mychar-tinted","detail":"roomJoinReady=false [+802ms]","src":"client"}
{"t":1782919072657,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"preload-occupants-done","detail":" [+870ms]","src":"client"}
{"t":1782919072661,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"preload-ready(occupants)","detail":" [+871ms]","src":"client"}
{"t":1782919072707,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"join-ok","detail":"peers=1 host=me map=mlsbbxfe bots=3 [+901ms]","src":"client"}
{"t":1782919072744,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+901ms]","src":"client"}
{"t":1782919072808,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"suspect-join","detail":"phaseActive=false pickIdx=0 postCase=false clientMapId=mlsbbxfe spaceId=a-1782919068596 mapName=LobbyA [+922ms]","src":"client"}
{"t":1782919072813,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:10.0,14.0->10.7,13.5 b1:16.0,14.0->15.3,13.5 b2:22.0,13.0->21.2,13.4] [+926ms]","src":"client"}
{"t":1782919076823,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:20.8,6.6->21.3,6.3 b1:8.3,5.9->8.8,5.6 b2:22.4,8.9->22.7,8.4] [+4954ms]","src":"client"}
{"t":1782919079658,"cat":"LobbyA","room":"a-1782919068596","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+7872ms]","src":"client"}
{"t":1782919079725,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=false [+7936ms]","src":"client"}
{"t":1782919080227,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"suspect-open-evt","detail":"idx=0 postCase=true [+8438ms]","src":"client"}
{"t":1782919080831,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:26.9,16.7->27.1,16.7 b1:7.4,12.3->7.4,12.3 b2:17.6,5.2->17.6,5.2] [+9029ms]","src":"client"}
{"t":1782919084191,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+12408ms]","src":"client"}
{"t":1782919084997,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:23.6,15.4->23.0,15.2 b1:15.4,13.3->16.0,13.3 b2:16.5,5.0->16.5,5.0] [+13216ms]","src":"client"}
{"t":1782919089041,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->12.9,9.4 b1:26.2,15.1->19.2,15.9 b2:14.1,12.1->8.0,4.2] [+17257ms]","src":"client"}
{"t":1782919093067,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->16.4,13.4 b1:26.2,15.1->14.8,12.9 b2:14.1,12.1->8.0,6.3] [+21289ms]","src":"client"}
{"t":1782919097110,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->16.3,13.1 b1:26.2,15.1->7.4,16.9 b2:14.1,12.1->8.7,10.0] [+25329ms]","src":"client"}
{"t":1782919101148,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->27.9,10.4 b1:26.2,15.1->5.4,15.1 b2:14.1,12.1->8.6,4.0] [+29367ms]","src":"client"}
{"t":1782919105185,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->26.5,11.9 b1:26.2,15.1->18.3,13.3 b2:14.1,12.1->8.6,4.0] [+33407ms]","src":"client"}
{"t":1782919109225,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->11.2,8.5 b1:26.2,15.1->5.4,16.8 b2:14.1,12.1->9.7,5.2] [+37444ms]","src":"client"}
{"t":1782919113264,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->12.2,8.5 b1:26.2,15.1->14.8,9.7 b2:14.1,12.1->27.9,14.9] [+41483ms]","src":"client"}
{"t":1782919117292,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->12.4,5.1 b1:26.2,15.1->19.4,13.5 b2:14.1,12.1->27.9,16.7] [+45514ms]","src":"client"}
{"t":1782919121330,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->9.7,6.0 b1:26.2,15.1->24.5,5.3 b2:14.1,12.1->19.1,10.7] [+49549ms]","src":"client"}
{"t":1782919125402,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->19.7,9.5 b1:26.2,15.1->8.3,7.7 b2:14.1,12.1->27.8,5.0] [+53623ms]","src":"client"}
{"t":1782919129459,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->28.0,5.2 b1:26.2,15.1->14.8,7.3 b2:14.1,12.1->28.9,12.2] [+57678ms]","src":"client"}
{"t":1782919133495,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.6,9.9->19.2,10.7 b1:26.2,15.1->9.7,5.8 b2:14.1,12.1->15.7,8.5] [+61715ms]","src":"client"}
{"t":1782919137529,"cat":"LobbyB","room":"a-1782919068596","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:19.2,9.1->18.6,9.0 b1:20.5,9.5->19.5,9.6 b2:10.4,12.2->9.6,12.8] [+65752ms]","src":"client"}
{"t":1782919145875,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"lobby-open","detail":"space=s-1782919142863 [+0ms]","src":"client"}
{"t":1782919145925,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"suspect-gate","detail":"postCase=false howtoOk=true micOk=true sent=false [+39ms]","src":"client"}
{"t":1782919145930,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"preload-start","detail":" [+40ms]","src":"client"}
{"t":1782919145995,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"manifest-done","detail":" [+138ms]","src":"client"}
{"t":1782919146007,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"colors-resolved","detail":" [+138ms]","src":"client"}
{"t":1782919146074,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"socket-connect","detail":" [+184ms]","src":"client"}
{"t":1782919146051,"cat":"LobbyA","room":"s","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782919146719,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"join-ok","detail":"peers=1 host=me map=mlsbbxfe bots=3 [+862ms]","src":"client"}
{"t":1782919146740,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"suspect-join","detail":"phaseActive=false pickIdx=0 postCase=false clientMapId=mlsbbxfe spaceId=s-1782919142863 mapName=LobbyA [+884ms]","src":"client"}
{"t":1782919147403,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"mychar-tinted","detail":"roomJoinReady=true [+1542ms]","src":"client"}
{"t":1782919147471,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:10.0,14.0->10.1,13.3 b1:16.0,14.0->15.3,13.7 b2:22.0,13.0->22.0,13.7] [+1612ms]","src":"client"}
{"t":1782919147843,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"preload-occupants-done","detail":" [+1978ms]","src":"client"}
{"t":1782919147845,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"preload-ready(occupants)","detail":" [+1979ms]","src":"client"}
{"t":1782919147848,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+1979ms]","src":"client"}
{"t":1782919153632,"cat":"LobbyA","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:11.7,4.2->11.7,4.2 b1:12.8,12.4->13.4,12.2 b2:28.0,13.4->28.0,13.3] [+7771ms]","src":"client"}
{"t":1782919154196,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=false [+8333ms]","src":"client"}
{"t":1782919154260,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+8399ms]","src":"client"}
{"t":1782919154690,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"suspect-open-evt","detail":"idx=0 postCase=true [+8828ms]","src":"client"}
{"t":1782919157683,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:26.9,16.9->26.9,16.9 b1:11.9,14.4->12.8,14.1 b2:25.4,16.8->24.8,16.4] [+11824ms]","src":"client"}
{"t":1782919161716,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->28.5,12.5 b1:27.5,12.0->27.5,12.0 b2:8.1,5.6->8.1,5.6] [+15856ms]","src":"client"}
{"t":1782919165753,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->23.5,6.2 b1:27.5,12.0->27.5,13.8 b2:13.6,8.4->28.0,16.1] [+19894ms]","src":"client"}
{"t":1782919169785,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->20.6,7.6 b1:27.5,12.0->17.9,8.7 b2:13.6,8.4->16.3,17.0] [+23927ms]","src":"client"}
{"t":1782919173828,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->9.2,13.0 b1:27.5,12.0->12.4,16.6 b2:13.6,8.4->13.0,17.0] [+27968ms]","src":"client"}
{"t":1782919177862,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->23.5,7.1 b1:27.5,12.0->13.4,15.9 b2:13.6,8.4->17.7,13.1] [+32002ms]","src":"client"}
{"t":1782919181898,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->24.3,11.3 b1:27.5,12.0->15.2,16.8 b2:13.6,8.4->23.3,15.2] [+36038ms]","src":"client"}
{"t":1782919185928,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->7.3,15.0 b1:27.5,12.0->14.9,11.8 b2:13.6,8.4->17.3,13.0] [+40070ms]","src":"client"}
{"t":1782919189971,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->6.2,15.3 b1:27.5,12.0->23.5,14.2 b2:13.6,8.4->26.6,10.1] [+44116ms]","src":"client"}
{"t":1782919193997,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->8.0,4.5 b1:27.5,12.0->27.7,15.7 b2:13.6,8.4->15.7,7.9] [+48137ms]","src":"client"}
{"t":1782919198029,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->15.6,6.3 b1:27.5,12.0->7.0,15.7 b2:13.6,8.4->20.1,11.1] [+52172ms]","src":"client"}
{"t":1782919202073,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->15.6,9.0 b1:27.5,12.0->7.7,10.4 b2:13.6,8.4->13.5,5.8] [+56214ms]","src":"client"}
{"t":1782919206116,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->27.5,9.7 b1:27.5,12.0->26.7,13.0 b2:13.6,8.4->24.2,9.6] [+60257ms]","src":"client"}
{"t":1782919210142,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->24.8,16.9 b1:27.5,12.0->7.2,14.4 b2:13.6,8.4->28.9,9.0] [+64283ms]","src":"client"}
{"t":1782919214180,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->23.7,10.4 b1:27.5,12.0->19.1,6.8 b2:13.6,8.4->19.9,12.6] [+68321ms]","src":"client"}
{"t":1782919218212,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->5.1,16.2 b1:27.5,12.0->28.4,12.7 b2:13.6,8.4->11.6,6.0] [+72357ms]","src":"client"}
{"t":1782919222258,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->25.7,6.3 b1:27.5,12.0->12.9,16.9 b2:13.6,8.4->29.0,12.7] [+76396ms]","src":"client"}
{"t":1782919226297,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->27.8,5.3 b1:27.5,12.0->12.1,16.5 b2:13.6,8.4->11.5,14.8] [+80437ms]","src":"client"}
{"t":1782919230355,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->24.0,5.3 b1:27.5,12.0->28.6,8.7 b2:13.6,8.4->28.0,10.3] [+84492ms]","src":"client"}
{"t":1782919234375,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->11.3,6.3 b1:27.5,12.0->20.6,13.2 b2:13.6,8.4->15.4,7.3] [+88513ms]","src":"client"}
{"t":1782919238409,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->12.9,7.6 b1:27.5,12.0->18.6,14.3 b2:13.6,8.4->27.3,12.8] [+92552ms]","src":"client"}
{"t":1782919242448,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->15.6,7.0 b1:27.5,12.0->27.6,9.2 b2:13.6,8.4->13.5,16.9] [+96587ms]","src":"client"}
{"t":1782919246483,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->22.5,7.2 b1:27.5,12.0->23.5,9.1 b2:13.6,8.4->13.7,16.9] [+100623ms]","src":"client"}
{"t":1782919250517,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->28.3,12.9 b1:27.5,12.0->19.2,11.7 b2:13.6,8.4->28.9,8.3] [+104662ms]","src":"client"}
{"t":1782919254557,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->24.1,7.3 b1:27.5,12.0->26.6,10.0 b2:13.6,8.4->28.9,7.6] [+108697ms]","src":"client"}
{"t":1782919258591,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->18.4,8.4 b1:27.5,12.0->28.0,9.5 b2:13.6,8.4->15.4,6.2] [+112731ms]","src":"client"}
{"t":1782919262627,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->7.1,14.0 b1:27.5,12.0->14.9,13.9 b2:13.6,8.4->28.7,8.8] [+116767ms]","src":"client"}
{"t":1782919266659,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->19.4,17.0 b1:27.5,12.0->14.3,9.7 b2:13.6,8.4->26.6,7.3] [+120800ms]","src":"client"}
{"t":1782919270697,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->18.4,14.5 b1:27.5,12.0->17.9,7.8 b2:13.6,8.4->24.7,12.2] [+124840ms]","src":"client"}
{"t":1782919274738,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->14.8,6.4 b1:27.5,12.0->8.3,6.7 b2:13.6,8.4->27.9,11.5] [+128877ms]","src":"client"}
{"t":1782919278771,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->25.5,15.3 b1:27.5,12.0->8.3,5.6 b2:13.6,8.4->25.2,11.6] [+132909ms]","src":"client"}
{"t":1782919282889,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->11.5,7.4 b1:27.5,12.0->10.0,5.4 b2:13.6,8.4->24.7,14.5] [+137033ms]","src":"client"}
{"t":1782919286900,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->21.6,7.8 b1:27.5,12.0->12.5,8.6 b2:13.6,8.4->19.3,13.8] [+141039ms]","src":"client"}
{"t":1782919290932,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->28.9,8.8 b1:27.5,12.0->26.4,9.1 b2:13.6,8.4->28.0,14.4] [+145074ms]","src":"client"}
{"t":1782919294963,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->27.7,12.6 b1:27.5,12.0->15.4,16.8 b2:13.6,8.4->13.4,16.8] [+149103ms]","src":"client"}
{"t":1782919298998,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->26.1,11.8 b1:27.5,12.0->9.0,4.3 b2:13.6,8.4->7.0,13.4] [+153139ms]","src":"client"}
{"t":1782919303033,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->14.7,8.1 b1:27.5,12.0->9.5,5.4 b2:13.6,8.4->15.7,6.3] [+157173ms]","src":"client"}
{"t":1782919307066,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->7.1,12.7 b1:27.5,12.0->16.5,6.6 b2:13.6,8.4->8.0,6.8] [+161206ms]","src":"client"}
{"t":1782919311099,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->23.2,15.9 b1:27.5,12.0->23.2,13.5 b2:13.6,8.4->7.9,10.6] [+165240ms]","src":"client"}
{"t":1782919315131,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->12.8,5.4 b1:27.5,12.0->18.7,13.2 b2:13.6,8.4->18.6,8.2] [+169277ms]","src":"client"}
{"t":1782919319175,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->5.4,9.1 b1:27.5,12.0->25.3,4.5 b2:13.6,8.4->10.4,6.5] [+173318ms]","src":"client"}
{"t":1782919323214,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->22.0,8.8 b1:27.5,12.0->19.4,8.4 b2:13.6,8.4->10.9,6.5] [+177354ms]","src":"client"}
{"t":1782919327250,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->27.8,10.9 b1:27.5,12.0->28.9,12.7 b2:13.6,8.4->10.9,6.5] [+181391ms]","src":"client"}
{"t":1782919331284,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->11.8,16.0 b1:27.5,12.0->22.6,16.7 b2:13.6,8.4->19.8,13.1] [+185424ms]","src":"client"}
{"t":1782919335311,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->23.2,8.9 b1:27.5,12.0->22.5,16.7 b2:13.6,8.4->26.7,5.4] [+189452ms]","src":"client"}
{"t":1782919339345,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->17.5,13.2 b1:27.5,12.0->6.3,9.1 b2:13.6,8.4->21.6,14.6] [+193491ms]","src":"client"}
{"t":1782919343380,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,12.5->18.2,13.2 b1:27.5,12.0->14.4,8.7 b2:13.6,8.4->15.7,6.0] [+197526ms]","src":"client"}
{"t":1782919347418,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.9,4.4->25.4,4.1 b1:28.5,7.9->19.4,9.8 b2:18.4,8.9->19.2,8.9] [+201563ms]","src":"client"}
{"t":1782919351454,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->25.4,4.2 b1:26.6,7.9->20.5,9.9 b2:19.1,9.5->19.1,9.5] [+205596ms]","src":"client"}
{"t":1782919355491,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->15.1,13.0 b1:26.6,7.9->15.7,6.4 b2:19.1,9.5->22.9,14.1] [+209634ms]","src":"client"}
{"t":1782919359519,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->7.0,10.6 b1:26.6,7.9->5.5,16.0 b2:19.1,9.5->16.7,16.8] [+213663ms]","src":"client"}
{"t":1782919363558,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->7.7,16.5 b1:26.6,7.9->14.6,11.2 b2:19.1,9.5->9.7,16.9] [+217701ms]","src":"client"}
{"t":1782919367591,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->25.6,3.9 b1:26.6,7.9->23.4,16.8 b2:19.1,9.5->13.7,5.5] [+221733ms]","src":"client"}
{"t":1782919371623,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->19.8,13.9 b1:26.6,7.9->15.8,13.2 b2:19.1,9.5->19.4,15.4] [+225764ms]","src":"client"}
{"t":1782919375652,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->11.5,16.7 b1:26.6,7.9->23.0,10.0 b2:19.1,9.5->18.8,6.5] [+229794ms]","src":"client"}
{"t":1782919379681,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->11.6,16.7 b1:26.6,7.9->20.9,14.4 b2:19.1,9.5->13.3,15.1] [+233823ms]","src":"client"}
{"t":1782919383716,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->11.2,16.7 b1:26.6,7.9->23.8,9.1 b2:19.1,9.5->12.6,16.7] [+237858ms]","src":"client"}
{"t":1782919387756,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->22.1,16.7 b1:26.6,7.9->6.6,15.7 b2:19.1,9.5->6.9,9.2] [+241897ms]","src":"client"}
{"t":1782919391981,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->7.4,11.9 b1:26.6,7.9->20.9,9.0 b2:19.1,9.5->8.1,13.7] [+246122ms]","src":"client"}
{"t":1782919396004,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->9.9,12.9 b1:26.6,7.9->8.2,8.8 b2:19.1,9.5->21.8,6.4] [+250146ms]","src":"client"}
{"t":1782919400051,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->9.8,16.9 b1:26.6,7.9->15.1,7.6 b2:19.1,9.5->23.9,13.8] [+254193ms]","src":"client"}
{"t":1782919404076,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->7.5,14.4 b1:26.6,7.9->8.0,7.6 b2:19.1,9.5->19.5,6.2] [+258216ms]","src":"client"}
{"t":1782919408106,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->16.1,14.8 b1:26.6,7.9->9.3,8.6 b2:19.1,9.5->15.9,8.8] [+262249ms]","src":"client"}
{"t":1782919412142,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->12.3,5.4 b1:26.6,7.9->13.2,16.7 b2:19.1,9.5->8.1,4.9] [+266283ms]","src":"client"}
{"t":1782919416176,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->27.8,10.7 b1:26.6,7.9->7.8,14.9 b2:19.1,9.5->13.8,8.9] [+270317ms]","src":"client"}
{"t":1782919420217,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->28.7,12.4 b1:26.6,7.9->16.0,8.8 b2:19.1,9.5->25.3,17.0] [+274359ms]","src":"client"}
{"t":1782919424252,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->28.9,13.0 b1:26.6,7.9->15.9,8.8 b2:19.1,9.5->23.2,10.9] [+278392ms]","src":"client"}
{"t":1782919428283,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->22.7,16.9 b1:26.6,7.9->14.2,6.2 b2:19.1,9.5->25.6,12.6] [+282419ms]","src":"client"}
{"t":1782919432328,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->21.9,16.9 b1:26.6,7.9->8.7,9.7 b2:19.1,9.5->7.3,11.0] [+286470ms]","src":"client"}
{"t":1782919436364,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->22.7,12.0 b1:26.6,7.9->17.2,6.4 b2:19.1,9.5->22.5,6.1] [+290506ms]","src":"client"}
{"t":1782919440404,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->8.2,5.8 b1:26.6,7.9->16.3,5.7 b2:19.1,9.5->27.2,5.0] [+294546ms]","src":"client"}
{"t":1782919444449,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->19.7,16.5 b1:26.6,7.9->17.8,5.8 b2:19.1,9.5->20.9,16.9] [+298586ms]","src":"client"}
{"t":1782919448481,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->19.5,6.1 b1:26.6,7.9->21.7,10.3 b2:19.1,9.5->20.9,16.9] [+302624ms]","src":"client"}
{"t":1782919452509,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->17.5,7.3 b1:26.6,7.9->8.3,16.8 b2:19.1,9.5->12.5,5.4] [+306654ms]","src":"client"}
{"t":1782919456541,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->17.9,5.5 b1:26.6,7.9->10.6,16.8 b2:19.1,9.5->24.3,11.3] [+310687ms]","src":"client"}
{"t":1782919460575,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->28.8,6.2 b1:26.6,7.9->13.1,12.7 b2:19.1,9.5->19.5,12.7] [+314719ms]","src":"client"}
{"t":1782919464614,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->21.8,7.2 b1:26.6,7.9->14.7,11.9 b2:19.1,9.5->11.0,16.8] [+318762ms]","src":"client"}
{"t":1782919468650,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->26.1,14.5 b1:26.6,7.9->14.6,11.3 b2:19.1,9.5->11.9,6.5] [+322794ms]","src":"client"}
{"t":1782919472685,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->11.1,17.0 b1:26.6,7.9->20.4,14.0 b2:19.1,9.5->12.6,16.6] [+326829ms]","src":"client"}
{"t":1782919476720,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->7.1,11.0 b1:26.6,7.9->20.6,16.8 b2:19.1,9.5->7.0,9.8] [+330863ms]","src":"client"}
{"t":1782919480874,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.4,4.2->15.3,16.8 b1:26.6,7.9->22.3,15.5 b2:19.1,9.5->21.4,11.2] [+335020ms]","src":"client"}
{"t":1782919484905,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:26.6,6.0->25.7,6.5 b1:14.5,8.2->13.4,8.0 b2:27.5,16.9->27.5,16.9] [+339049ms]","src":"client"}
{"t":1782919488943,"cat":"LobbyB","room":"s-1782919142863","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:19.2,11.3->19.2,11.9 b1:8.1,6.6->20.7,5.5 b2:27.5,16.9->21.7,5.0] [+343086ms]","src":"client"}
{"t":1782922304648,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"lobby-open","detail":"space=a-1782922301574 [+1ms]","src":"client"}
{"t":1782922304692,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"preload-start","detail":" [+34ms]","src":"client"}
{"t":1782922304692,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"suspect-gate","detail":"postCase=false howtoOk=true micOk=true sent=false [+32ms]","src":"client"}
{"t":1782922304791,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"manifest-done","detail":" [+134ms]","src":"client"}
{"t":1782922304793,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"colors-resolved","detail":" [+135ms]","src":"client"}
{"t":1782922304804,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"socket-connect","detail":" [+162ms]","src":"client"}
{"t":1782922304809,"cat":"LobbyA","room":"a","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782922305623,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"join-ok","detail":"peers=1 host=me map=mlsbbxfe bots=3 [+994ms]","src":"client"}
{"t":1782922305644,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"suspect-join","detail":"phaseActive=false pickIdx=0 postCase=false clientMapId=mlsbbxfe spaceId=a-1782922301574 mapName=LobbyA [+1016ms]","src":"client"}
{"t":1782922305646,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:10.0,14.0->10.5,13.8 b1:16.0,14.0->16.2,13.5 b2:22.0,13.0->22.5,13.1] [+1021ms]","src":"client"}
{"t":1782922306027,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"mychar-tinted","detail":"roomJoinReady=true [+1400ms]","src":"client"}
{"t":1782922307000,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"preload-occupants-done","detail":" [+2374ms]","src":"client"}
{"t":1782922307001,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"preload-ready(occupants)","detail":" [+2374ms]","src":"client"}
{"t":1782922307013,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+2374ms]","src":"client"}
{"t":1782922310702,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:15.7,9.8->16.2,9.8 b1:18.8,13.0->18.9,13.0 b2:24.6,13.7->24.6,13.7] [+6072ms]","src":"client"}
{"t":1782922314732,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.4,10.5->29.3,10.6 b1:20.8,5.5->20.8,5.5 b2:27.0,14.8->27.0,14.8] [+10102ms]","src":"client"}
{"t":1782922318769,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:20.1,11.9->20.1,11.9 b1:22.5,8.0->22.4,7.0 b2:22.3,13.6->22.3,13.6] [+14141ms]","src":"client"}
{"t":1782922322820,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.4,7.3->7.4,7.1 b1:21.0,8.6->20.7,9.5 b2:19.8,8.4->18.8,8.2] [+18180ms]","src":"client"}
{"t":1782922326837,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->21.5,12.0 b1:29.9,11.1->23.4,11.7 b2:12.7,11.6->14.8,10.6] [+22209ms]","src":"client"}
{"t":1782922330870,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->18.0,13.5 b1:29.9,11.1->20.2,12.1 b2:12.7,11.6->7.4,17.8] [+26241ms]","src":"client"}
{"t":1782922334909,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.0,14.0 b1:29.9,11.1->7.6,16.9 b2:12.7,11.6->21.5,14.4] [+30278ms]","src":"client"}
{"t":1782922338947,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->17.9,15.3 b1:29.9,11.1->22.8,17.0 b2:12.7,11.6->25.8,16.2] [+34318ms]","src":"client"}
{"t":1782922342984,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->13.8,12.1 b1:29.9,11.1->21.7,17.3 b2:12.7,11.6->27.0,13.4] [+38355ms]","src":"client"}
{"t":1782922347020,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->10.0,4.1 b1:29.9,11.1->6.4,10.2 b2:12.7,11.6->6.5,7.1] [+42388ms]","src":"client"}
{"t":1782922351046,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->23.3,6.7 b1:29.9,11.1->7.3,10.6 b2:12.7,11.6->11.1,13.8] [+46416ms]","src":"client"}
{"t":1782922355086,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->29.8,7.9 b1:29.9,11.1->12.7,10.6 b2:12.7,11.6->6.3,16.2] [+50453ms]","src":"client"}
{"t":1782922359123,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->18.0,4.3 b1:29.9,11.1->18.8,8.1 b2:12.7,11.6->16.9,8.8] [+54491ms]","src":"client"}
{"t":1782922363152,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.0,16.3 b1:29.9,11.1->15.0,14.5 b2:12.7,11.6->26.5,5.1] [+58521ms]","src":"client"}
{"t":1782922367188,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->14.1,5.4 b1:29.9,11.1->14.9,11.2 b2:12.7,11.6->16.3,4.0] [+62556ms]","src":"client"}
{"t":1782922371218,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->22.3,18.0 b1:29.9,11.1->13.5,6.3 b2:12.7,11.6->17.0,10.0] [+66586ms]","src":"client"}
{"t":1782922375261,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->22.3,18.0 b1:29.9,11.1->6.1,4.5 b2:12.7,11.6->11.0,6.4] [+70625ms]","src":"client"}
{"t":1782922379291,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->22.9,14.7 b1:29.9,11.1->29.8,7.7 b2:12.7,11.6->9.3,4.1] [+74659ms]","src":"client"}
{"t":1782922383319,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->13.7,8.5 b1:29.9,11.1->28.6,12.5 b2:12.7,11.6->28.3,8.9] [+78691ms]","src":"client"}
{"t":1782922387356,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->17.4,9.6 b1:29.9,11.1->28.6,12.5 b2:12.7,11.6->12.8,10.6] [+82724ms]","src":"client"}
{"t":1782922391391,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.0,8.4 b1:29.9,11.1->27.7,5.4 b2:12.7,11.6->10.7,6.2] [+86760ms]","src":"client"}
{"t":1782922395425,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.0,8.4 b1:29.9,11.1->18.4,4.0 b2:12.7,11.6->20.3,10.6] [+90793ms]","src":"client"}
{"t":1782922399460,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->16.7,5.6 b1:29.9,11.1->24.0,5.1 b2:12.7,11.6->17.6,9.6] [+94828ms]","src":"client"}
{"t":1782922403499,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->25.7,16.8 b1:29.9,11.1->20.1,11.6 b2:12.7,11.6->28.4,5.5] [+98866ms]","src":"client"}
{"t":1782922407526,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->18.0,9.9 b1:29.9,11.1->16.4,13.6 b2:12.7,11.6->21.6,13.7] [+102894ms]","src":"client"}
{"t":1782922411558,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->10.3,17.8 b1:29.9,11.1->9.2,14.5 b2:12.7,11.6->29.9,9.2] [+106925ms]","src":"client"}
{"t":1782922415596,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->12.8,5.4 b1:29.9,11.1->10.6,4.3 b2:12.7,11.6->10.4,6.5] [+110965ms]","src":"client"}
{"t":1782922419639,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->23.6,5.3 b1:29.9,11.1->8.9,15.0 b2:12.7,11.6->20.3,13.0] [+115005ms]","src":"client"}
{"t":1782922423670,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.2,14.3 b1:29.9,11.1->6.1,11.9 b2:12.7,11.6->6.3,12.1] [+119037ms]","src":"client"}
{"t":1782922427704,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->19.1,4.4 b1:29.9,11.1->6.1,16.1 b2:12.7,11.6->11.9,7.9] [+123070ms]","src":"client"}
{"t":1782922431736,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.4,9.9 b1:29.9,11.1->12.5,11.9 b2:12.7,11.6->16.0,9.5] [+127103ms]","src":"client"}
{"t":1782922435806,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->14.5,11.6 b1:29.9,11.1->16.3,4.1 b2:12.7,11.6->21.0,6.3] [+131178ms]","src":"client"}
{"t":1782922439870,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->24.1,17.0 b1:29.9,11.1->6.1,5.3 b2:12.7,11.6->29.7,6.6] [+135238ms]","src":"client"}
{"t":1782922443904,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->24.1,17.0 b1:29.9,11.1->14.7,8.2 b2:12.7,11.6->12.6,9.6] [+139275ms]","src":"client"}
{"t":1782922447950,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->20.2,11.0 b1:29.9,11.1->11.4,4.1 b2:12.7,11.6->7.7,17.7] [+143317ms]","src":"client"}
{"t":1782922451984,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->20.2,10.8 b1:29.9,11.1->11.9,7.1 b2:12.7,11.6->6.2,17.9] [+147352ms]","src":"client"}
{"t":1782922456019,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->20.2,12.2 b1:29.9,11.1->26.0,7.9 b2:12.7,11.6->25.6,15.7] [+151385ms]","src":"client"}
{"t":1782922460044,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->17.7,8.9 b1:29.9,11.1->7.7,4.2 b2:12.7,11.6->17.4,13.1] [+155411ms]","src":"client"}
{"t":1782922464074,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->28.5,12.0 b1:29.9,11.1->13.2,10.7 b2:12.7,11.6->19.9,13.1] [+159442ms]","src":"client"}
{"t":1782922468111,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->14.6,5.1 b1:29.9,11.1->21.3,6.6 b2:12.7,11.6->19.9,13.1] [+163479ms]","src":"client"}
{"t":1782922472155,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->7.8,4.2 b1:29.9,11.1->6.2,7.0 b2:12.7,11.6->8.8,7.4] [+167523ms]","src":"client"}
{"t":1782922476179,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->7.8,4.2 b1:29.9,11.1->17.8,9.9 b2:12.7,11.6->6.0,12.4] [+171545ms]","src":"client"}
{"t":1782922480212,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->18.4,5.8 b1:29.9,11.1->29.6,7.5 b2:12.7,11.6->6.3,12.5] [+175580ms]","src":"client"}
{"t":1782922484246,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->22.1,6.3 b1:29.9,11.1->29.6,7.4 b2:12.7,11.6->11.0,11.2] [+179614ms]","src":"client"}
{"t":1782922488303,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->9.7,16.9 b1:29.9,11.1->14.8,7.5 b2:12.7,11.6->14.6,11.3] [+183655ms]","src":"client"}
{"t":1782922492323,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->14.3,5.2 b1:29.9,11.1->22.6,17.6 b2:12.7,11.6->14.6,11.3] [+187690ms]","src":"client"}
{"t":1782922496358,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->29.6,5.4 b1:29.9,11.1->29.6,10.9 b2:12.7,11.6->15.0,5.3] [+191725ms]","src":"client"}
{"t":1782922500392,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->29.6,5.4 b1:29.9,11.1->22.5,10.2 b2:12.7,11.6->20.8,10.1] [+195760ms]","src":"client"}
{"t":1782922504445,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->17.0,13.2 b1:29.9,11.1->6.3,11.1 b2:12.7,11.6->6.0,6.5] [+199804ms]","src":"client"}
{"t":1782922508464,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->18.6,13.3 b1:29.9,11.1->6.3,11.8 b2:12.7,11.6->7.7,6.8] [+203830ms]","src":"client"}
{"t":1782922512500,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.5,16.8 b1:29.9,11.1->23.1,8.4 b2:12.7,11.6->22.2,16.6] [+207866ms]","src":"client"}
{"t":1782922516532,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->18.8,7.6 b1:29.9,11.1->27.6,5.2 b2:12.7,11.6->25.2,16.8] [+211903ms]","src":"client"}
{"t":1782922520577,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->17.6,13.3 b1:29.9,11.1->8.3,10.6 b2:12.7,11.6->29.6,5.2] [+215942ms]","src":"client"}
{"t":1782922524606,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->7.0,4.4 b1:29.9,11.1->6.0,8.6 b2:12.7,11.6->23.4,14.8] [+219973ms]","src":"client"}
{"t":1782922528641,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->8.8,14.3 b1:29.9,11.1->13.9,14.4 b2:12.7,11.6->27.6,13.1] [+224007ms]","src":"client"}
{"t":1782922532683,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->26.7,14.6 b1:29.9,11.1->29.8,6.1 b2:12.7,11.6->20.3,10.4] [+228048ms]","src":"client"}
{"t":1782922536719,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->21.0,14.6 b1:29.9,11.1->10.8,12.3 b2:12.7,11.6->6.3,7.6] [+232084ms]","src":"client"}
{"t":1782922540755,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->27.0,14.0 b1:29.9,11.1->14.6,10.6 b2:12.7,11.6->6.3,7.2] [+236121ms]","src":"client"}
{"t":1782922544784,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->18.7,17.8 b1:29.9,11.1->6.2,4.5 b2:12.7,11.6->19.0,13.3] [+240150ms]","src":"client"}
{"t":1782922548815,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->18.7,17.8 b1:29.9,11.1->20.1,8.7 b2:12.7,11.6->9.7,13.0] [+244181ms]","src":"client"}
{"t":1782922552850,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.6,5.1 b1:29.9,11.1->16.8,9.6 b2:12.7,11.6->6.4,9.4] [+248216ms]","src":"client"}
{"t":1782922556888,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.6,11.3 b1:29.9,11.1->6.3,12.7 b2:12.7,11.6->7.9,6.1] [+252253ms]","src":"client"}
{"t":1782922560933,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->14.7,7.4 b1:29.9,11.1->6.0,6.6 b2:12.7,11.6->7.9,6.4] [+256298ms]","src":"client"}
{"t":1782922564971,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.4,17.6 b1:29.9,11.1->7.7,6.7 b2:12.7,11.6->14.3,6.8] [+260335ms]","src":"client"}
{"t":1782922569004,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->13.8,14.2 b1:29.9,11.1->16.7,6.2 b2:12.7,11.6->23.5,15.7] [+264369ms]","src":"client"}
{"t":1782922573044,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->19.5,5.4 b1:29.9,11.1->6.0,7.8 b2:12.7,11.6->8.9,9.7] [+268407ms]","src":"client"}
{"t":1782922577072,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->29.9,7.3 b1:29.9,11.1->11.9,12.5 b2:12.7,11.6->25.6,15.2] [+272435ms]","src":"client"}
{"t":1782922581101,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->10.5,17.9 b1:29.9,11.1->19.9,4.4 b2:12.7,11.6->21.8,6.1] [+276465ms]","src":"client"}
{"t":1782922585139,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->10.8,16.9 b1:29.9,11.1->23.4,14.8 b2:12.7,11.6->24.8,13.9] [+280503ms]","src":"client"}
{"t":1782922589177,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->19.8,9.9 b1:29.9,11.1->10.9,4.3 b2:12.7,11.6->29.5,6.6] [+284541ms]","src":"client"}
{"t":1782922593211,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.3,5.8 b1:29.9,11.1->19.0,14.2 b2:12.7,11.6->12.7,7.7] [+288576ms]","src":"client"}
{"t":1782922597250,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->11.4,9.1 b1:29.9,11.1->20.2,11.5 b2:12.7,11.6->28.5,10.0] [+292613ms]","src":"client"}
{"t":1782922601286,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->14.8,16.5 b1:29.9,11.1->16.0,7.7 b2:12.7,11.6->21.2,5.3] [+296649ms]","src":"client"}
{"t":1782922605316,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->23.0,17.4 b1:29.9,11.1->6.7,7.3 b2:12.7,11.6->29.8,9.2] [+300678ms]","src":"client"}
{"t":1782922609347,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->22.7,13.2 b1:29.9,11.1->11.6,9.2 b2:12.7,11.6->12.8,12.5] [+304711ms]","src":"client"}
{"t":1782922613383,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->21.5,5.8 b1:29.9,11.1->23.5,16.5 b2:12.7,11.6->6.1,8.5] [+308746ms]","src":"client"}
{"t":1782922617609,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->29.0,7.3 b1:29.9,11.1->27.1,7.3 b2:12.7,11.6->14.7,11.2] [+312913ms]","src":"client"}
{"t":1782922621583,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->8.6,4.0 b1:29.9,11.1->29.8,8.0 b2:12.7,11.6->15.7,13.2] [+316948ms]","src":"client"}
{"t":1782922625625,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->8.2,16.0 b1:29.9,11.1->19.7,15.4 b2:12.7,11.6->20.0,12.4] [+320987ms]","src":"client"}
{"t":1782922629667,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->6.3,6.6 b1:29.9,11.1->22.7,5.3 b2:12.7,11.6->19.6,17.9] [+325030ms]","src":"client"}
{"t":1782922633709,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->8.4,4.2 b1:29.9,11.1->15.2,7.0 b2:12.7,11.6->10.5,9.2] [+329070ms]","src":"client"}
{"t":1782922637748,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->11.7,4.8 b1:29.9,11.1->21.9,16.5 b2:12.7,11.6->16.9,5.0] [+333109ms]","src":"client"}
{"t":1782922641782,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->10.0,13.3 b1:29.9,11.1->15.1,9.9 b2:12.7,11.6->18.0,8.1] [+337143ms]","src":"client"}
{"t":1782922645815,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->15.8,5.3 b1:29.9,11.1->6.3,10.7 b2:12.7,11.6->11.2,4.9] [+341177ms]","src":"client"}
{"t":1782922649851,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->15.8,5.3 b1:29.9,11.1->6.3,10.7 b2:12.7,11.6->22.7,5.1] [+345211ms]","src":"client"}
{"t":1782922653883,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->26.2,14.1 b1:29.9,11.1->11.6,4.2 b2:12.7,11.6->18.8,4.1] [+349244ms]","src":"client"}
{"t":1782922657914,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->14.0,5.1 b1:29.9,11.1->15.6,15.3 b2:12.7,11.6->12.7,15.5] [+353275ms]","src":"client"}
{"t":1782922661948,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->23.1,5.3 b1:29.9,11.1->10.0,10.6 b2:12.7,11.6->25.9,11.9] [+357310ms]","src":"client"}
{"t":1782922665980,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->14.9,10.4 b1:29.9,11.1->19.3,6.7 b2:12.7,11.6->6.2,14.9] [+361341ms]","src":"client"}
{"t":1782922670020,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->9.2,6.8 b1:29.9,11.1->29.6,5.2 b2:12.7,11.6->14.6,12.2] [+365381ms]","src":"client"}
{"t":1782922674054,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->14.7,12.5 b1:29.9,11.1->28.8,12.8 b2:12.7,11.6->30.0,10.4] [+369416ms]","src":"client"}
{"t":1782922678088,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->28.1,5.1 b1:29.9,11.1->25.3,11.6 b2:12.7,11.6->13.1,5.3] [+373449ms]","src":"client"}
{"t":1782922682130,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->28.2,5.1 b1:29.9,11.1->9.8,9.6 b2:12.7,11.6->15.6,5.3] [+377492ms]","src":"client"}
{"t":1782922686167,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->22.4,12.6 b1:29.9,11.1->15.8,5.0 b2:12.7,11.6->11.1,17.6] [+381530ms]","src":"client"}
{"t":1782922690202,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->17.7,13.8 b1:29.9,11.1->16.1,4.5 b2:12.7,11.6->6.4,13.0] [+385564ms]","src":"client"}
{"t":1782922694234,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->7.4,4.2 b1:29.9,11.1->16.1,4.2 b2:12.7,11.6->27.0,14.1] [+389597ms]","src":"client"}
{"t":1782922698274,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->19.9,9.5 b1:29.9,11.1->18.9,8.1 b2:12.7,11.6->14.0,13.0] [+393636ms]","src":"client"}
{"t":1782922702308,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->9.1,17.8 b1:29.9,11.1->25.3,16.6 b2:12.7,11.6->6.4,12.3] [+397675ms]","src":"client"}
{"t":1782922706353,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.8,6.9->16.0,5.2 b1:29.9,11.1->26.9,14.7 b2:12.7,11.6->14.7,10.8] [+401716ms]","src":"client"}
{"t":1782922710401,"cat":"LobbyA","room":"a-1782922301574","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:14.9,8.0->13.9,8.5 b1:21.2,12.9->21.2,12.9 b2:14.7,10.8->14.7,10.8] [+405762ms]","src":"client"}
{"t":1782932303827,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"lobby-open","detail":"space=a-1782932300753 [+0ms]","src":"client"}
{"t":1782932303872,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"suspect-gate","detail":"postCase=false howtoOk=true micOk=true sent=false [+17ms]","src":"client"}
{"t":1782932303875,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"preload-start","detail":" [+19ms]","src":"client"}
{"t":1782932303928,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"manifest-done","detail":" [+109ms]","src":"client"}
{"t":1782932303933,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"colors-resolved","detail":" [+110ms]","src":"client"}
{"t":1782932303962,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"socket-connect","detail":" [+134ms]","src":"client"}
{"t":1782932303965,"cat":"LobbyA","room":"a","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 0","src":"server"}
{"t":1782932304524,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"join-ok","detail":"peers=1 host=me map=mlsbbxfe bots=0 [+688ms]","src":"client"}
{"t":1782932304531,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"suspect-join","detail":"phaseActive=false pickIdx=0 postCase=false clientMapId=mlsbbxfe spaceId=a-1782932300753 mapName=LobbyA [+710ms]","src":"client"}
{"t":1782932305089,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"mychar-tinted","detail":"roomJoinReady=true [+1276ms]","src":"client"}
{"t":1782932305334,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"preload-occupants-done","detail":" [+1504ms]","src":"client"}
{"t":1782932305335,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"preload-ready(occupants)","detail":" [+1504ms]","src":"client"}
{"t":1782932305335,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+1504ms]","src":"client"}
{"t":1782932312869,"cat":"LobbyA","room":"a","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host เปิด wizard เลือกคดี → ล็อก set-ready ทั้งห้อง (1 คนในห้อง)","src":"server"}
{"t":1782932324475,"cat":"LobbyB","room":"a","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host ปิด wizard → ปลดล็อก set-ready (1 คนในห้อง)","src":"server"}
{"t":1782932324929,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+21113ms]","src":"client"}
{"t":1782932325050,"cat":"LobbyB","room":"a-1782932300753","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=false [+21233ms]","src":"client"}
{"t":1782932325644,"cat":"LobbyB","room":"a-1782932300753","who":"บอท7","ev":"suspect-open-evt","detail":"idx=0 postCase=true [+21812ms]","src":"client"}
{"t":1782932326728,"cat":"LobbyB","room":"a","who":"บอท7","ev":"story-gate","detail":"[TC156] อ่าน story จบ 1/1","src":"server"}
{"t":1782932326728,"cat":"LobbyB","room":"a","who":"","ev":"story-gate","detail":"[TC156] ทุกคนอ่าน story ครบ (1) → ปลดล็อกเลือกผู้ต้องสงสัย (pass)","src":"server"}
{"t":1782932327182,"cat":"LobbyB","room":"a-1782932300753","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+23365ms]","src":"client"}
{"t":1782932350834,"cat":"MG2","room":"a","who":"","ev":"game-start","detail":"เริ่มมินิเกม: Minigame-2 วิ่งหลบสิ่งกีดขวาง (การ์ด 1)","src":"server"}
{"t":1782932350844,"cat":"MG2","room":"a","who":"บอท7","ev":"lobbyb-gate","detail":"[TC144] เริ่มสืบสวน OK — ผู้เล่นครบ 1 คน · ผู้ต้องสงสัย #1","src":"server"}
{"t":1782932350889,"cat":"MG2","room":"a","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host ปิด wizard → ปลดล็อก set-ready (1 คนในห้อง)","src":"server"}
{"t":1782932351381,"cat":"MG2","room":"a","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 0","src":"server"}
{"t":1782932383445,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"lobby-open","detail":"space=a-1782932300753 [+0ms]","src":"client"}
{"t":1782932383502,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=false [+54ms]","src":"client"}
{"t":1782932383502,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"preload-start","detail":" [+56ms]","src":"client"}
{"t":1782932383547,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=true [+60ms]","src":"client"}
{"t":1782932383661,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"manifest-done","detail":" [+218ms]","src":"client"}
{"t":1782932383661,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"socket-connect","detail":" [+213ms]","src":"client"}
{"t":1782932383663,"cat":"LobbyA","room":"a-1782932300753","who":"บอท7","ev":"colors-resolved","detail":" [+219ms]","src":"client"}
{"t":1782932383810,"cat":"MG2","room":"a","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 0","src":"server"}
{"t":1782932384806,"cat":"LobbyB","room":"a-1782932300753","who":"บอท7","ev":"mychar-tinted","detail":"roomJoinReady=false [+1363ms]","src":"client"}
{"t":1782932384867,"cat":"LobbyB","room":"a-1782932300753","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=false [+1414ms]","src":"client"}
{"t":1782932384944,"cat":"LobbyB","room":"a-1782932300753","who":"บอท7","ev":"preload-occupants-done","detail":" [+1490ms]","src":"client"}
{"t":1782932384944,"cat":"LobbyB","room":"a-1782932300753","who":"บอท7","ev":"preload-ready(occupants)","detail":" [+1491ms]","src":"client"}
{"t":1782932385142,"cat":"LobbyB","room":"a-1782932300753","who":"บอท7","ev":"join-ok","detail":"peers=1 host=me map=mn8nx46h bots=0 [+1670ms]","src":"client"}
{"t":1782932385144,"cat":"LobbyB","room":"a-1782932300753","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+1670ms]","src":"client"}
{"t":1782932385144,"cat":"LobbyB","room":"a-1782932300753","who":"บอท7","ev":"suspect-join","detail":"phaseActive=true pickIdx=0 postCase=true clientMapId=mn8nx46h spaceId=a-1782932300753 mapName=LobbyB [+1680ms]","src":"client"}
{"t":1782932393634,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"lobby-open","detail":"space=aad-1782932390649 [+0ms]","src":"client"}
{"t":1782932393680,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"suspect-gate","detail":"postCase=false howtoOk=true micOk=true sent=false [+26ms]","src":"client"}
{"t":1782932393682,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"preload-start","detail":" [+27ms]","src":"client"}
{"t":1782932393737,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"manifest-done","detail":" [+128ms]","src":"client"}
{"t":1782932393741,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"colors-resolved","detail":" [+129ms]","src":"client"}
{"t":1782932393772,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"socket-connect","detail":" [+139ms]","src":"client"}
{"t":1782932393775,"cat":"LobbyA","room":"aad","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782932394456,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"mychar-tinted","detail":"roomJoinReady=false [+847ms]","src":"client"}
{"t":1782932394563,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"preload-occupants-done","detail":" [+950ms]","src":"client"}
{"t":1782932394574,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"preload-ready(occupants)","detail":" [+950ms]","src":"client"}
{"t":1782932394599,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"join-ok","detail":"peers=1 host=me map=mlsbbxfe bots=3 [+979ms]","src":"client"}
{"t":1782932394609,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+980ms]","src":"client"}
{"t":1782932394621,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"suspect-join","detail":"phaseActive=false pickIdx=0 postCase=false clientMapId=mlsbbxfe spaceId=aad-1782932390649 mapName=LobbyA [+1000ms]","src":"client"}
{"t":1782932395321,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:10.0,14.0->10.2,13.3 b1:16.0,14.0->16.1,14.7 b2:22.0,13.0->21.4,12.5] [+1679ms]","src":"client"}
{"t":1782932397778,"cat":"LobbyA","room":"aad","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host เปิด wizard เลือกคดี → ล็อก set-ready ทั้งห้อง (1 คนในห้อง)","src":"server"}
{"t":1782932400207,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:10.7,4.3->10.7,4.3 b1:22.7,17.5->22.7,17.5 b2:9.0,4.1->9.0,4.1] [+6598ms]","src":"client"}
{"t":1782932401161,"cat":"LobbyB","room":"aad","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host ปิด wizard → ปลดล็อก set-ready (1 คนในห้อง)","src":"server"}
{"t":1782932401612,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+8006ms]","src":"client"}
{"t":1782932401703,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=false [+8091ms]","src":"client"}
{"t":1782932402197,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"suspect-open-evt","detail":"idx=0 postCase=true [+8590ms]","src":"client"}
{"t":1782932403160,"cat":"LobbyB","room":"aad","who":"บอท7","ev":"story-gate","detail":"[TC156] อ่าน story จบ 1/1","src":"server"}
{"t":1782932403160,"cat":"LobbyB","room":"aad","who":"","ev":"story-gate","detail":"[TC156] ทุกคนอ่าน story ครบ (1) → ปลดล็อกเลือกผู้ต้องสงสัย (pass)","src":"server"}
{"t":1782932403736,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+10129ms]","src":"client"}
{"t":1782932404378,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:9.8,10.2->9.1,9.9 b1:15.0,9.3->15.0,9.3 b2:14.6,12.4->14.6,12.4] [+10762ms]","src":"client"}
{"t":1782932405228,"cat":"MG2","room":"aad","who":"","ev":"game-start","detail":"เริ่มมินิเกม: Minigame-2 วิ่งหลบสิ่งกีดขวาง (การ์ด 1)","src":"server"}
{"t":1782932405240,"cat":"MG2","room":"aad","who":"บอท7","ev":"lobbyb-gate","detail":"[TC144] เริ่มสืบสวน OK — ผู้เล่นครบ 1 คน · ผู้ต้องสงสัย #1","src":"server"}
{"t":1782932405299,"cat":"MG2","room":"aad","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host ปิด wizard → ปลดล็อก set-ready (1 คนในห้อง)","src":"server"}
{"t":1782932405913,"cat":"MG2","room":"aad","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782932467036,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"lobby-open","detail":"space=aad-1782932390649 [+0ms]","src":"client"}
{"t":1782932467081,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=false [+22ms]","src":"client"}
{"t":1782932467083,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"preload-start","detail":" [+23ms]","src":"client"}
{"t":1782932467084,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=true [+27ms]","src":"client"}
{"t":1782932467131,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"manifest-done","detail":" [+139ms]","src":"client"}
{"t":1782932467136,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"colors-resolved","detail":" [+139ms]","src":"client"}
{"t":1782932467178,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"socket-connect","detail":" [+180ms]","src":"client"}
{"t":1782932467267,"cat":"LobbyB","room":"aad","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782932467802,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"mychar-tinted","detail":"roomJoinReady=false [+774ms]","src":"client"}
{"t":1782932467854,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"preload-occupants-done","detail":" [+858ms]","src":"client"}
{"t":1782932467859,"cat":"LobbyA","room":"aad-1782932390649","who":"บอท7","ev":"preload-ready(occupants)","detail":" [+858ms]","src":"client"}
{"t":1782932468486,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"join-ok","detail":"peers=1 host=me map=mn8nx46h bots=3 [+1450ms]","src":"client"}
{"t":1782932468489,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+1450ms]","src":"client"}
{"t":1782932468490,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"suspect-join","detail":"phaseActive=true pickIdx=0 postCase=true clientMapId=mn8nx46h spaceId=aad-1782932390649 mapName=LobbyB [+1473ms]","src":"client"}
{"t":1782932468535,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:10.0,15.0->9.8,14.3 b1:15.0,15.0->15.6,15.4 b2:21.0,15.0->21.8,14.8] [+1537ms]","src":"client"}
{"t":1782932474638,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.4,9.8->13.4,9.8 b1:15.1,13.0->15.6,13.3 b2:7.1,14.7->7.1,14.7] [+7641ms]","src":"client"}
{"t":1782932480186,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:14.9,11.2->14.9,11.2 b1:25.7,13.2->26.1,13.5 b2:7.1,14.7->7.1,14.7] [+13188ms]","src":"client"}
{"t":1782932484200,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:9.4,16.6->9.4,16.6 b1:23.6,8.5->24.3,7.8 b2:19.9,11.1->20.6,11.6] [+17204ms]","src":"client"}
{"t":1782932488235,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:14.8,16.9->14.8,16.9 b1:8.4,4.3->8.4,4.3 b2:19.2,10.0->19.2,10.0] [+21239ms]","src":"client"}
{"t":1782932492274,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:15.6,13.2->15.7,13.1 b1:15.0,11.3->15.0,11.8 b2:15.8,13.3->14.8,13.3] [+25276ms]","src":"client"}
{"t":1782932496308,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:15.6,13.1->15.1,13.1 b1:15.8,7.1->15.0,6.5 b2:11.0,13.7->11.8,14.3] [+29313ms]","src":"client"}
{"t":1782932500342,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.2,5.7->8.2,5.7 b1:23.9,14.4->23.9,14.4 b2:16.8,16.9->16.8,16.9] [+33345ms]","src":"client"}
{"t":1782932504385,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:21.8,6.4->21.8,6.4 b1:13.5,8.4->12.5,8.3 b2:6.2,10.2->6.2,10.2] [+37387ms]","src":"client"}
{"t":1782932508415,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:7.1,12.4->7.1,12.4 b1:8.2,7.8->8.2,7.8 b2:5.4,9.1->5.4,9.1] [+41419ms]","src":"client"}
{"t":1782932512451,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.2,6.1->12.3,6.1 b1:8.2,6.3->8.2,6.3 b2:5.4,9.1->5.4,9.1] [+45453ms]","src":"client"}
{"t":1782932516481,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:9.0,6.4->9.0,6.4 b1:8.2,6.3->8.2,6.3 b2:14.6,10.1->14.6,10.1] [+49489ms]","src":"client"}
{"t":1782932520522,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:19.7,12.6->20.6,12.2 b1:12.7,16.8->12.7,16.8 b2:9.3,15.6->9.3,15.6] [+53526ms]","src":"client"}
{"t":1782932524563,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:24.0,5.6->24.0,5.6 b1:6.6,15.2->5.7,15.7 b2:9.2,5.3->9.2,5.3] [+57566ms]","src":"client"}
{"t":1782932528597,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.5,8.7->27.8,8.9 b1:27.4,5.0->27.7,5.0 b2:25.8,11.3->26.7,11.6] [+61600ms]","src":"client"}
{"t":1782932532630,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:5.0,15.9->5.0,15.9 b1:21.1,6.0->20.2,6.0 b2:14.7,8.7->13.7,8.6] [+65634ms]","src":"client"}
{"t":1782932536662,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:19.8,16.9->19.8,16.9 b1:14.0,7.8->15.0,8.1 b2:20.2,5.4->20.1,5.2] [+69665ms]","src":"client"}
{"t":1782932540692,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:20.4,14.8->20.7,13.8 b1:22.7,6.4->22.7,6.4 b2:21.7,5.0->21.7,5.0] [+73695ms]","src":"client"}
{"t":1782932544729,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:25.8,15.3->25.8,15.3 b1:27.4,12.4->28.0,12.8 b2:15.3,8.6->15.3,8.6] [+77731ms]","src":"client"}
{"t":1782932548771,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.7,12.0->28.7,12.0 b1:18.8,9.1->18.1,8.9 b2:16.0,8.6->16.1,8.6] [+81773ms]","src":"client"}
{"t":1782932552805,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:16.9,8.6->17.4,8.6 b1:14.3,13.0->14.3,13.0 b2:16.8,8.6->16.8,8.6] [+85808ms]","src":"client"}
{"t":1782932556832,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->13.8,16.9 b1:24.4,5.2->24.4,5.2 b2:8.2,8.3->8.2,8.3] [+89836ms]","src":"client"}
{"t":1782932560863,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->13.8,16.9 b1:24.4,5.8->24.4,5.8 b2:8.4,8.0->10.6,6.2] [+93868ms]","src":"client"}
{"t":1782932564894,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->11.8,15.9 b1:24.4,5.8->14.8,16.9 b2:8.4,8.0->13.0,5.1] [+97898ms]","src":"client"}
{"t":1782932568932,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->10.7,6.2 b1:24.4,5.8->11.8,16.9 b2:8.4,8.0->28.9,7.2] [+101935ms]","src":"client"}
{"t":1782932572983,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->21.0,16.9 b1:24.4,5.8->9.0,5.2 b2:8.4,8.0->19.4,9.6] [+105974ms]","src":"client"}
{"t":1782932577000,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->21.0,16.9 b1:24.4,5.8->12.7,6.5 b2:8.4,8.0->21.1,6.3] [+110004ms]","src":"client"}
{"t":1782932581035,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->24.5,5.5 b1:24.4,5.8->24.5,8.8 b2:8.4,8.0->18.6,16.7] [+114039ms]","src":"client"}
{"t":1782932585065,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->24.4,5.6 b1:24.4,5.8->25.4,5.5 b2:8.4,8.0->16.3,17.0] [+118070ms]","src":"client"}
{"t":1782932589097,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->5.1,9.3 b1:24.4,5.8->19.2,11.2 b2:8.4,8.0->23.5,7.5] [+122102ms]","src":"client"}
{"t":1782932593135,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->17.7,5.3 b1:24.4,5.8->15.1,17.0 b2:8.4,8.0->19.1,11.3] [+126140ms]","src":"client"}
{"t":1782932597179,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->14.1,13.1 b1:24.4,5.8->14.1,6.3 b2:8.4,8.0->12.8,13.1] [+130183ms]","src":"client"}
{"t":1782932601215,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->23.7,6.1 b1:24.4,5.8->25.8,16.9 b2:8.4,8.0->25.4,10.9] [+134219ms]","src":"client"}
{"t":1782932605251,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->11.0,11.8 b1:24.4,5.8->6.8,9.0 b2:8.4,8.0->27.8,16.4] [+138254ms]","src":"client"}
{"t":1782932609285,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->19.6,6.0 b1:24.4,5.8->26.5,16.5 b2:8.4,8.0->7.3,17.0] [+142289ms]","src":"client"}
{"t":1782932613320,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->19.3,12.6 b1:24.4,5.8->15.7,15.0 b2:8.4,8.0->12.6,12.5] [+146324ms]","src":"client"}
{"t":1782932617355,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->8.3,4.6 b1:24.4,5.8->25.3,12.2 b2:8.4,8.0->25.8,4.9] [+150360ms]","src":"client"}
{"t":1782932621392,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->14.7,12.9 b1:24.4,5.8->19.3,11.8 b2:8.4,8.0->25.1,3.3] [+154396ms]","src":"client"}
{"t":1782932625419,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->5.9,16.3 b1:24.4,5.8->28.2,6.7 b2:8.4,8.0->13.9,5.3] [+158424ms]","src":"client"}
{"t":1782932629453,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->20.5,15.5 b1:24.4,5.8->19.2,10.3 b2:8.4,8.0->16.2,5.7] [+162456ms]","src":"client"}
{"t":1782932633486,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->22.5,15.2 b1:24.4,5.8->19.0,12.2 b2:8.4,8.0->9.6,16.9] [+166490ms]","src":"client"}
{"t":1782932637516,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->27.8,9.1 b1:24.4,5.8->7.2,14.2 b2:8.4,8.0->14.8,11.2] [+170521ms]","src":"client"}
{"t":1782932641551,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->16.3,6.4 b1:24.4,5.8->14.9,11.3 b2:8.4,8.0->14.8,9.1] [+174556ms]","src":"client"}
{"t":1782932645583,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->14.4,16.8 b1:24.4,5.8->28.9,8.3 b2:8.4,8.0->21.0,10.2] [+178586ms]","src":"client"}
{"t":1782932649613,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->6.4,10.3 b1:24.4,5.8->28.9,6.9 b2:8.4,8.0->13.4,13.4] [+182617ms]","src":"client"}
{"t":1782932653643,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->22.8,10.7 b1:24.4,5.8->28.9,6.8 b2:8.4,8.0->15.0,9.2] [+186646ms]","src":"client"}
{"t":1782932657672,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->18.1,6.3 b1:24.4,5.8->19.8,9.0 b2:8.4,8.0->28.9,6.9] [+190676ms]","src":"client"}
{"t":1782932661705,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->21.9,5.4 b1:24.4,5.8->5.9,15.1 b2:8.4,8.0->28.9,6.9] [+194709ms]","src":"client"}
{"t":1782932665742,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->20.1,5.2 b1:24.4,5.8->6.6,15.1 b2:8.4,8.0->8.1,9.6] [+198744ms]","src":"client"}
{"t":1782932669774,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->14.4,15.9 b1:24.4,5.8->18.9,6.2 b2:8.4,8.0->23.2,16.7] [+202778ms]","src":"client"}
{"t":1782932673809,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->16.4,13.1 b1:24.4,5.8->14.8,11.9 b2:8.4,8.0->10.2,16.3] [+206814ms]","src":"client"}
{"t":1782932677850,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->17.2,13.1 b1:24.4,5.8->14.8,10.8 b2:8.4,8.0->23.1,14.0] [+210854ms]","src":"client"}
{"t":1782932681885,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->6.6,15.2 b1:24.4,5.8->15.0,6.4 b2:8.4,8.0->14.7,16.9] [+214889ms]","src":"client"}
{"t":1782932685918,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->5.2,16.6 b1:24.4,5.8->9.4,7.1 b2:8.4,8.0->8.8,4.3] [+218921ms]","src":"client"}
{"t":1782932689949,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->19.8,7.8 b1:24.4,5.8->16.9,14.1 b2:8.4,8.0->17.3,8.8] [+222954ms]","src":"client"}
{"t":1782932693985,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->21.0,9.4 b1:24.4,5.8->19.9,6.3 b2:8.4,8.0->27.3,5.1] [+226989ms]","src":"client"}
{"t":1782932698018,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->22.1,10.9 b1:24.4,5.8->8.3,6.1 b2:8.4,8.0->18.8,7.1] [+231022ms]","src":"client"}
{"t":1782932702064,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->8.4,4.7 b1:24.4,5.8->8.3,6.1 b2:8.4,8.0->5.8,9.3] [+235067ms]","src":"client"}
{"t":1782932706095,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->9.9,5.8 b1:24.4,5.8->16.7,16.8 b2:8.4,8.0->14.7,10.4] [+239101ms]","src":"client"}
{"t":1782932710133,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->22.7,6.8 b1:24.4,5.8->27.5,15.8 b2:8.4,8.0->8.4,4.9] [+243138ms]","src":"client"}
{"t":1782932714169,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.8,16.9->15.5,8.9 b1:24.4,5.8->27.5,15.8 b2:8.4,8.0->16.3,17.0] [+247173ms]","src":"client"}
{"t":1782932718200,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:22.8,16.6->27.6,17.0 b1:17.8,10.5->14.2,13.1 b2:21.1,11.6->27.9,13.5] [+251204ms]","src":"client"}
{"t":1782932722227,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->11.3,6.5 b1:8.3,4.7->14.0,7.8 b2:27.9,13.5->19.3,12.8] [+255232ms]","src":"client"}
{"t":1782932726251,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->27.7,16.1 b1:8.3,4.7->25.2,8.3 b2:27.9,13.5->19.3,12.4] [+259256ms]","src":"client"}
{"t":1782932730278,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->19.1,9.5 b1:8.3,4.7->28.6,12.2 b2:27.9,13.5->28.9,8.3] [+263282ms]","src":"client"}
{"t":1782932734312,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->19.1,9.2 b1:8.3,4.7->17.9,5.2 b2:27.9,13.5->12.4,5.5] [+267317ms]","src":"client"}
{"t":1782932738351,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->16.6,8.8 b1:8.3,4.7->17.9,5.3 b2:27.9,13.5->27.5,16.8] [+271356ms]","src":"client"}
{"t":1782932742393,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->9.1,12.1 b1:8.3,4.7->24.3,12.9 b2:27.9,13.5->19.4,11.6] [+275398ms]","src":"client"}
{"t":1782932746429,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->12.0,14.0 b1:8.3,4.7->14.6,9.9 b2:27.9,13.5->19.4,12.3] [+279434ms]","src":"client"}
{"t":1782932750465,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->27.9,9.6 b1:8.3,4.7->18.1,8.9 b2:27.9,13.5->19.4,9.9] [+283470ms]","src":"client"}
{"t":1782932754503,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->11.2,14.1 b1:8.3,4.7->24.7,8.7 b2:27.9,13.5->19.4,9.1] [+287508ms]","src":"client"}
{"t":1782932758540,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->14.5,12.3 b1:8.3,4.7->19.3,9.5 b2:27.9,13.5->18.7,8.9] [+291545ms]","src":"client"}
{"t":1782932762587,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->5.0,15.2 b1:8.3,4.7->11.6,16.8 b2:27.9,13.5->27.7,16.3] [+295592ms]","src":"client"}
{"t":1782932766631,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->13.2,9.6 b1:8.3,4.7->17.2,15.9 b2:27.9,13.5->23.7,6.1] [+299626ms]","src":"client"}
{"t":1782932770663,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->18.6,13.0 b1:8.3,4.7->28.0,16.8 b2:27.9,13.5->11.8,12.6] [+303666ms]","src":"client"}
{"t":1782932774701,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->15.0,9.4 b1:8.3,4.7->20.3,9.8 b2:27.9,13.5->12.0,6.1] [+307705ms]","src":"client"}
{"t":1782932778735,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->8.0,7.2 b1:8.3,4.7->16.1,15.7 b2:27.9,13.5->15.1,7.4] [+311739ms]","src":"client"}
{"t":1782932782768,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->12.0,8.9 b1:8.3,4.7->19.4,9.6 b2:27.9,13.5->13.3,9.6] [+315772ms]","src":"client"}
{"t":1782932786805,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->18.1,6.2 b1:8.3,4.7->7.9,10.6 b2:27.9,13.5->6.6,10.2] [+319810ms]","src":"client"}
{"t":1782932790836,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->20.4,5.0 b1:8.3,4.7->28.1,6.2 b2:27.9,13.5->12.2,5.0] [+323840ms]","src":"client"}
{"t":1782932794869,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->9.0,11.1 b1:8.3,4.7->12.5,16.4 b2:27.9,13.5->12.2,5.0] [+327873ms]","src":"client"}
{"t":1782932798901,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->12.2,5.9 b1:8.3,4.7->22.0,5.1 b2:27.9,13.5->28.8,8.3] [+331904ms]","src":"client"}
{"t":1782932802943,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->10.9,11.3 b1:8.3,4.7->8.4,6.8 b2:27.9,13.5->19.0,12.3] [+335947ms]","src":"client"}
{"t":1782932806980,"cat":"LobbyB","room":"aad-1782932390649","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.1,9.4->5.9,16.7 b1:8.3,4.7->8.5,11.2 b2:27.9,13.5->29.0,6.3] [+339983ms]","src":"client"}
{"t":1782962916968,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"lobby-open","detail":"space=a-1782962913897 [+0ms]","src":"client"}
{"t":1782962917014,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"suspect-gate","detail":"postCase=false howtoOk=true micOk=true sent=false [+38ms]","src":"client"}
{"t":1782962917036,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"preload-start","detail":" [+40ms]","src":"client"}
{"t":1782962917101,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"manifest-done","detail":" [+128ms]","src":"client"}
{"t":1782962917110,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"colors-resolved","detail":" [+129ms]","src":"client"}
{"t":1782962917158,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"socket-connect","detail":" [+178ms]","src":"client"}
{"t":1782962917177,"cat":"LobbyA","room":"a","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782962918258,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"mychar-tinted","detail":"roomJoinReady=false [+1294ms]","src":"client"}
{"t":1782962918374,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"preload-occupants-done","detail":" [+1384ms]","src":"client"}
{"t":1782962918380,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"preload-ready(occupants)","detail":" [+1385ms]","src":"client"}
{"t":1782962918689,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"join-ok","detail":"peers=1 host=me map=mlsbbxfe bots=3 [+1719ms]","src":"client"}
{"t":1782962918714,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+1720ms]","src":"client"}
{"t":1782962918716,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"suspect-join","detail":"phaseActive=false pickIdx=0 postCase=false clientMapId=mlsbbxfe spaceId=a-1782962913897 mapName=LobbyA [+1742ms]","src":"client"}
{"t":1782962918717,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:10.0,14.0->11.2,12.7 b1:16.0,14.0->17.8,13.7 b2:22.0,13.0->20.2,13.1] [+1746ms]","src":"client"}
{"t":1782962922949,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:11.7,11.1->11.9,10.6 b1:19.4,13.4->19.9,13.3 b2:18.6,13.1->18.6,13.1] [+5983ms]","src":"client"}
{"t":1782962927963,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:6.2,12.2->6.2,12.2 b1:29.8,10.0->29.8,10.0 b2:6.5,5.3->6.5,5.3] [+11000ms]","src":"client"}
{"t":1782962931984,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:11.0,11.2->16.2,15.0 b1:10.6,4.0->10.6,4.0 b2:14.9,12.6->9.2,6.7] [+15020ms]","src":"client"}
{"t":1782962936025,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:22.5,17.6->22.5,17.6 b1:28.1,11.8->28.1,11.8 b2:6.2,12.5->6.2,12.5] [+19061ms]","src":"client"}
{"t":1782962936470,"cat":"LobbyA","room":"a","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host เปิด wizard เลือกคดี → ล็อก set-ready ทั้งห้อง (1 คนในห้อง)","src":"server"}
{"t":1782962938417,"cat":"LobbyB","room":"a","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host ปิด wizard → ปลดล็อก set-ready (1 คนในห้อง)","src":"server"}
{"t":1782962938875,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+21908ms]","src":"client"}
{"t":1782962939566,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=false [+22598ms]","src":"client"}
{"t":1782962940050,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:14.5,12.0->14.5,12.2 b1:5.4,15.7->5.4,15.7 b2:18.7,6.0->19.4,6.1] [+23084ms]","src":"client"}
{"t":1782962940211,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"suspect-open-evt","detail":"idx=0 postCase=true [+23247ms]","src":"client"}
{"t":1782962940707,"cat":"LobbyB","room":"a","who":"บอท7","ev":"story-gate","detail":"[TC156] อ่าน story จบ 1/1","src":"server"}
{"t":1782962940707,"cat":"LobbyB","room":"a","who":"","ev":"story-gate","detail":"[TC156] ทุกคนอ่าน story ครบ (1) → ปลดล็อกเลือกผู้ต้องสงสัย (pass)","src":"server"}
{"t":1782962941373,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+24416ms]","src":"client"}
{"t":1782962944105,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:18.2,16.8->17.2,17.0 b1:15.5,6.3->15.5,6.3 b2:28.6,6.5->28.6,6.5] [+27138ms]","src":"client"}
{"t":1782962948133,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:24.9,9.8->25.8,9.4 b1:9.9,9.3->9.0,9.8 b2:25.7,3.4->25.7,3.4] [+31166ms]","src":"client"}
{"t":1782962952168,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:13.5,9.8->12.7,10.2 b1:7.9,10.3->7.9,10.1 b2:25.7,3.4->25.7,3.4] [+35200ms]","src":"client"}
{"t":1782962954734,"cat":"MG2","room":"a","who":"","ev":"game-start","detail":"เริ่มมินิเกม: Minigame-2 วิ่งหลบสิ่งกีดขวาง (การ์ด 1)","src":"server"}
{"t":1782962954754,"cat":"MG2","room":"a","who":"บอท7","ev":"lobbyb-gate","detail":"[TC144] เริ่มสืบสวน OK — ผู้เล่นครบ 1 คน · ผู้ต้องสงสัย #1","src":"server"}
{"t":1782962954799,"cat":"MG2","room":"a","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host ปิด wizard → ปลดล็อก set-ready (1 คนในห้อง)","src":"server"}
{"t":1782962955223,"cat":"MG2","room":"a","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782963015648,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"lobby-open","detail":"space=a-1782962913897 [+0ms]","src":"client"}
{"t":1782963015692,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=false [+10ms]","src":"client"}
{"t":1782963015719,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"preload-start","detail":" [+12ms]","src":"client"}
{"t":1782963015731,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=true [+14ms]","src":"client"}
{"t":1782963015783,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"colors-resolved","detail":" [+138ms]","src":"client"}
{"t":1782963015784,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"manifest-done","detail":" [+137ms]","src":"client"}
{"t":1782963015818,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"socket-connect","detail":" [+149ms]","src":"client"}
{"t":1782963015874,"cat":"LobbyB","room":"a","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782963017140,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"mychar-tinted","detail":"roomJoinReady=false [+1495ms]","src":"client"}
{"t":1782963017233,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"preload-occupants-done","detail":" [+1568ms]","src":"client"}
{"t":1782963017234,"cat":"LobbyA","room":"a-1782962913897","who":"บอท7","ev":"preload-ready(occupants)","detail":" [+1568ms]","src":"client"}
{"t":1782963017253,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"join-ok","detail":"peers=1 host=me map=mn8nx46h bots=3 [+1605ms]","src":"client"}
{"t":1782963017273,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+1606ms]","src":"client"}
{"t":1782963017278,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"suspect-join","detail":"phaseActive=true pickIdx=0 postCase=true clientMapId=mn8nx46h spaceId=a-1782962913897 mapName=LobbyB [+1629ms]","src":"client"}
{"t":1782963017559,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:10.0,15.0->10.9,15.1 b1:15.0,15.0->14.1,14.9 b2:21.0,15.0->21.9,15.0] [+1891ms]","src":"client"}
{"t":1782963021756,"cat":"LobbyB","room":"a-1782962913897","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:24.0,13.4->23.7,13.0 b1:13.7,11.2->14.2,10.9 b2:27.5,15.5->27.5,15.5] [+6106ms]","src":"client"}
{"t":1782963024158,"cat":"MG1","room":"a","who":"","ev":"game-start","detail":"เริ่มมินิเกม: Minigame-1 จริงหรือไม่ (การ์ด 2)","src":"server"}
{"t":1782963024165,"cat":"MG1","room":"a","who":"บอท7","ev":"lobbyb-gate","detail":"[TC144] เริ่มสืบสวน OK — ผู้เล่นครบ 1 คน · ผู้ต้องสงสัย #2","src":"server"}
{"t":1782963024204,"cat":"MG1","room":"a","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host ปิด wizard → ปลดล็อก set-ready (1 คนในห้อง)","src":"server"}
{"t":1782963024612,"cat":"MG1","room":"a","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782965050184,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"lobby-open","detail":"space=a-1782965047174 [+1ms]","src":"client"}
{"t":1782965050222,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"suspect-gate","detail":"postCase=false howtoOk=true micOk=true sent=false [+32ms]","src":"client"}
{"t":1782965050244,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"preload-start","detail":" [+34ms]","src":"client"}
{"t":1782965050300,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"colors-resolved","detail":" [+129ms]","src":"client"}
{"t":1782965050302,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"manifest-done","detail":" [+129ms]","src":"client"}
{"t":1782965050324,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"socket-connect","detail":" [+140ms]","src":"client"}
{"t":1782965050348,"cat":"LobbyA","room":"a","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782965051043,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"mychar-tinted","detail":"roomJoinReady=false [+831ms]","src":"client"}
{"t":1782965051043,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"preload-occupants-done","detail":" [+877ms]","src":"client"}
{"t":1782965051085,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"join-ok","detail":"peers=1 host=me map=mlsbbxfe bots=3 [+900ms]","src":"client"}
{"t":1782965051087,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"preload-ready(occupants)","detail":" [+877ms]","src":"client"}
{"t":1782965051091,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+900ms]","src":"client"}
{"t":1782965051094,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"suspect-join","detail":"phaseActive=false pickIdx=0 postCase=false clientMapId=mlsbbxfe spaceId=a-1782965047174 mapName=LobbyA [+924ms]","src":"client"}
{"t":1782965051132,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:10.0,14.0->9.4,14.3 b1:16.0,14.0->16.5,13.6 b2:22.0,13.0->22.4,12.5] [+929ms]","src":"client"}
{"t":1782965055566,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:6.1,17.2->6.1,17.2 b1:22.7,8.6->22.7,8.6 b2:27.0,6.5->26.5,6.7] [+5398ms]","src":"client"}
{"t":1782965059599,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:16.3,13.0->16.3,13.0 b1:6.3,10.2->6.3,10.2 b2:22.2,11.1->22.2,11.1] [+9433ms]","src":"client"}
{"t":1782965063636,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:22.9,15.7->23.8,16.1 b1:15.0,11.1->15.0,11.1 b2:6.4,17.6->6.4,17.7] [+13470ms]","src":"client"}
{"t":1782965066818,"cat":"LobbyA","room":"a","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host เปิด wizard เลือกคดี → ล็อก set-ready ทั้งห้อง (1 คนในห้อง)","src":"server"}
{"t":1782965067676,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:8.0,4.6->8.9,4.9 b1:15.0,11.7->15.0,11.7 b2:24.5,5.2->25.0,5.2] [+17506ms]","src":"client"}
{"t":1782965069985,"cat":"LobbyB","room":"a","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host ปิด wizard → ปลดล็อก set-ready (1 คนในห้อง)","src":"server"}
{"t":1782965070442,"cat":"LobbyA","room":"a-1782965047174","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+20271ms]","src":"client"}
{"t":1782965071023,"cat":"LobbyB","room":"a-1782965047174","who":"บอท7","ev":"suspect-gate","detail":"postCase=true howtoOk=true micOk=true sent=false [+20847ms]","src":"client"}
{"t":1782965071523,"cat":"LobbyB","room":"a-1782965047174","who":"บอท7","ev":"suspect-open-evt","detail":"idx=0 postCase=true [+21350ms]","src":"client"}
{"t":1782965071642,"cat":"LobbyB","room":"a","who":"บอท7","ev":"story-gate","detail":"[TC156] อ่าน story จบ 1/1","src":"server"}
{"t":1782965071642,"cat":"LobbyB","room":"a","who":"","ev":"story-gate","detail":"[TC156] ทุกคนอ่าน story ครบ (1) → ปลดล็อกเลือกผู้ต้องสงสัย (pass)","src":"server"}
{"t":1782965071750,"cat":"LobbyB","room":"a-1782965047174","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:9.6,5.7->9.6,5.9 b1:9.2,15.3->10.1,14.9 b2:24.9,15.9->24.9,15.9] [+21582ms]","src":"client"}
{"t":1782965072133,"cat":"LobbyB","room":"a-1782965047174","who":"บอท7","ev":"loading-hide","detail":"เริ่มเล่นได้ [+21963ms]","src":"client"}
{"t":1782965075792,"cat":"LobbyB","room":"a-1782965047174","who":"บอท7","ev":"bot-pos","detail":"map=35x20 n=3 [b0:28.9,12.2->28.9,12.2 b1:26.5,7.8->25.8,8.5 b2:18.2,13.2->17.3,13.4] [+25626ms]","src":"client"}
{"t":1782965078994,"cat":"MG4","room":"a","who":"","ev":"game-start","detail":"เริ่มมินิเกม: Minigame-4 คำศัพท์ในกระบวนการยุติธรรม (การ์ด 1)","src":"server"}
{"t":1782965078999,"cat":"MG4","room":"a","who":"บอท7","ev":"lobbyb-gate","detail":"[TC144] เริ่มสืบสวน OK — ผู้เล่นครบ 1 คน · ผู้ต้องสงสัย #1","src":"server"}
{"t":1782965079043,"cat":"MG4","room":"a","who":"บอท7","ev":"preplay-lock","detail":"[TC154] host ปิด wizard → ปลดล็อก set-ready (1 คนในห้อง)","src":"server"}
{"t":1782965079429,"cat":"MG4","room":"a","who":"บอท7","ev":"join","detail":"สี#7 · คน 1 + บอท 3","src":"server"}
{"t":1782965086771,"cat":"MG4","room":"a","who":"","ev":"mg4-read","detail":"q=1 deck=29 rounds=0/10","src":"server"}
{"t":1782965104774,"cat":"MG4","room":"a","who":"","ev":"mg4-round","detail":"resolve 1/10 q=1 winner=- willEnd=false","src":"server"}
{"t":1782965107276,"cat":"MG4","room":"a","who":"","ev":"mg4-read","detail":"q=2 deck=28 rounds=1/10","src":"server"}
{"t":1782965113308,"cat":"MG4","room":"a","who":"","ev":"mg4-round","detail":"resolve 2/10 q=2 winner=cMav5ieq7U8JmdqiAAAL willEnd=false","src":"server"}
{"t":1782965115808,"cat":"MG4","room":"a","who":"","ev":"mg4-read","detail":"q=3 deck=27 rounds=2/10","src":"server"}
{"t":1782965126886,"cat":"MG4","room":"a","who":"","ev":"mg4-round","detail":"resolve 3/10 q=3 winner=__pv_bot_1 willEnd=false","src":"server"}
{"t":1782965129387,"cat":"MG4","room":"a","who":"","ev":"mg4-read","detail":"q=4 deck=26 rounds=3/10","src":"server"}
+5
View File
@@ -48,6 +48,11 @@
<body>
<header>
<h1>🎮 Game Log <small> 7 มินิเกม + LobbyA / LobbyB · srv1361159</small></h1>
<div style="margin:0 0 8px;font-size:12px;color:#9fb0d0">
🔎 ค้นหา <b>TC154 / TC156 / TC157 / TC144 / TC158</b> (หรือ ev: preplay-lock · story-gate · vote-gate · lobbyb-gate · mg4-warp)
ดูว่าฟีเจอร์ทำงานไหม แล้วอัปเดตผลที่ <a href="/testcase/" style="color:#37e0ff" target="_blank">/testcase/</a>
· เสียง (TC159-164) = ฟังเอง ไม่มีใน log
</div>
<div class="tabs" id="tabs"></div>
<div class="bar">
<label><input type="checkbox" id="auto" checked> auto-refresh 3s</label>
+129
View File
@@ -0,0 +1,129 @@
<?php /* gamelog viewer — log รวม 7 มินิเกม + LobbyA/B (อ่านจาก log.php) */ ?>
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Game Log · Justice</title>
<style>
:root { --bg:#0a0e1a; --panel:#121a2e; --line:#23304d; --txt:#cfe0ff; --dim:#7f93bd; --acc:#37e0ff; }
* { box-sizing:border-box; }
body { margin:0; background:var(--bg); color:var(--txt); font:14px/1.5 "Kanit",system-ui,sans-serif; }
header { position:sticky; top:0; z-index:5; background:linear-gradient(180deg,#0d1426,#0a0e1a); border-bottom:1px solid var(--line); padding:10px 14px; }
h1 { margin:0 0 8px; font-size:18px; letter-spacing:.5px; color:#fff; }
h1 small { color:var(--dim); font-size:12px; font-weight:400; }
.tabs { display:flex; flex-wrap:wrap; gap:6px; }
.tab { cursor:pointer; padding:5px 11px; border-radius:8px; border:1px solid var(--line); background:#0f1730; color:var(--dim); font-size:13px; user-select:none; }
.tab:hover { border-color:var(--acc); color:var(--txt); }
.tab.active { background:var(--acc); color:#05101f; border-color:var(--acc); font-weight:700; }
.tab .n { opacity:.7; font-size:11px; margin-left:4px; }
.bar { display:flex; align-items:center; gap:12px; margin-top:8px; font-size:12px; color:var(--dim); flex-wrap:wrap; }
.bar label { cursor:pointer; }
.bar input[type=text]{ background:#0f1730; border:1px solid var(--line); color:var(--txt); border-radius:7px; padding:5px 9px; min-width:160px; }
.btn { cursor:pointer; padding:5px 11px; border-radius:8px; border:1px solid var(--line); background:#0f1730; color:var(--txt); font-size:12px; }
.btn:hover { border-color:var(--acc); }
.btn.danger:hover { border-color:#ff5b6e; color:#ff8a97; }
#wrap { padding:6px 8px 60px; }
table { width:100%; border-collapse:collapse; }
th,td { text-align:left; padding:5px 9px; border-bottom:1px solid #182238; vertical-align:top; }
th { position:sticky; top:0; color:var(--dim); font-weight:600; font-size:12px; background:var(--bg); }
td.t { color:var(--dim); white-space:nowrap; font-variant-numeric:tabular-nums; font-size:12px; }
td.cat span { display:inline-block; padding:1px 8px; border-radius:6px; font-size:12px; font-weight:700; }
td.room { color:var(--dim); font-size:12px; max-width:130px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
td.who { color:#bcd; font-size:13px; }
td.ev { font-weight:600; }
td.detail { color:var(--dim); font-size:12px; word-break:break-word; }
tr.src-client td.ev::after { content:" ·c"; color:#6a7da6; font-size:10px; font-weight:400; }
.empty { text-align:center; color:var(--dim); padding:40px; }
/* cat colors */
.c-LobbyA{background:#1d3a5f;color:#9fd4ff} .c-LobbyB{background:#2a2f63;color:#c4c2ff}
.c-MG1{background:#7a2540;color:#ffc0d4} .c-MG2{background:#2a5f3a;color:#bfffd0}
.c-MG3{background:#5f4a1d;color:#ffe6a0} .c-MG4{background:#1d5f5a;color:#a0fff2}
.c-MG5{background:#3a2a5f;color:#d6c0ff} .c-MG6{background:#5f1d3a;color:#ffb0c8}
.c-MG7{background:#5f3a1d;color:#ffd0a0} .cother{background:#2a3550;color:#9fb0d0}
.ev-leave td.ev, .ev-disconnect td.ev{color:#ff8a97} .ev-join td.ev{color:#7ee787}
.ev-bot-takeover td.ev,.ev-ghost-prune td.ev{color:#ffd166} .ev-error td.ev{color:#ff5b6e}
</style>
</head>
<body>
<header>
<h1>🎮 Game Log <small>— 7 มินิเกม + LobbyA / LobbyB · srv1361159</small></h1>
<div class="tabs" id="tabs"></div>
<div class="bar">
<label><input type="checkbox" id="auto" checked> auto-refresh 3s</label>
<input type="text" id="search" placeholder="ค้นหา (ชื่อ/ห้อง/event/detail)">
<span id="status"></span>
<span style="flex:1"></span>
<button class="btn" id="reload">รีโหลด</button>
<button class="btn danger" id="clear">ล้าง log</button>
</div>
</header>
<div id="wrap"><div class="empty">กำลังโหลด...</div></div>
<script>
var CATS = ['ALL','LobbyA','LobbyB','MG1','MG2','MG3','MG4','MG5','MG6','MG7','อื่นๆ'];
var curCat = 'ALL';
var rows = [];
var counts = {};
function catClass(c){ var m={'LobbyA':'c-LobbyA','LobbyB':'c-LobbyB','MG1':'c-MG1','MG2':'c-MG2','MG3':'c-MG3','MG4':'c-MG4','MG5':'c-MG5','MG6':'c-MG6','MG7':'c-MG7'}; return m[c]||'cother'; }
function fmtTime(ms){ var d=new Date(ms); function p(n){return (n<10?'0':'')+n;} return p(d.getHours())+':'+p(d.getMinutes())+':'+p(d.getSeconds()); }
function esc(s){ return String(s==null?'':s).replace(/[&<>]/g,function(c){return{'&':'&amp;','<':'&lt;','>':'&gt;'}[c];}); }
function renderTabs(){
var t=document.getElementById('tabs'); t.innerHTML='';
CATS.forEach(function(c){
var d=document.createElement('div'); d.className='tab'+(c===curCat?' active':'');
var n=counts[c]!=null?('<span class="n">'+counts[c]+'</span>'):'';
d.innerHTML=esc(c)+n;
d.onclick=function(){ curCat=c; renderTabs(); render(); load(); };
t.appendChild(d);
});
}
function render(){
var wrap=document.getElementById('wrap');
var q=(document.getElementById('search').value||'').toLowerCase().trim();
var list=rows.filter(function(r){
if(!q) return true;
return ((r.who||'')+' '+(r.room||'')+' '+(r.ev||'')+' '+(r.detail||'')).toLowerCase().indexOf(q)>=0;
});
if(!list.length){ wrap.innerHTML='<div class="empty">ยังไม่มี log'+(curCat!=='ALL'?(' ใน '+esc(curCat)):'')+'</div>'; return; }
var h='<table><thead><tr><th>เวลา</th><th>หมวด</th><th>ห้อง</th><th>ใคร</th><th>event</th><th>รายละเอียด</th></tr></thead><tbody>';
list.forEach(function(r){
h+='<tr class="src-'+esc(r.src||'')+' ev-'+esc((r.ev||'').replace(/[^a-z-]/gi,''))+'">'+
'<td class="t">'+fmtTime(r.t)+'</td>'+
'<td class="cat"><span class="'+catClass(r.cat)+'">'+esc(r.cat)+'</span></td>'+
'<td class="room" title="'+esc(r.room)+'">'+esc(r.room)+'</td>'+
'<td class="who">'+esc(r.who)+'</td>'+
'<td class="ev">'+esc(r.ev)+'</td>'+
'<td class="detail">'+esc(r.detail)+'</td></tr>';
});
h+='</tbody></table>';
wrap.innerHTML=h;
}
function load(){
fetch('log.php?cat='+encodeURIComponent(curCat)+'&limit=800&_='+Date.now())
.then(function(r){return r.json();})
.then(function(j){
rows = (j&&j.logs)||[];
document.getElementById('status').textContent = (rows.length)+' รายการ · '+new Date().toLocaleTimeString('th-TH');
render();
}).catch(function(){ document.getElementById('status').textContent='โหลดไม่ได้'; });
// counts ทุกหมวด (จาก ALL)
fetch('log.php?cat=ALL&limit=2000&_c='+Date.now()).then(function(r){return r.json();}).then(function(j){
counts={ALL:0}; CATS.forEach(function(c){counts[c]=0;});
((j&&j.logs)||[]).forEach(function(r){ counts.ALL++; if(counts[r.cat]!=null) counts[r.cat]++; else counts['อื่นๆ']++; });
renderTabs();
}).catch(function(){});
}
document.getElementById('reload').onclick=load;
document.getElementById('search').oninput=render;
document.getElementById('clear').onclick=function(){
if(!confirm('ล้าง log ทั้งหมด?')) return;
fetch('log.php?action=clear').then(function(){ load(); });
};
renderTabs(); load();
setInterval(function(){ if(document.getElementById('auto').checked) load(); }, 3000);
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1
View File
@@ -9,5 +9,6 @@
"Minigame 5",
"Minigame 6",
"Minigame 7",
"เสียง (Sound)",
"อื่นๆ"
]
@@ -0,0 +1,13 @@
[
"LobbyA",
"LobbyB",
"ระบบ disconnect",
"Minigame 1",
"Minigame 2",
"Minigame 3",
"Minigame 4",
"Minigame 5",
"Minigame 6",
"Minigame 7",
"อื่นๆ"
]