diff --git a/www/html/Game/public/js/play.js b/www/html/Game/public/js/play.js index 8fad99b..d68412e 100644 --- a/www/html/Game/public/js/play.js +++ b/www/html/Game/public/js/play.js @@ -29,6 +29,8 @@ const QUIZ_QUESTION_MISSION_MAP_ID = 'mng8a80o'; /** Stack ซ้อนตึก — ฉากภารกิจ (HOWTO → นับถอยหลัง → เล่น → สรุป) รูปใน `/Game/img/TowerBlock` */ const STACK_TOWER_MISSION_MAP_ID = 'mnn93hpi'; + /** ครบชั้นนี้ขึ้นไป — ยกจุดแกว่ง/เชือกขึ้น (world px) ป้องกันชนกองสูง (เฉพาะ Tower mission) */ + const STACK_TOWER_SWING_LIFT_FROM_LAYER = 9; /** Violent Crime mission: asteroid strikes ship → invuln → 3 strikes = eliminated */ const SPACE_SHOOTER_MISSION_MAX_ASTEROID_HITS = 3; const SPACE_SHOOTER_MISSION_HIT_INVULN_MS = 1400; @@ -6553,6 +6555,16 @@ return { enabled: raw.enabled !== false, pxPerLayer, maxPx }; } + /** ยกจุดยึดเชือกขึ้นเมื่อหอสูง (y ลดลง = สูงขึ้นในโลก) — เฉพาะ mnn93hpi */ + function getStackTowerSwingLiftWorldPx(layerCount, layerWorldHPx) { + if (!isStackTowerMissionUiMapPlay()) return 0; + const n = Math.floor(Number(layerCount) || 0); + if (n < STACK_TOWER_SWING_LIFT_FROM_LAYER) return 0; + const lh = Math.max(10, Number(layerWorldHPx) || Math.max(14, (tileSize || 32) * 0.3)); + const tiers = n - (STACK_TOWER_SWING_LIFT_FROM_LAYER - 1); + return Math.min(lh * 20, tiers * lh * 0.98); + } + /** world px ตามความสูงหอ (mnn93hpi) — ใช้เลื่อนกล้องให้บล็อก/ฉากไปกับมุมมอง */ function getStackTowerBgScrollHeightBoostPx() { if (!isStackTowerMissionUiMapPlay() || !stackMini) return 0; @@ -6863,29 +6875,31 @@ const tw = m.widthTiles * tileSize; const swingXW = (m.topCenterX + m.swingAmp * Math.sin(m.phase)) * tileSize; const lh = m.layerWorldH || Math.max(14, tileSize * 0.3); + const swingLift = getStackTowerSwingLiftWorldPx(m.layers.length, lh); + const swingAttachY = m.swingWorldY - swingLift; let y1 = m.floorWorldY - (m.layers.length + 1) * lh; - if (y1 <= m.swingWorldY) y1 = m.swingWorldY + lh * 0.55; + if (y1 <= swingAttachY) y1 = swingAttachY + lh * 0.55; const landOff = hit.landOffsetTiles || 0; const landCxWorld = (m.topCenterX + landOff) * tileSize; const xLeft0 = swingXW - tw / 2; const xLeft1 = landCxWorld - tw / 2; const offN = Math.min(1, Math.abs(landOff) / Math.max(0.01, m.swingAmp)); - const dur = Math.max(400, Math.min(1280, 240 + (y1 - m.swingWorldY) * 0.92 + offN * 560)); + const dur = Math.max(400, Math.min(1280, 240 + (y1 - swingAttachY) * 0.92 + offN * 560)); const tiltMax = hit.miss ? 0.28 * (0.25 + offN) : 0.16 * offN * (hit.perfect ? 0.1 : 1); const isHumanPreview = !!(previewActor && previewActor.human); const botIdPreview = previewActor && previewActor.botId ? previewActor.botId : null; - const cableTopYRel = Math.max(0, m.swingWorldY - tileSize * 6); + const cableTopYRel = Math.max(0, swingAttachY - tileSize * 6); const craneXRel = m.craneWorldX != null ? m.craneWorldX : m.topCenterX * tileSize; - const releaseRopeAng = Math.atan2(m.swingWorldY - cableTopYRel, swingXW - craneXRel); + const releaseRopeAng = Math.atan2(swingAttachY - cableTopYRel, swingXW - craneXRel); stackFall = { t0: performance.now(), dur, xLeft0, xLeft1, tw, - y0: m.swingWorldY, + y0: swingAttachY, y1, hit, tiltMax, @@ -6894,7 +6908,7 @@ previewBotId: botIdPreview, releaseRopeAng, releaseAttachWorldX: swingXW, - releaseAttachWorldY: m.swingWorldY, + releaseAttachWorldY: swingAttachY, }; return true; } @@ -7060,7 +7074,9 @@ const layerWorldH = m.layerWorldH || Math.max(14, tileSize * 0.3); const stripH = m.blockStripH || Math.max(16, tileSize * 0.32); const floorY = m.floorWorldY; - const guideTopY = Math.max(0, m.swingWorldY - tileSize * 6.5); + const swingLiftDraw = getStackTowerSwingLiftWorldPx(m.layers.length, layerWorldH); + const swingDrawY = m.swingWorldY - swingLiftDraw; + const guideTopY = Math.max(0, swingDrawY - tileSize * 6.5); const [gtx, gty] = worldToScreen(m.topCenterX * tileSize, guideTopY); const [gbx, gby] = worldToScreen(m.topCenterX * tileSize, floorY); ctx.strokeStyle = 'rgba(255,255,255,0.22)'; @@ -7116,7 +7132,7 @@ } else { const twWorld = m.widthTiles * tileSize; const drawStripPx = stripH * zoom; - const cableTopY = Math.max(0, m.swingWorldY - tileSize * 6); + const cableTopY = Math.max(0, swingDrawY - tileSize * 6); const craneX = m.craneWorldX != null ? m.craneWorldX : m.topCenterX * tileSize; let blockLeftWorld; let blockTopWorld; @@ -7131,7 +7147,7 @@ } else { const swingXW = (m.topCenterX + m.swingAmp * Math.sin(m.phase)) * tileSize; blockLeftWorld = swingXW - twWorld / 2; - blockTopWorld = m.swingWorldY; + blockTopWorld = swingDrawY; } const cxMid = blockLeftWorld + twWorld / 2; const [tcx, tcy] = worldToScreen(craneX, cableTopY); diff --git a/www/html/Game/public/play.html b/www/html/Game/public/play.html index 07ac273..af9f0b4 100644 --- a/www/html/Game/public/play.html +++ b/www/html/Game/public/play.html @@ -2009,7 +2009,7 @@ - +
v —