fix game5 and 7

This commit is contained in:
2026-07-09 05:56:59 +00:00
parent 29ea63ac30
commit 36f3ea2d7a
29 changed files with 184201 additions and 20363 deletions
+9
View File
@@ -3909,6 +3909,11 @@
var bp = Number(data.balloonBossBalloonsPerPlayer);
inpBp.value = String(Number.isFinite(bp) && bp > 0 ? Math.min(12, Math.floor(bp)) : 0);
}
var inpDh = el('mega-virus-damage-per-hit');
if (inpDh && Object.prototype.hasOwnProperty.call(data, 'balloonBossDamagePerHit')) {
var dh = Number(data.balloonBossDamagePerHit);
inpDh.value = String(Number.isFinite(dh) && dh > 0 ? Math.max(1, Math.min(100, Math.floor(dh))) : 10);
}
var bossInp = el('mega-virus-boss-url');
if (bossInp && Object.prototype.hasOwnProperty.call(data, 'balloonBossBossImageUrl')) {
bossInp.value = data.balloonBossBossImageUrl != null ? String(data.balloonBossBossImageUrl) : '';
@@ -3956,6 +3961,9 @@
var balloonsPer = el('mega-virus-balloons-per-player') ? parseInt(String(el('mega-virus-balloons-per-player').value), 10) : 0;
if (Number.isNaN(balloonsPer) || balloonsPer < 0) balloonsPer = 0;
balloonsPer = Math.max(0, Math.min(12, balloonsPer));
var dmgPerHit = el('mega-virus-damage-per-hit') ? parseInt(String(el('mega-virus-damage-per-hit').value), 10) : 10;
if (Number.isNaN(dmgPerHit) || dmgPerHit < 1) dmgPerHit = 10;
dmgPerHit = Math.max(1, Math.min(100, dmgPerHit));
gameTimingFetch('GET')
.then(function (data) {
data.balloonBossMissionTimeSec = limSs;
@@ -3963,6 +3971,7 @@
data.balloonBossPlayerBalloonImageUrls = balloonUrls;
data.balloonBossPlayerBalloonFallbackUrl = fbUrl;
data.balloonBossBalloonsPerPlayer = balloonsPer;
data.balloonBossDamagePerHit = dmgPerHit;
return gameTimingFetch('PUT', data);
})
.then(function (res) {
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -821,6 +821,7 @@
<div class="form-grid form-inline quiz-timing-grid">
<label title="0 = ใช้ 120 วิเมื่อแมปไม่กำหนด · ตั้งอย่างน้อย 10 ถ้าต้องการกำหนดเอง">เวลารอบ (วินาที) <input type="number" id="mega-virus-mission-sec" min="0" max="7200" step="5" value="0"></label>
<label title="จำนวนลูกโป่ง (ชีวิต) ต่อผู้เล่น · 0 = ใช้ค่าจากแมป หรือ default 3 · แมปกำหนดทับค่านี้">ลูกโป่งต่อคน <input type="number" id="mega-virus-balloons-per-player" min="0" max="12" step="1" value="0"></label>
<label title="ยิงโดนบอส 1 นัด = ลบเลือดบอสเท่านี้ (แยกจากคะแนน) · default 10 · เลือดบอสตั้งในแมป (balloonBossMaxHp default 100)">ลบเลือดบอส/นัด <input type="number" id="mega-virus-damage-per-hit" min="1" max="100" step="1" value="10"></label>
</div>
<div class="form-grid form-inline" style="margin-top:0.75rem;align-items:flex-end;gap:0.75rem;flex-wrap:wrap">
<label class="space-shooter-ship-url-label" style="flex:1;min-width:14rem">รูปบอส (URL) <input type="text" id="mega-virus-boss-url" maxlength="500" spellcheck="false" placeholder="/Game/img/MegaVirus/boss.png" autocomplete="off"></label>
@@ -1357,7 +1358,7 @@
</div>
</main>
</div>
<script src="admin.js?v=94"></script>
<script src="admin.js?v=95"></script>
<script>
/* toggle: เปิด/ปิด HUD โหลด LobbyA (Iron Man) ให้ "ผู้เล่นทั่วไป" เห็น (เก็บใน game-timing.json: lobbyDebugHud)
— dev เปิดเครื่องตัวเองได้เสมอด้วย ?dbg=1 หรือ localStorage.lobbyDbg='1' โดยไม่ต้องใช้ปุ่มนี้ */
File diff suppressed because it is too large Load Diff
+453 -75
View File
@@ -114,9 +114,9 @@
"providerUserId": "p_1775128666204_xzgg2n6x8h",
"notes": "auto: player-coins",
"blocked": false,
"coins": 363,
"coins": 437,
"createdAt": "2026-04-02T11:17:46+00:00",
"updatedAt": "2026-07-03T11:54:27+00:00",
"updatedAt": "2026-07-08T12:21:48+00:00",
"lobbyColorThemeIndex": 1,
"lobbySkinToneIndex": 3,
"daily": {
@@ -132,12 +132,12 @@
],
"lockUntilMs": 0
},
"score": 318,
"score": 392,
"scoreByCase": {
"6": 56,
"13": 50,
"13": 70,
"5": 8,
"12": 6,
"12": 60,
"10": 106,
"3": 10,
"2": 26,
@@ -148,11 +148,26 @@
"achievements": {
"d1_minigame_solver": 20,
"a1_first_deduction": 1,
"a5_truth_hunter": 3,
"a5_truth_hunter": 4,
"e2_the_impostor": 1,
"e4_agent_of_chaos": 1,
"e3_master_of_doubt": 1,
"e5_slippery_eel": 1
"e5_slippery_eel": 1,
"b1_evidence_collector": 6,
"b4_data_miner": 4,
"a2_sharp_eye": 2,
"d3_the_backbone": 6,
"c5_lone_wolf": 1,
"c2_high_stakes": 1,
"a4_logic_over_luck": 1,
"d2_silent_guardian": 2,
"a6_unbreakable_logic": 1,
"d4_flawless_diver": 1,
"b2_relentless_investigator": 1
},
"achvStreak": {
"a6_unbreakable_logic": 1,
"d4_flawless_diver": 0
}
},
{
@@ -340,7 +355,7 @@
"blocked": false,
"coins": 50,
"createdAt": "2026-06-19T06:13:44+00:00",
"updatedAt": "2026-07-02T10:45:20+00:00",
"updatedAt": "2026-07-08T07:22:42+00:00",
"score": 50,
"scoreByCase": {
"1": 12,
@@ -364,9 +379,9 @@
"providerUserId": "p_1781849642042_x2vt68wscm",
"notes": "auto: player-coins",
"blocked": false,
"coins": 169,
"coins": 183,
"createdAt": "2026-06-19T06:14:02+00:00",
"updatedAt": "2026-07-03T11:55:41+00:00",
"updatedAt": "2026-07-08T12:21:48+00:00",
"daily": {
"anchorMs": 1781802000000,
"claimedDays": [
@@ -380,18 +395,22 @@
],
"lockUntilMs": 0
},
"score": 144,
"score": 158,
"scoreByCase": {
"1": 66,
"7": 16,
"5": 10,
"2": 40,
"6": 10,
"3": 2
"3": 2,
"12": 8,
"13": 6
},
"lbName": "tomato",
"achievements": {
"d1_minigame_solver": 19
"d1_minigame_solver": 20,
"b5_deep_scanner": 1,
"b1_evidence_collector": 1
},
"lobbyColorThemeIndex": 1,
"lobbySkinToneIndex": 1
@@ -749,18 +768,19 @@
"providerUserId": "p_1782122326943_7p2fnvivscm",
"notes": "auto: player-coins",
"blocked": false,
"coins": 309,
"coins": 335,
"createdAt": "2026-06-22T09:58:46+00:00",
"updatedAt": "2026-07-06T11:31:06+00:00",
"lobbyColorThemeIndex": 7,
"updatedAt": "2026-07-08T17:04:52+00:00",
"lobbyColorThemeIndex": 1,
"lobbySkinToneIndex": 2,
"score": 284,
"score": 310,
"scoreByCase": {
"10": 44,
"10": 52,
"12": 142,
"3": 54,
"13": 30,
"8": 14
"8": 14,
"2": 18
},
"lbName": "Q",
"achievements": {
@@ -769,9 +789,9 @@
"e4_agent_of_chaos": 1,
"e3_master_of_doubt": 1,
"e5_slippery_eel": 1,
"b4_data_miner": 5,
"b4_data_miner": 12,
"a2_sharp_eye": 2,
"b1_evidence_collector": 2,
"b1_evidence_collector": 10,
"b3_hidden_fragment": 1,
"d3_the_backbone": 3,
"a3_mind_architect": 1,
@@ -790,7 +810,7 @@
false,
false
],
"lockUntilMs": 1783357200000
"lockUntilMs": 0
},
"achvStreak": {
"a6_unbreakable_logic": 0,
@@ -932,17 +952,17 @@
"providerUserId": "p_1782300287206_l5omneu1yeo",
"notes": "auto: player-coins",
"blocked": false,
"coins": 169,
"coins": 207,
"createdAt": "2026-06-24T11:24:48+00:00",
"updatedAt": "2026-07-01T12:20:59+00:00",
"lobbyColorThemeIndex": 3,
"updatedAt": "2026-07-08T12:21:48+00:00",
"lobbyColorThemeIndex": 6,
"lobbySkinToneIndex": 3,
"score": 144,
"score": 162,
"scoreByCase": {
"6": 24,
"13": 44,
"13": 52,
"5": 16,
"12": 8,
"12": 18,
"3": 20,
"7": 4,
"2": 14,
@@ -952,20 +972,30 @@
"achievements": {
"d1_minigame_solver": 20,
"a1_first_deduction": 1,
"a5_truth_hunter": 1
"a5_truth_hunter": 1,
"b4_data_miner": 4,
"a2_sharp_eye": 1,
"d3_the_backbone": 3,
"b2_relentless_investigator": 1,
"d2_silent_guardian": 1,
"e1_the_observer": 1,
"b1_evidence_collector": 2
},
"daily": {
"anchorMs": 1782406800000,
"claimedDays": [
true,
true,
false,
true,
false,
false,
false,
false
],
"lockUntilMs": 1782925200000
"lockUntilMs": 1783530000000
},
"achvStreak": {
"e1_the_observer": 1
}
},
{
@@ -1066,25 +1096,39 @@
"providerUserId": "p_1782472374020_hlha51h8q2m",
"notes": "auto: player-coins",
"blocked": false,
"coins": 183,
"coins": 260,
"createdAt": "2026-06-26T11:12:52+00:00",
"updatedAt": "2026-07-02T07:25:12+00:00",
"updatedAt": "2026-07-08T12:21:48+00:00",
"lobbyColorThemeIndex": 8,
"lobbySkinToneIndex": 3,
"score": 138,
"score": 190,
"scoreByCase": {
"10": 60,
"6": 8,
"3": 16,
"12": 10,
"12": 44,
"1": 10,
"7": 10,
"2": 14,
"13": 10
"13": 28
},
"lbName": "MOOKIZ",
"achievements": {
"d1_minigame_solver": 16
"d1_minigame_solver": 20,
"b5_deep_scanner": 1,
"b4_data_miner": 6,
"b1_evidence_collector": 5,
"d3_the_backbone": 6,
"a1_first_deduction": 1,
"c5_lone_wolf": 1,
"c2_high_stakes": 1,
"a4_logic_over_luck": 1,
"b2_relentless_investigator": 1,
"d2_silent_guardian": 1,
"e1_the_observer": 1,
"d4_flawless_diver": 1,
"a6_unbreakable_logic": 1,
"a2_sharp_eye": 1
},
"daily": {
"anchorMs": 1782666000000,
@@ -1092,12 +1136,17 @@
true,
true,
true,
false,
true,
false,
false,
false
],
"lockUntilMs": 1783011600000
"lockUntilMs": 1783530000000
},
"achvStreak": {
"e1_the_observer": 1,
"d4_flawless_diver": 1,
"a6_unbreakable_logic": 1
}
},
{
@@ -1120,26 +1169,39 @@
"providerUserId": "p_1778156246099_lbrni0cvx8",
"notes": "auto: player-coins",
"blocked": false,
"coins": 116,
"coins": 142,
"createdAt": "2026-06-29T07:25:24+00:00",
"updatedAt": "2026-07-03T11:58:39+00:00",
"score": 116,
"updatedAt": "2026-07-08T12:12:56+00:00",
"score": 142,
"scoreByCase": {
"10": 58,
"8": 10,
"7": 2,
"1": 18,
"6": 28
"6": 28,
"12": 16,
"13": 10
},
"lbName": "บอท 666",
"lbName": "สรยุทธ์",
"achievements": {
"d1_minigame_solver": 15,
"d1_minigame_solver": 20,
"e2_the_impostor": 1,
"e4_agent_of_chaos": 2,
"e4_agent_of_chaos": 3,
"e3_master_of_doubt": 1,
"e5_slippery_eel": 1,
"e5_slippery_eel": 2,
"a1_first_deduction": 1,
"a5_truth_hunter": 1
"a5_truth_hunter": 1,
"b4_data_miner": 7,
"a2_sharp_eye": 1,
"b1_evidence_collector": 3,
"d3_the_backbone": 6,
"e1_the_observer": 2,
"d4_flawless_diver": 0,
"b3_hidden_fragment": 1
},
"achvStreak": {
"e1_the_observer": 2,
"d4_flawless_diver": 0
}
},
{
@@ -1231,16 +1293,16 @@
"providerUserId": "p_1782921490642_wkx6gl2hwtn",
"notes": "auto: game-award",
"blocked": false,
"coins": 24,
"score": 24,
"coins": 32,
"score": 32,
"scoreByCase": {
"1": 24
"1": 32
},
"lbName": "MONE",
"lbName": "Guest",
"createdAt": "2026-07-01T16:01:03+00:00",
"updatedAt": "2026-07-01T16:08:23+00:00",
"updatedAt": "2026-07-08T10:34:54+00:00",
"achievements": {
"d1_minigame_solver": 3
"d1_minigame_solver": 4
}
},
{
@@ -1251,16 +1313,18 @@
"providerUserId": "p_1782921488461_e17kxhzmrl8",
"notes": "auto: game-award",
"blocked": false,
"coins": 18,
"score": 18,
"coins": 28,
"score": 28,
"scoreByCase": {
"1": 18
"1": 28
},
"lbName": "ผู้เล่น",
"lbName": "Guest",
"createdAt": "2026-07-01T16:01:03+00:00",
"updatedAt": "2026-07-01T16:08:23+00:00",
"updatedAt": "2026-07-08T10:34:54+00:00",
"achievements": {
"d1_minigame_solver": 1
"d1_minigame_solver": 2,
"b4_data_miner": 1,
"b1_evidence_collector": 1
}
},
{
@@ -1355,16 +1419,16 @@
"providerUserId": "g_103253816568665853265",
"notes": "auto: game-award",
"blocked": false,
"coins": 30,
"score": 30,
"coins": 70,
"score": 70,
"scoreByCase": {
"1": 30
"1": 70
},
"lbName": "TOY Studio",
"createdAt": "2026-07-07T07:06:32+00:00",
"updatedAt": "2026-07-07T07:21:02+00:00",
"updatedAt": "2026-07-08T06:57:39+00:00",
"achievements": {
"d1_minigame_solver": 1
"d1_minigame_solver": 5
}
},
{
@@ -1375,20 +1439,38 @@
"providerUserId": "p_1783423451842_11irmcfil84",
"notes": "auto: player-coins",
"blocked": false,
"coins": 10,
"coins": 84,
"createdAt": "2026-07-07T11:24:11+00:00",
"updatedAt": "2026-07-07T13:10:37+00:00",
"score": 10,
"updatedAt": "2026-07-08T17:17:36+00:00",
"score": 84,
"scoreByCase": {
"2": 10
"2": 20,
"12": 24,
"13": 20,
"10": 20
},
"lbName": "ผู้เล่น",
"lbName": "กัน จอมพลัง",
"achievements": {
"d1_minigame_solver": 1,
"b4_data_miner": 3,
"b1_evidence_collector": 1,
"a2_sharp_eye": 2
}
"d1_minigame_solver": 11,
"b4_data_miner": 19,
"b1_evidence_collector": 11,
"a2_sharp_eye": 7,
"d3_the_backbone": 6,
"d4_flawless_diver": 0,
"b2_relentless_investigator": 1,
"d2_silent_guardian": 1,
"b5_deep_scanner": 1,
"e1_the_observer": 1,
"a6_unbreakable_logic": 0,
"b3_hidden_fragment": 1
},
"achvStreak": {
"d4_flawless_diver": 0,
"e1_the_observer": 1,
"a6_unbreakable_logic": 0
},
"lobbyColorThemeIndex": 7,
"lobbySkinToneIndex": 1
},
{
"id": "056ac410650650b51ad4f969",
@@ -1401,6 +1483,302 @@
"coins": 0,
"createdAt": "2026-07-07T13:14:37+00:00",
"updatedAt": "2026-07-07T13:14:37+00:00"
},
{
"id": "c102247fb56343cb7c07d383",
"email": "",
"displayName": "Guest",
"loginType": "guest",
"providerUserId": "p_1783488401360_la99satzc7m",
"notes": "auto: player-coins",
"blocked": false,
"coins": 10,
"createdAt": "2026-07-08T05:26:41+00:00",
"updatedAt": "2026-07-09T04:02:24+00:00",
"daily": {
"anchorMs": 1783530000000,
"claimedDays": [
true,
false,
false,
false,
false,
false,
false
],
"lockUntilMs": 1783616400000
},
"lobbyColorThemeIndex": 5,
"lobbySkinToneIndex": 1
},
{
"id": "99ceaaa5bba7f30ccaacf955",
"email": "",
"displayName": "Guest",
"loginType": "guest",
"providerUserId": "p_1783490562751_hcpqt0gpbj5",
"notes": "auto: player-coins",
"blocked": false,
"coins": 10,
"createdAt": "2026-07-08T06:02:42+00:00",
"updatedAt": "2026-07-08T11:51:25+00:00",
"daily": {
"anchorMs": 1783443600000,
"claimedDays": [
true,
false,
false,
false,
false,
false,
false
],
"lockUntilMs": 1783530000000
},
"lobbyColorThemeIndex": 7,
"lobbySkinToneIndex": 3,
"achievements": {
"b4_data_miner": 3,
"a2_sharp_eye": 2,
"b3_hidden_fragment": 1
}
},
{
"id": "a4ee55fab2ff81fdadd86874",
"email": "",
"displayName": "Guest",
"loginType": "guest",
"providerUserId": "p_1783491385591_hxztc6q0pup",
"notes": "auto: player-coins",
"blocked": false,
"coins": 10,
"createdAt": "2026-07-08T06:16:25+00:00",
"updatedAt": "2026-07-08T06:16:49+00:00",
"daily": {
"anchorMs": 1783443600000,
"claimedDays": [
true,
false,
false,
false,
false,
false,
false
],
"lockUntilMs": 1783530000000
}
},
{
"id": "a552b03c208421f2e15d1e5c",
"email": "",
"displayName": "Guest",
"loginType": "guest",
"providerUserId": "p_1783492264923_akwsutojqys",
"notes": "auto: player-coins",
"blocked": false,
"coins": 0,
"createdAt": "2026-07-08T06:31:04+00:00",
"updatedAt": "2026-07-08T06:31:04+00:00"
},
{
"id": "099987d8b3b22a5fd72de4ab",
"email": "",
"displayName": "Guest",
"loginType": "guest",
"providerUserId": "p_1783498064493_7q7w9qal0bc",
"notes": "auto: achievements",
"blocked": false,
"coins": 44,
"achievements": {
"b5_deep_scanner": 2,
"d1_minigame_solver": 5
},
"createdAt": "2026-07-08T08:24:23+00:00",
"updatedAt": "2026-07-08T10:34:54+00:00",
"score": 44,
"scoreByCase": {
"1": 44
},
"lbName": "Guest"
},
{
"id": "c32c748d2c799560ac6817d6",
"email": "",
"displayName": "SimSolo",
"loginType": "guest",
"providerUserId": "simkey_ho00kinngy",
"notes": "auto: game-award",
"blocked": false,
"coins": 10,
"score": 10,
"scoreByCase": {
"1": 10
},
"lbName": "SimSolo",
"createdAt": "2026-07-08T09:00:55+00:00",
"updatedAt": "2026-07-08T09:00:55+00:00",
"achievements": {
"d1_minigame_solver": 1
}
},
{
"id": "cd7961fe98cddb94988a53fe",
"email": "",
"displayName": "SimSolo",
"loginType": "guest",
"providerUserId": "simkey_r9zqefndca",
"notes": "auto: achievements",
"blocked": false,
"coins": 10,
"achievements": {
"d1_minigame_solver": 1
},
"createdAt": "2026-07-08T09:02:07+00:00",
"updatedAt": "2026-07-08T09:02:07+00:00",
"score": 10,
"scoreByCase": {
"1": 10
},
"lbName": "SimSolo"
},
{
"id": "9e9f65d26b0de4e149d4949d",
"email": "",
"displayName": "Guest",
"loginType": "guest",
"providerUserId": "simkey_sg3pikxq3x",
"notes": "auto: achievements",
"blocked": false,
"coins": 0,
"achievements": {
"b1_evidence_collector": 1,
"d1_minigame_solver": 1,
"b4_data_miner": 1
},
"createdAt": "2026-07-08T09:07:18+00:00",
"updatedAt": "2026-07-08T09:07:18+00:00"
},
{
"id": "cce5a4032e3a1d477af96ba1",
"email": "",
"displayName": "Guest",
"loginType": "guest",
"providerUserId": "p_1783504619686_yd6bngw7w1j",
"notes": "auto: player-coins",
"blocked": false,
"coins": 0,
"createdAt": "2026-07-08T09:57:00+00:00",
"updatedAt": "2026-07-08T10:04:41+00:00",
"achievements": {
"b5_deep_scanner": 1
}
},
{
"id": "409de8e9da4690a6fcc8c527",
"email": "",
"displayName": "Guest",
"loginType": "guest",
"providerUserId": "p_1783499004206_k0t9nw3s8s",
"notes": "auto: achievements",
"blocked": false,
"coins": 6,
"achievements": {
"d1_minigame_solver": 1,
"b5_deep_scanner": 1,
"b4_data_miner": 1
},
"createdAt": "2026-07-08T10:34:54+00:00",
"updatedAt": "2026-07-08T13:16:15+00:00",
"score": 6,
"scoreByCase": {
"1": 6
},
"lbName": "Guest"
},
{
"id": "d5f19965d63102d32f1e7ad2",
"email": "",
"displayName": "Guest",
"loginType": "guest",
"providerUserId": "p_1783510048205_5nggtubx9f3",
"notes": "auto: player-coins",
"blocked": false,
"coins": 0,
"createdAt": "2026-07-08T11:27:28+00:00",
"updatedAt": "2026-07-08T11:27:28+00:00"
},
{
"id": "0dd6bbeb46926b62ba3c8b87",
"email": "",
"displayName": "Guest",
"loginType": "guest",
"providerUserId": "p_1783512570968_6r0ooctea8",
"notes": "auto: player-coins",
"blocked": false,
"coins": 0,
"createdAt": "2026-07-08T12:09:31+00:00",
"updatedAt": "2026-07-08T12:09:31+00:00"
},
{
"id": "5a94f9199f1412978b1aee8a",
"email": "",
"displayName": "Guest",
"loginType": "guest",
"providerUserId": "p_1783520037906_2d2qs3gr7us",
"notes": "auto: achievements",
"blocked": false,
"coins": 20,
"achievements": {
"b4_data_miner": 6,
"b1_evidence_collector": 5,
"b3_hidden_fragment": 1,
"b5_deep_scanner": 2,
"d1_minigame_solver": 2,
"a2_sharp_eye": 1
},
"createdAt": "2026-07-08T14:15:53+00:00",
"updatedAt": "2026-07-08T17:31:49+00:00",
"score": 20,
"scoreByCase": {
"1": 20
},
"lbName": "Guest"
},
{
"id": "fb4b4dea7f60a773a456b2e5",
"email": "",
"displayName": "ผู้เล่น",
"loginType": "guest",
"providerUserId": "p_1783523564193_ag9odfihrd",
"notes": "auto: player-coins",
"blocked": false,
"coins": 20,
"createdAt": "2026-07-08T15:12:42+00:00",
"updatedAt": "2026-07-08T15:18:54+00:00",
"achievements": {
"b5_deep_scanner": 1,
"b1_evidence_collector": 1,
"d1_minigame_solver": 1,
"b4_data_miner": 1
},
"score": 10,
"scoreByCase": {
"1": 10
},
"lbName": "ผู้เล่น",
"daily": {
"anchorMs": 1783443600000,
"claimedDays": [
true,
false,
false,
false,
false,
false,
false
],
"lockUntilMs": 1783530000000
}
}
]
}
+6 -5
View File
@@ -1,7 +1,7 @@
{
"gauntletTickMs": 220,
"gauntletJumpTicks": 4,
"gauntletJumpHeightMult": 0.52,
"gauntletJumpTicks": 1,
"gauntletJumpHeightMult": 1.5,
"gauntletTimeLimitSec": 0,
"troublesomeOfferSec": 15,
"gauntletLaneImageUrls": [
@@ -96,10 +96,11 @@
],
"balloonBossPlayerBalloonFallbackUrl": "/Game/img/MegaVirus/Artboard%209.png",
"balloonBossBalloonsPerPlayer": 3,
"balloonBossDamagePerHit": 10,
"forcedMinigameKeys": [
"quiz_carry",
"jump_survive",
"balloon_boss"
"",
"",
""
],
"testSpecialCardByMap": {},
"troublesomeForceOffer": false,
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+62 -17
View File
@@ -564,7 +564,7 @@
'</div>';
document.body.appendChild(ov);
var closeFn = function () { ov.style.display = 'none'; };
ov.addEventListener('click', function (e) { if (e.target === ov || (e.target.classList && e.target.classList.contains('ecl-close'))) closeFn(); });
ov.addEventListener('click', function (e) { if (e.target === ov || (e.target.closest && e.target.closest('.ecl-close'))) closeFn(); });
document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && ov.style.display !== 'none') closeFn(); });
}
var img = ov.querySelector('.ecl-img');
@@ -3646,6 +3646,22 @@
function isMeGauntletJumpAnimActivePlay() {
return meGauntletJumpAnimStart > 0 && (Date.now() - meGauntletJumpAnimStart) < meGauntletJumpAnimDur;
}
/** peer : "" server gauntletJumpSeq ()
แก "คนอื่นกระโดดแล้วเราไม่เห็น": gauntletJumpTicks กต 0 ใน tick เดยวกนตอนขามสำเร
peer ไมเคยเหนค >0 ไมเด · seq ไมกรเซ งจ "เริ่มกระโดด" ไดเสมอ (mirror อาร local) */
function notePeerGauntletJumpFromSync(o, seqRaw) {
if (!o) return;
const seq = Number(seqRaw) || 0;
if (!Object.prototype.hasOwnProperty.call(o, 'gauntletJumpSeq')) { o.gauntletJumpSeq = seq; return; }
if (seq > (o.gauntletJumpSeq || 0)) {
o.gauntletJumpSeq = seq;
o.gauntletJumpAnimStart = Date.now();
o.gauntletJumpAnimDur = Math.max(360, (gauntletRuntimeJumpTicks || 6) * (gauntletRuntimeTickMs || 220));
}
}
function isPeerGauntletJumpAnimActive(o) {
return !!(o && o.gauntletJumpAnimStart > 0 && (Date.now() - o.gauntletJumpAnimStart) < o.gauntletJumpAnimDur);
}
/** ซิงก์จากเซิร์ฟเวอร์ (gauntlet-sync / GET /api/game-timing) */
let gauntletRuntimeTickMs = 220;
let gauntletRuntimeJumpTicks = 6;
@@ -3688,6 +3704,8 @@
let playSpaceShooterShipDamageOverlayUrls = ['', '', ''];
/** balloon_boss / Mega Virus — จาก game-timing */
let playBalloonBossMissionTimeSec = 0;
/** ดาเมจต่อการยิงโดนบอส (ลบเลือดบอส/นัด) — Admin Minigame-7 · แยกจากคะแนน · default 10 */
let playBalloonBossDamagePerHit = 10;
let playBalloonBossBossImageUrl = '';
let playBalloonBossPlayerBalloonImageUrls = ['', '', '', '', '', ''];
let playBalloonBossPlayerBalloonFallbackUrl = '';
@@ -6700,18 +6718,15 @@
if (isSpaceShooter() || isBalloonBoss()) {
const mwPx = w * tileSize;
const mhPx = h * tileSize;
/* fit / clamp [22, mw-22]
(เด balloon_boss มเขาหา content-window ทำใหขอบแมปหลดนอกจอ = ลมกระโชกดนยาน/บอทลอยหายนอกเฟรม)
BG วาด cover เตมจอแล (draw ~25633) ขอบดำซาย-ขวาจงไมโผลแมมออก แค world rect เลกลงเลกนอย */
zDraw = Math.min(canvas.width / mwPx, canvas.height / mhPx) * 0.96;
/* MG7 (balloon_boss) fit : + (crop -)
แมป 20×15 (aspect 1.33) บนจอ 16:9 fit งแมปจะเหลอขอบดำซาย-ขวาเยอะ */
if (isBalloonBoss()) {
const win = getBalloonBossVisibleHalfTilesPlay(mapData);
if (win) {
const needWpx = win.halfW * 2 * tileSize;
const needHpx = win.halfH * 2 * tileSize;
const zContent = Math.min(canvas.width / needWpx, canvas.height / needHpx);
if (Number.isFinite(zContent) && zContent > zDraw) zDraw = zContent;
}
}
} else if (isJumpSurvive()) {
/* MG5 (jump_survive) zoom 1.4 ( fit = -)
fit ความกวางเตมจอ (vertical scroller เลอนแนวตงดวย jumpSurviveCamCenterY อยแล) */
const mwPx = w * tileSize;
if (mwPx > 0) zDraw = canvas.width / mwPx;
} else if (isQuizQuestionMissionHudActivePlay()) {
const qmc = getQuizQuestionMissionMapCenterWorldPxPlay();
if (qmc) {
@@ -10350,6 +10365,13 @@
quizCarryPregameActive = true;
quizCarryLobbyReadyMap = {};
quizCarryPregameHumanIds().forEach((id) => { quizCarryLobbyReadyMap[id] = false; });
/* MG4: sprite + tint (+) HOW TO avatar /SCORE bar ( silhouette)
ตอน pregame เพราะเลเยอรอมส in-game งโหลดไมเสร (เกม crown ใช lobby-avatar warm แลวจงไมเจอ) */
try {
const warmEnt = (cid, tint) => { if (!cid) return; preloadPlayCharacterLayers(cid); if (tint) preloadPlayTintForAvatar(cid, tint); };
warmEnt(me.characterId || getPlayCharacterId(), me.playTint);
others.forEach((o) => { if (o) warmEnt(o.characterId, o.playTint); });
} catch (e) { /* ignore */ }
showQuizCarryPregameOverlay();
/* ขอสถานะ ready ปัจจุบันจาก server (authoritative) — ทุกคนรวม host ต้องกด READY เองตาม flow */
if (socket && socket.connected) socket.emit('quiz-carry-lobby-sync-request');
@@ -13417,6 +13439,10 @@
playBalloonBossMissionTimeSec = 0;
}
}
if (Object.prototype.hasOwnProperty.call(payload, 'balloonBossDamagePerHit')) {
const dh = Number(payload.balloonBossDamagePerHit);
playBalloonBossDamagePerHit = Math.max(1, Math.min(100, Number.isFinite(dh) && dh > 0 ? Math.floor(dh) : 10));
}
if (Object.prototype.hasOwnProperty.call(payload, 'balloonBossBossImageUrl')) {
playBalloonBossBossImageUrl = normalizeGauntletAssetUrlForPlay(
typeof payload.balloonBossBossImageUrl === 'string' ? payload.balloonBossBossImageUrl : ''
@@ -18504,7 +18530,7 @@
tMax: 0.85,
});
const addScore = 10;
const addBossDmg = 2;
const addBossDmg = playBalloonBossDamagePerHit; /* ลบเลือดบอส/นัด (ตั้งใน Admin) — แยกจากคะแนน · default 10 */
/* score/dmg: (= broadcast move, =host broadcast fill-bot-state)
เครองอนหามบวกเอง เด non-owner บวกจากกระสนทงคนละจงหวะ คะแนน/HP ดทายไมตรง */
if (b.ownerId === myId) {
@@ -20141,6 +20167,13 @@
const prevWasSpaceShooter = mapData && mapData.gameType === 'space_shooter';
const prevWasBalloonBoss = mapData && mapData.gameType === 'balloon_boss';
mapData = gameMapData;
/* MG5 (jump_survive): server pattern 1 / game-start (res.jsLayout)
override layout ให client เห pattern เดยวก (client physics/render าน mapData ตรง ไม cache) */
if (res && res.jsLayout && mapData && mapData.gameType === 'jump_survive'
&& Array.isArray(res.jsLayout.platformArea) && Array.isArray(res.jsLayout.variantArea)) {
mapData.jumpSurvivePlatformArea = res.jsLayout.platformArea;
mapData.jumpSurvivePlatformVariantArea = res.jsLayout.variantArea;
}
playEmbedUserZoomMul = 1;
if (mapData.gameType !== 'quiz_carry') {
quizCarryWalkSpeedMultActive = QUIZ_CARRY_WALK_SPEED_MULT;
@@ -22445,6 +22478,7 @@
const jt = Number(p.gauntletJumpTicks);
o.gauntletJumpTicks = Number.isFinite(jt) ? jt : 0;
if (o.gauntletJumpVis == null) o.gauntletJumpVis = o.gauntletJumpTicks;
notePeerGauntletJumpFromSync(o, p.gauntletJumpSeq);
const sc = Number(p.gauntletScore);
const newSc = Number.isFinite(sc) ? Math.max(0, sc) : 0;
o.gauntletScore = newSc;
@@ -22500,6 +22534,7 @@
const jt = Number(p.gauntletJumpTicks);
o.gauntletJumpTicks = Number.isFinite(jt) ? jt : 0;
if (o.gauntletJumpVis == null) o.gauntletJumpVis = o.gauntletJumpTicks;
notePeerGauntletJumpFromSync(o, p.gauntletJumpSeq);
const sc = Number(p.gauntletScore);
const newSc = Number.isFinite(sc) ? Math.max(0, sc) : 0;
o.gauntletScore = newSc;
@@ -23503,6 +23538,7 @@
const tx = +p[0], ty = +p[1];
if (!bp[ty] || bp[ty][tx] !== 1) continue;
for (const [, o] of others) {
if (o.quizCannotTrue && o.quizCannotFalse) continue; /* MG1: ผี (ตกรอบ) = spectator ไม่บล็อกการเดิน */
if (playPeerBlockPlayerOccupiesTile(o.x, o.y, tx, ty)) return false;
}
}
@@ -23552,9 +23588,11 @@
if (!bp[ty] || bp[ty][tx] !== 1) continue;
for (const [, peer] of others) {
if (o && peer === o) continue;
if (peer.quizCannotTrue && peer.quizCannotFalse) continue; /* MG1: ผีไม่บล็อก */
if (playPeerBlockPlayerOccupiesTile(peer.x, peer.y, tx, ty)) return false;
}
if (o && playPeerBlockPlayerOccupiesTile(me.x, me.y, tx, ty)) return false;
const meGhost = !!(playQuizPlayerLocal && playQuizPlayerLocal.cannotTrue && playQuizPlayerLocal.cannotFalse);
if (o && !meGhost && playPeerBlockPlayerOccupiesTile(me.x, me.y, tx, ty)) return false;
}
}
if (isQuiz()) {
@@ -26868,9 +26906,16 @@
const op = lerpGauntletEntityPos(o.x, o.y, o.tx, o.ty, oAir ? GAUNTLET_AIR_X_LERP : GAUNTLET_VIS_LERP);
o.x = op.nx;
o.y = op.ny;
if (gauntletFinishWalkPose) { o.gauntletJumpTicks = 0; o.gauntletJumpVis = 0; return; }
if (o.gauntletJumpVis == null) o.gauntletJumpVis = o.gauntletJumpTicks || 0;
o.gauntletJumpVis = stepGauntletJumpVis(o.gauntletJumpVis, o.gauntletJumpTicks || 0);
if (gauntletFinishWalkPose) { o.gauntletJumpTicks = 0; o.gauntletJumpVis = 0; o.gauntletJumpAnimStart = 0; return; }
if (isPeerGauntletJumpAnimActive(o)) {
/* อาร์ค peer: prog 0→1 ; vis = max·(1prog) → เห็นคนอื่นกระโดดขึ้น-ลงเต็มโค้ง (mirror อาร์ค local) */
const oprog = Math.max(0, Math.min(1, (Date.now() - o.gauntletJumpAnimStart) / o.gauntletJumpAnimDur));
o.gauntletJumpVis = (gauntletRuntimeJumpTicks || 6) * (1 - oprog);
} else {
if (o.gauntletJumpAnimStart > 0) o.gauntletJumpAnimStart = 0;
if (o.gauntletJumpVis == null) o.gauntletJumpVis = o.gauntletJumpTicks || 0;
o.gauntletJumpVis = stepGauntletJumpVis(o.gauntletJumpVis, o.gauntletJumpTicks || 0);
}
});
clampPlayEntityFootprintToMap(me, mapData);
others.forEach((o) => {
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 -1
View File
@@ -6426,7 +6426,7 @@
document.head.appendChild(st);
}
var closeFn = function () { ov.classList.add('is-hidden'); ov.style.display = 'none'; };
ov.addEventListener('click', function (e) { if (e.target === ov || e.target.classList.contains('ecl-close')) closeFn(); });
ov.addEventListener('click', function (e) { if (e.target === ov || (e.target.closest && e.target.closest('.ecl-close'))) closeFn(); });
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape' && ov.style.display !== 'none') closeFn();
});
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -5458,7 +5458,7 @@
<script src="/Game/socket.io/socket.io.js"></script>
<script src="js/version.js?v=0.0306"></script>
<script src="js/sound.js?v=1"></script>
<script src="js/play.js?v=0.006301082"></script>
<script src="js/play.js?v=0.006301121"></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)
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 -1
View File
@@ -1648,7 +1648,7 @@
<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/sound.js?v=1"></script>
<script src="js/room-lobby.js?v=0.0351"></script>
<script src="js/room-lobby.js?v=0.0352"></script>
<div class="version-tag">v —</div>
</body>
</html>
File diff suppressed because it is too large Load Diff
+75 -18
View File
@@ -2288,6 +2288,8 @@ function defaultGameTiming() {
balloonBossPlayerBalloonFallbackUrl: '/Game/img/MegaVirus/Artboard 9.png',
/** จำนวนลูกโป่งต่อคน (0 = ใช้ค่าจากแมป หรือ default 3) */
balloonBossBalloonsPerPlayer: 0,
/** ดาเมจต่อการยิงโดนบอส (ลบเลือดบอส/นัด) — ตั้งใน Admin Minigame-7 · แยกจากคะแนน */
balloonBossDamagePerHit: 10,
/** โหมดเทสต์: เกมบังคับต่อการ์ด 3 ใบ — ['','',''] = สุ่มหมด, แต่ละช่องใส่ key เพื่อเจาะจงใบนั้น */
forcedMinigameKeys: ['', '', ''],
/** โหมดเทสต์: บังคับการ์ดพิเศษต่อเกม { mapId: cardId } */
@@ -2713,6 +2715,9 @@ function loadGameTiming() {
balloonBossBalloonsPerPlayer: Object.prototype.hasOwnProperty.call(j, 'balloonBossBalloonsPerPlayer')
? Math.max(0, Math.min(12, Math.floor(Number(j.balloonBossBalloonsPerPlayer)) || 0))
: 0,
balloonBossDamagePerHit: Object.prototype.hasOwnProperty.call(j, 'balloonBossDamagePerHit')
? Math.max(1, Math.min(100, Math.floor(Number(j.balloonBossDamagePerHit)) || 10))
: 10,
forcedMinigameKeys: normalizeForcedMinigameKeys(
j.forcedMinigameKeys != null ? j.forcedMinigameKeys : j.forcedMinigameKey,
),
@@ -2739,6 +2744,44 @@ function loadGameTiming() {
let runtimeGameTiming = loadGameTiming();
/** MG5 jump_survive: pool pattern (verify reachability offline ) 1 /
เพอให layout หลากหลาย/เดายาก · pattern[0] = layout เด (baseline) · โหลดครงเดยวตอน boot */
let jumpSurvivePatterns = [];
function loadJumpSurvivePatterns() {
try {
const p = path.join(__dirname, 'data', 'jump-survive-patterns.json');
if (fs.existsSync(p)) {
const j = JSON.parse(fs.readFileSync(p, 'utf8'));
if (j && Array.isArray(j.patterns)) {
jumpSurvivePatterns = j.patterns.filter((x) => x && Array.isArray(x.platformArea) && Array.isArray(x.variantArea));
}
}
} catch (e) { console.error('loadJumpSurvivePatterns', e.message); jumpSurvivePatterns = []; }
}
loadJumpSurvivePatterns();
/** เลือก pattern สุ่ม → เก็บบน space (ใช้ทั้ง server bot physics + ส่งให้ client) · คงเดิมถ้าไม่มี pool */
function pickJumpSurviveLayoutForSpace(space) {
if (!space || !jumpSurvivePatterns.length) return null;
const idx = Math.floor(Math.random() * jumpSurvivePatterns.length);
const pat = jumpSurvivePatterns[idx] || jumpSurvivePatterns[0];
space.jsLayout = { idx, platformArea: pat.platformArea, variantArea: pat.variantArea };
space._jsEffMd = null; /* invalidate effMd cache */
return space.jsLayout;
}
/** md override platformArea/variantArea pattern ( 1 /, cache space)
ไม mutate แมป share (หลายหองเลนพรอมกนได) */
function jsMap(space) {
const base = (space && space.mapId && maps.get(space.mapId)) || (space && space.mapData) || null;
if (!base || !space || !space.jsLayout) return base;
if (space._jsEffMd && space._jsEffMd.__base === base) return space._jsEffMd;
space._jsEffMd = Object.assign(Object.create(base), {
__base: base,
jumpSurvivePlatformArea: space.jsLayout.platformArea,
jumpSurvivePlatformVariantArea: space.jsLayout.variantArea,
});
return space._jsEffMd;
}
/** จำนวนลูกโป่งต่อคน Mega Virus — แมปกำหนดก่อน, ไม่งั้นใช้ค่ากลางจาก admin, สุดท้าย default 3 (clamp 1-12) */
function balloonBossBalloonsForMap(md) {
const fromMap = Math.floor(Number(md && md.balloonBossBalloonsPerPlayer)) || 0;
@@ -2873,6 +2916,13 @@ function saveGameTimingToFile(d) {
const balloonBossBalloonsPerPlayer = Object.prototype.hasOwnProperty.call(d, 'balloonBossBalloonsPerPlayer')
? Math.max(0, Math.min(12, Math.floor(Number(d.balloonBossBalloonsPerPlayer)) || 0))
: prevBbCount;
/* ดาเมจต่อการยิงโดนบอส (แยกจากคะแนน) — Admin Minigame-7 */
const prevBbDmg = Object.prototype.hasOwnProperty.call(prev, 'balloonBossDamagePerHit')
? Math.max(1, Math.min(100, Math.floor(Number(prev.balloonBossDamagePerHit)) || 10))
: 10;
const balloonBossDamagePerHit = Object.prototype.hasOwnProperty.call(d, 'balloonBossDamagePerHit')
? Math.max(1, Math.min(100, Math.floor(Number(d.balloonBossDamagePerHit)) || 10))
: prevBbDmg;
const prevStackTowerSec = Object.prototype.hasOwnProperty.call(prev, 'stackTowerMissionTimeSec')
? prev.stackTowerMissionTimeSec
: 90;
@@ -2938,6 +2988,7 @@ function saveGameTimingToFile(d) {
balloonBossPlayerBalloonImageUrls,
balloonBossPlayerBalloonFallbackUrl,
balloonBossBalloonsPerPlayer,
balloonBossDamagePerHit,
forcedMinigameKeys: Object.prototype.hasOwnProperty.call(d, 'forcedMinigameKeys')
? normalizeForcedMinigameKeys(d.forcedMinigameKeys)
: (Object.prototype.hasOwnProperty.call(d, 'forcedMinigameKey')
@@ -4006,6 +4057,9 @@ function beginDetectiveSuspectMinigame(sid, space, cardEntry, selectedIndex) {
space.quizSession = null;
space.mapId = mapId;
space.mapData = md;
/* MG5: สุ่ม pattern แพลตฟอร์ม 1 อัน/เกม (layout หลากหลาย/เดายาก) — เก็บบน space, ส่งให้ client ผ่าน game-start */
space.jsLayout = null; space._jsEffMd = null;
if (md && md.gameType === 'jump_survive') pickJumpSurviveLayoutForSpace(space);
glog(sid, space, 'game-start', 'เริ่มมินิเกม: ' + ((md && md.name) || mapId) + ' (การ์ด ' + ((selectedIndex != null ? selectedIndex + 1 : '?')) + ')');
/* สุ่มไอคอนคำถามพิเศษสำหรับรอบนี้ (1 ใน 3) — ส่งจริงผ่าน joinCb เมื่อ client เข้า play.html */
maybeSpawnSpecialQuizForRun(space);
@@ -4091,6 +4145,7 @@ function beginDetectiveSuspectMinigame(sid, space, cardEntry, selectedIndex) {
minigameLabel: cardEntry.labelTh,
bannedPlayerId: space.bannedThisRunPlayerId || null,
};
if (space.jsLayout) gameStartPayload.jsLayout = space.jsLayout;
if (md.gameType === 'gauntlet' && space.gauntletRun) {
gameStartPayload.gauntletEndsAt = space.gauntletRun.endsAt != null ? space.gauntletRun.endsAt : null;
}
@@ -4811,7 +4866,6 @@ function resolveQuizRound(sid, space, md) {
const results = [];
const ejectMoves = [];
const tc191Rows = []; /* [TC191] verify: เทียบผลตัดสิน "แถวเท้า" vs "หัว(เดิม)" ต่อคน */
space.peers.forEach((p, peerId) => {
const st = sess.players[peerId];
@@ -4860,14 +4914,6 @@ function resolveQuizRound(sid, space, md) {
});
}
/* [TC191] เก็บบรรทัดเทียบ: เท้า(ที่ใช้จริง) vs หัว(สูตรเดิม single-tile) → พิสูจน์ว่าตัดสินที่แถวเท้า */
{
const headY = Math.floor(Number(p.y));
tc191Rows.push((p.nickname || '?').slice(0, 8) + ' fY=' + qFeetTy + ' hY=' + headY
+ ' เท้า[T' + (inT ? 1 : 0) + 'F' + (inF ? 1 : 0) + ']'
+ ' หัวเดิม[T' + (quizCellOn(tGrid, qBaseTx, headY) ? 1 : 0) + 'F' + (quizCellOn(fGrid, qBaseTx, headY) ? 1 : 0) + ']'
+ ' → ' + (choice === true ? 'จริง' : choice === false ? 'เท็จ' : '-') + (right ? '✓' : '✗'));
}
results.push({
id: peerId,
nickname: p.nickname || '',
@@ -4878,10 +4924,6 @@ function resolveQuizRound(sid, space, md) {
});
});
if (tc191Rows.length) {
try { glog(sid, space, 'mg1-feet', '[TC191] Q' + (idx + 1) + ' ตัดสินแถวเท้า: ' + tc191Rows.join(' | ')); } catch (e) { /* ignore */ }
}
ejectMoves.forEach((ev) => {
io.to(sid).emit('user-move', ev);
try {
@@ -8012,9 +8054,10 @@ function gauntletBotDecideJump(b, obstacles, md, w, h) {
const roll = Math.random();
if (sameCell && roll < pSame) {
b.gauntletJumpTicks = getGauntletJumpTicks();
b.gauntletJumpSeq = (b.gauntletJumpSeq || 0) + 1;
return;
}
if (incomingCol && roll < pAhead) b.gauntletJumpTicks = getGauntletJumpTicks();
if (incomingCol && roll < pAhead) { b.gauntletJumpTicks = getGauntletJumpTicks(); b.gauntletJumpSeq = (b.gauntletJumpSeq || 0) + 1; }
}
/** ฟิสิกส์บอท 1 ตัว 1 tick (server) — mirror applyGauntletPhysicsToPreviewBot + runGauntletTick peer loop */
@@ -8117,6 +8160,7 @@ function emitGauntletSync(sid, space) {
lobbyColorThemeIndex: p.lobbyColorThemeIndex || null,
lobbySkinToneIndex: p.lobbySkinToneIndex || null,
gauntletJumpTicks: p.gauntletJumpTicks || 0,
gauntletJumpSeq: p.gauntletJumpSeq || 0,
gauntletScore: p.gauntletScore || 0,
gauntletEliminated: !!p.gauntletEliminated,
}));
@@ -8130,6 +8174,7 @@ function emitGauntletSync(sid, space) {
direction: b.dir || 'right',
isBot: true,
gauntletJumpTicks: b.gauntletJumpTicks || 0,
gauntletJumpSeq: b.gauntletJumpSeq || 0,
gauntletScore: b.gauntletScore || 0,
gauntletEliminated: !!b.gauntletEliminated,
};
@@ -8869,7 +8914,7 @@ function createJumpSurviveBots(space, md) {
}
}
function startJumpSurviveGame(sid, space) {
const md = (space.mapId && maps.get(space.mapId)) || space.mapData;
const md = jsMap(space); /* ใช้ pattern ที่สุ่มไว้ (effMd) — bot/spawn ตรงกับ client */
if (!md || md.gameType !== 'jump_survive') return;
if (!space.detectiveMinigameActive) return; /* เกมจริงเท่านั้น — editor preview คง client-sim */
if (space.jumpSurviveSession && space.jumpSurviveSession.active) return;
@@ -8923,7 +8968,7 @@ function endJumpSurviveGame(sid, space, reason) {
function stepJumpSurviveBots(sid, space, dt, now) {
const s = space.jumpSurviveSession;
if (!s || !s.active || s.ended) return;
const md = (space.mapId && maps.get(space.mapId)) || space.mapData;
const md = jsMap(space); /* ใช้ pattern ที่สุ่มไว้ (effMd) */
if (!md || md.gameType !== 'jump_survive') return;
/* 3-2-1 (liveBeginsAt) session active
ทำใหบอทว/กระโดดกอน "1" จบ นดวยการ return จนถงเวลาจร (เหมอน scroll liveBeginsAt อยแล) */
@@ -9179,6 +9224,8 @@ function bbTimeLimitSec(md) {
return Number.isFinite(rt) && rt > 0 && rt < 7200 ? Math.floor(rt) : 120;
}
function bbMaxHp(md) { const n = Number(md.balloonBossMaxHp); return Math.max(20, Math.min(9999, Number.isFinite(n) ? Math.floor(n) : 100)); }
/* ดาเมจต่อการยิงโดนบอส (ลบเลือดบอส/นัด) จาก game-timing (Admin Minigame-7) — แยกจากคะแนน · default 10 */
function bbDamagePerHit() { const n = Number(runtimeGameTiming && runtimeGameTiming.balloonBossDamagePerHit); return Math.max(1, Math.min(100, Number.isFinite(n) && n > 0 ? Math.floor(n) : 10)); }
function bbBossCenter(md, ts) {
const bx = md.balloonBossBossSpawn;
if (bx && Number.isFinite(Number(bx.x)) && Number.isFinite(Number(bx.y))) return { cx: (Number(bx.x) + 0.5) * ts, cy: (Number(bx.y) + 0.5) * ts };
@@ -9331,7 +9378,7 @@ function stepBalloonBossBots(sid, space, dt, now) {
io.to(sid).emit('balloon-boss-shot', { sx, sy, vx, vy, ownerId: id, t0: now });
b.score = Math.max(0, (b.score | 0) - 5); /* สเปก: ยิง 1 ครั้ง −5 */
const hitProb = b.tier === 'sharp' ? 0.55 : b.tier === 'weak' ? 0.26 : 0.4;
if (Math.random() < hitProb) { b.score += 10; b.dmg += 2; } /* โดนบอส: +10 คะแนน, −2 HP บอส */
if (Math.random() < hitProb) { b.score += 10; b.dmg += bbDamagePerHit(); } /* โดนบอส: +10 คะแนน, −HP บอสตามค่า Admin (default 10) */
}
outBots.push({ id, cx: b.cx, cy: b.cy, score: b.score, dmg: b.dmg, balloons: b.balloons, elim: false });
});
@@ -9899,6 +9946,9 @@ function runGauntletTick(sid, space) {
if (p.gauntletJumpPending) {
if ((p.gauntletJumpTicks || 0) === 0) {
p.gauntletJumpTicks = getGauntletJumpTicks();
/* () peer
แม gauntletJumpTicks กต 0 ใน tick เดยวกนตอน advanceX (peer ไมเคยเหนค >0) */
p.gauntletJumpSeq = (p.gauntletJumpSeq || 0) + 1;
}
p.gauntletJumpPending = false;
}
@@ -11083,6 +11133,7 @@ io.on('connection', (socket) => {
missionLiveBeginsAt: space.missionLiveBeginsAt || null,
missionLive: isMinigameLiveForRejoinResume(space), /* rejoin กลางเกม live → client ข้าม how-to เข้าเล่นต่อ */
};
if (space.jsLayout) joinCb.jsLayout = space.jsLayout; /* MG5: ส่ง pattern ที่สุ่มไว้ให้ client (initial + late-join) */
if (serverMapIsPostCaseLobbyB(space)) {
joinCb.detectiveLobbyLevel = space.detectiveLobbyLevel != null ? space.detectiveLobbyLevel : null;
joinCb.detectiveLobbyCaseId = space.detectiveLobbyCaseId != null ? space.detectiveLobbyCaseId : null;
@@ -12276,6 +12327,9 @@ io.on('connection', (socket) => {
space.mapId = mapId;
space.mapData = maps.get(mapId);
const md = space.mapData;
/* MG5: สุ่ม pattern แพลตฟอร์ม 1 อัน/เกม (เหมือน detective starter) */
space.jsLayout = null; space._jsEffMd = null;
if (md && md.gameType === 'jump_survive') pickJumpSurviveLayoutForSpace(space);
if (md && md.gameType === 'quiz_battle' && quizBattlePathModeActiveServer(md)) {
space.peers.forEach((p) => {
const sn = snapPositionOntoQuizBattlePathServer(md, Number(p.x), Number(p.y));
@@ -12324,6 +12378,7 @@ io.on('connection', (socket) => {
caseId: caseId || undefined,
peersSnap: peersSnap || undefined,
};
if (space.jsLayout) gameStartPayload.jsLayout = space.jsLayout;
if (peersSnap) gameStartPayload.gauntletEndsAt = gauntletEndsAtEmit != null ? gauntletEndsAtEmit : null;
if (mapId && maps.has(mapId) && (isBalloonBossMissionShellSpace(space) || isQuizQuestionMissionShellSpace(space) || isStackTowerMissionShellSpace(space) || isJumpSurviveMissionShellSpace(space) || isSpaceShooterMissionShellSpace(space))) {
const grs = space.gauntletRun;
@@ -13072,7 +13127,9 @@ io.on('connection', (socket) => {
const nd = Math.floor(Number(data.balloonBossBossDmg));
if (Number.isFinite(nd) && nd >= 0) {
const prevD = Math.max(0, p.balloonBossBossDmg | 0);
if (nd <= prevD + 8) p.balloonBossBossDmg = Math.max(prevD, nd);
/* เพดานเพิ่ม/แพ็กเก็ต = เผื่อยิงโดนหลายนัดต่อ move (ดาเมจ/นัดตั้งได้ถึง 100) */
const bbDmgCap = Math.max(8, bbDamagePerHit() * 3);
if (nd <= prevD + bbDmgCap) p.balloonBossBossDmg = Math.max(prevD, nd);
}
}
if (data.balloonBossBalloons != null) {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3013 -15836
View File
File diff suppressed because it is too large Load Diff