fix(play+editor): quiz_carry question on map panel in embed + optional Q zone
play: show quiz-map-question-panel in editor embed for quiz_carry only; bounds from quizQuestionArea when painted else hub; refactor tile bounds helper; init quizQuestionArea on join; draw gold Q tiles in play; strip hidden for carry editor: paint quizQuestion on quiz_carry, ensureQuizCarryAreas syncs quizQuestionArea, toggle draw mode + hints; editor.html help + cache v0.040 play.js v=0.093 Made-with: Cursor
This commit is contained in:
@@ -173,7 +173,7 @@
|
||||
<li><strong>พื้นที่สุ่มจุดเกิด</strong> (ฟ้าอ่อน) — ไม่วาดช่องนี้ได้ ใช้ปุ่ม «ตั้งจุดเกิด»</li>
|
||||
<li><strong>พื้นที่เริ่มเกม</strong> (ห้องโถง — ส้ม) — host ยืนแล้วกดเริ่ม</li>
|
||||
<li><strong>ถามตอบ</strong>: โซนถูก/ผิด + พื้นที่คำถาม (ทอง)</li>
|
||||
<li><strong>หยิบมาวาง</strong>: ม่วง = โชว์คำถาม (กำแพง) · <strong>interactive เขียว</strong> = ยืนแล้วกด F ส่งคำตอบ · สีต่าง ๆ = ตัวเลือก 1–16 · คำถามในแมป <code>quizQuestions</code> ใส่ <code>choices</code> + <code>correctIndex</code> หรือ <code>answerTrue</code></li>
|
||||
<li><strong>หยิบมาวาง</strong>: ม่วง = โซนกลาง (กำแพง) · <strong>ทอง</strong> = พื้นที่โชว์ข้อความคำถามบนแผนที่ (ถ้าไม่วาดทอง ข้อความไปที่โซนม่วง) · <strong>interactive เขียว</strong> = ยืนแล้วกด F ส่งคำตอบ · สี = ตัวเลือก 1–16 · <code>quizQuestions</code> ใส่ <code>choices</code> + <code>correctIndex</code> หรือ <code>answerTrue</code></li>
|
||||
<li><strong>Stack</strong>: โหมดวาดจุดปล่อย (ฟ้า) · จุดซ้อนตึก (ชมพู)</li>
|
||||
<li><strong>กระโดดให้รอด</strong>: โหมด <strong>แพลตฟอร์ม</strong> (ฟ้าอมเขียว) · กำแพง = ขอบซ้ายขวา/บน · Space / W = กระโดด</li>
|
||||
<li><strong>ลูกโป้งยิงบอส</strong>: จุดเกิดผู้เล่น P1–P6 + <strong>จุดเกิดบอส</strong> 1 ช่อง · ในเกมเดินช้า ยิงมีดีเลย์ · ลูกโป้งหมด = ตกรอบ</li>
|
||||
@@ -188,7 +188,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/version.js?v=0.0104"></script>
|
||||
<script src="js/editor.js?v=0.039"></script>
|
||||
<script src="js/editor.js?v=0.040"></script>
|
||||
<div class="version-tag">v —</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -203,6 +203,18 @@
|
||||
if (!quizCarryOptionArea[y] || quizCarryOptionArea[y].length !== width) quizCarryOptionArea[y] = Array(width).fill(0);
|
||||
}
|
||||
}
|
||||
if (!quizQuestionArea.length || quizQuestionArea.length !== height) {
|
||||
const existingQ = quizQuestionArea.slice().map(r => r && r.slice());
|
||||
quizQuestionArea = [];
|
||||
for (let y = 0; y < height; y++) {
|
||||
const row = existingQ[y] && existingQ[y].length === width ? existingQ[y].slice() : Array(width).fill(0);
|
||||
quizQuestionArea.push(row);
|
||||
}
|
||||
} else {
|
||||
for (let y = 0; y < height; y++) {
|
||||
if (!quizQuestionArea[y] || quizQuestionArea[y].length !== width) quizQuestionArea[y] = Array(width).fill(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ensureQuizBattleDomeArea() {
|
||||
@@ -450,7 +462,7 @@
|
||||
const gt = gameTypeEl ? gameTypeEl.value : 'zep';
|
||||
if (dqTrue) dqTrue.hidden = gt !== 'quiz';
|
||||
if (dqFalse) dqFalse.hidden = gt !== 'quiz';
|
||||
if (dqQ) dqQ.hidden = gt !== 'quiz';
|
||||
if (dqQ) dqQ.hidden = gt !== 'quiz' && gt !== 'quiz_carry';
|
||||
if (dqStackR) dqStackR.hidden = gt !== 'stack';
|
||||
if (dqStackL) dqStackL.hidden = gt !== 'stack';
|
||||
const showCarry = gt === 'quiz_carry';
|
||||
@@ -528,7 +540,8 @@
|
||||
froggerWrap.style.display = 'none';
|
||||
if (hint) {
|
||||
hint.innerHTML = '<p class="editor-hint-lead"><strong>หยิบมาวาง</strong> — หยิบตัวเลือกแล้วไปส่งที่โซน interactive (เขียว)</p>' + editorHintBulletList([
|
||||
'<strong>โซนกลาง (ม่วง)</strong> — แสดงคำถาม · ในเกมเป็นกำแพง (เดินเข้าไม่ได้)',
|
||||
'<strong>โซนกลาง (ม่วง)</strong> — กำแพง · ถ้าไม่วาดโซนทองด้านล่าง ข้อความคำถามจะโชว์บนโซนม่วงในเกม',
|
||||
'<strong>พื้นที่โชว์ข้อความคำถาม (ทอง)</strong> — วาดโซนทองแยกได้ · ในเกมข้อความจะอยู่ตรงโซนที่วาด',
|
||||
'<strong>โซน interactive (เขียว)</strong> — ยืนบนหรือชิดขอบแล้วกด <kbd>F</kbd> ส่งคำตอบ (วาดอย่างน้อย 1 ช่อง — ถ้าไม่วาดจะใช้ชิดโซนกลางแทน)',
|
||||
'<strong>ตัวเลือก 1–16</strong> — ตรงกับลำดับ <code>choices</code> ใน Admin หรือแมป',
|
||||
'เล่นพร้อมกันได้ · คำถามจากแมปหรือ Admin',
|
||||
@@ -645,7 +658,10 @@
|
||||
if (btnClrBb) btnClrBb.hidden = gt !== 'balloon_boss';
|
||||
if (drawModeEl && drawModeEl.value === 'balloonBossPlayerPaint' && gt !== 'balloon_boss') drawModeEl.value = 'wall';
|
||||
if (drawModeEl && drawModeEl.value === 'balloonBossBossPaint' && gt !== 'balloon_boss') drawModeEl.value = 'wall';
|
||||
if (drawModeEl && (drawModeEl.value === 'quizTrue' || drawModeEl.value === 'quizFalse' || drawModeEl.value === 'quizQuestion') && gt !== 'quiz') {
|
||||
if (drawModeEl && (drawModeEl.value === 'quizTrue' || drawModeEl.value === 'quizFalse') && gt !== 'quiz') {
|
||||
drawModeEl.value = 'wall';
|
||||
}
|
||||
if (drawModeEl && drawModeEl.value === 'quizQuestion' && gt !== 'quiz' && gt !== 'quiz_carry') {
|
||||
drawModeEl.value = 'wall';
|
||||
}
|
||||
if (drawModeEl && (drawModeEl.value === 'stackRelease' || drawModeEl.value === 'stackLand') && gt !== 'stack') {
|
||||
@@ -903,6 +919,19 @@
|
||||
ctx.textAlign = 'left';
|
||||
}
|
||||
if (gtDraw === 'quiz_carry') {
|
||||
if (quizQuestionArea[y] && quizQuestionArea[y][x] === 1) {
|
||||
ctx.fillStyle = 'rgba(255, 214, 102, 0.44)';
|
||||
ctx.fillRect(tx + 2, ty + 2, tileSize - 4, tileSize - 4);
|
||||
ctx.strokeStyle = 'rgba(224, 185, 70, 0.96)';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.strokeRect(tx + 2, ty + 2, tileSize - 4, tileSize - 4);
|
||||
ctx.lineWidth = 1;
|
||||
ctx.fillStyle = '#1a1b26';
|
||||
ctx.font = 'bold 9px sans-serif';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('Q', tx + tileSize / 2, ty + tileSize / 2 + 3);
|
||||
ctx.textAlign = 'left';
|
||||
}
|
||||
const ov = quizCarryOptionArea[y] && quizCarryOptionArea[y][x];
|
||||
if (quizCarryHubArea[y] && quizCarryHubArea[y][x] === 1) {
|
||||
ctx.fillStyle = 'rgba(187, 154, 247, 0.45)';
|
||||
@@ -1145,9 +1174,14 @@
|
||||
quizFalseArea[y][x] = left ? 1 : 0;
|
||||
if (left) quizTrueArea[y][x] = 0;
|
||||
} else if (drawModeEl.value === 'quizQuestion') {
|
||||
if ((gameTypeEl ? gameTypeEl.value : gameType) !== 'quiz') return;
|
||||
ensureQuizAreas();
|
||||
quizQuestionArea[y][x] = left ? 1 : 0;
|
||||
const gtq = gameTypeEl ? gameTypeEl.value : gameType;
|
||||
if (gtq === 'quiz') {
|
||||
ensureQuizAreas();
|
||||
quizQuestionArea[y][x] = left ? 1 : 0;
|
||||
} else if (gtq === 'quiz_carry') {
|
||||
ensureQuizCarryAreas();
|
||||
quizQuestionArea[y][x] = left ? 1 : 0;
|
||||
} else return;
|
||||
} else if (drawModeEl.value === 'stackRelease') {
|
||||
if ((gameTypeEl ? gameTypeEl.value : gameType) !== 'stack') return;
|
||||
ensureStackAreas();
|
||||
@@ -1324,7 +1358,8 @@
|
||||
gameType = gameTypeEl.value;
|
||||
if (drawModeEl && drawModeEl.value === 'startGame' && gameType !== 'lobby') drawModeEl.value = 'wall';
|
||||
if (drawModeEl && drawModeEl.value === 'spawnArea' && gameType === 'frogger') drawModeEl.value = 'wall';
|
||||
if (drawModeEl && (drawModeEl.value === 'quizTrue' || drawModeEl.value === 'quizFalse' || drawModeEl.value === 'quizQuestion') && gameType !== 'quiz') drawModeEl.value = 'wall';
|
||||
if (drawModeEl && (drawModeEl.value === 'quizTrue' || drawModeEl.value === 'quizFalse') && gameType !== 'quiz') drawModeEl.value = 'wall';
|
||||
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';
|
||||
|
||||
@@ -688,9 +688,7 @@
|
||||
window.__playQuizFeedbackT = setTimeout(() => { el.classList.add('is-hidden'); }, 4200);
|
||||
}
|
||||
|
||||
function getQuizQuestionAreaTileBounds(md) {
|
||||
if (!md || md.gameType !== 'quiz') return null;
|
||||
const grid = md.quizQuestionArea;
|
||||
function getTileBoundsForOnesGrid(grid) {
|
||||
if (!grid || !grid.length) return null;
|
||||
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
||||
for (let yy = 0; yy < grid.length; yy++) {
|
||||
@@ -709,12 +707,23 @@
|
||||
return { minX, minY, maxX, maxY };
|
||||
}
|
||||
|
||||
function getQuizQuestionAreaTileBounds(md) {
|
||||
if (!md || md.gameType !== 'quiz') return null;
|
||||
return getTileBoundsForOnesGrid(md.quizQuestionArea);
|
||||
}
|
||||
|
||||
/** quiz_carry: โซนทองพิเศษสำหรับข้อความคำถาม (ถ้าไม่วาด ใช้โซนกลางม่วงแทนใน syncPlayQuizMapPanel) */
|
||||
function getQuizCarryQuestionAreaTileBounds(md) {
|
||||
if (!md || md.gameType !== 'quiz_carry') return null;
|
||||
return getTileBoundsForOnesGrid(md.quizQuestionArea);
|
||||
}
|
||||
|
||||
function syncPlayQuizMapPanel() {
|
||||
const panel = document.getElementById('quiz-map-question-panel');
|
||||
const textEl = document.getElementById('quiz-map-question-text');
|
||||
if (!panel || !textEl || !mapData) return;
|
||||
/* เอดิเตอร์ embed: อย่าวางแผงคำถามทับกลางจอ (quiz / quiz_carry ใช้กรอบทองนี้) — บังมองและรู้สึกเหมือนค้าง */
|
||||
if (previewMode && editorEmbedReturn) {
|
||||
/* เอดิเตอร์ embed: ซ่อนแผงทองเฉพาะโหมด quiz (ทับกลาง) — quiz_carry ต้องโชว์ตามโซนที่วาดบนแผนที่ */
|
||||
if (previewMode && editorEmbedReturn && !isQuizCarry()) {
|
||||
panel.classList.add('is-hidden');
|
||||
panel.setAttribute('aria-hidden', 'true');
|
||||
return;
|
||||
@@ -727,7 +736,7 @@
|
||||
if (!isQuiz() && !isQuizCarry()) return;
|
||||
const bounds = isQuiz()
|
||||
? getQuizQuestionAreaTileBounds(mapData)
|
||||
: getQuizCarryHubTileBounds(mapData);
|
||||
: (getQuizCarryQuestionAreaTileBounds(mapData) || getQuizCarryHubTileBounds(mapData));
|
||||
const text = (playQuizText || '').trim();
|
||||
if (!bounds || !text) {
|
||||
panel.classList.add('is-hidden');
|
||||
@@ -749,41 +758,14 @@
|
||||
panel.setAttribute('aria-hidden', 'false');
|
||||
}
|
||||
|
||||
/** เอดิเตอร์ embed quiz_carry: แผงทองทับกลางถูกปิด — แสดงคำถามแถบล่างแทน (ไม่บังจอ) */
|
||||
/** quiz_carry + embed: คำถามไปที่แผงทองบนแผนที่ / ใน overlay นับถอยหลัง — ไม่ใช้แถบบน */
|
||||
function syncQuizCarryEmbedQuestionStrip() {
|
||||
const wrap = document.getElementById('quiz-carry-embed-q-strip');
|
||||
const p = document.getElementById('quiz-carry-embed-q-strip-text');
|
||||
if (!wrap || !p) return;
|
||||
if (!(previewMode && editorEmbedReturn && isQuizCarry())) {
|
||||
wrap.classList.remove('quiz-carry-embed-q-strip--countdown');
|
||||
wrap.classList.add('is-hidden');
|
||||
wrap.setAttribute('aria-hidden', 'true');
|
||||
return;
|
||||
}
|
||||
const blocking = isQuizCarryEmbedCountdownBlockingMovement();
|
||||
const pending = quizCarryEmbedPendingQuestion;
|
||||
let t = '';
|
||||
if (blocking && pending) {
|
||||
t = formatQuizCarryQuestionHud(pending);
|
||||
if (t) wrap.classList.add('quiz-carry-embed-q-strip--countdown');
|
||||
else wrap.classList.remove('quiz-carry-embed-q-strip--countdown');
|
||||
} else if (blocking) {
|
||||
wrap.classList.remove('quiz-carry-embed-q-strip--countdown');
|
||||
wrap.classList.add('is-hidden');
|
||||
wrap.setAttribute('aria-hidden', 'true');
|
||||
return;
|
||||
} else {
|
||||
wrap.classList.remove('quiz-carry-embed-q-strip--countdown');
|
||||
t = (playQuizText || '').trim();
|
||||
}
|
||||
if (!t) {
|
||||
wrap.classList.add('is-hidden');
|
||||
wrap.setAttribute('aria-hidden', 'true');
|
||||
return;
|
||||
}
|
||||
p.textContent = t;
|
||||
wrap.classList.remove('is-hidden');
|
||||
wrap.setAttribute('aria-hidden', 'false');
|
||||
wrap.classList.remove('quiz-carry-embed-q-strip--countdown');
|
||||
wrap.classList.add('is-hidden');
|
||||
wrap.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
|
||||
function updatePlayQuizTimerDisplay() {
|
||||
@@ -5027,6 +5009,7 @@
|
||||
if (!mapData.quizCarryHubArea) mapData.quizCarryHubArea = [];
|
||||
if (!mapData.quizCarryOptionArea) mapData.quizCarryOptionArea = [];
|
||||
if (!mapData.quizQuestions) mapData.quizQuestions = [];
|
||||
if (!mapData.quizQuestionArea) mapData.quizQuestionArea = [];
|
||||
normalizeQuizCarryLayersInPlay(mapData);
|
||||
}
|
||||
if (mapData.gameType === 'quiz_battle') {
|
||||
@@ -6944,6 +6927,13 @@
|
||||
ctx.strokeStyle = 'rgba(200, 170, 255, 0.75)';
|
||||
ctx.strokeRect(sx + 2, sy + 2, size - 4, size - 4);
|
||||
}
|
||||
const isCarryQ = mapData.quizQuestionArea && mapData.quizQuestionArea[y] && mapData.quizQuestionArea[y][x] === 1;
|
||||
if (isCarryQ) {
|
||||
ctx.fillStyle = 'rgba(255, 214, 102, 0.3)';
|
||||
ctx.fillRect(sx + 2, sy + 2, size - 4, size - 4);
|
||||
ctx.strokeStyle = 'rgba(224, 185, 70, 0.82)';
|
||||
ctx.strokeRect(sx + 2, sy + 2, size - 4, size - 4);
|
||||
}
|
||||
const ov = mapData.quizCarryOptionArea && mapData.quizCarryOptionArea[y] && mapData.quizCarryOptionArea[y][x];
|
||||
if (ov >= 1 && ov <= QUIZ_CARRY_MAX_OPTION_SLOTS) {
|
||||
ctx.fillStyle = quizCarryMinimapOptionFillCss(ov);
|
||||
|
||||
@@ -765,7 +765,7 @@
|
||||
</div>
|
||||
<script src="/Game/socket.io/socket.io.js"></script>
|
||||
<script src="js/version.js?v=0.0166"></script>
|
||||
<script src="js/play.js?v=0.091"></script>
|
||||
<script src="js/play.js?v=0.093"></script>
|
||||
<div class="version-tag">v —</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user