update card system
@@ -572,6 +572,182 @@ legend {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* —— Tab group dividers (จัดหมวดเมนูให้สแกนง่าย) —— */
|
||||
.admin-tab-sep {
|
||||
flex: 1 1 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
margin: 0.35rem 0.15rem 0;
|
||||
padding: 0 0.15rem;
|
||||
user-select: none;
|
||||
}
|
||||
.admin-tab-sep:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.admin-tab-sep span {
|
||||
font-size: 0.66rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.09em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.admin-tab-sep::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, var(--border), transparent);
|
||||
}
|
||||
@media (max-width: 899px) {
|
||||
/* มือถือ: แถบเลื่อนแนวนอน — ไม่ต้องแสดงหัวข้อกลุ่ม */
|
||||
.admin-tab-sep { display: none; }
|
||||
}
|
||||
|
||||
/* —— ชุดคำถามพิเศษ (Special Quiz panel) —— */
|
||||
.sq-title { margin: 0 0 0.35rem; }
|
||||
.sq-steps {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.6rem;
|
||||
margin: 0.9rem 0 1.1rem;
|
||||
padding: 0;
|
||||
}
|
||||
.sq-steps li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex: 1 1 220px;
|
||||
padding: 0.55rem 0.8rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
.sq-step-no {
|
||||
flex: 0 0 auto;
|
||||
width: 1.65rem;
|
||||
height: 1.65rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background: var(--accent-dim);
|
||||
color: var(--accent);
|
||||
font-weight: 700;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.sq-fieldset {
|
||||
margin: 0 0 1.1rem;
|
||||
padding: 0.95rem 1.1rem 1.1rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--bg-elevated, rgba(255, 255, 255, 0.02));
|
||||
}
|
||||
.sq-fieldset > legend {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
padding: 0 0.45rem;
|
||||
color: var(--text);
|
||||
}
|
||||
.sq-pick-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.sq-select { min-width: 200px; }
|
||||
.sq-set-tag {
|
||||
margin-left: auto;
|
||||
align-self: center;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
background: var(--accent-dim);
|
||||
padding: 0.3rem 0.7rem;
|
||||
border-radius: 999px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.sq-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 0.85rem;
|
||||
}
|
||||
.sq-card-grid .sq-card-url { grid-column: 1 / -1; }
|
||||
.sq-card-grid input,
|
||||
.sq-card-grid select { width: 100%; }
|
||||
.sq-count {
|
||||
font-weight: 400;
|
||||
font-size: 0.8rem;
|
||||
color: var(--muted);
|
||||
margin-left: 0.3rem;
|
||||
}
|
||||
|
||||
/* —— คำถามตัวเลือก A/B/C/D (Special Quiz MCQ rows) —— */
|
||||
.sq-mcq-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.7rem;
|
||||
padding: 0.85rem 0.95rem;
|
||||
margin-bottom: 0.85rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
.sq-mcq-q {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
color: var(--muted);
|
||||
}
|
||||
.sq-mcq-text { width: 100%; }
|
||||
.sq-mcq-choices {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.55rem;
|
||||
}
|
||||
.sq-mcq-choice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.sq-mcq-letter {
|
||||
flex: 0 0 auto;
|
||||
width: 1.7rem;
|
||||
height: 1.7rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
background: var(--accent-dim);
|
||||
color: var(--accent);
|
||||
font-weight: 700;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.sq-mcq-choice-input { flex: 1 1 auto; min-width: 0; }
|
||||
.sq-mcq-foot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.sq-mcq-ans {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
}
|
||||
.sq-mcq-correct { min-width: 5rem; }
|
||||
@media (max-width: 620px) {
|
||||
.sq-mcq-choices { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.tab-panel[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -246,6 +246,189 @@
|
||||
});
|
||||
}
|
||||
|
||||
/* ===== ชุดคำถามพิเศษ (Level×Case = 15 ชุด) รับการ์ดพิเศษ ===== */
|
||||
var SPECIAL_CARD_RARITIES = ['common', 'rare', 'legendary'];
|
||||
var specialQuizSetsState = {};
|
||||
var specialQuizCurrentKey = 'L1_C1';
|
||||
|
||||
function specialQuizSelectorKey() {
|
||||
var L = el('special-quiz-level');
|
||||
var C = el('special-quiz-case');
|
||||
return 'L' + ((L && L.value) || '1') + '_C' + ((C && C.value) || '1');
|
||||
}
|
||||
|
||||
function updateSpecialQuizCount() {
|
||||
var c = el('special-quiz-count');
|
||||
if (!c) return;
|
||||
var n = document.querySelectorAll('#special-quiz-questions-list .quiz-admin-q-row').length;
|
||||
c.textContent = '(' + n + ' ข้อ)';
|
||||
}
|
||||
|
||||
var SPECIAL_QUIZ_CHOICE_COUNT = 4;
|
||||
var SPECIAL_QUIZ_LETTERS = ['A', 'B', 'C', 'D', 'E', 'F'];
|
||||
|
||||
/** คำถามตัวเลือก A/B/C/D — เลือกคำตอบถูก 1 ข้อ */
|
||||
function addSpecialQuizRow(q) {
|
||||
q = q || {};
|
||||
var list = el('special-quiz-questions-list');
|
||||
if (!list) return;
|
||||
var choices = Array.isArray(q.choices) ? q.choices : [];
|
||||
var correctIndex = Number(q.correctIndex);
|
||||
if (!(correctIndex >= 0 && correctIndex < SPECIAL_QUIZ_CHOICE_COUNT)) correctIndex = 0;
|
||||
|
||||
var row = document.createElement('div');
|
||||
row.className = 'quiz-admin-q-row sq-mcq-row';
|
||||
|
||||
var qLab = document.createElement('label');
|
||||
qLab.className = 'sq-mcq-q';
|
||||
qLab.appendChild(document.createTextNode('คำถาม'));
|
||||
var qInp = document.createElement('input');
|
||||
qInp.type = 'text';
|
||||
qInp.className = 'sq-mcq-text';
|
||||
qInp.maxLength = 500;
|
||||
qInp.placeholder = 'พิมพ์คำถาม...';
|
||||
qInp.value = q.text || '';
|
||||
qLab.appendChild(qInp);
|
||||
|
||||
var grid = document.createElement('div');
|
||||
grid.className = 'sq-mcq-choices';
|
||||
for (var i = 0; i < SPECIAL_QUIZ_CHOICE_COUNT; i++) {
|
||||
var cl = document.createElement('label');
|
||||
cl.className = 'sq-mcq-choice';
|
||||
var badge = document.createElement('span');
|
||||
badge.className = 'sq-mcq-letter';
|
||||
badge.textContent = SPECIAL_QUIZ_LETTERS[i];
|
||||
var ci = document.createElement('input');
|
||||
ci.type = 'text';
|
||||
ci.className = 'sq-mcq-choice-input';
|
||||
ci.maxLength = 200;
|
||||
ci.placeholder = 'ตัวเลือก ' + SPECIAL_QUIZ_LETTERS[i];
|
||||
ci.value = choices[i] || '';
|
||||
ci.setAttribute('data-choice-index', String(i));
|
||||
cl.appendChild(badge);
|
||||
cl.appendChild(ci);
|
||||
grid.appendChild(cl);
|
||||
}
|
||||
|
||||
var foot = document.createElement('div');
|
||||
foot.className = 'sq-mcq-foot';
|
||||
var ansLab = document.createElement('label');
|
||||
ansLab.className = 'sq-mcq-ans';
|
||||
ansLab.appendChild(document.createTextNode('คำตอบที่ถูก '));
|
||||
var ansSel = document.createElement('select');
|
||||
ansSel.className = 'sq-mcq-correct';
|
||||
for (var j = 0; j < SPECIAL_QUIZ_CHOICE_COUNT; j++) {
|
||||
var o = document.createElement('option');
|
||||
o.value = String(j);
|
||||
o.textContent = SPECIAL_QUIZ_LETTERS[j];
|
||||
if (j === correctIndex) o.selected = true;
|
||||
ansSel.appendChild(o);
|
||||
}
|
||||
ansLab.appendChild(ansSel);
|
||||
|
||||
var rm = document.createElement('button');
|
||||
rm.type = 'button';
|
||||
rm.className = 'btn btn-danger btn-sm quiz-admin-q-remove';
|
||||
rm.setAttribute('aria-label', 'ลบข้อนี้');
|
||||
rm.textContent = 'ลบ';
|
||||
rm.addEventListener('click', function () {
|
||||
row.remove();
|
||||
updateSpecialQuizCount();
|
||||
});
|
||||
foot.appendChild(ansLab);
|
||||
foot.appendChild(rm);
|
||||
|
||||
row.appendChild(qLab);
|
||||
row.appendChild(grid);
|
||||
row.appendChild(foot);
|
||||
list.appendChild(row);
|
||||
}
|
||||
|
||||
function renderSpecialQuizSet(key) {
|
||||
var set = specialQuizSetsState[key] || { questions: [], specialCard: {} };
|
||||
var card = (set.specialCard && typeof set.specialCard === 'object') ? set.specialCard : {};
|
||||
if (el('special-card-th')) el('special-card-th').value = card.th || '';
|
||||
if (el('special-card-en')) el('special-card-en').value = card.en || '';
|
||||
if (el('special-card-rarity')) {
|
||||
el('special-card-rarity').value = SPECIAL_CARD_RARITIES.indexOf(card.rarity) >= 0 ? card.rarity : 'rare';
|
||||
}
|
||||
if (el('special-card-image')) el('special-card-image').value = card.imageUrl || '';
|
||||
var list = el('special-quiz-questions-list');
|
||||
if (list) {
|
||||
list.innerHTML = '';
|
||||
var qs = (set.questions && set.questions.length)
|
||||
? set.questions
|
||||
: [{ type: 'mcq', text: '', choices: ['', '', '', ''], correctIndex: 0 }];
|
||||
qs.forEach(addSpecialQuizRow);
|
||||
}
|
||||
var tag = el('special-quiz-set-tag');
|
||||
if (tag) tag.textContent = 'ชุดที่แก้: ' + key;
|
||||
updateSpecialQuizCount();
|
||||
}
|
||||
|
||||
function captureSpecialQuizForm(key) {
|
||||
var questions = [];
|
||||
document.querySelectorAll('#special-quiz-questions-list .sq-mcq-row').forEach(function (row) {
|
||||
var inp = row.querySelector('.sq-mcq-text');
|
||||
var t = inp && inp.value ? String(inp.value).trim() : '';
|
||||
if (!t) return;
|
||||
var choices = [];
|
||||
row.querySelectorAll('.sq-mcq-choice-input').forEach(function (ci) {
|
||||
choices.push(String(ci.value || '').trim());
|
||||
});
|
||||
if (choices.filter(function (c) { return c; }).length < 2) return;
|
||||
var sel = row.querySelector('.sq-mcq-correct');
|
||||
var correctIndex = sel ? parseInt(sel.value, 10) : 0;
|
||||
if (!(correctIndex >= 0 && correctIndex < choices.length) || !choices[correctIndex]) {
|
||||
correctIndex = choices.findIndex(function (c) { return c; });
|
||||
if (correctIndex < 0) correctIndex = 0;
|
||||
}
|
||||
questions.push({ type: 'mcq', text: t, choices: choices, correctIndex: correctIndex });
|
||||
});
|
||||
var rar = el('special-card-rarity') ? el('special-card-rarity').value : 'rare';
|
||||
specialQuizSetsState[key] = {
|
||||
questions: questions,
|
||||
specialCard: {
|
||||
th: el('special-card-th') ? String(el('special-card-th').value || '').trim() : '',
|
||||
en: el('special-card-en') ? String(el('special-card-en').value || '').trim() : '',
|
||||
rarity: SPECIAL_CARD_RARITIES.indexOf(rar) >= 0 ? rar : 'rare',
|
||||
imageUrl: el('special-card-image') ? String(el('special-card-image').value || '').trim() : '',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function onSpecialQuizSelectorChange() {
|
||||
captureSpecialQuizForm(specialQuizCurrentKey);
|
||||
specialQuizCurrentKey = specialQuizSelectorKey();
|
||||
renderSpecialQuizSet(specialQuizCurrentKey);
|
||||
}
|
||||
|
||||
function loadSpecialQuizPanel() {
|
||||
setMsg('special-quiz-msg', 'กำลังโหลด...', '');
|
||||
gameQuizFetch('GET').then(function (data) {
|
||||
specialQuizSetsState = (data.specialQuizSets && typeof data.specialQuizSets === 'object') ? data.specialQuizSets : {};
|
||||
specialQuizCurrentKey = specialQuizSelectorKey();
|
||||
renderSpecialQuizSet(specialQuizCurrentKey);
|
||||
setMsg('special-quiz-msg', '', '');
|
||||
}).catch(function (e) {
|
||||
setMsg('special-quiz-msg', e.message || 'โหลดไม่ได้', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
function saveSpecialQuizPanel() {
|
||||
captureSpecialQuizForm(specialQuizCurrentKey);
|
||||
setMsg('special-quiz-msg', 'กำลังบันทึก...', '');
|
||||
gameQuizFetch('PUT', { specialQuizSets: specialQuizSetsState }).then(function (res) {
|
||||
if (res && res.specialQuizSets && typeof res.specialQuizSets === 'object') {
|
||||
specialQuizSetsState = res.specialQuizSets;
|
||||
}
|
||||
setMsg('special-quiz-msg', 'บันทึกแล้ว (15 ชุด)', 'ok');
|
||||
renderSpecialQuizSet(specialQuizCurrentKey);
|
||||
}).catch(function (e) {
|
||||
setMsg('special-quiz-msg', e.message || 'บันทึกไม่ได้', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
function quizTfThemeHiddenId(kind) {
|
||||
if (kind === 'bg') return 'quiz-tf-theme-bg';
|
||||
if (kind === 'border') return 'quiz-tf-theme-border';
|
||||
@@ -3740,6 +3923,7 @@
|
||||
}
|
||||
});
|
||||
if (name === 'quiz') loadQuizSettingsPanel();
|
||||
if (name === 'special-quiz') loadSpecialQuizPanel();
|
||||
if (name === 'quiz-carry') loadQuizCarryPanel();
|
||||
if (name === 'quiz-battle') loadQbBattlePanel();
|
||||
if (name === 'jump-survive') loadJumpSurviveTimingPanel();
|
||||
@@ -3935,6 +4119,20 @@
|
||||
}
|
||||
if (btnQuizSave) btnQuizSave.addEventListener('click', saveQuizSettingsPanel);
|
||||
|
||||
var btnSpecialQuizAdd = el('btn-special-quiz-add');
|
||||
var btnSpecialQuizSave = el('btn-special-quiz-save');
|
||||
if (btnSpecialQuizAdd) {
|
||||
btnSpecialQuizAdd.addEventListener('click', function () {
|
||||
addSpecialQuizRow({ type: 'tf', text: '', answerTrue: true });
|
||||
updateSpecialQuizCount();
|
||||
});
|
||||
}
|
||||
if (btnSpecialQuizSave) btnSpecialQuizSave.addEventListener('click', saveSpecialQuizPanel);
|
||||
var specialQuizLevelSel = el('special-quiz-level');
|
||||
var specialQuizCaseSel = el('special-quiz-case');
|
||||
if (specialQuizLevelSel) specialQuizLevelSel.addEventListener('change', onSpecialQuizSelectorChange);
|
||||
if (specialQuizCaseSel) specialQuizCaseSel.addEventListener('change', onSpecialQuizSelectorChange);
|
||||
|
||||
var btnQuizCarryAdd = el('btn-quiz-carry-add');
|
||||
var btnQuizCarrySave = el('btn-quiz-carry-save');
|
||||
if (btnQuizCarryAdd) {
|
||||
@@ -4228,7 +4426,7 @@
|
||||
try {
|
||||
want = new URL(window.location.href).searchParams.get('tab');
|
||||
} catch (e) { /* ignore */ }
|
||||
var allowed = { 'change-password': true, oauth: true, 'map-editor': true, quiz: true, 'quiz-carry': true, 'quiz-battle': true, 'jump-survive': true, 'space-shooter': true, 'mega-virus': true, 'game-timing': true, 'stack-game': true, characters: true, accounts: true, admins: true };
|
||||
var allowed = { 'change-password': true, oauth: true, 'map-editor': true, quiz: true, 'special-quiz': true, 'quiz-carry': true, 'quiz-battle': true, 'jump-survive': true, 'space-shooter': true, 'mega-virus': true, 'game-timing': true, 'stack-game': true, characters: true, accounts: true, admins: true };
|
||||
if (!want || !allowed[want]) return 'oauth';
|
||||
if (want === 'admins' && (!admin || admin.role !== 'super')) return 'oauth';
|
||||
return want;
|
||||
|
||||
@@ -52,7 +52,7 @@ function merge_quiz_settings_disk_from_put(string $rawBody): bool
|
||||
if ($hadFileButInvalidJson) {
|
||||
return false;
|
||||
}
|
||||
$mergeKeys = ['readMs', 'answerMs', 'betweenMs', 'carryReadMs', 'carryAnswerMs', 'carrySessionLength', 'carryMapPanelTheme', 'quizMapPanelTheme', 'carryEmbedCountdownTheme', 'carryChoicePlaqueTheme', 'carryChoicePlaqueThemes', 'carryChoicePlaqueMapScale', 'carryWalkSpeedMultForMapId', 'carryWalkSpeedMult', 'quizRoundQuestionCount', 'questions', 'carryQuestions', 'battleQuizMcq'];
|
||||
$mergeKeys = ['readMs', 'answerMs', 'betweenMs', 'carryReadMs', 'carryAnswerMs', 'carrySessionLength', 'carryMapPanelTheme', 'quizMapPanelTheme', 'carryEmbedCountdownTheme', 'carryChoicePlaqueTheme', 'carryChoicePlaqueThemes', 'carryChoicePlaqueMapScale', 'carryWalkSpeedMultForMapId', 'carryWalkSpeedMult', 'quizRoundQuestionCount', 'questions', 'carryQuestions', 'battleQuizMcq', 'specialQuizSets'];
|
||||
foreach ($mergeKeys as $k) {
|
||||
if (array_key_exists($k, $patch)) {
|
||||
$base[$k] = $patch[$k];
|
||||
@@ -96,6 +96,9 @@ function overlay_quiz_settings_from_disk(string $nodeBody): string
|
||||
if (array_key_exists('battleQuizMcq', $disk)) {
|
||||
$j['battleQuizMcq'] = $disk['battleQuizMcq'];
|
||||
}
|
||||
if (array_key_exists('specialQuizSets', $disk) && is_array($disk['specialQuizSets'])) {
|
||||
$j['specialQuizSets'] = $disk['specialQuizSets'];
|
||||
}
|
||||
if (array_key_exists('carryMapPanelTheme', $disk) && is_array($disk['carryMapPanelTheme'])) {
|
||||
$j['carryMapPanelTheme'] = $disk['carryMapPanelTheme'];
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Kanit:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="admin.css?v=31">
|
||||
<link rel="stylesheet" href="admin.css?v=33">
|
||||
</head>
|
||||
<body>
|
||||
<a class="skip-link" href="#admin-main">ข้ามไปเนื้อหา</a>
|
||||
@@ -66,9 +66,12 @@
|
||||
|
||||
<div id="panel-app" class="admin-app" hidden>
|
||||
<nav class="admin-tabs" role="tablist" aria-label="เมนูหลัก Admin">
|
||||
<button type="button" class="tab" data-tab="change-password" role="tab" id="tab-change-password" aria-selected="false" aria-controls="tab-panel-change-password"><span class="tab-label">รหัสผ่าน</span><span class="tab-desc tab-desc--wide">เปลี่ยนรหัสของคุณ · กดซ้ำเพื่อปิด</span></button>
|
||||
<div class="admin-tab-sep" aria-hidden="true"><span>ทั่วไป & ฉาก</span></div>
|
||||
<button type="button" class="tab is-active" data-tab="oauth" role="tab" id="tab-oauth" aria-selected="true" aria-controls="tab-panel-oauth"><span class="tab-label">OAuth</span><span class="tab-desc">Facebook / Google</span></button>
|
||||
<button type="button" class="tab" data-tab="map-editor" role="tab" id="tab-map-editor" aria-controls="tab-panel-map-editor"><span class="tab-label">Editor</span><span class="tab-desc">แผนที่ฉาก</span></button>
|
||||
<button type="button" class="tab" data-tab="map-editor" role="tab" id="tab-map-editor" aria-controls="tab-panel-map-editor"><span class="tab-label">Editor ฉาก</span><span class="tab-desc">แผนที่ฉาก / โซนเกม</span></button>
|
||||
<button type="button" class="tab" data-tab="change-password" role="tab" id="tab-change-password" aria-selected="false" aria-controls="tab-panel-change-password"><span class="tab-label">รหัสผ่าน</span><span class="tab-desc tab-desc--wide">เปลี่ยนรหัสของคุณ · กดซ้ำเพื่อปิด</span></button>
|
||||
|
||||
<div class="admin-tab-sep" aria-hidden="true"><span>มินิเกม</span></div>
|
||||
<button type="button" class="tab" data-tab="quiz" role="tab" id="tab-quiz" aria-controls="tab-panel-quiz"><span class="tab-heading-row"><img class="tab-heading-icon" src="/Game/img/QUESTION/admin-tab-minigame-1.png" width="22" height="22" alt="" decoding="async"><span class="tab-label">Minigame-1-จริงหรือไม่</span></span><span class="tab-desc" aria-hidden="true"></span></button>
|
||||
<button type="button" class="tab" data-tab="game-timing" role="tab" id="tab-game-timing" aria-controls="tab-panel-game-timing"><span class="tab-heading-row"><img class="tab-heading-icon" src="/Game/img/gauntlet-assets/gauntlet-dd51baed17270995.png" width="22" height="22" alt="" decoding="async"><span class="tab-label">Minigame-2-วิ่งหลบสิ่งกีดขวาง</span></span><span class="tab-desc" aria-hidden="true"></span></button>
|
||||
<button type="button" class="tab" data-tab="stack-game" role="tab" id="tab-stack-game" aria-controls="tab-panel-stack-game"><span class="tab-heading-row"><img class="tab-heading-icon tab-heading-icon--stack-tab" src="/Game/img/TowerBlock/admin-tab-minigame-3.png" width="48" height="18" alt="" decoding="async"><span class="tab-label">Minigame-3-Tower block</span></span><span class="tab-desc" aria-hidden="true"></span></button>
|
||||
@@ -77,6 +80,11 @@
|
||||
<button type="button" class="tab" data-tab="jump-survive" role="tab" id="tab-jump-survive" aria-controls="tab-panel-jump-survive"><span class="tab-heading-row"><img class="tab-heading-icon" src="/Game/img/Jumper/admin-tab-minigame-5.png" width="22" height="22" alt="" decoding="async"><span class="tab-label">Minigame-5-กระโดดขึ้นแท่น</span></span><span class="tab-desc" aria-hidden="true"></span></button>
|
||||
<button type="button" class="tab" data-tab="space-shooter" role="tab" id="tab-space-shooter" aria-controls="tab-panel-space-shooter"><span class="tab-heading-row"><img class="tab-heading-icon" src="/Game/img/ViolentCrime/Meteo-1.png" width="22" height="22" alt="" decoding="async"><span class="tab-label">Minigame-6-ยิงอุกาบาต Violent Crime</span></span><span class="tab-desc" aria-hidden="true"></span></button>
|
||||
<button type="button" class="tab" data-tab="mega-virus" role="tab" id="tab-mega-virus" aria-controls="tab-panel-mega-virus"><span class="tab-label">Minigame-7-ยิง Mega Virus</span><span class="tab-desc" aria-hidden="true"></span></button>
|
||||
|
||||
<div class="admin-tab-sep" aria-hidden="true"><span>คำถาม & การ์ดพิเศษ</span></div>
|
||||
<button type="button" class="tab" data-tab="special-quiz" role="tab" id="tab-special-quiz" aria-controls="tab-panel-special-quiz"><span class="tab-label">ชุดคำถามพิเศษ</span><span class="tab-desc">15 ชุด (Level × Case) · การ์ดรางวัล</span></button>
|
||||
|
||||
<div class="admin-tab-sep" aria-hidden="true"><span>ระบบ & บัญชี</span></div>
|
||||
<button type="button" class="tab" data-tab="characters" role="tab" id="tab-characters" aria-controls="tab-panel-characters"><span class="tab-label">ตัวละคร</span><span class="tab-desc">อัปโหลด · เลือกใช้ในเกม</span></button>
|
||||
<button type="button" class="tab" data-tab="accounts" role="tab" id="tab-accounts" aria-controls="tab-panel-accounts"><span class="tab-label">ผู้ใช้</span><span class="tab-desc">บัญชี & COINS</span></button>
|
||||
<button type="button" class="tab" data-tab="admins" role="tab" id="tab-admins" aria-controls="tab-panel-admins"><span class="tab-label">แอดมิน</span><span class="tab-desc">สิทธิ์ระบบ</span></button>
|
||||
@@ -226,6 +234,73 @@
|
||||
<p id="quiz-settings-msg" class="msg" role="status"></p>
|
||||
</section>
|
||||
|
||||
<section id="tab-panel-special-quiz" class="tab-panel card" hidden role="tabpanel" aria-labelledby="tab-special-quiz">
|
||||
<h2 class="sq-title">ชุดคำถามพิเศษ — รับการ์ดพิเศษ</h2>
|
||||
<p class="muted">มี <strong>15 ชุด</strong> = <strong>ระดับ (Level 1–5)</strong> × <strong>คดี (Case 1–3)</strong> · แต่ละชุดมีคำถามเป็นของตัวเอง (สุ่มมาเล่นในเกม) และให้ <strong>การ์ดพิเศษ 1 ใบ</strong> เป็นรางวัล · เก็บที่ <code>specialQuizSets</code> ใน <code>quiz-settings.json</code> · <em>English:</em> 15 sets (Level × Case), multiple-choice (A/B/C/D), each grants one special card.</p>
|
||||
|
||||
<ol class="sq-steps">
|
||||
<li><span class="sq-step-no">1</span> เลือก <strong>ระดับ + คดี</strong> ที่จะแก้</li>
|
||||
<li><span class="sq-step-no">2</span> ตั้ง <strong>การ์ดพิเศษ</strong> ของชุดนั้น</li>
|
||||
<li><span class="sq-step-no">3</span> ใส่ <strong>คำถาม</strong> แล้วกด <strong>บันทึก</strong></li>
|
||||
</ol>
|
||||
|
||||
<fieldset class="sq-fieldset sq-pick">
|
||||
<legend>1 · เลือกชุดที่จะแก้ไข</legend>
|
||||
<div class="sq-pick-row">
|
||||
<label class="admin-field">ระดับ (Level)
|
||||
<select id="special-quiz-level" class="admin-inp-num sq-select">
|
||||
<option value="1">ระดับ 1 · ROOKIE</option>
|
||||
<option value="2">ระดับ 2</option>
|
||||
<option value="3">ระดับ 3</option>
|
||||
<option value="4">ระดับ 4</option>
|
||||
<option value="5">ระดับ 5</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="admin-field">คดี (Case)
|
||||
<select id="special-quiz-case" class="admin-inp-num sq-select">
|
||||
<option value="1">คดี 1 · คดีโจรกรรมไซเบอร์</option>
|
||||
<option value="2">คดี 2 · คดีปล้นร้านอัญมณี</option>
|
||||
<option value="3">คดี 3</option>
|
||||
</select>
|
||||
</label>
|
||||
<span id="special-quiz-set-tag" class="sq-set-tag">ชุดที่แก้: L1_C1</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="sq-fieldset sq-card">
|
||||
<legend>2 · การ์ดพิเศษของชุดนี้</legend>
|
||||
<div class="sq-card-grid">
|
||||
<label class="admin-field">ชื่อการ์ด (ไทย)
|
||||
<input type="text" id="special-card-th" maxlength="160" placeholder="เช่น เบาะแสลับ">
|
||||
</label>
|
||||
<label class="admin-field">ชื่อการ์ด (อังกฤษ)
|
||||
<input type="text" id="special-card-en" maxlength="160" placeholder="e.g. Secret Clue">
|
||||
</label>
|
||||
<label class="admin-field">ระดับการ์ด
|
||||
<select id="special-card-rarity" class="admin-inp-num">
|
||||
<option value="common">Common</option>
|
||||
<option value="rare" selected>Rare</option>
|
||||
<option value="legendary">Legendary</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="admin-field sq-card-url">URL รูปการ์ด
|
||||
<input type="text" id="special-card-image" maxlength="600" placeholder="/Main-Lobby/IMAGE/... หรือ https://...">
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="sq-fieldset sq-questions">
|
||||
<legend>3 · คำถามของชุดนี้ <span id="special-quiz-count" class="sq-count"></span></legend>
|
||||
<p class="muted" style="margin:0 0 0.7rem">รูปแบบ <strong>ตัวเลือก A B C D</strong> — กรอกตัวเลือกแล้วเลือก “คำตอบที่ถูก” 1 ข้อ (อย่างน้อย 2 ตัวเลือกต่อข้อ) · สุ่มมาเล่นตามจำนวน “สุ่มสูงสุดกี่ข้อต่อรอบ” ที่ตั้งในแท็บ <strong>Minigame-1-จริงหรือไม่</strong></p>
|
||||
<div id="special-quiz-questions-list" class="quiz-admin-questions-list"></div>
|
||||
<div class="quiz-admin-actions">
|
||||
<button type="button" class="btn btn-ghost" id="btn-special-quiz-add">+ เพิ่มคำถาม</button>
|
||||
<button type="button" class="btn btn-primary" id="btn-special-quiz-save">บันทึกชุดคำถามพิเศษทั้งหมด (15 ชุด)</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<p id="special-quiz-msg" class="msg" role="status"></p>
|
||||
</section>
|
||||
|
||||
<section id="tab-panel-quiz-carry" class="tab-panel card" hidden role="tabpanel" aria-labelledby="tab-quiz-carry">
|
||||
<h2>คำถามหลายตัวเลือก (หยิบมาวาง)</h2>
|
||||
<p class="muted">ใช้กับฉากประเภท <strong>ตอบคำถาม — หยิบคำตอบมาวางกลาง</strong> ใน Editor — ผู้เล่นหยิบตัวเลือกไปวางโซนกลาง · ถ้ามีรายการที่นี่ เกมจะใช้<strong>เฉพาะชุดนี้</strong> (ไม่ผสมกับคำถามถูก/ผิดแท็บคำถามเกม) · เก็บที่ <code>/Game/data/quiz-settings.json</code> ฟิลด์ <code>carryQuestions</code></p>
|
||||
@@ -927,6 +1002,6 @@
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<script src="admin.js?v=71"></script>
|
||||
<script src="admin.js?v=73"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,291 +1,428 @@
|
||||
{
|
||||
"readMs": 15000,
|
||||
"answerMs": 5000,
|
||||
"betweenMs": 3000,
|
||||
"carryReadMs": 3000,
|
||||
"carryAnswerMs": 15000,
|
||||
"carrySessionLength": 2,
|
||||
"carryMapPanelTheme": {
|
||||
"panelBg": "rgba(255, 0, 0, 0)",
|
||||
"panelBorder": "rgba(255, 255, 255, 0)",
|
||||
"textColor": "rgba(241, 245, 249, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"questionFontMinPx": 10,
|
||||
"questionFontMaxPx": 24
|
||||
"readMs": 15000,
|
||||
"answerMs": 5000,
|
||||
"betweenMs": 3000,
|
||||
"carryReadMs": 3000,
|
||||
"carryAnswerMs": 15000,
|
||||
"carrySessionLength": 2,
|
||||
"carryMapPanelTheme": {
|
||||
"panelBg": "rgba(255, 0, 0, 0)",
|
||||
"panelBorder": "rgba(255, 255, 255, 0)",
|
||||
"borderWidthPx": 0,
|
||||
"textColor": "rgba(241, 245, 249, 1)",
|
||||
"questionFontMinPx": 10,
|
||||
"questionFontMaxPx": 24
|
||||
},
|
||||
"quizMapPanelTheme": {
|
||||
"panelBg": "rgba(12, 14, 28, 0)",
|
||||
"panelBorder": "rgba(255, 214, 102, 0)",
|
||||
"borderWidthPx": 2,
|
||||
"textColor": "rgba(255, 224, 102, 1)",
|
||||
"questionFontMinPx": 10,
|
||||
"questionFontMaxPx": 28
|
||||
},
|
||||
"carryEmbedCountdownTheme": {
|
||||
"overlayBackdrop": "rgba(8, 10, 20, 0)",
|
||||
"innerBg": "rgba(12, 14, 28, 0)",
|
||||
"innerBorder": "rgba(122, 162, 247, 0)",
|
||||
"innerBorderWpx": 1,
|
||||
"innerRadiusPx": 12,
|
||||
"digitColor": "#f2f2f2",
|
||||
"mapDigitCqmin": 78,
|
||||
"mapDigitCqh": 82,
|
||||
"mapDigitMaxPx": 200,
|
||||
"screenDigitVw": 28,
|
||||
"screenDigitMaxPx": 132
|
||||
},
|
||||
"carryChoicePlaqueThemes": [
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-2.png"
|
||||
},
|
||||
"quizMapPanelTheme": {
|
||||
"panelBg": "rgba(12, 14, 28, 0)",
|
||||
"panelBorder": "rgba(255, 214, 102, 0)",
|
||||
"borderWidthPx": 2,
|
||||
"textColor": "rgba(255, 224, 102, 1)",
|
||||
"questionFontMinPx": 10,
|
||||
"questionFontMaxPx": 28
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-2.png"
|
||||
},
|
||||
"carryEmbedCountdownTheme": {
|
||||
"overlayBackdrop": "rgba(8, 10, 20, 0)",
|
||||
"innerBg": "rgba(12, 14, 28, 0)",
|
||||
"innerBorder": "rgba(122, 162, 247, 0)",
|
||||
"innerBorderWpx": 1,
|
||||
"innerRadiusPx": 12,
|
||||
"digitColor": "#f2f2f2",
|
||||
"mapDigitCqmin": 78,
|
||||
"mapDigitCqh": 82,
|
||||
"mapDigitMaxPx": 200,
|
||||
"screenDigitVw": 28,
|
||||
"screenDigitMaxPx": 132
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-1.png"
|
||||
},
|
||||
"carryChoicePlaqueThemes": [
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-2.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-2.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-1.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-1.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-1.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-3.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-3.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-4.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-4.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-5.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-5.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-5.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-6.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-6.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "neon",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0.9)",
|
||||
"fillBg": "rgba(12, 10, 20, 0.88)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 2.5,
|
||||
"plaqueImageUrl": ""
|
||||
},
|
||||
{
|
||||
"borderMode": "neon",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0.9)",
|
||||
"fillBg": "rgba(12, 10, 20, 0.88)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 2.5,
|
||||
"plaqueImageUrl": ""
|
||||
}
|
||||
],
|
||||
"carryChoicePlaqueTheme": {
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https:\/\/srv1361159.hstgr.cloud\/Game\/img\/quiz-carry\/board-2.png"
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-1.png"
|
||||
},
|
||||
"carryChoicePlaqueMapScale": 1.9,
|
||||
"carryWalkSpeedMultForMapId": "",
|
||||
"carryWalkSpeedMult": null,
|
||||
"quizRoundQuestionCount": 3,
|
||||
"questions": [
|
||||
{
|
||||
"text": "test1",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test2",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test3",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test4",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test5",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test6",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test7",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test8",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test9",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test10",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test11",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test12",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test13",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test14",
|
||||
"answerTrue": true
|
||||
}
|
||||
],
|
||||
"carryQuestions": [
|
||||
{
|
||||
"text": "ผู้มีอํานาจในการพิจารณาพิพากษาตัดสินคดีความในศาล",
|
||||
"choices": [
|
||||
"จําเลย",
|
||||
"ผู้เสียหาย",
|
||||
"อัยการ",
|
||||
"ทนายความ",
|
||||
"โจทก์",
|
||||
"ตํารวจ",
|
||||
"ผู้ไกล่เกลี่ย",
|
||||
"ผู้พิพากษา",
|
||||
"นิติกร",
|
||||
"พยานบุคคล",
|
||||
"หมายค้น",
|
||||
"หมายจับ",
|
||||
"หมายเรียก",
|
||||
"พยานหลักฐาน"
|
||||
],
|
||||
"correctIndex": 7
|
||||
},
|
||||
{
|
||||
"text": "ผู้ที่ถูกกล่าวหาว่ากระทําความผิดทางอาญา และถูกฟ้องต่อศาลแล้ว",
|
||||
"choices": [
|
||||
"ผู้พิพากษา",
|
||||
"โจทก์",
|
||||
"พยานบุคคล",
|
||||
"การประกันตัว",
|
||||
"นิติกร",
|
||||
"ผู้เสียหาย",
|
||||
"สัญญา",
|
||||
"หมายจับ",
|
||||
"ตํารวจ",
|
||||
"ผู้ไกล่เกลี่ย",
|
||||
"อัยการ",
|
||||
"ทนายความ",
|
||||
"จําเลย",
|
||||
"พยานหลักฐาน"
|
||||
],
|
||||
"correctIndex": 12
|
||||
}
|
||||
],
|
||||
"battleQuizMcq": [
|
||||
{
|
||||
"categoryId": "cybercrime",
|
||||
"text": "ฟหกฟหก",
|
||||
"choices": [
|
||||
"ๆไำ",
|
||||
"ฟหฟหด",
|
||||
"ฟหกไๆไก"
|
||||
],
|
||||
"correctIndex": 0
|
||||
}
|
||||
]
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-1.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-3.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-3.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-4.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-4.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-5.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-5.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-5.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-6.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-6.png"
|
||||
},
|
||||
{
|
||||
"borderMode": "neon",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0.9)",
|
||||
"fillBg": "rgba(12, 10, 20, 0.88)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 2.5,
|
||||
"plaqueImageUrl": ""
|
||||
},
|
||||
{
|
||||
"borderMode": "neon",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0.9)",
|
||||
"fillBg": "rgba(12, 10, 20, 0.88)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 2.5,
|
||||
"plaqueImageUrl": ""
|
||||
}
|
||||
],
|
||||
"carryChoicePlaqueTheme": {
|
||||
"borderMode": "fixed",
|
||||
"fixedBorder": "rgba(122, 200, 255, 0)",
|
||||
"fillBg": "rgba(12, 10, 20, 0)",
|
||||
"textColor": "rgba(248, 249, 255, 1)",
|
||||
"borderWidthPx": 0,
|
||||
"plaqueImageUrl": "https://srv1361159.hstgr.cloud/Game/img/quiz-carry/board-2.png"
|
||||
},
|
||||
"carryChoicePlaqueMapScale": 1.9,
|
||||
"carryWalkSpeedMultForMapId": "",
|
||||
"carryWalkSpeedMult": null,
|
||||
"quizRoundQuestionCount": 3,
|
||||
"questions": [
|
||||
{
|
||||
"text": "test1",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test2",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test3",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test4",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test5",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test6",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test7",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test8",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test9",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test10",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test11",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test12",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test13",
|
||||
"answerTrue": true
|
||||
},
|
||||
{
|
||||
"text": "test14",
|
||||
"answerTrue": true
|
||||
}
|
||||
],
|
||||
"carryQuestions": [
|
||||
{
|
||||
"text": "ผู้มีอํานาจในการพิจารณาพิพากษาตัดสินคดีความในศาล",
|
||||
"choices": [
|
||||
"จําเลย",
|
||||
"ผู้เสียหาย",
|
||||
"อัยการ",
|
||||
"ทนายความ",
|
||||
"โจทก์",
|
||||
"ตํารวจ",
|
||||
"ผู้ไกล่เกลี่ย",
|
||||
"ผู้พิพากษา",
|
||||
"นิติกร",
|
||||
"พยานบุคคล",
|
||||
"หมายค้น",
|
||||
"หมายจับ",
|
||||
"หมายเรียก",
|
||||
"พยานหลักฐาน"
|
||||
],
|
||||
"correctIndex": 7
|
||||
},
|
||||
{
|
||||
"text": "ผู้ที่ถูกกล่าวหาว่ากระทําความผิดทางอาญา และถูกฟ้องต่อศาลแล้ว",
|
||||
"choices": [
|
||||
"ผู้พิพากษา",
|
||||
"โจทก์",
|
||||
"พยานบุคคล",
|
||||
"การประกันตัว",
|
||||
"นิติกร",
|
||||
"ผู้เสียหาย",
|
||||
"สัญญา",
|
||||
"หมายจับ",
|
||||
"ตํารวจ",
|
||||
"ผู้ไกล่เกลี่ย",
|
||||
"อัยการ",
|
||||
"ทนายความ",
|
||||
"จําเลย",
|
||||
"พยานหลักฐาน"
|
||||
],
|
||||
"correctIndex": 12
|
||||
}
|
||||
],
|
||||
"battleQuizMcq": [
|
||||
{
|
||||
"categoryId": "cybercrime",
|
||||
"text": "ฟหกฟหก",
|
||||
"choices": [
|
||||
"ๆไำ",
|
||||
"ฟหฟหด",
|
||||
"ฟหกไๆไก"
|
||||
],
|
||||
"correctIndex": 0
|
||||
}
|
||||
],
|
||||
"specialQuizSets": {
|
||||
"L1_C1": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L1_C2": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L1_C3": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L2_C1": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L2_C2": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L2_C3": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L3_C1": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L3_C2": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L3_C3": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L4_C1": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L4_C2": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L4_C3": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L5_C1": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L5_C2": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
},
|
||||
"L5_C3": {
|
||||
"questions": [],
|
||||
"specialCard": {
|
||||
"th": "",
|
||||
"en": "",
|
||||
"rarity": "rare",
|
||||
"imageUrl": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11243,6 +11243,103 @@
|
||||
};
|
||||
}
|
||||
|
||||
/* ===== ชุดคำถามพิเศษ (รับการ์ดพิเศษ) — โมดูลกลาง ใช้ได้หลายเกม =====
|
||||
* จุดต่อเข้าเกมจริง (trigger) จะ wire ภายหลังตามที่ผู้ใช้ระบุ
|
||||
* วิธีใช้: SpecialQuiz.fetchSettings() -> getSet(level,caseId) -> pickQuestions(set,n)
|
||||
* เล่นจบแล้ว awardCard(set, correct, total) -> set mission.specialCardAwarded = card
|
||||
*/
|
||||
let __specialQuizSettingsCache = null;
|
||||
let __specialQuizFetchPromise = null;
|
||||
|
||||
function specialQuizFetchSettings() {
|
||||
if (__specialQuizSettingsCache) return Promise.resolve(__specialQuizSettingsCache);
|
||||
if (__specialQuizFetchPromise) return __specialQuizFetchPromise;
|
||||
__specialQuizFetchPromise = fetch(BASE + '/api/quiz-settings', { cache: 'no-store' })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (j) { __specialQuizSettingsCache = j || {}; return __specialQuizSettingsCache; })
|
||||
.catch(function () { __specialQuizFetchPromise = null; return {}; });
|
||||
return __specialQuizFetchPromise;
|
||||
}
|
||||
|
||||
function specialQuizCurrentLevelCase() {
|
||||
const meta = window.__detectiveLobbyMeta || {};
|
||||
let level = Number(meta.level);
|
||||
let caseId = Number(meta.caseId);
|
||||
if (!(level >= 1 && level <= 5)) {
|
||||
const lp = Number(params.get('lobbyLevel'));
|
||||
if (lp >= 1 && lp <= 5) level = lp;
|
||||
}
|
||||
if (!(caseId >= 1 && caseId <= 3)) {
|
||||
const cp = Number(params.get('case') || params.get('caseId'));
|
||||
if (cp >= 1 && cp <= 3) caseId = cp;
|
||||
}
|
||||
return {
|
||||
level: (level >= 1 && level <= 5) ? level : 1,
|
||||
caseId: (caseId >= 1 && caseId <= 3) ? caseId : 1,
|
||||
};
|
||||
}
|
||||
|
||||
function specialQuizGetSet(settings, level, caseId) {
|
||||
const sets = (settings && settings.specialQuizSets) || {};
|
||||
const key = 'L' + level + '_C' + caseId;
|
||||
return sets[key] || sets.L1_C1 || { questions: [], specialCard: {} };
|
||||
}
|
||||
|
||||
function specialQuizPickQuestions(set, count) {
|
||||
const qs = (set && Array.isArray(set.questions)) ? set.questions.slice() : [];
|
||||
for (let i = qs.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
const t = qs[i]; qs[i] = qs[j]; qs[j] = t;
|
||||
}
|
||||
let n = Number(count);
|
||||
if (!(n >= 1)) n = qs.length;
|
||||
return qs.slice(0, Math.min(n, qs.length));
|
||||
}
|
||||
|
||||
/** กติกาได้การ์ด: ตอบถูก >= ครึ่งหนึ่ง และชุดนั้นตั้งการ์ดไว้ — คืน card หรือ null */
|
||||
function specialQuizAwardCard(set, correctCount, totalCount) {
|
||||
const card = (set && set.specialCard) || null;
|
||||
if (!card || !(card.th || card.en || card.imageUrl)) return null;
|
||||
const total = Number(totalCount) || 0;
|
||||
const correct = Number(correctCount) || 0;
|
||||
const passNeed = total > 0 ? Math.ceil(total / 2) : 1;
|
||||
if (correct < passNeed) return null;
|
||||
return card;
|
||||
}
|
||||
|
||||
/** วาดการ์ดพิเศษลงในโซนโบนัสของสรุปผล (#gcm-bonus / .sm-bonus-right) */
|
||||
function renderSpecialCardInBonus(bonusEl, card) {
|
||||
if (!bonusEl || !card || !(card.th || card.en || card.imageUrl)) return;
|
||||
const wrap = document.createElement('div');
|
||||
wrap.className = 'gcm-special-card sm-bonus-special rarity-' + (card.rarity || 'rare');
|
||||
if (card.imageUrl) {
|
||||
const img = document.createElement('img');
|
||||
img.className = 'gcm-special-card-img';
|
||||
img.src = card.imageUrl;
|
||||
img.alt = card.th || card.en || '';
|
||||
wrap.appendChild(img);
|
||||
}
|
||||
const cap = document.createElement('div');
|
||||
cap.className = 'gcm-special-card-cap';
|
||||
const strong = document.createElement('strong');
|
||||
strong.textContent = card.th || '';
|
||||
const span = document.createElement('span');
|
||||
span.textContent = card.en || '';
|
||||
cap.appendChild(strong);
|
||||
cap.appendChild(span);
|
||||
wrap.appendChild(cap);
|
||||
bonusEl.appendChild(wrap);
|
||||
}
|
||||
|
||||
window.SpecialQuiz = {
|
||||
fetchSettings: specialQuizFetchSettings,
|
||||
currentLevelCase: specialQuizCurrentLevelCase,
|
||||
getSet: specialQuizGetSet,
|
||||
pickQuestions: specialQuizPickQuestions,
|
||||
awardCard: specialQuizAwardCard,
|
||||
renderCardInBonus: renderSpecialCardInBonus,
|
||||
};
|
||||
|
||||
function showGauntletCrownMissionOverlay(mission) {
|
||||
const ov = document.getElementById('gauntlet-crown-mission-overlay');
|
||||
const rowEl = document.getElementById('gcm-rank-row');
|
||||
@@ -11495,6 +11592,10 @@
|
||||
pl.innerHTML = '<strong>ไม่ได้รับการ์ด</strong><span>เกรด ' + gLetter + ' · ภารกิจไม่ผ่านเกณฑ์</span>';
|
||||
bonusEl.appendChild(pl);
|
||||
}
|
||||
/* การ์ดพิเศษจากชุดคำถาม (ถ้ารอบนี้ได้รับ) — wire จุด trigger ภายหลัง */
|
||||
if (mission && mission.specialCardAwarded) {
|
||||
renderSpecialCardInBonus(bonusEl, mission.specialCardAwarded);
|
||||
}
|
||||
}
|
||||
const gcmHead = document.getElementById('gcm-heading');
|
||||
if (gcmHead) {
|
||||
|
||||
@@ -1608,6 +1608,24 @@
|
||||
}
|
||||
.gcm-plaque strong { color: #f1f5f9; display: block; }
|
||||
.gcm-plaque span { color: #7af8ff; font-size: 0.92em; }
|
||||
.gcm-special-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-top: 8px;
|
||||
padding: 8px 10px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 214, 102, 0.6);
|
||||
background: linear-gradient(165deg, rgba(40, 30, 10, 0.96), rgba(20, 14, 6, 0.98));
|
||||
max-width: 200px;
|
||||
}
|
||||
.gcm-special-card.rarity-rare { border-color: rgba(122, 162, 247, 0.75); }
|
||||
.gcm-special-card.rarity-legendary { border-color: rgba(255, 184, 77, 0.9); box-shadow: 0 0 12px rgba(255, 184, 77, 0.45); }
|
||||
.gcm-special-card-img { width: 100%; max-width: 120px; height: auto; border-radius: 8px; display: block; }
|
||||
.gcm-special-card-cap { text-align: center; line-height: 1.25; }
|
||||
.gcm-special-card-cap strong { display: block; color: #ffe066; font-size: 0.95em; }
|
||||
.gcm-special-card-cap span { color: #cbd5e1; font-size: 0.82em; }
|
||||
.btn-gcm-done {
|
||||
display: block;
|
||||
margin: 4px auto 0;
|
||||
@@ -3842,7 +3860,7 @@
|
||||
<script src="/app-base.js?v=2"></script>
|
||||
<script src="/Game/socket.io/socket.io.js"></script>
|
||||
<script src="js/version.js?v=0.0306"></script>
|
||||
<script src="js/play.js?v=0.0499"></script>
|
||||
<script src="js/play.js?v=0.0500"></script>
|
||||
<div class="version-tag">v —</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 140 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 140 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 118 KiB |
@@ -283,6 +283,72 @@ const defaultMap = () => ({
|
||||
jumpSurviveMovePxPerSec: 200,
|
||||
});
|
||||
|
||||
/* ===== Special Quiz Sets (Level 1-5 × Case 1-3 = 15 ชุด) — คำถามรับการ์ดพิเศษ ใช้ได้หลายเกม ===== */
|
||||
const SPECIAL_QUIZ_LEVELS = [1, 2, 3, 4, 5];
|
||||
const SPECIAL_QUIZ_CASES = [1, 2, 3];
|
||||
const SPECIAL_QUIZ_CARD_RARITIES = ['common', 'rare', 'legendary'];
|
||||
|
||||
function specialQuizSetKey(level, caseId) {
|
||||
return 'L' + level + '_C' + caseId;
|
||||
}
|
||||
|
||||
/** คำถาม 1 ข้อ — รองรับทั้งจริง/เท็จ (tf) และตัวเลือก A/B/C (mcq) เพื่อขยายภายหลัง */
|
||||
function sanitizeSpecialQuizQuestion(q) {
|
||||
if (!q || typeof q !== 'object') return null;
|
||||
const text = String(q.text == null ? '' : q.text).trim();
|
||||
if (!text) return null;
|
||||
const type = q.type === 'mcq' ? 'mcq' : 'tf';
|
||||
if (type === 'mcq') {
|
||||
/* รักษาตำแหน่งตัวเลือก (A=0,B=1,...) — ตัดเฉพาะช่องว่างท้ายสุด ไม่ขยับ index คำตอบ */
|
||||
const choices = (Array.isArray(q.choices) ? q.choices : [])
|
||||
.map((c) => String(c == null ? '' : c).trim())
|
||||
.slice(0, 8);
|
||||
while (choices.length && choices[choices.length - 1] === '') choices.pop();
|
||||
if (choices.filter((c) => c).length < 2) return null;
|
||||
let ci = Number(q.correctIndex);
|
||||
if (!Number.isInteger(ci) || ci < 0 || ci >= choices.length || choices[ci] === '') {
|
||||
ci = choices.findIndex((c) => c);
|
||||
if (ci < 0) ci = 0;
|
||||
}
|
||||
return { type: 'mcq', text: text.slice(0, 500), choices, correctIndex: ci };
|
||||
}
|
||||
return { type: 'tf', text: text.slice(0, 500), answerTrue: !!q.answerTrue };
|
||||
}
|
||||
|
||||
function sanitizeSpecialCard(c) {
|
||||
const src = (c && typeof c === 'object') ? c : {};
|
||||
const rarity = SPECIAL_QUIZ_CARD_RARITIES.indexOf(src.rarity) >= 0 ? src.rarity : 'rare';
|
||||
return {
|
||||
th: String(src.th == null ? '' : src.th).trim().slice(0, 160),
|
||||
en: String(src.en == null ? '' : src.en).trim().slice(0, 160),
|
||||
rarity,
|
||||
imageUrl: String(src.imageUrl == null ? '' : src.imageUrl).trim().slice(0, 600),
|
||||
};
|
||||
}
|
||||
|
||||
/** คืน object 15 ชุดเสมอ (ชุดที่ยังไม่ตั้ง = ว่าง) */
|
||||
function sanitizeSpecialQuizSets(obj) {
|
||||
const out = {};
|
||||
SPECIAL_QUIZ_LEVELS.forEach((L) => SPECIAL_QUIZ_CASES.forEach((C) => {
|
||||
const key = specialQuizSetKey(L, C);
|
||||
const src = (obj && typeof obj === 'object' && obj[key] && typeof obj[key] === 'object') ? obj[key] : {};
|
||||
const questions = (Array.isArray(src.questions) ? src.questions : [])
|
||||
.map(sanitizeSpecialQuizQuestion)
|
||||
.filter(Boolean)
|
||||
.slice(0, 50);
|
||||
out[key] = { questions, specialCard: sanitizeSpecialCard(src.specialCard) };
|
||||
}));
|
||||
return out;
|
||||
}
|
||||
|
||||
/** เลือกชุดคำถามตาม level+case (fallback ชุด L1_C1) */
|
||||
function getSpecialQuizSet(settings, level, caseId) {
|
||||
const sets = (settings && settings.specialQuizSets) || sanitizeSpecialQuizSets({});
|
||||
const L = SPECIAL_QUIZ_LEVELS.indexOf(Number(level)) >= 0 ? Number(level) : 1;
|
||||
const C = SPECIAL_QUIZ_CASES.indexOf(Number(caseId)) >= 0 ? Number(caseId) : 1;
|
||||
return sets[specialQuizSetKey(L, C)] || sets[specialQuizSetKey(1, 1)] || { questions: [], specialCard: sanitizeSpecialCard({}) };
|
||||
}
|
||||
|
||||
function defaultQuizSettings() {
|
||||
return {
|
||||
readMs: 10000,
|
||||
@@ -314,6 +380,8 @@ function defaultQuizSettings() {
|
||||
questions: [],
|
||||
carryQuestions: [],
|
||||
battleQuizMcq: [],
|
||||
/** 15 ชุดคำถามพิเศษ (Level×Case) สำหรับรับการ์ดพิเศษ */
|
||||
specialQuizSets: sanitizeSpecialQuizSets({}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -684,6 +752,7 @@ function loadQuizSettings() {
|
||||
questions,
|
||||
carryQuestions,
|
||||
battleQuizMcq,
|
||||
specialQuizSets: sanitizeSpecialQuizSets(j.specialQuizSets),
|
||||
};
|
||||
return mergeQuizCarryFromMirrorIfSet(out);
|
||||
}
|
||||
@@ -1489,6 +1558,9 @@ function saveQuizSettings(d) {
|
||||
const quizRoundQuestionCount = d.quizRoundQuestionCount != null
|
||||
? clampQuizRoundQuestionCount(d.quizRoundQuestionCount, prev.quizRoundQuestionCount)
|
||||
: prev.quizRoundQuestionCount;
|
||||
const specialQuizSets = d.specialQuizSets != null
|
||||
? sanitizeSpecialQuizSets(d.specialQuizSets)
|
||||
: sanitizeSpecialQuizSets(prev.specialQuizSets);
|
||||
const out = {
|
||||
readMs,
|
||||
answerMs,
|
||||
@@ -1508,12 +1580,14 @@ function saveQuizSettings(d) {
|
||||
questions,
|
||||
carryQuestions,
|
||||
battleQuizMcq,
|
||||
specialQuizSets,
|
||||
};
|
||||
fs.writeFileSync(QUIZ_SETTINGS_PATH, JSON.stringify(out, null, 2), 'utf8');
|
||||
return {
|
||||
ok: true,
|
||||
battleQuizMcqSaved: (out.battleQuizMcq || []).length,
|
||||
carryQuestionsSaved: (out.carryQuestions || []).length,
|
||||
specialQuizSets: out.specialQuizSets,
|
||||
carryMapPanelTheme: out.carryMapPanelTheme,
|
||||
quizMapPanelTheme: out.quizMapPanelTheme,
|
||||
carryEmbedCountdownTheme: out.carryEmbedCountdownTheme,
|
||||
@@ -2979,6 +3053,7 @@ const server = http.createServer((req, res) => {
|
||||
ok: true,
|
||||
battleQuizMcqSaved: saved.battleQuizMcqSaved,
|
||||
carryQuestionsSaved: saved.carryQuestionsSaved,
|
||||
specialQuizSets: saved.specialQuizSets,
|
||||
carryMapPanelTheme: saved.carryMapPanelTheme,
|
||||
carryEmbedCountdownTheme: saved.carryEmbedCountdownTheme,
|
||||
carryChoicePlaqueThemes: saved.carryChoicePlaqueThemes,
|
||||
|
||||