minigame 5 add more design 1.41

This commit is contained in:
2026-05-05 19:12:15 +00:00
parent ba58cd1b74
commit ca572a4589
9 changed files with 469 additions and 44 deletions
+77
View File
@@ -2903,6 +2903,63 @@
});
}
function normalizeJumpSurvivePlatformTileUrlInput(v) {
var s = String(v || '').trim().slice(0, 500);
if (!s) return '';
if (!/^https?:\/\//i.test(s) && s.charAt(0) !== '/') s = '/' + s.replace(/^\/+/, '');
return s;
}
function updateJumpSurvivePlatformTilePreview(slot) {
var img = el('jump-survive-platform-tile-prev-' + slot);
var inp = el('jump-survive-platform-tile-url-' + slot);
if (!img) return;
var v = inp && inp.value ? normalizeJumpSurvivePlatformTileUrlInput(inp.value) : '';
if (!v) {
img.removeAttribute('src');
img.alt = '';
return;
}
img.alt = 'Jump platform tile ' + slot + ' preview';
img.src = v;
}
function readJumpSurvivePlatformTilesFromForm() {
var out = [];
for (var s = 1; s <= 3; s++) {
var inpU = el('jump-survive-platform-tile-url-' + s);
var url = inpU ? normalizeJumpSurvivePlatformTileUrlInput(inpU.value) : '';
var inpW = el('jump-survive-platform-tile-w-' + s);
var inpH = el('jump-survive-platform-tile-h-' + s);
var w = inpW ? parseInt(String(inpW.value), 10) : 0;
var h = inpH ? parseInt(String(inpH.value), 10) : 0;
if (!Number.isFinite(w) || w < 0) w = 0;
if (!Number.isFinite(h) || h < 0) h = 0;
out.push({ url: url, w: w, h: h });
}
return out;
}
function bindJumpSurvivePlatformTileInputs() {
for (var s = 1; s <= 3; s++) {
(function (slot) {
var inp = el('jump-survive-platform-tile-url-' + slot);
var btn = el('btn-jump-survive-platform-tile-clear-' + slot);
if (inp) {
inp.addEventListener('change', function () { updateJumpSurvivePlatformTilePreview(slot); });
inp.addEventListener('blur', function () { updateJumpSurvivePlatformTilePreview(slot); });
}
if (btn) {
btn.addEventListener('click', function () {
var i = el('jump-survive-platform-tile-url-' + slot);
if (i) i.value = '';
updateJumpSurvivePlatformTilePreview(slot);
});
}
})(s);
}
}
function loadJumpSurviveTimingPanel() {
gameTimingFetch('GET')
.then(function (data) {
@@ -2916,6 +2973,22 @@
var jss = Number(data.jumpSurviveMissionTimeSec);
inpT.value = String(Number.isFinite(jss) && jss > 0 ? Math.floor(jss) : 0);
}
var tiles = Array.isArray(data.jumpSurvivePlatformTiles) ? data.jumpSurvivePlatformTiles : [];
var legacy = typeof data.jumpSurvivePlatformTileUrl === 'string' ? data.jumpSurvivePlatformTileUrl : '';
for (var s = 1; s <= 3; s++) {
var o = tiles[s - 1] && typeof tiles[s - 1] === 'object' ? tiles[s - 1] : {};
var url = typeof o.url === 'string' ? o.url : '';
if (s === 1 && !url && legacy) url = legacy;
var inpU = el('jump-survive-platform-tile-url-' + s);
if (inpU) inpU.value = url;
var w = Number(o.w);
var h = Number(o.h);
var inpW = el('jump-survive-platform-tile-w-' + s);
var inpH = el('jump-survive-platform-tile-h-' + s);
if (inpW) inpW.value = String(Number.isFinite(w) && w > 0 ? Math.floor(w) : 0);
if (inpH) inpH.value = String(Number.isFinite(h) && h > 0 ? Math.floor(h) : 0);
updateJumpSurvivePlatformTilePreview(s);
}
setMsg('jump-survive-timing-msg', '', '');
})
.catch(function (e) {
@@ -3577,10 +3650,13 @@
var limJump = el('jump-survive-mission-sec') ? parseInt(String(el('jump-survive-mission-sec').value), 10) : 0;
if (Number.isNaN(limJump) || limJump < 0) limJump = 0;
limJump = limJump <= 0 ? 0 : Math.max(10, Math.min(7200, limJump));
var platTiles = readJumpSurvivePlatformTilesFromForm();
gameTimingFetch('GET')
.then(function (data) {
data.jumpSurviveJumpHeightMult = jumpSurvMult;
data.jumpSurviveMissionTimeSec = limJump;
delete data.jumpSurvivePlatformTileUrl;
data.jumpSurvivePlatformTiles = platTiles;
return gameTimingFetch('PUT', data);
})
.then(function () {
@@ -3791,6 +3867,7 @@
if (btnJumpSurviveSave) {
btnJumpSurviveSave.addEventListener('click', saveJumpSurviveTimingPanel);
}
bindJumpSurvivePlatformTileInputs();
var btnSpaceShooterSave = el('btn-space-shooter-save');
if (btnSpaceShooterSave) {
btnSpaceShooterSave.addEventListener('click', saveSpaceShooterTimingPanel);
+11 -2
View File
@@ -516,7 +516,7 @@
<section id="tab-panel-jump-survive" class="tab-panel card" hidden role="tabpanel" aria-labelledby="tab-jump-survive">
<h2>กระโดดให้รอด — ตั้งค่าเกม</h2>
<p class="muted">คนละโหมดกับ <strong>พรมแดง (Gauntlet)</strong> · เก็บที่ <code>/Game/data/game-timing.json</code> ฟิลด์ <code>jumpSurviveJumpHeightMult</code> และ <code>jumpSurviveMissionTimeSec</code> · ผู้เล่นได้ค่าใหม่เมื่อโหลดหน้าเล่น / <code>GET /api/game-timing</code> · ถ้า API 404 ให้รีสตาร์ท Node ที่รัน <code>Game/server.js</code></p>
<p class="muted">คนละโหมดกับ <strong>พรมแดง (Gauntlet)</strong> · เก็บที่ <code>/Game/data/game-timing.json</code> ฟิลด์ <code>jumpSurviveJumpHeightMult</code> · <code>jumpSurviveMissionTimeSec</code> · <code>jumpSurvivePlatformTiles</code> (3 ช่อง) · ผู้เล่นได้ค่าใหม่เมื่อโหลดหน้าเล่น / <code>GET /api/game-timing</code> · ถ้า API 404 ให้รีสตาร์ท Node ที่รัน <code>Game/server.js</code></p>
<fieldset class="quiz-timing-fieldset">
<legend>ความสูงกระโดด</legend>
<div class="form-grid form-inline quiz-timing-grid">
@@ -531,6 +531,15 @@
</div>
</fieldset>
<p class="muted" style="margin-top:-0.25rem;margin-bottom:0.65rem">นับจากเริ่มรอบจริง (หลังนับถอยหลัง) · ถ้าในแมปตั้ง <code>jumpSurviveTimeSec</code> &gt; 0 จะใช้ค่าบนแมปแทนทั้งหมด · ไม่ใช่ค่าเดียวกับ &quot;จำกัดเวลาเกม&quot; ของพรมแดง · <em>English:</em> Per-map <code>jumpSurviveTimeSec</code> overrides this global default.</p>
<fieldset class="quiz-timing-fieldset">
<legend>รูปแพลตฟอร์ม 1–3 (ช่องยืนได้ — เลือกโหมดวาด 1/2/3 ใน Map Editor)</legend>
<p class="muted" style="margin-top:0">แต่ละช่อง: URL + ความกว้าง/สูงเป็น <strong>พิกเซลในโลกเกม</strong> (เทียบกับขนาดไทล์แมป) · กว้าง/สูง = <strong>0</strong> ให้ใช้ขนาดเท่าไทล์หนึ่งช่อง · ว่าง URL = กราฟิก cyan เดิม · อัปโหลดไปที่ <code>/Game/public/img/Jumper/</code> · <em>English:</em> Three platform sprites; W/H in world px (0 = one tile).</p>
<div class="space-shooter-ship-grid" role="group" aria-label="Jump survive platform tiles 13">
<div class="space-shooter-ship-row"><span class="space-shooter-ship-slot">1</span><label class="space-shooter-ship-url-label">URL <input type="text" id="jump-survive-platform-tile-url-1" maxlength="500" spellcheck="false" placeholder="/Game/img/Jumper/platform-1.png" autocomplete="off"></label><label class="space-shooter-ship-url-label" title="พิกเซลในโลกเกม · 0 = เท่าไทล์">W <input type="number" id="jump-survive-platform-tile-w-1" min="0" max="4096" step="1" value="0"></label><label class="space-shooter-ship-url-label" title="พิกเซลในโลกเกม · 0 = เท่าไทล์">H <input type="number" id="jump-survive-platform-tile-h-1" min="0" max="4096" step="1" value="0"></label><img class="space-shooter-ship-prev" id="jump-survive-platform-tile-prev-1" alt="" width="56" height="56" decoding="async"><button type="button" class="btn btn-ghost" id="btn-jump-survive-platform-tile-clear-1">ล้าง</button></div>
<div class="space-shooter-ship-row"><span class="space-shooter-ship-slot">2</span><label class="space-shooter-ship-url-label">URL <input type="text" id="jump-survive-platform-tile-url-2" maxlength="500" spellcheck="false" placeholder="/Game/img/Jumper/platform-2.png" autocomplete="off"></label><label class="space-shooter-ship-url-label" title="พิกเซลในโลกเกม · 0 = เท่าไทล์">W <input type="number" id="jump-survive-platform-tile-w-2" min="0" max="4096" step="1" value="0"></label><label class="space-shooter-ship-url-label" title="พิกเซลในโลกเกม · 0 = เท่าไทล์">H <input type="number" id="jump-survive-platform-tile-h-2" min="0" max="4096" step="1" value="0"></label><img class="space-shooter-ship-prev" id="jump-survive-platform-tile-prev-2" alt="" width="56" height="56" decoding="async"><button type="button" class="btn btn-ghost" id="btn-jump-survive-platform-tile-clear-2">ล้าง</button></div>
<div class="space-shooter-ship-row"><span class="space-shooter-ship-slot">3</span><label class="space-shooter-ship-url-label">URL <input type="text" id="jump-survive-platform-tile-url-3" maxlength="500" spellcheck="false" placeholder="/Game/img/Jumper/platform-3.png" autocomplete="off"></label><label class="space-shooter-ship-url-label" title="พิกเซลในโลกเกม · 0 = เท่าไทล์">W <input type="number" id="jump-survive-platform-tile-w-3" min="0" max="4096" step="1" value="0"></label><label class="space-shooter-ship-url-label" title="พิกเซลในโลกเกม · 0 = เท่าไทล์">H <input type="number" id="jump-survive-platform-tile-h-3" min="0" max="4096" step="1" value="0"></label><img class="space-shooter-ship-prev" id="jump-survive-platform-tile-prev-3" alt="" width="56" height="56" decoding="async"><button type="button" class="btn btn-ghost" id="btn-jump-survive-platform-tile-clear-3">ล้าง</button></div>
</div>
</fieldset>
<div class="quiz-admin-actions">
<button type="button" class="btn btn-primary" id="btn-jump-survive-save">บันทึก</button>
</div>
@@ -895,6 +904,6 @@
</div>
</main>
</div>
<script src="admin.js?v=68"></script>
<script src="admin.js?v=70"></script>
</body>
</html>
+17
View File
@@ -38,6 +38,23 @@
"stackHeavyBlockPercent": 35,
"jumpSurviveJumpHeightMult": 1.5,
"jumpSurviveMissionTimeSec": 0,
"jumpSurvivePlatformTiles": [
{
"url": "/Game/img/Jumper/platfrom-1.png",
"w": 1392,
"h": 136
},
{
"url": "/Game/img/Jumper/platfrom-2.png",
"w": 389,
"h": 77
},
{
"url": "/Game/img/Jumper/platfrom-3.png",
"w": 212,
"h": 77
}
],
"spaceShooterMissionTimeSec": 0,
"spaceShooterShipImageUrls": [
"/Game/img/ViolentCrime/Rocket-1.png",
+4 -2
View File
@@ -122,7 +122,9 @@
<option value="quizBattleDome" id="draw-mode-option-quiz-battle-dome" hidden>โดมคำถาม (ช่องกด E ในเกม)</option>
</optgroup>
<optgroup label="กระโดดให้รอด">
<option value="jumpSurvivePlatform" id="draw-mode-option-jump-platform" hidden>แพลตฟอร์ม (ยืนได้ — ลอยขึ้นตามกล้องในเกม)</option>
<option value="jumpSurvivePlatform1" id="draw-mode-option-jump-platform-1" hidden>แพลตฟอร์ม 1 (ยืนได้ — รูปช่อง 1 จาก Admin)</option>
<option value="jumpSurvivePlatform2" id="draw-mode-option-jump-platform-2" hidden>แพลตฟอร์ม 2 (ยืนได้ — รูปช่อง 2 จาก Admin)</option>
<option value="jumpSurvivePlatform3" id="draw-mode-option-jump-platform-3" hidden>แพลตฟอร์ม 3 (ยืนได้ — รูปช่อง 3 จาก Admin)</option>
<option value="jumpSurviveHazard" id="draw-mode-option-jump-hazard" hidden>โซนตาย (แดง — ตัวละครโดนกล่องชนแล้วตายทันที)</option>
</optgroup>
<optgroup label="ยิงยานอวกาศ">
@@ -360,7 +362,7 @@
</div>
</div>
<script src="js/version.js?v=0.0258"></script>
<script src="js/editor.js?v=0.0316"></script>
<script src="js/editor.js?v=0.0318"></script>
<div class="version-tag">v —</div>
</body>
</html>
+156 -14
View File
@@ -108,6 +108,16 @@
let jumpSurvivePlatformArea = [];
/** jump_survive: กริด 0/1 — ช่องที่ 1 = โซนตาย (ชน hitbox แล้วตายทันทีในเกม) */
let jumpSurviveHazardArea = [];
/** กริด 0 / 1–3 = รูปแพลตฟอร์มจาก jumpSurvivePlatformTiles ใน game-timing */
let jumpSurvivePlatformVariantArea = [];
/** จาก GET /api/game-timing — แสดงในแคนวาสเอดิเตอร์ตามช่อง variant */
let editorJumpSurvivePlatformTilesCfg = [
{ url: '', w: 0, h: 0 },
{ url: '', w: 0, h: 0 },
{ url: '', w: 0, h: 0 },
];
let editorJumpSurvivePlatformTileImgs = [null, null, null];
let editorJumpSurvivePlatformTimingGen = 0;
let cellColors = [];
let gauntletPlayerSpawns = [];
/** gauntlet: แถว y บน–ล่างของแถบเลเซอร์ (null = เต็มความสูงแมป) */
@@ -1258,6 +1268,35 @@
}
}
}
ensureJumpSurvivePlatformVariantArea();
}
function ensureJumpSurvivePlatformVariantArea() {
if (!jumpSurvivePlatformVariantArea.length || jumpSurvivePlatformVariantArea.length !== height) {
const existing = jumpSurvivePlatformVariantArea.slice().map((r) => r && r.slice());
jumpSurvivePlatformVariantArea = [];
for (let y = 0; y < height; y++) {
const row = existing[y] && existing[y].length === width ? existing[y].slice() : Array(width).fill(0);
jumpSurvivePlatformVariantArea.push(row);
}
} else {
for (let y = 0; y < height; y++) {
if (!jumpSurvivePlatformVariantArea[y] || jumpSurvivePlatformVariantArea[y].length !== width) {
jumpSurvivePlatformVariantArea[y] = Array(width).fill(0);
}
}
}
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
if (jumpSurvivePlatformArea[y] && jumpSurvivePlatformArea[y][x] === 1) {
let v = jumpSurvivePlatformVariantArea[y][x];
if (!Number.isFinite(v) || v < 1) jumpSurvivePlatformVariantArea[y][x] = 1;
else if (v > 3) jumpSurvivePlatformVariantArea[y][x] = 3;
} else {
jumpSurvivePlatformVariantArea[y][x] = 0;
}
}
}
}
function ensureJumpSurviveHazardArea() {
@@ -1277,6 +1316,68 @@
}
}
function normalizeEditorJumpSurvivePlatformTileUrl(v) {
let s = String(v || '').trim().slice(0, 500);
if (!s) return '';
if (!/^https?:\/\//i.test(s) && s.charAt(0) !== '/') s = '/' + s.replace(/^\/+/, '');
return s;
}
function normalizeEditorJumpSurvivePlatformTilesFromTiming(data) {
const legacy = normalizeEditorJumpSurvivePlatformTileUrl(data.jumpSurvivePlatformTileUrl);
const arr = Array.isArray(data.jumpSurvivePlatformTiles) ? data.jumpSurvivePlatformTiles : [];
const out = [];
for (let i = 0; i < 3; i++) {
const o = arr[i] && typeof arr[i] === 'object' ? arr[i] : {};
let url = normalizeEditorJumpSurvivePlatformTileUrl(o.url);
if (i === 0 && !url && legacy) url = legacy;
let ww = Number(o.w);
let hh = Number(o.h);
if (!Number.isFinite(ww) || ww <= 0) ww = 0;
else ww = Math.max(8, Math.min(4096, Math.round(ww)));
if (!Number.isFinite(hh) || hh <= 0) hh = 0;
else hh = Math.max(8, Math.min(4096, Math.round(hh)));
out.push({ url, w: ww, h: hh });
}
return out;
}
function refreshEditorJumpSurvivePlatformTileFromTiming() {
editorJumpSurvivePlatformTimingGen += 1;
const gen = editorJumpSurvivePlatformTimingGen;
editorJumpSurvivePlatformTileImgs = [null, null, null];
fetch(BASE + '/api/game-timing?_=' + Date.now(), { cache: 'no-store' })
.then((r) => (r.ok ? r.json() : null))
.then((data) => {
if (!data || gen !== editorJumpSurvivePlatformTimingGen) return;
const gtNow = gameTypeEl ? gameTypeEl.value : gameType;
if (gtNow !== 'jump_survive') return;
editorJumpSurvivePlatformTilesCfg = normalizeEditorJumpSurvivePlatformTilesFromTiming(data);
let pending = 0;
for (let i = 0; i < 3; i++) {
const u = editorJumpSurvivePlatformTilesCfg[i].url;
if (!u) continue;
pending += 1;
const idx = i;
const im = new Image();
im.onload = function () {
if (gen !== editorJumpSurvivePlatformTimingGen) return;
editorJumpSurvivePlatformTileImgs[idx] = im;
pending -= 1;
if (pending <= 0) draw();
};
im.onerror = function () {
if (gen !== editorJumpSurvivePlatformTimingGen) return;
pending -= 1;
if (pending <= 0) draw();
};
im.src = u;
}
if (pending === 0) draw();
})
.catch(() => {});
}
function sanitizeGauntletPlayerSpawns() {
gauntletPlayerSpawns = gauntletPlayerSpawns
.filter((s) => s && Number.isFinite(s.x) && Number.isFinite(s.y) &&
@@ -1733,6 +1834,7 @@
const dqBattlePath = document.getElementById('draw-mode-option-quiz-battle-path');
if (!froggerWrap) return;
const gt = gameTypeEl ? gameTypeEl.value : 'zep';
if (drawModeEl && drawModeEl.value === 'jumpSurvivePlatform') drawModeEl.value = 'jumpSurvivePlatform1';
if (dqTrue) dqTrue.hidden = gt !== 'quiz';
if (dqFalse) dqFalse.hidden = gt !== 'quiz';
if (dqQ) dqQ.hidden = gt !== 'quiz' && gt !== 'quiz_carry';
@@ -1827,6 +1929,7 @@
if (editorFroggerAnimationId != null) { cancelAnimationFrame(editorFroggerAnimationId); editorFroggerAnimationId = null; }
draw();
} else if (gt === 'jump_survive') {
refreshEditorJumpSurvivePlatformTileFromTiming();
froggerWrap.style.display = 'none';
if (hint) {
hint.innerHTML = '<p class="editor-hint-lead"><strong>กระโดดให้รอด</strong> — กำแพง + แพลตฟอร์มเลื่อนขึ้นในกรอบจอ</p>' + editorHintBulletList([
@@ -1966,12 +2069,15 @@
if (drawModeEl && (drawModeEl.value === 'quizBattleDome' || drawModeEl.value === 'quizBattlePath') && gt !== 'quiz_battle') {
drawModeEl.value = 'wall';
}
const jPlatOpt = document.getElementById('draw-mode-option-jump-platform');
const jPlat1 = document.getElementById('draw-mode-option-jump-platform-1');
const jPlat2 = document.getElementById('draw-mode-option-jump-platform-2');
const jPlat3 = document.getElementById('draw-mode-option-jump-platform-3');
const jHazOpt = document.getElementById('draw-mode-option-jump-hazard');
if (jPlatOpt) {
jPlatOpt.hidden = gt !== 'jump_survive';
if (gt !== 'jump_survive' && drawModeEl && drawModeEl.value === 'jumpSurvivePlatform') drawModeEl.value = 'wall';
}
const showJumpPlat = gt === 'jump_survive';
if (jPlat1) jPlat1.hidden = !showJumpPlat;
if (jPlat2) jPlat2.hidden = !showJumpPlat;
if (jPlat3) jPlat3.hidden = !showJumpPlat;
if (!showJumpPlat && drawModeEl && /^jumpSurvivePlatform\d$/.test(drawModeEl.value)) drawModeEl.value = 'wall';
if (jHazOpt) {
jHazOpt.hidden = gt !== 'jump_survive';
if (gt !== 'jump_survive' && drawModeEl && drawModeEl.value === 'jumpSurviveHazard') drawModeEl.value = 'wall';
@@ -2007,6 +2113,7 @@
stackReleaseArea = Array(height).fill(0).map(() => Array(width).fill(0));
stackLandArea = Array(height).fill(0).map(() => Array(width).fill(0));
jumpSurvivePlatformArea = Array(height).fill(0).map(() => Array(width).fill(0));
jumpSurvivePlatformVariantArea = Array(height).fill(0).map(() => Array(width).fill(0));
jumpSurviveHazardArea = Array(height).fill(0).map(() => Array(width).fill(0));
shooterSpawnSlots = Array(height).fill(0).map(() => Array(width).fill(0));
balloonBossPlayerSlots = Array(height).fill(0).map(() => Array(width).fill(0));
@@ -2242,12 +2349,36 @@
}
}
if (gtDraw === 'jump_survive' && jumpSurvivePlatformArea[y] && jumpSurvivePlatformArea[y][x] === 1) {
ctx.fillStyle = 'rgba(125, 235, 200, 0.48)';
ctx.fillRect(tx + 3, ty + 3, tileSize - 6, tileSize - 6);
ctx.strokeStyle = 'rgba(160, 255, 220, 0.92)';
ctx.lineWidth = 2;
ctx.strokeRect(tx + 3, ty + 3, tileSize - 6, tileSize - 6);
ctx.lineWidth = 1;
let v = jumpSurvivePlatformVariantArea[y] ? Math.floor(Number(jumpSurvivePlatformVariantArea[y][x])) : 1;
if (!Number.isFinite(v) || v < 1) v = 1;
if (v > 3) v = 3;
const cfg = editorJumpSurvivePlatformTilesCfg[v - 1] || { url: '', w: 0, h: 0 };
const im = editorJumpSurvivePlatformTileImgs[v - 1];
const px0 = tx + 3;
const py0 = ty + 3;
const pw = tileSize - 6;
const ph = tileSize - 6;
let dw = cfg.w > 0 ? cfg.w : pw;
let dh = cfg.h > 0 ? cfg.h : ph;
const maxDim = tileSize * 4;
if (dw > maxDim) dw = maxDim;
if (dh > maxDim) dh = maxDim;
const dx = tx + (tileSize - dw) / 2;
const dy = ty + tileSize - dh - 2;
if (im && im.complete && im.naturalWidth > 0) {
ctx.drawImage(im, dx, dy, dw, dh);
ctx.strokeStyle = 'rgba(160, 255, 220, 0.92)';
ctx.lineWidth = 2;
ctx.strokeRect(dx, dy, dw, dh);
ctx.lineWidth = 1;
} else {
ctx.fillStyle = 'rgba(125, 235, 200, 0.48)';
ctx.fillRect(px0, py0, pw, ph);
ctx.strokeStyle = 'rgba(160, 255, 220, 0.92)';
ctx.lineWidth = 2;
ctx.strokeRect(px0, py0, pw, ph);
ctx.lineWidth = 1;
}
}
if (gtDraw === 'jump_survive' && jumpSurviveHazardArea[y] && jumpSurviveHazardArea[y][x] === 1) {
ctx.fillStyle = 'rgba(220, 40, 60, 0.52)';
@@ -2776,10 +2907,17 @@
if ((gameTypeEl ? gameTypeEl.value : gameType) !== 'stack') return;
ensureStackAreas();
stackLandArea[y][x] = left ? 1 : 0;
} else if (drawModeEl.value === 'jumpSurvivePlatform') {
} else if (drawModeEl.value === 'jumpSurvivePlatform1' || drawModeEl.value === 'jumpSurvivePlatform2' || drawModeEl.value === 'jumpSurvivePlatform3') {
if ((gameTypeEl ? gameTypeEl.value : gameType) !== 'jump_survive') return;
const slot = drawModeEl.value === 'jumpSurvivePlatform1' ? 1 : drawModeEl.value === 'jumpSurvivePlatform2' ? 2 : 3;
ensureJumpSurvivePlatformArea();
jumpSurvivePlatformArea[y][x] = left ? 1 : 0;
if (left) {
jumpSurvivePlatformArea[y][x] = 1;
jumpSurvivePlatformVariantArea[y][x] = slot;
} else {
jumpSurvivePlatformArea[y][x] = 0;
jumpSurvivePlatformVariantArea[y][x] = 0;
}
} else if (drawModeEl.value === 'jumpSurviveHazard') {
if ((gameTypeEl ? gameTypeEl.value : gameType) !== 'jump_survive') return;
ensureJumpSurviveHazardArea();
@@ -3237,7 +3375,7 @@
if (drawModeEl && drawModeEl.value === 'quizQuestion' && gameType !== 'quiz' && gameType !== 'quiz_carry') drawModeEl.value = 'wall';
if (drawModeEl && (drawModeEl.value === 'stackRelease' || drawModeEl.value === 'stackLand') && gameType !== 'stack') drawModeEl.value = 'wall';
if (drawModeEl && quizCarryEditorCarryModes().indexOf(drawModeEl.value) >= 0 && gameType !== 'quiz_carry') drawModeEl.value = 'wall';
if (drawModeEl && drawModeEl.value === 'jumpSurvivePlatform' && gameType !== 'jump_survive') drawModeEl.value = 'wall';
if (drawModeEl && /^jumpSurvivePlatform\d$/.test(drawModeEl.value) && gameType !== 'jump_survive') drawModeEl.value = 'wall';
if (drawModeEl && drawModeEl.value === 'gauntletPlayerSpawn' && gameType !== 'gauntlet') drawModeEl.value = 'wall';
if (drawModeEl && drawModeEl.value === 'gauntletLaserStart' && gameType !== 'gauntlet') drawModeEl.value = 'wall';
if (drawModeEl && drawModeEl.value === 'gauntletLaserEnd' && gameType !== 'gauntlet') drawModeEl.value = 'wall';
@@ -3429,6 +3567,7 @@
stackLandArea: gameType === 'stack' ? stackLandArea.map(r => r.slice()) : [],
jumpSurvivePlatforms: gameType === 'jump_survive' ? jumpSurvivePlatforms.slice() : [],
jumpSurvivePlatformArea: gameType === 'jump_survive' ? jumpSurvivePlatformArea.map((r) => r.slice()) : [],
jumpSurvivePlatformVariantArea: gameType === 'jump_survive' ? jumpSurvivePlatformVariantArea.map((r) => r.slice()) : [],
jumpSurviveHazardArea: gameType === 'jump_survive' ? jumpSurviveHazardArea.map((r) => r.slice()) : [],
shooterSpawnSlots: (gameType === 'space_shooter' || gameType === 'jump_survive') ? shooterSpawnSlots.map((r) => r.slice()) : [],
balloonBossPlayerSlots: gameType === 'balloon_boss' ? balloonBossPlayerSlots.map((r) => r.slice()) : [],
@@ -3716,6 +3855,9 @@
quizBattlePathArea = m.quizBattlePathArea && m.quizBattlePathArea.length ? m.quizBattlePathArea.map(r => r && r.slice()) : Array(height).fill(0).map(() => Array(width).fill(0));
jumpSurvivePlatforms = Array.isArray(m.jumpSurvivePlatforms) ? m.jumpSurvivePlatforms.map((p) => (p && typeof p === 'object' ? { ...p } : null)).filter(Boolean) : [];
jumpSurvivePlatformArea = m.jumpSurvivePlatformArea && m.jumpSurvivePlatformArea.length ? m.jumpSurvivePlatformArea.map((r) => r && r.slice()) : Array(height).fill(0).map(() => Array(width).fill(0));
jumpSurvivePlatformVariantArea = m.jumpSurvivePlatformVariantArea && m.jumpSurvivePlatformVariantArea.length
? m.jumpSurvivePlatformVariantArea.map((r) => r && r.slice())
: Array(height).fill(0).map(() => Array(width).fill(0));
ensureJumpSurvivePlatformArea();
jumpSurviveHazardArea = m.jumpSurviveHazardArea && m.jumpSurviveHazardArea.length ? m.jumpSurviveHazardArea.map((r) => r && r.slice()) : Array(height).fill(0).map(() => Array(width).fill(0));
ensureJumpSurviveHazardArea();
+111 -24
View File
@@ -1675,6 +1675,12 @@
let playJumpSurviveJumpHeightMult = 1.5;
/** จำกัดเวลารอบภารกิจกระโดดขึ้นแท่น (วินาที) — จาก GET /api/game-timing; 0 = ใช้ค่าเริ่ม 60 ในเกม */
let playJumpSurviveMissionTimeSec = 0;
/** รูปแพลตฟอร์ม jump_survive ช่อง 13 จาก game-timing — url ว่าง = วาด cyan; w/h 0 = ใช้ขนาดไทล์ */
let playJumpSurvivePlatformTiles = [
{ url: '', w: 0, h: 0 },
{ url: '', w: 0, h: 0 },
{ url: '', w: 0, h: 0 },
];
/** ยิงยานอวกาศ (space_shooter): เวลารอบจาก game-timing; 0 = ใช้ค่าเริ่ม 90 ในเกมถ้าแมปไม่ทับ */
let playSpaceShooterMissionTimeSec = 0;
/** รูปยานช่อง 16 จาก game-timing (spawn slot); ว่าง = วาดยานเวกเตอร์ */
@@ -9196,6 +9202,28 @@
playJumpSurviveMissionTimeSec = 0;
}
}
if (Object.prototype.hasOwnProperty.call(payload, 'jumpSurvivePlatformTiles')
|| Object.prototype.hasOwnProperty.call(payload, 'jumpSurvivePlatformTileUrl')) {
const legacy = Object.prototype.hasOwnProperty.call(payload, 'jumpSurvivePlatformTileUrl')
? normalizeGauntletAssetUrlForPlay(typeof payload.jumpSurvivePlatformTileUrl === 'string' ? payload.jumpSurvivePlatformTileUrl : '')
: '';
const arr = Array.isArray(payload.jumpSurvivePlatformTiles) ? payload.jumpSurvivePlatformTiles : [];
const next = [];
for (let pi = 0; pi < 3; pi++) {
const o = arr[pi] && typeof arr[pi] === 'object' ? arr[pi] : {};
let url = normalizeGauntletAssetUrlForPlay(typeof o.url === 'string' ? o.url : '');
if (pi === 0 && !url && legacy) url = legacy;
let ww = Number(o.w);
let hh = Number(o.h);
if (!Number.isFinite(ww) || ww <= 0) ww = 0;
else ww = Math.max(8, Math.min(4096, Math.round(ww)));
if (!Number.isFinite(hh) || hh <= 0) hh = 0;
else hh = Math.max(8, Math.min(4096, Math.round(hh)));
next.push({ url, w: ww, h: hh });
if (url) ensureGauntletAssetImage(url);
}
playJumpSurvivePlatformTiles = next;
}
if (Object.prototype.hasOwnProperty.call(payload, 'spaceShooterMissionTimeSec')) {
const st = Number(payload.spaceShooterMissionTimeSec);
if (Number.isFinite(st) && st > 0) {
@@ -10527,6 +10555,37 @@
md.jumpSurvivePlatformArea = rows;
}
function normalizeJumpSurvivePlatformVariantAreaInPlay(md) {
if (!md || md.gameType !== 'jump_survive') return;
const w = md.width || 20, h = md.height || 15;
const pa = md.jumpSurvivePlatformArea || [];
const src = md.jumpSurvivePlatformVariantArea || [];
const rows = [];
for (let y = 0; y < h; y++) {
const row = [];
for (let x = 0; x < w; x++) {
const has = pa[y] && pa[y][x] === 1;
let v = has ? Math.floor(Number(src[y] && src[y][x])) : 0;
if (has && (!Number.isFinite(v) || v < 1)) v = 1;
if (v > 3) v = 3;
if (!has) v = 0;
row.push(v);
}
rows.push(row);
}
md.jumpSurvivePlatformVariantArea = rows;
}
function jumpSurvivePlatformVariantIndexAtPlay(md, tx, ty) {
const pa = md && md.jumpSurvivePlatformArea;
if (!pa || !pa[ty] || pa[ty][tx] !== 1) return 0;
const va = md.jumpSurvivePlatformVariantArea;
let v = va && va[ty] ? Math.floor(Number(va[ty][tx])) : 1;
if (!Number.isFinite(v) || v < 1) v = 1;
if (v > 3) v = 3;
return v;
}
function normalizeJumpSurviveHazardAreaInPlay(md) {
if (!md || md.gameType !== 'jump_survive') return;
const w = md.width || 20, h = md.height || 15;
@@ -13055,7 +13114,9 @@
if (!Array.isArray(mapData.jumpSurvivePlatforms)) mapData.jumpSurvivePlatforms = [];
if (!mapData.jumpSurvivePlatformArea) mapData.jumpSurvivePlatformArea = [];
if (!mapData.jumpSurviveHazardArea) mapData.jumpSurviveHazardArea = [];
if (!mapData.jumpSurvivePlatformVariantArea) mapData.jumpSurvivePlatformVariantArea = [];
normalizeJumpSurvivePlatformAreaInPlay(mapData);
normalizeJumpSurvivePlatformVariantAreaInPlay(mapData);
normalizeJumpSurviveHazardAreaInPlay(mapData);
normalizeShooterSpawnSlotsInPlay(mapData);
jumpSurviveEliminated = false;
@@ -13889,7 +13950,9 @@
if (!Array.isArray(mapData.jumpSurvivePlatforms)) mapData.jumpSurvivePlatforms = [];
if (!mapData.jumpSurvivePlatformArea) mapData.jumpSurvivePlatformArea = [];
if (!mapData.jumpSurviveHazardArea) mapData.jumpSurviveHazardArea = [];
if (!mapData.jumpSurvivePlatformVariantArea) mapData.jumpSurvivePlatformVariantArea = [];
normalizeJumpSurvivePlatformAreaInPlay(mapData);
normalizeJumpSurvivePlatformVariantAreaInPlay(mapData);
normalizeJumpSurviveHazardAreaInPlay(mapData);
normalizeShooterSpawnSlotsInPlay(mapData);
jumpSurviveEliminated = false;
@@ -16033,6 +16096,11 @@
for (let py = 0; py < h; py++) {
for (let px = 0; px < w; px++) {
if (!pa[py] || pa[py][px] !== 1) continue;
const vIdx = jumpSurvivePlatformVariantIndexAtPlay(mapData, px, py);
const cfg = playJumpSurvivePlatformTiles[vIdx - 1] || { url: '', w: 0, h: 0 };
const jumpPlatU = normalizeGauntletAssetUrlForPlay(cfg.url || '');
const jumpPlatRec = jumpPlatU ? ensureGauntletAssetImage(jumpPlatU) : null;
const jumpPlatImg = jumpPlatRec && jumpPlatRec.ready && jumpPlatRec.img && jumpPlatRec.img.naturalWidth > 0 ? jumpPlatRec.img : null;
const tileWorldLeft = px * tsz;
const tileWorldRight = tileWorldLeft + tsz;
if (tileWorldRight <= worldMinX || tileWorldLeft >= worldMaxX) continue;
@@ -16045,32 +16113,51 @@
if (platTop + tsz <= visTop || platTop >= visBot) continue;
const [psx, psy] = worldToScreen(tileWorldLeft, platTop);
const psz = tsz * zDraw;
ctx.fillStyle = 'rgba(0, 40, 52, 0.72)';
ctx.fillRect(psx + 3, psy + 3, psz - 6, psz - 6);
ctx.strokeStyle = 'rgba(0, 255, 240, 0.55)';
ctx.lineWidth = 2;
ctx.strokeRect(psx + 3, psy + 3, psz - 6, psz - 6);
ctx.strokeStyle = 'rgba(120, 255, 255, 0.35)';
ctx.lineWidth = 1;
ctx.strokeRect(psx + 5, psy + 5, psz - 10, psz - 10);
const grad = ctx.createLinearGradient(psx, psy, psx, psy + psz);
grad.addColorStop(0, 'rgba(0, 255, 240, 0.12)');
grad.addColorStop(0.5, 'rgba(0, 0, 0, 0)');
grad.addColorStop(1, 'rgba(0, 180, 200, 0.08)');
ctx.fillStyle = grad;
ctx.fillRect(psx + 4, psy + 4, psz - 8, psz - 8);
ctx.lineWidth = 1;
if (zDraw >= 1.15 && psz > 22) {
let dw = cfg.w > 0 ? cfg.w * zDraw : psz - 4;
let dh = cfg.h > 0 ? cfg.h * zDraw : psz - 4;
const maxDim = psz * 4;
if (dw > maxDim) dw = maxDim;
if (dh > maxDim) dh = maxDim;
const marginBot = 2;
const dx = psx + (psz - dw) / 2;
const dy = psy + psz - dh - marginBot;
if (jumpPlatImg) {
ctx.save();
ctx.font = `600 ${Math.max(7, Math.min(11, psz * 0.14))}px "Share Tech Mono", ui-monospace, monospace`;
ctx.fillStyle = 'rgba(180, 255, 255, 0.5)';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('DATA', psx + psz * 0.5, psy + psz * 0.38);
ctx.font = `500 ${Math.max(5, Math.min(8, psz * 0.1))}px "Share Tech Mono", ui-monospace, monospace`;
ctx.fillStyle = 'rgba(120, 230, 255, 0.38)';
ctx.fillText('/SEC/BLOCK', psx + psz * 0.5, psy + psz * 0.62);
try { ctx.imageSmoothingEnabled = true; } catch (e) { /* ignore */ }
ctx.drawImage(jumpPlatImg, dx, dy, dw, dh);
ctx.restore();
ctx.strokeStyle = 'rgba(0, 255, 240, 0.4)';
ctx.lineWidth = 1.5;
ctx.strokeRect(dx, dy, dw, dh);
ctx.lineWidth = 1;
} else {
ctx.fillStyle = 'rgba(0, 40, 52, 0.72)';
ctx.fillRect(psx + 3, psy + 3, psz - 6, psz - 6);
ctx.strokeStyle = 'rgba(0, 255, 240, 0.55)';
ctx.lineWidth = 2;
ctx.strokeRect(psx + 3, psy + 3, psz - 6, psz - 6);
ctx.strokeStyle = 'rgba(120, 255, 255, 0.35)';
ctx.lineWidth = 1;
ctx.strokeRect(psx + 5, psy + 5, psz - 10, psz - 10);
const grad = ctx.createLinearGradient(psx, psy, psx, psy + psz);
grad.addColorStop(0, 'rgba(0, 255, 240, 0.12)');
grad.addColorStop(0.5, 'rgba(0, 0, 0, 0)');
grad.addColorStop(1, 'rgba(0, 180, 200, 0.08)');
ctx.fillStyle = grad;
ctx.fillRect(psx + 4, psy + 4, psz - 8, psz - 8);
ctx.lineWidth = 1;
if (zDraw >= 1.15 && psz > 22) {
ctx.save();
ctx.font = `600 ${Math.max(7, Math.min(11, psz * 0.14))}px "Share Tech Mono", ui-monospace, monospace`;
ctx.fillStyle = 'rgba(180, 255, 255, 0.5)';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('DATA', psx + psz * 0.5, psy + psz * 0.38);
ctx.font = `500 ${Math.max(5, Math.min(8, psz * 0.1))}px "Share Tech Mono", ui-monospace, monospace`;
ctx.fillStyle = 'rgba(120, 230, 255, 0.38)';
ctx.fillText('/SEC/BLOCK', psx + psz * 0.5, psy + psz * 0.62);
ctx.restore();
}
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
// ทุกครั้งที่มีการเพิ่มหรือเปลี่ยน ให้เพิ่ม v +0.0001
// หลังแก้ค่าแล้วต้อง copy ไป path ที่ Nginx ชี้ (หรือรัน copy-frogger-files-only.sh) ถึงจะเห็นบนเว็บ
window.APP_VERSION = '0.0316';
window.APP_VERSION = '0.0317';
document.addEventListener('DOMContentLoaded', function () {
var t = document.querySelector('.version-tag');
if (t) t.textContent = 'v ' + window.APP_VERSION;
+1 -1
View File
@@ -3026,7 +3026,7 @@
</div>
<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.0316"></script>
<script src="js/play.js?v=0.0318"></script>
<div class="version-tag">v —</div>
</body>
</html>
+91
View File
@@ -167,6 +167,8 @@ const defaultMap = () => ({
/** กระโดดให้รอด — แพลตฟอร์มในระบบ tile (ร่างสำหรับ side-view ภายหลัง) */
jumpSurvivePlatforms: [],
jumpSurvivePlatformArea: [],
/** กริดช่องละ 0 หรือ 1–3 = รูปแพลตฟอร์มจาก jumpSurvivePlatformTiles[index-1] */
jumpSurvivePlatformVariantArea: [],
jumpSurviveHazardArea: [],
jumpSurviveRisePxPerSec: 42,
jumpSurviveGravity: 3200,
@@ -601,6 +603,12 @@ function defaultGameTiming() {
jumpSurviveJumpHeightMult: 1.5,
/** จำกัดเวลารอบภารกิจ/มินิเกมกระโดดขึ้นแท่น (วินาที) — 0 = ไคลเอนต์ใช้ 60 วิ; ไม่ใช่ค่าเดียวกับพรมแดง */
jumpSurviveMissionTimeSec: 0,
/** รูปแพลตฟอร์ม jump_survive ช่อง 1–3 — ว่าง = ไคลเอนต์วาด cyan; w/h 0 = ใช้ขนาดไทล์ */
jumpSurvivePlatformTiles: [
{ url: '', w: 0, h: 0 },
{ url: '', w: 0, h: 0 },
{ url: '', w: 0, h: 0 },
],
/** Stack ภารกิจ Tower (mnn93hpi): จำกัดเวลารอบ (วินาที) — ไคลเอนต์ใช้เมื่อเล่นภารกิจ */
stackTowerMissionTimeSec: 90,
/** Stack ภารกิจ Tower: ทีมพลาดได้กี่ครั้งก่อนจบ (ไม่รีเซ็ตหอ) */
@@ -698,6 +706,36 @@ function clampJumpSurviveMissionTimeSec(n) {
return Math.max(10, Math.min(7200, Math.floor(v)));
}
/** กระโดดให้รอด: รูปแพลตฟอร์ม 3 ช่อง — url ว่าง = ไคลเอนต์วาด cyan; w/h ≤0 = ใช้ขนาดไทล์ตอนรัน */
function normalizeJumpSurvivePlatformTilesFromTiming(val, legacyTileUrl) {
let arr = val;
if (typeof arr === 'string') {
try {
const p = JSON.parse(arr);
if (Array.isArray(p)) arr = p;
} catch (e) {
arr = [];
}
}
if (!Array.isArray(arr)) arr = [];
const legacy = typeof legacyTileUrl === 'string' ? sanitizeGauntletAssetUrl(legacyTileUrl) : '';
const out = [];
for (let i = 0; i < 3; i++) {
const o = arr[i];
const obj = o && typeof o === 'object' ? o : {};
let url = sanitizeGauntletAssetUrl(typeof obj.url === 'string' ? obj.url : '');
if (i === 0 && !url && legacy) url = legacy;
let ww = Number(obj.w);
let hh = Number(obj.h);
if (!Number.isFinite(ww) || ww <= 0) ww = 0;
else ww = Math.max(8, Math.min(4096, Math.round(ww)));
if (!Number.isFinite(hh) || hh <= 0) hh = 0;
else hh = Math.max(8, Math.min(4096, Math.round(hh)));
out.push({ url, w: ww, h: hh });
}
return out;
}
function clampSpaceShooterMissionTimeSec(n) {
const v = Number(n);
if (Number.isNaN(v) || v <= 0) return 0;
@@ -940,6 +978,10 @@ function loadGameTiming() {
jumpSurviveMissionTimeSec: Object.prototype.hasOwnProperty.call(j, 'jumpSurviveMissionTimeSec')
? clampJumpSurviveMissionTimeSec(j.jumpSurviveMissionTimeSec)
: 0,
jumpSurvivePlatformTiles: normalizeJumpSurvivePlatformTilesFromTiming(
j.jumpSurvivePlatformTiles,
j.jumpSurvivePlatformTileUrl,
),
spaceShooterMissionTimeSec: Object.prototype.hasOwnProperty.call(j, 'spaceShooterMissionTimeSec')
? clampSpaceShooterMissionTimeSec(j.spaceShooterMissionTimeSec)
: 0,
@@ -1008,6 +1050,28 @@ function saveGameTimingToFile(d) {
const jumpMissionSec = Object.prototype.hasOwnProperty.call(d, 'jumpSurviveMissionTimeSec')
? clampJumpSurviveMissionTimeSec(d.jumpSurviveMissionTimeSec)
: clampJumpSurviveMissionTimeSec(prevJumpMissionSec);
const prevJumpTiles = normalizeJumpSurvivePlatformTilesFromTiming(
prev.jumpSurvivePlatformTiles,
prev.jumpSurvivePlatformTileUrl,
);
let jumpSurvivePlatformTiles;
if (Object.prototype.hasOwnProperty.call(d, 'jumpSurvivePlatformTiles')) {
jumpSurvivePlatformTiles = normalizeJumpSurvivePlatformTilesFromTiming(
d.jumpSurvivePlatformTiles,
d.jumpSurvivePlatformTileUrl,
);
} else if (Object.prototype.hasOwnProperty.call(d, 'jumpSurvivePlatformTileUrl')) {
jumpSurvivePlatformTiles = normalizeJumpSurvivePlatformTilesFromTiming(
[
{ url: d.jumpSurvivePlatformTileUrl, w: 0, h: 0 },
prevJumpTiles[1],
prevJumpTiles[2],
],
'',
);
} else {
jumpSurvivePlatformTiles = prevJumpTiles;
}
const prevSpaceShooterMissionSec = Object.prototype.hasOwnProperty.call(prev, 'spaceShooterMissionTimeSec')
? prev.spaceShooterMissionTimeSec
: 0;
@@ -1119,6 +1183,7 @@ function saveGameTimingToFile(d) {
stackHeavyBlockPercent,
jumpSurviveJumpHeightMult: jumpMult,
jumpSurviveMissionTimeSec: jumpMissionSec,
jumpSurvivePlatformTiles,
spaceShooterMissionTimeSec: spaceShooterMissionSec,
spaceShooterShipImageUrls,
spaceShooterAsteroidSpriteUrls,
@@ -1865,6 +1930,27 @@ function normalizeJumpSurvivePlatformAreaOnMap(m) {
m.jumpSurvivePlatformArea = rows;
}
function normalizeJumpSurvivePlatformVariantAreaOnMap(m) {
if (!m || m.gameType !== 'jump_survive') return;
const w = m.width || 20, h = m.height || 15;
const pa = m.jumpSurvivePlatformArea || [];
const src = m.jumpSurvivePlatformVariantArea || [];
const rows = [];
for (let y = 0; y < h; y++) {
const row = [];
for (let x = 0; x < w; x++) {
const has = pa[y] && pa[y][x] === 1;
let v = has ? Math.floor(Number(src[y] && src[y][x])) : 0;
if (has && (!Number.isFinite(v) || v < 1)) v = 1;
if (v > 3) v = 3;
if (!has) v = 0;
row.push(v);
}
rows.push(row);
}
m.jumpSurvivePlatformVariantArea = rows;
}
function normalizeJumpSurviveHazardAreaOnMap(m) {
if (!m || m.gameType !== 'jump_survive') return;
const w = m.width || 20, h = m.height || 15;
@@ -1893,6 +1979,7 @@ function loadMaps() {
const data = JSON.parse(fs.readFileSync(path.join(MAPS_DIR, f), 'utf8'));
normalizeQuizCarryLayersOnMap(data);
normalizeJumpSurvivePlatformAreaOnMap(data);
normalizeJumpSurvivePlatformVariantAreaOnMap(data);
normalizeJumpSurviveHazardAreaOnMap(data);
normalizeQuizBattleDomeAreaOnMap(data);
normalizeQuizBattlePathAreaOnMap(data);
@@ -1974,9 +2061,11 @@ const server = http.createServer((req, res) => {
if (!m.stackLandArea) m.stackLandArea = [];
if (!Array.isArray(m.jumpSurvivePlatforms)) m.jumpSurvivePlatforms = [];
if (!m.jumpSurvivePlatformArea) m.jumpSurvivePlatformArea = [];
if (!m.jumpSurvivePlatformVariantArea) m.jumpSurvivePlatformVariantArea = [];
if (!m.jumpSurviveHazardArea) m.jumpSurviveHazardArea = [];
normalizeQuizCarryLayersOnMap(m);
normalizeJumpSurvivePlatformAreaOnMap(m);
normalizeJumpSurvivePlatformVariantAreaOnMap(m);
normalizeJumpSurviveHazardAreaOnMap(m);
normalizeQuizBattleDomeAreaOnMap(m);
normalizeQuizBattlePathAreaOnMap(m);
@@ -2016,9 +2105,11 @@ const server = http.createServer((req, res) => {
if (!m.stackLandArea) m.stackLandArea = [];
if (!Array.isArray(m.jumpSurvivePlatforms)) m.jumpSurvivePlatforms = [];
if (!m.jumpSurvivePlatformArea) m.jumpSurvivePlatformArea = [];
if (!m.jumpSurvivePlatformVariantArea) m.jumpSurvivePlatformVariantArea = [];
if (!m.jumpSurviveHazardArea) m.jumpSurviveHazardArea = [];
normalizeQuizCarryLayersOnMap(m);
normalizeJumpSurvivePlatformAreaOnMap(m);
normalizeJumpSurvivePlatformVariantAreaOnMap(m);
normalizeJumpSurviveHazardAreaOnMap(m);
normalizeQuizBattleDomeAreaOnMap(m);
normalizeQuizBattlePathAreaOnMap(m);