minigame 2 just begin1.67

This commit is contained in:
2026-04-30 21:03:58 +00:00
parent f04060c07c
commit aacc7c6e08
4 changed files with 229 additions and 19 deletions
+113 -8
View File
@@ -5382,6 +5382,106 @@
return g !== 'F';
}
function gauntletCrownRankBonusLocal(rankOrdinal) {
if (rankOrdinal === 1) return 100;
if (rankOrdinal === 2) return 80;
if (rankOrdinal === 3) return 60;
return 0;
}
function gauntletCrownRollRewardCardLocal(grade) {
const r = Math.random();
if (grade === 'A') {
if (r < 0.3) return { kind: 'culprit', th: 'การ์ดชี้คนร้าย', en: 'Culprit card' };
if (r < 0.8) return { kind: 'rare', th: 'การ์ด Rare', en: 'Rare card' };
return { kind: 'common', th: 'การ์ดธรรมดา', en: 'Common card' };
}
if (grade === 'B') {
if (r < 0.2) return { kind: 'culprit', th: 'การ์ดชี้คนร้าย', en: 'Culprit card' };
if (r < 0.5) return { kind: 'rare', th: 'การ์ด Rare', en: 'Rare card' };
return { kind: 'common', th: 'การ์ดธรรมดา', en: 'Common card' };
}
if (r < 0.2) return { kind: 'rare', th: 'การ์ด Rare', en: 'Rare card' };
return { kind: 'common', th: 'การ์ดธรรมดา', en: 'Common card' };
}
/**
* Editor embed + preview bots: รวมแถวอนดบกบบอท (งส 5 อง) และคำนวณรวม/เฉล/เกรดใหสอดคลองกบแถวทโชว
* นดบในชองใชลำด 1..5 หลงเรยงคะแนน (เหมอนแนว quiz_carry mission row)
*/
function gauntletCrownBuildDisplayMission(mission) {
if (!mission || !Array.isArray(mission.ranked)) return mission;
if (!(previewFillBots && isGauntletCrownHeistMapPlay() && others && typeof others.forEach === 'function')) return mission;
const seen = new Set();
const baseRows = [];
mission.ranked.forEach((r) => {
if (!r) return;
const sid = String(r.id);
if (seen.has(sid)) return;
seen.add(sid);
baseRows.push({
id: r.id,
nickname: (r.nickname && String(r.nickname).trim()) ? String(r.nickname).trim() : 'ผู้เล่น',
characterId: r.characterId ?? null,
baseScore: r.eliminated ? 0 : Math.max(0, Number(r.baseScore) || 0),
eliminated: !!r.eliminated,
});
});
others.forEach((o, id) => {
if (!o || !isPreviewBotId(id)) return;
const sid = String(id);
if (seen.has(sid)) return;
seen.add(sid);
baseRows.push({
id: id,
nickname: (o.nickname && String(o.nickname).trim()) ? String(o.nickname).trim() : sid,
characterId: o.characterId ?? null,
baseScore: o.gauntletEliminated ? 0 : Math.max(0, Number(o.gauntletScore) | 0),
eliminated: !!o.gauntletEliminated,
});
});
baseRows.sort((a, b) => {
if (b.baseScore !== a.baseScore) return b.baseScore - a.baseScore;
const nick = String(a.nickname).localeCompare(String(b.nickname), 'th');
if (nick !== 0) return nick;
return String(a.id).localeCompare(String(b.id));
});
const top = baseRows.slice(0, 5);
const ranked = top.map((row, idx) => {
const pos = idx + 1;
const rankBonus = gauntletCrownRankBonusLocal(pos);
const rankLabel = pos === 1 ? '1st' : pos === 2 ? '2nd' : pos === 3 ? '3rd' : String(pos);
const finalScore = row.baseScore + rankBonus;
return {
id: row.id,
nickname: row.nickname,
characterId: row.characterId,
baseScore: row.baseScore,
eliminated: row.eliminated,
rank: pos,
rankLabel: rankLabel,
rankBonus: rankBonus,
finalScore: finalScore,
};
});
const totalSum = ranked.reduce(function (s, r) { return s + r.finalScore; }, 0);
const n = ranked.length || 1;
const averageScore = Math.floor(totalSum / n);
const grade = averageScore >= 80 ? 'A' : averageScore >= 60 ? 'B' : 'C';
const rewardCard = gauntletCrownRollRewardCardLocal(grade);
return {
ranked: ranked,
totalSum: totalSum,
averageScore: averageScore,
grade: grade,
rewardCard: rewardCard,
totalParts: ranked.map(function (r) { return r.finalScore; }),
};
}
function showGauntletCrownMissionOverlay(mission) {
const ov = document.getElementById('gauntlet-crown-mission-overlay');
const rowEl = document.getElementById('gcm-rank-row');
@@ -5390,8 +5490,10 @@
const bonusEl = document.getElementById('gcm-bonus');
const btn = document.getElementById('btn-gcm-done');
if (!ov || !rowEl || !mission || !Array.isArray(mission.ranked)) return;
const disp = gauntletCrownBuildDisplayMission(mission);
if (!disp || !Array.isArray(disp.ranked)) return;
rowEl.innerHTML = '';
mission.ranked.forEach((r) => {
disp.ranked.forEach((r) => {
const cell = document.createElement('div');
cell.className = 'gcm-cell';
const tag = document.createElement('div');
@@ -5436,7 +5538,10 @@
nick.textContent = r.nickname || '—';
const sc = document.createElement('div');
sc.className = 'gcm-sc';
sc.textContent = String(r.baseScore || 0) + '(+' + String(r.rankBonus || 0) + ')';
const botScorePlain = previewFillBots && isGauntletCrownHeistMapPlay() && isPreviewBotId(r.id);
sc.textContent = botScorePlain
? String(Math.max(0, Number(r.baseScore) || 0))
: String(r.baseScore || 0) + '(+' + String(r.rankBonus || 0) + ')';
cell.appendChild(tag);
cell.appendChild(frame);
cell.appendChild(nick);
@@ -5444,13 +5549,13 @@
rowEl.appendChild(cell);
});
if (totalEl) {
const parts = (mission.totalParts || []).map((n) => String(Math.max(0, Number(n) || 0)));
const sum = Math.max(0, Number(mission.totalSum) || 0);
const avg = Math.max(0, Math.floor(Number(mission.averageScore) || 0));
const parts = (disp.totalParts || []).map((n) => String(Math.max(0, Number(n) || 0)));
const sum = Math.max(0, Number(disp.totalSum) || 0);
const avg = Math.max(0, Math.floor(Number(disp.averageScore) || 0));
totalEl.innerHTML = 'คะแนนรวม <span class="gcm-total-nums">(' + parts.join('+') + ') = ' + sum + '</span> · เฉลี่ย ' + avg + ' → เกรด';
}
if (gradeEl) {
const g = String(mission.grade || 'C').toUpperCase().charAt(0);
const g = String(disp.grade || 'C').toUpperCase().charAt(0);
gradeEl.textContent = g;
gradeEl.className = 'gcm-grade gcm-grade--' + g.toLowerCase();
}
@@ -5472,7 +5577,7 @@
row.appendChild(chk);
row.appendChild(sp);
bonusEl.appendChild(row);
const rc = mission.rewardCard;
const rc = disp.rewardCard;
if (rc && rc.th) {
const pl = document.createElement('div');
pl.className = 'gcm-plaque';
@@ -5489,7 +5594,7 @@
btn.onclick = function () {
if (previewMode && editorEmbedReturn) {
ov.classList.add('is-hidden');
showQuizCarryTimeupOnDeskLayer(function () { return gauntletCrownEmbedMissionAnyOk(mission); });
showQuizCarryTimeupOnDeskLayer(function () { return gauntletCrownEmbedMissionAnyOk(disp); });
} else {
goLobby();
}
+1 -1
View File
@@ -1,6 +1,6 @@
// ทุกครั้งที่มีการเพิ่มหรือเปลี่ยน ให้เพิ่ม v +0.0001
// หลังแก้ค่าแล้วต้อง copy ไป path ที่ Nginx ชี้ (หรือรัน copy-frogger-files-only.sh) ถึงจะเห็นบนเว็บ
window.APP_VERSION = '0.0174';
window.APP_VERSION = '0.0175';
document.addEventListener('DOMContentLoaded', function () {
var t = document.querySelector('.version-tag');
if (t) t.textContent = 'v ' + window.APP_VERSION;
+2 -2
View File
@@ -1858,8 +1858,8 @@
</div>
</div>
<script src="/Game/socket.io/socket.io.js"></script>
<script src="js/version.js?v=0.0174"></script>
<script src="js/play.js?v=0.199"></script>
<script src="js/version.js?v=0.0175"></script>
<script src="js/play.js?v=0.201"></script>
<div class="version-tag">v —</div>
</body>
</html>
+113 -8
View File
@@ -5382,6 +5382,106 @@
return g !== 'F';
}
function gauntletCrownRankBonusLocal(rankOrdinal) {
if (rankOrdinal === 1) return 100;
if (rankOrdinal === 2) return 80;
if (rankOrdinal === 3) return 60;
return 0;
}
function gauntletCrownRollRewardCardLocal(grade) {
const r = Math.random();
if (grade === 'A') {
if (r < 0.3) return { kind: 'culprit', th: 'การ์ดชี้คนร้าย', en: 'Culprit card' };
if (r < 0.8) return { kind: 'rare', th: 'การ์ด Rare', en: 'Rare card' };
return { kind: 'common', th: 'การ์ดธรรมดา', en: 'Common card' };
}
if (grade === 'B') {
if (r < 0.2) return { kind: 'culprit', th: 'การ์ดชี้คนร้าย', en: 'Culprit card' };
if (r < 0.5) return { kind: 'rare', th: 'การ์ด Rare', en: 'Rare card' };
return { kind: 'common', th: 'การ์ดธรรมดา', en: 'Common card' };
}
if (r < 0.2) return { kind: 'rare', th: 'การ์ด Rare', en: 'Rare card' };
return { kind: 'common', th: 'การ์ดธรรมดา', en: 'Common card' };
}
/**
* Editor embed + preview bots: รวมแถวอนดบกบบอท (งส 5 อง) และคำนวณรวม/เฉล/เกรดใหสอดคลองกบแถวทโชว
* นดบในชองใชลำด 1..5 หลงเรยงคะแนน (เหมอนแนว quiz_carry mission row)
*/
function gauntletCrownBuildDisplayMission(mission) {
if (!mission || !Array.isArray(mission.ranked)) return mission;
if (!(previewFillBots && isGauntletCrownHeistMapPlay() && others && typeof others.forEach === 'function')) return mission;
const seen = new Set();
const baseRows = [];
mission.ranked.forEach((r) => {
if (!r) return;
const sid = String(r.id);
if (seen.has(sid)) return;
seen.add(sid);
baseRows.push({
id: r.id,
nickname: (r.nickname && String(r.nickname).trim()) ? String(r.nickname).trim() : 'ผู้เล่น',
characterId: r.characterId ?? null,
baseScore: r.eliminated ? 0 : Math.max(0, Number(r.baseScore) || 0),
eliminated: !!r.eliminated,
});
});
others.forEach((o, id) => {
if (!o || !isPreviewBotId(id)) return;
const sid = String(id);
if (seen.has(sid)) return;
seen.add(sid);
baseRows.push({
id: id,
nickname: (o.nickname && String(o.nickname).trim()) ? String(o.nickname).trim() : sid,
characterId: o.characterId ?? null,
baseScore: o.gauntletEliminated ? 0 : Math.max(0, Number(o.gauntletScore) | 0),
eliminated: !!o.gauntletEliminated,
});
});
baseRows.sort((a, b) => {
if (b.baseScore !== a.baseScore) return b.baseScore - a.baseScore;
const nick = String(a.nickname).localeCompare(String(b.nickname), 'th');
if (nick !== 0) return nick;
return String(a.id).localeCompare(String(b.id));
});
const top = baseRows.slice(0, 5);
const ranked = top.map((row, idx) => {
const pos = idx + 1;
const rankBonus = gauntletCrownRankBonusLocal(pos);
const rankLabel = pos === 1 ? '1st' : pos === 2 ? '2nd' : pos === 3 ? '3rd' : String(pos);
const finalScore = row.baseScore + rankBonus;
return {
id: row.id,
nickname: row.nickname,
characterId: row.characterId,
baseScore: row.baseScore,
eliminated: row.eliminated,
rank: pos,
rankLabel: rankLabel,
rankBonus: rankBonus,
finalScore: finalScore,
};
});
const totalSum = ranked.reduce(function (s, r) { return s + r.finalScore; }, 0);
const n = ranked.length || 1;
const averageScore = Math.floor(totalSum / n);
const grade = averageScore >= 80 ? 'A' : averageScore >= 60 ? 'B' : 'C';
const rewardCard = gauntletCrownRollRewardCardLocal(grade);
return {
ranked: ranked,
totalSum: totalSum,
averageScore: averageScore,
grade: grade,
rewardCard: rewardCard,
totalParts: ranked.map(function (r) { return r.finalScore; }),
};
}
function showGauntletCrownMissionOverlay(mission) {
const ov = document.getElementById('gauntlet-crown-mission-overlay');
const rowEl = document.getElementById('gcm-rank-row');
@@ -5390,8 +5490,10 @@
const bonusEl = document.getElementById('gcm-bonus');
const btn = document.getElementById('btn-gcm-done');
if (!ov || !rowEl || !mission || !Array.isArray(mission.ranked)) return;
const disp = gauntletCrownBuildDisplayMission(mission);
if (!disp || !Array.isArray(disp.ranked)) return;
rowEl.innerHTML = '';
mission.ranked.forEach((r) => {
disp.ranked.forEach((r) => {
const cell = document.createElement('div');
cell.className = 'gcm-cell';
const tag = document.createElement('div');
@@ -5436,7 +5538,10 @@
nick.textContent = r.nickname || '—';
const sc = document.createElement('div');
sc.className = 'gcm-sc';
sc.textContent = String(r.baseScore || 0) + '(+' + String(r.rankBonus || 0) + ')';
const botScorePlain = previewFillBots && isGauntletCrownHeistMapPlay() && isPreviewBotId(r.id);
sc.textContent = botScorePlain
? String(Math.max(0, Number(r.baseScore) || 0))
: String(r.baseScore || 0) + '(+' + String(r.rankBonus || 0) + ')';
cell.appendChild(tag);
cell.appendChild(frame);
cell.appendChild(nick);
@@ -5444,13 +5549,13 @@
rowEl.appendChild(cell);
});
if (totalEl) {
const parts = (mission.totalParts || []).map((n) => String(Math.max(0, Number(n) || 0)));
const sum = Math.max(0, Number(mission.totalSum) || 0);
const avg = Math.max(0, Math.floor(Number(mission.averageScore) || 0));
const parts = (disp.totalParts || []).map((n) => String(Math.max(0, Number(n) || 0)));
const sum = Math.max(0, Number(disp.totalSum) || 0);
const avg = Math.max(0, Math.floor(Number(disp.averageScore) || 0));
totalEl.innerHTML = 'คะแนนรวม <span class="gcm-total-nums">(' + parts.join('+') + ') = ' + sum + '</span> · เฉลี่ย ' + avg + ' → เกรด';
}
if (gradeEl) {
const g = String(mission.grade || 'C').toUpperCase().charAt(0);
const g = String(disp.grade || 'C').toUpperCase().charAt(0);
gradeEl.textContent = g;
gradeEl.className = 'gcm-grade gcm-grade--' + g.toLowerCase();
}
@@ -5472,7 +5577,7 @@
row.appendChild(chk);
row.appendChild(sp);
bonusEl.appendChild(row);
const rc = mission.rewardCard;
const rc = disp.rewardCard;
if (rc && rc.th) {
const pl = document.createElement('div');
pl.className = 'gcm-plaque';
@@ -5489,7 +5594,7 @@
btn.onclick = function () {
if (previewMode && editorEmbedReturn) {
ov.classList.add('is-hidden');
showQuizCarryTimeupOnDeskLayer(function () { return gauntletCrownEmbedMissionAnyOk(mission); });
showQuizCarryTimeupOnDeskLayer(function () { return gauntletCrownEmbedMissionAnyOk(disp); });
} else {
goLobby();
}