fixgame 1 and 2 and 3

This commit is contained in:
2026-06-24 09:37:03 +00:00
parent a67fe4e408
commit 390f0e3a5e
4 changed files with 148 additions and 38 deletions
+9 -9
View File
@@ -51,9 +51,9 @@
"providerUserId": "p_1775109142385_wq7wfy1p32j",
"notes": "auto: player-coins",
"blocked": false,
"coins": 1358,
"coins": 1422,
"createdAt": "2026-04-02T05:52:21+00:00",
"updatedAt": "2026-06-24T08:45:00+00:00",
"updatedAt": "2026-06-24T09:36:08+00:00",
"daily": {
"anchorMs": 1781197200000,
"claimedDays": [
@@ -67,13 +67,13 @@
],
"lockUntilMs": 1782320400000
},
"score": 1208,
"score": 1252,
"scoreByCase": {
"1": 16,
"10": 358,
"8": 238,
"11": 20,
"13": 96,
"13": 140,
"14": 20,
"9": 40,
"12": 272,
@@ -619,21 +619,21 @@
"providerUserId": "p_1782016990238_0u37bv7pxlxs",
"notes": "auto: player-coins",
"blocked": false,
"coins": 58,
"coins": 124,
"createdAt": "2026-06-21T04:43:11+00:00",
"updatedAt": "2026-06-24T08:45:00+00:00",
"updatedAt": "2026-06-24T09:36:08+00:00",
"lobbyColorThemeIndex": 8,
"lobbySkinToneIndex": 1,
"score": 48,
"score": 94,
"scoreByCase": {
"13": 10,
"13": 56,
"10": 20,
"6": 8,
"8": 10
},
"lbName": "MONE",
"achievements": {
"d1_minigame_solver": 4
"d1_minigame_solver": 9
}
},
{
+103 -26
View File
@@ -1065,6 +1065,10 @@
const GAUNTLET_CROWN_RUNWAY_BG_MAP_ID = 'mno9kb07';
/** หลังหยุดเลื่อนที่จุด FINISH — รอก่อน latch + โฟลว์สรุป (มิลลิวิ) */
const GAUNTLET_CROWN_RUNWAY_POST_STOP_MS = 2000;
/** ความเร็วเดินเข้าเส้นชัยตอนจบ (ช่อง/วินาที) — ค่อยๆ เดินแทนกระพริบ snap */
const GAUNTLET_FINISH_WALK_TILES_PER_SEC = 7;
/** เพดานเวลาเดินเข้าเส้นชัย (กันค้างถ้าใครติด) — ต้อง < server grace (GAUNTLET_FINISH_WALK_MS) */
const GAUNTLET_FINISH_WALK_MAX_MS = 2600;
const GAUNTLET_CROWN_RUNWAY_BG_DEFAULT_START = BASE + '/img/editor-bg-mno9kb07/start.png';
const GAUNTLET_CROWN_RUNWAY_BG_DEFAULT_LOOP2 = BASE + '/img/editor-bg-mno9kb07/loop2.png';
const GAUNTLET_CROWN_RUNWAY_BG_DEFAULT_LOOP3 = BASE + '/img/editor-bg-mno9kb07/loop3.png';
@@ -1077,6 +1081,10 @@
let gauntletCrownRunwayBgFinishLatched = false;
/** ส่งสัญญาณ "ถึงเส้นชัย" ให้ server แล้วหรือยัง (กันส่งซ้ำ) — server จะหยุด obstacle/collision */
let gauntletFinishPhaseSignaled = false;
/** กำลังเดินค่อยๆ เข้าเส้นชัย (ก่อน freeze) — true ระหว่างทุกคนทยอยเดินมาที่เส้น */
let gauntletCrownRunwayWalkActive = false;
/** เวลาเริ่มเดินเข้าเส้นชัย (ms) — ใช้เพดานเวลา GAUNTLET_FINISH_WALK_MAX_MS */
let gauntletCrownRunwayWalkStartMs = 0;
/** >0 = หยุดเลื่อนแล้ว (timestamp ms) รอ POST_STOP ก่อน latch */
let gauntletCrownRunwayBgStripFreezeSinceMs = 0;
/** คอลัมน์แผนที่ที่ล็อกตอน freeze — แนบตัวนำแทนขอบขวาสูงสุดของแมป */
@@ -1205,7 +1213,7 @@
}
function gauntletCrownRunwayStripFrozenPlay() {
return gauntletCrownRunwayBgStripFreezeSinceMs > 0 || gauntletCrownRunwayBgFinishLatched;
return gauntletCrownRunwayWalkActive || gauntletCrownRunwayBgStripFreezeSinceMs > 0 || gauntletCrownRunwayBgFinishLatched;
}
/** จุดอ้างอิงกลางตัวนำ (map world px) — ใช้หยุด FINISH ตรงตัวละคร ไม่ใช่ขอบขวาแมป */
@@ -1267,6 +1275,73 @@
others.forEach((o, id) => { if (!playBotsEnabled() && isPreviewBotId(id)) return; snap(o); });
}
/** tx เป้าหมายที่เส้นชัย (คอลัมน์ที่ทุกคนต้องมายืน) — null ถ้าคำนวณไม่ได้ */
function gauntletFinishTargetTxPlay() {
if (!mapData || !isGauntletCrownHeistMapPlay()) return null;
const ts = mapData.tileSize || 32;
const { cw } = getCharacterFootprintWH(mapData);
if (gauntletCrownRunwayFinishAlignLatchedWorldX != null) {
return gauntletCrownRunwayFinishAlignLatchedWorldX / ts - cw * 0.5;
}
let leadTx = -Infinity;
const consider = (ent) => {
if (!ent || ent.gauntletEliminated) return;
const tx = Number.isFinite(ent.tx) ? ent.tx : Number(ent.x);
if (Number.isFinite(tx)) leadTx = Math.max(leadTx, tx);
};
consider(me);
others.forEach((o, id) => { if (!playBotsEnabled() && isPreviewBotId(id)) return; consider(o); });
return (Number.isFinite(leadTx) && leadTx !== -Infinity) ? leadTx : null;
}
/** "" ( snap )
true เมอทกคนถงเสนแล (เร freezeจบเกมต) */
function gauntletWalkLivingToFinishStepPlay(dtSec) {
const targetTx = gauntletFinishTargetTxPlay();
if (targetTx == null || !Number.isFinite(targetTx)) return true;
const step = Math.max(0.04, GAUNTLET_FINISH_WALK_TILES_PER_SEC * Math.max(0, Number(dtSec) || 0));
const eps = 0.06;
let allArrived = true;
const walk = (ent) => {
if (!ent || ent.gauntletEliminated) return;
let x = Number.isFinite(ent.x) ? ent.x : (Number.isFinite(ent.tx) ? ent.tx : targetTx);
if (x < targetTx - eps) {
x = Math.min(targetTx, x + step);
ent.direction = 'right';
ent.isWalking = true;
allArrived = false;
} else {
x = targetTx; /* ไม่ให้ใครเลยเส้นชัย (เลยมา → ดึงกลับมาที่เส้น) */
ent.isWalking = false;
}
ent.x = x;
ent.tx = x;
};
walk(me);
others.forEach((o, id) => { if (!playBotsEnabled() && isPreviewBotId(id)) return; walk(o); });
return allArrived;
}
/** "": align snap scroll server obstacle ()
จากน tick จะคอยๆ เดนทกคนมาทเส แลวคอยเข freezeจบเกม */
function gauntletCrownRunwayBeginWalkToFinishPlay() {
if (gauntletCrownRunwayWalkActive || gauntletCrownRunwayBgStripFreezeSinceMs > 0 || gauntletCrownRunwayBgFinishLatched) return;
if (gauntletCrownRunwayFinishAlignLatchedWorldX == null) {
const leadAlign = gauntletCrownRunwayLeadingEntityAlignWorldXPlay();
if (leadAlign != null) gauntletCrownRunwayFinishAlignLatchedWorldX = leadAlign;
}
gauntletCrownRunwaySnapScrollToFinishStopPlay();
gauntletCrownRunwayWalkActive = true;
gauntletCrownRunwayWalkStartMs = Date.now();
/* แจ้ง server ครั้งเดียว: เข้าโซนเส้นชัย → หยุด obstacle + collision (กันโดนชน/-10 ตอนกำลงเดนเขาเส)
server จะรอ grace (GAUNTLET_FINISH_WALK_MS) ใหเดนครบกอนคอยจบ */
if (!gauntletFinishPhaseSignaled) {
gauntletFinishPhaseSignaled = true;
try { socket.emit('gauntlet-finish-phase'); } catch (_e) { /* ignore */ }
}
try { syncGauntletCrownJumpButton(); } catch (_sj) { /* ignore */ }
}
/**
* คอลมนบนกรดทเส FINISH องแนบ (map world px)
@@ -1573,21 +1648,10 @@
gauntletCrownRunwayBgScrollPx = t;
}
/** ลำดับการหยุดที่เส้นชัย: ล็อก align (ครั้งเดียว) → snap เป๊ะ → เริ่ม freeze → (latch+mission ทีหลังใน tick) */
/** : align () ( snap )
tick จะเดนทกคนมาทเสนจนครบแลวคอยเข freezeจบเกม */
function gauntletCrownRunwayBeginFinishStopPlay() {
if (gauntletCrownRunwayFinishAlignLatchedWorldX == null) {
const leadAlign = gauntletCrownRunwayLeadingEntityAlignWorldXPlay();
if (leadAlign != null) gauntletCrownRunwayFinishAlignLatchedWorldX = leadAlign;
}
gauntletSnapLivingToFinishPlay(); /* ทุกคนที่ยังไม่ตายมายืนที่เส้นชัย ไม่มีใครเลยเส้น */
gauntletCrownRunwaySnapScrollToFinishStopPlay();
gauntletCrownRunwayBgStripFreezeSinceMs = Date.now();
/* แจ้ง server ครั้งเดียว: ถึงเส้นชัยแล้ว → หยุด obstacle + collision (กัน -10 ตอน obstacle หายแล้ว) */
if (!gauntletFinishPhaseSignaled) {
gauntletFinishPhaseSignaled = true;
try { socket.emit('gauntlet-finish-phase'); } catch (_e) { /* ignore */ }
}
try { syncGauntletCrownJumpButton(); } catch (_sj) { /* ignore */ }
gauntletCrownRunwayBeginWalkToFinishPlay();
try { draw(); } catch (_d) { /* ignore */ }
}
@@ -1639,6 +1703,8 @@
gauntletCrownRunwayBgScrollPx = 0;
gauntletCrownRunwayBgFinishLatched = false;
gauntletFinishPhaseSignaled = false;
gauntletCrownRunwayWalkActive = false;
gauntletCrownRunwayWalkStartMs = 0;
gauntletCrownRunwayBgStripFreezeSinceMs = 0;
gauntletCrownRunwayFinishAlignLatchedWorldX = null;
gauntletCrownRunwayClientMissionShown = false;
@@ -1684,6 +1750,20 @@
if (usesCrownLobbyShellPlay() && gauntletCrownPregamePhase !== 'live') return;
if (gauntletCrownRunwayBgFinishLatched) { gauntletSnapLivingToFinishPlay(); return; }
/* เฟส "เดินเข้าเส้นชัย" — ค่อยๆ เดินทุกคนมาที่เส้นแทน snap กระพริบ แล้วค่อยเข้า freeze→จบ */
if (gauntletCrownRunwayWalkActive) {
const forceDone = (Date.now() - gauntletCrownRunwayWalkStartMs) >= GAUNTLET_FINISH_WALK_MAX_MS;
const arrived = gauntletWalkLivingToFinishStepPlay(dtSec);
if (arrived || forceDone) {
gauntletCrownRunwayWalkActive = false;
gauntletSnapLivingToFinishPlay(); /* จัดเป๊ะที่เส้นชัยครั้งเดียว */
gauntletCrownRunwayBgStripFreezeSinceMs = Date.now();
}
try { syncGauntletCrownJumpButton(); } catch (_sj) { /* ignore */ }
try { draw(); } catch (_d) { /* ignore */ }
return;
}
if (gauntletCrownRunwayBgStripFreezeSinceMs > 0) {
gauntletCrownRunwayMaintainFinishScrollPlay();
gauntletSnapLivingToFinishPlay(); /* ตรึงทุกคนที่ยังไม่ตายไว้ที่เส้นชัยทุกเฟรม กันบอทไหลหลุด */
@@ -1719,16 +1799,7 @@
}
if (gauntletCrownRunwayBgMapEligiblePlay() && gauntletCrownRunwayScrollStripStopZoneReachedPlay()) {
if (gauntletCrownRunwayFinishAlignLatchedWorldX == null) {
const leadAlign = gauntletCrownRunwayLeadingEntityAlignWorldXPlay();
if (leadAlign != null) gauntletCrownRunwayFinishAlignLatchedWorldX = leadAlign;
}
gauntletSnapLivingToFinishPlay(); /* ทุกคนที่ยังไม่ตายมายืนที่เส้นชัย ไม่มีใครเลยเส้น */
gauntletCrownRunwaySnapScrollToFinishStopPlay();
gauntletCrownRunwayBgStripFreezeSinceMs = Date.now();
try {
syncGauntletCrownJumpButton();
} catch (_sj) { /* ignore */ }
gauntletCrownRunwayBeginWalkToFinishPlay(); /* เริ่มเดินค่อยๆ เข้าเส้นชัย (แทน snap+freeze ทันที) */
try {
draw();
} catch (_d) { /* ignore */ }
@@ -20473,7 +20544,8 @@
nickname: p.nickname || 'ผู้เล่น',
characterId: p.characterId ?? null,
spawnJoinOrder: 0,
playTint: playTintForPreviewBotId(p.id) || resolvePlayTintForPeer(p.id, p),
/* สีจาก lobby (theme/skin index ที่ server พ่วงมาใน gauntlet-sync) ก่อน — กันได้สี hash สุ่มไม่ตรง lobbyB */
playTint: playTintFromJoinPeer(p) || playTintForPreviewBotId(p.id) || resolvePlayTintForPeer(p.id, p),
gauntletJumpTicks: 0, gauntletJumpVis: 0, gauntletScore: 0,
gauntletEliminated: !!p.gauntletEliminated,
jumpSurviveEliminated: false,
@@ -20493,6 +20565,9 @@
if (Number.isFinite(py)) o.ty = py;
if (p.direction) o.direction = p.direction;
if (o.characterId == null && p.characterId != null) o.characterId = p.characterId;
/* รีเฟรชสีจาก lobby index ที่ server ส่งมา — กัน peer ที่เคยได้สี hash (re-create เก่า) ค้างสีผิด */
const lobbyTint = playTintFromJoinPeer(p);
if (lobbyTint) o.playTint = lobbyTint;
const jt = Number(p.gauntletJumpTicks);
o.gauntletJumpTicks = Number.isFinite(jt) ? jt : 0;
if (o.gauntletJumpVis == null) o.gauntletJumpVis = o.gauntletJumpTicks;
@@ -20554,6 +20629,8 @@
gauntletEndsAtMs = null;
gauntletCrownRunwayBgFinishLatched = false;
gauntletFinishPhaseSignaled = false;
gauntletCrownRunwayWalkActive = false;
gauntletCrownRunwayWalkStartMs = 0;
gauntletCrownRunwayBgStripFreezeSinceMs = 0;
gauntletCrownRunwayFinishAlignLatchedWorldX = null;
gauntletCrownRunwayClientMissionShown = false;
+1 -1
View File
@@ -5371,7 +5371,7 @@
<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.006232022"></script>
<script src="js/play.js?v=0.006242301"></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)
+35 -2
View File
@@ -6232,6 +6232,9 @@ const io = new Server(server, { path: BASE_PATH + '/socket.io', cors: { origin:
const spaces = new Map();
const GAUNTLET_MAX_PLAYERS = 6;
/** obstacle grace client (ms)
อง >= client GAUNTLET_FINISH_WALK_MAX_MS (2600) + เผอยนทเสนเลกนอย */
const GAUNTLET_FINISH_WALK_MS = 3000;
/** ระยะอยู่กลางอากาศ (tick) — ปรับได้ที่ Admin / data/game-timing.json */
/** สุ่มเป็นคอลัมน์เลเซอร์ (ทุกแถว) ต่อหนึ่งรอบเกิด */
const GAUNTLET_LASER_SPAWN_CHANCE = 0.14;
@@ -6485,6 +6488,7 @@ function newGauntletRunState(space) {
nextSpawnIn: 3,
crownRunHeld: crown,
finishPhase: false,
finishEndAt: null,
};
}
@@ -6507,7 +6511,11 @@ function emitGauntletSync(sid, space) {
x: p.x,
y: p.y,
direction: p.direction || 'down',
nickname: (p.nickname || '').trim() || 'ผู้เล่น',
characterId: p.characterId ?? null,
/* สีจาก lobbyB — กัน client ที่ re-create peer ผ่าน gauntlet-sync ได้สี hash สุ่มไม่ตรง */
lobbyColorThemeIndex: p.lobbyColorThemeIndex || null,
lobbySkinToneIndex: p.lobbySkinToneIndex || null,
gauntletJumpTicks: p.gauntletJumpTicks || 0,
gauntletScore: p.gauntletScore || 0,
gauntletEliminated: !!p.gauntletEliminated,
@@ -6696,10 +6704,15 @@ function runGauntletTick(sid, space) {
return;
}
/* ถึงเส้นชัยแล้ว (client แจ้ง) — จบรอบทันที (ผู้ใช้ต้องการ: ไม่ให้เดินเลยเส้นชัย) → สรุปผล */
/* (client ) obstacle/collision grace client
เดนทกคน "ค่อยๆ" เขาเสนชยจนครบ อยสรปผล (ไม snap กระพร / ไมจบทนท) */
if (gr.finishPhase) {
if (gr.obstacles.length) { gr.obstacles = []; }
endGauntletGame(sid, space, 'finish');
if (gr.finishEndAt == null) gr.finishEndAt = Date.now() + GAUNTLET_FINISH_WALK_MS;
if (Date.now() >= gr.finishEndAt) {
endGauntletGame(sid, space, 'finish');
}
/* ไม่ emitGauntletSync ระหว่าง grace — ปล่อย client คุมการเดินเข้าเส้นเอง (กัน sync ดึงตำแหน่งกลับ) */
return;
}
@@ -7581,6 +7594,26 @@ io.on('connection', (socket) => {
io.to(spaceId).emit('user-left', { id: pid });
});
}
/* reconnect dedup 2: playerKey match (/ peer lobbyB playerKey)
คนเดมกลบเขามากลายเปนตวซ (ghost) playerKey block บไมได เห "ตัวละครซ้ำ 2 ตัว" บน "ทุกจอรวม host"
(fill-bot-state humans cleanup เป non-host only host ไมเคยลบ ghost). ลบทนทางดวย "ชื่อ custom เดียวกัน".
ามช default (เล/บอท/าง) เลนจร 2 คนทไมงชออาจชนช default นได */
const newNickNorm = normalizeLobbyNickname(nickname);
const newNickIsCustom = newNickNorm && newNickNorm !== 'ผู้เล่น'
&& newNickNorm.indexOf('ผู้เล่น') !== 0 && newNickNorm.indexOf('บอท') !== 0;
if (newNickIsCustom) {
const ghostIds = [];
space.peers.forEach((p, pid) => {
if (pid === socket.id || !p) return;
if (normalizeLobbyNickname(p.nickname) === newNickNorm) ghostIds.push(pid);
});
ghostIds.forEach((pid) => {
space.peers.delete(pid);
if (space.quizCarryLobbyReady) delete space.quizCarryLobbyReady[pid];
if (space.gauntletCrownLobbyReady) delete space.gauntletCrownLobbyReady[pid];
io.to(spaceId).emit('user-left', { id: pid });
});
}
if (serverMapIsPostCaseLobbyB(space)) initTroublesomeState(space);
ensurePeerLobbyThemes(space);
const mdJoin = (space.mapId && maps.get(space.mapId)) || space.mapData;