807 lines
26 KiB
JavaScript
807 lines
26 KiB
JavaScript
var tdv_sdk = {};
|
|
tdv_sdk.list = [
|
|
// ==================== PART 1: MULTIPLE CHOICE (Q1-Q10) - DỄ → TRUNG BÌNH ====================
|
|
{
|
|
"id": 1,
|
|
"question": "“Hi! My name is Rosy. I am in class 4B.” Who is speaking?",
|
|
"options": ["Tim", "Billy", "Rosy", "Miss Jones"],
|
|
"answer": "Rosy",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 2,
|
|
"question": "Which is a day of the week AFTER Thursday?",
|
|
"options": ["Wednesday", "Friday", "Monday", "Tuesday"],
|
|
"answer": "Friday",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 3,
|
|
"question": "Who works at the airport?",
|
|
"options": ["Pilot", "Firefighter", "Doctor", "Police officer"],
|
|
"answer": "Pilot",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 4,
|
|
"question": "Which place is NOT a workplace?",
|
|
"options": ["Hospital", "Fire station", "Bedroom", "Police station"],
|
|
"answer": "Bedroom",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 5,
|
|
"question": "Choose the correct sentence.",
|
|
"options": [
|
|
"She work at the hospital.",
|
|
"She works at the hospital",
|
|
"She working at the hospital",
|
|
"She worked at hospital"
|
|
],
|
|
"answer": "She works at the hospital",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 6,
|
|
"question": "What do the children like at the beach?",
|
|
"options": [
|
|
"Surf and play with a ball",
|
|
"Study English",
|
|
"Write in notebooks",
|
|
"Paint pictures"
|
|
],
|
|
"answer": "Surf and play with a ball",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 7,
|
|
"question": "Which number is BETWEEN 29 and 40?",
|
|
"options": ["30", "20", "50", "29"],
|
|
"answer": "30",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 8,
|
|
"question": "Which sentence is correct?",
|
|
"options": [
|
|
"I have English on Wednesday.",
|
|
"I has English on Wednesday.",
|
|
"I have English in Wednesday.",
|
|
"I am have English on Wednesday."
|
|
],
|
|
"answer": "I have English on Wednesday.",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 9,
|
|
"question": "Which activity is done in a group?",
|
|
"options": [
|
|
"Write in a notebook",
|
|
"Play with a ball",
|
|
"Eat a sandwich",
|
|
"Take a photo"
|
|
],
|
|
"answer": "Play with a ball",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 10,
|
|
"question": "“The firefighter helps people every day.” What does the firefighter do?",
|
|
"options": [
|
|
"Eats sandwiches",
|
|
"Helps people",
|
|
"Goes to school",
|
|
"Collects shells"
|
|
],
|
|
"answer": "Helps people",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 11,
|
|
"question": "Which is NOT a fast food?",
|
|
"options": ["Fries", "Pizza", "Soup", "Chicken"],
|
|
"answer": "Soup",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 12,
|
|
"question": "The funny monkey wears a hat and eats a sandwich. Then it takes a photo. Which is TRUE?",
|
|
"options": [
|
|
"The monkey eats a sandwich first",
|
|
"The monkey takes a photo before eating",
|
|
"The monkey wears a hat first",
|
|
"The monkey writes in a notebook"
|
|
],
|
|
"answer": "The monkey wears a hat first",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 13,
|
|
"question": "What does Billy like?",
|
|
"options": ["His school", "His bag", "His teacher", "His toys"],
|
|
"answer": "His school",
|
|
"audio": "https://audio.senaai.tech/audio/Sena_Voice1_hello_im_billy_i_am_in_class_4a_today_is_monday_i__b775daf7.mp3"
|
|
},
|
|
{
|
|
"id": 14,
|
|
"question": "What is her job?",
|
|
"options": ["Nurse", "Doctor", "Teacher", "Pilot"],
|
|
"answer": "Nurse",
|
|
"audio": "https://audio.senaai.tech/audio/Sena_Voice1_my_mom_works_at_a_hospital_she_is_not_a_doctor_she_130967d2.mp3"
|
|
},
|
|
{
|
|
"id": 15,
|
|
"question": "What does the monkey do last?",
|
|
"options": [
|
|
"Eats a sandwich",
|
|
"Takes a photo",
|
|
"Wears a hat",
|
|
"Writes in a notebook"
|
|
],
|
|
"answer": "Takes a photo",
|
|
"audio": "https://audio.senaai.tech/audio/Sena_Voice1_the_monkey_wears_a_hat_and_a_scarf_it_eats_a_sandw_ba8a2f89.mp3"
|
|
},
|
|
{
|
|
"id": 16,
|
|
"question": "Which food does the speaker prefer?",
|
|
"options": ["Pizza", "Bubble tea", "Chicken", "Fries"],
|
|
"answer": "Bubble tea",
|
|
"audio": "https://audio.senaai.tech/audio/Sena_Voice1_i_have_a_bubble_tea_my_brother_has_pizza_i_like_bu_a94a29b8.mp3"
|
|
},
|
|
{
|
|
"id": 17,
|
|
"question": "Why does the speaker like P.E?",
|
|
"options": [
|
|
"Because it is difficult",
|
|
"Because he can read books",
|
|
"Because he can run and play",
|
|
"Because it is in the art room"
|
|
],
|
|
"answer": "Because he can run and play",
|
|
"audio": "https://audio.senaai.tech/audio/Sena_Voice1_look_at_the_school_subjects_i_have_english_math_ar_2f34d40d.mp3"
|
|
},
|
|
{
|
|
"id": 18,
|
|
"question": "Which sentence is TRUE?",
|
|
"options": [
|
|
"He is a police officer",
|
|
"He works at a fire station",
|
|
"He works at a hospital",
|
|
"He collects shells"
|
|
],
|
|
"answer": "He works at a fire station",
|
|
"audio": "https://audio.senaai.tech/audio/Sena_Voice1_my_dad_is_a_firefighter_he_works_at_the_fire_stati_abd4086a.mp3"
|
|
},
|
|
{
|
|
"id": 19,
|
|
"question": "In which lunar month does Tet (Vietnamese New Year) usually begin?",
|
|
"answer": "January",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 20,
|
|
"question": "Banh Chung is made from sticky rice, green beans, and ____?",
|
|
"answer": "pork",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 21,
|
|
"question": "What flower is most popular during Tet in the North of Vietnam?",
|
|
"answer": "peach blossom",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 22,
|
|
"question": "Who do Vietnamese usually give lucky money to during Tet?",
|
|
"answer": "children",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 23,
|
|
"question": "Which square-shaped cake represents the Earth during Tet?",
|
|
"answer": "Banh Chung",
|
|
"audio": ""
|
|
},
|
|
{
|
|
"id": 24,
|
|
"question": "Where do people usually go during Tet to pray for health and good luck?",
|
|
"answer": "pagoda",
|
|
"audio": ""
|
|
}
|
|
];
|
|
|
|
tdv_sdk.currentIndex = 0;
|
|
tdv_sdk.shuffleArray = function (Array) {
|
|
for (let i = Array.length - 1; i > 0; i--) {
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
[Array[i], Array[j]] = [Array[j], Array[i]];
|
|
}
|
|
};
|
|
|
|
tdv_sdk.start = function () {
|
|
tdv_sdk.currentIndex = 0;
|
|
tdv_sdk.listquestion = [];
|
|
tdv_sdk.totalquestion = tdv_sdk.list.length;
|
|
for (let i = 0; i < tdv_sdk.totalquestion; i++) {
|
|
tdv_sdk.listquestion.push(tdv_sdk.list[i]);
|
|
}
|
|
};
|
|
|
|
tdv_sdk.loadquestion = function () {
|
|
if (tdv_sdk.currentIndex >= tdv_sdk.totalquestion) {
|
|
console.log("🎉 Game Over! No more questions.");
|
|
tdv_sdk.curQuestion = null;
|
|
tdv_sdk.questionState = -1;
|
|
return 0;
|
|
}
|
|
|
|
tdv_sdk.curQuestion = tdv_sdk.listquestion[tdv_sdk.currentIndex];
|
|
tdv_sdk.correctAnswer = tdv_sdk.curQuestion.answer;
|
|
|
|
// ✅ CHỈ shuffle nếu có options (Multiple choice)
|
|
if (Array.isArray(tdv_sdk.curQuestion.options)) {
|
|
tdv_sdk.shuffleArray(tdv_sdk.curQuestion.options);
|
|
}
|
|
|
|
tdv_sdk.questionState = 0;
|
|
return 1;
|
|
};
|
|
|
|
|
|
// ==================== QUESTION STATE MACHINE ====================
|
|
// State: 0 = Roll dice, 1 = Chờ start timer, 2 = Đang đếm, 3 = Chờ hiện đáp án, 4 = Chờ đóng layer
|
|
tdv_sdk.questionState = 0;
|
|
|
|
// Lấy state hiện tại (dùng để check trong Construct)
|
|
tdv_sdk.getQuestionState = function () {
|
|
return tdv_sdk.questionState;
|
|
};
|
|
|
|
// Set state (dùng khi cần set thủ công)
|
|
tdv_sdk.setQuestionState = function (state) {
|
|
tdv_sdk.questionState = state;
|
|
console.log("📍 Question State set to:", state);
|
|
return state;
|
|
};
|
|
|
|
// Xử lý khi bấm Space - trả về state mới
|
|
// questionState: 0 = Roll dice, 1 = Start timer, 2 = Đang đếm, 3 = Show answer, 4 = Close layer
|
|
|
|
tdv_sdk.handleSpacePress = function () {
|
|
switch (tdv_sdk.questionState) {
|
|
case 0:
|
|
// Space: Roll dice
|
|
console.log("🎲 Space 0: Roll dice!");
|
|
return 0;
|
|
|
|
case 1:
|
|
// Space: Bắt đầu đếm giờ (chờ hết giờ mới được bấm tiếp)
|
|
tdv_sdk.questionState = 2;
|
|
gameTimer.resetQuestionTimer();
|
|
console.log("▶️ Space 1: Timer started!");
|
|
return 1;
|
|
|
|
case 2:
|
|
// Đang đếm giờ - Bấm Space sẽ dừng timer và hiện đáp án ngay
|
|
gameTimer.stopTimer();
|
|
tdv_sdk.questionState = 3;
|
|
console.log("⏹️ Space 2: Timer stopped! Show answer.");
|
|
return 2;
|
|
|
|
case 3:
|
|
// Space: Hiện đáp án đúng
|
|
tdv_sdk.questionState = 4;
|
|
console.log("✅ Space 3: Show correct answer!");
|
|
return 3;
|
|
|
|
case 4:
|
|
// Space: Đóng layer câu hỏi
|
|
// LƯU Ý: KHÔNG gọi nextQuestion() ở đây vì Construct đã gọi riêng
|
|
tdv_sdk.questionState = 0;
|
|
console.log("🚪 Space 4: Close question layer!");
|
|
return 4;
|
|
|
|
default:
|
|
return tdv_sdk.questionState;
|
|
}
|
|
};
|
|
|
|
// Gọi khi bắt đầu hiện câu hỏi (sau khi thỏ di chuyển xong)
|
|
// QUAN TRỌNG: Reset timer về 15s và KHÔNG start - chờ Space mới start
|
|
tdv_sdk.startQuestion = function () {
|
|
// Dừng timer cũ nếu đang chạy
|
|
gameTimer.stopTimer();
|
|
// Reset timer về giá trị ban đầu (15s) nhưng KHÔNG start
|
|
gameTimer.currentTime = gameTimer.questionTime;
|
|
// Set state = 1 (chờ Space để start timer)
|
|
tdv_sdk.questionState = 1;
|
|
console.log("❓ Question ready! Timer set to", gameTimer.questionTime, "s. Press Space to start.");
|
|
return 1;
|
|
};
|
|
|
|
// Gọi khi hết giờ (timer = 0)
|
|
tdv_sdk.onTimeUp = function () {
|
|
if (tdv_sdk.questionState === 2) {
|
|
gameTimer.currentTime = 0; // Đảm bảo hiển thị 0
|
|
gameTimer.stopTimer();
|
|
tdv_sdk.questionState = 3;
|
|
console.log("⏰ Time up! Press Space to see answer.");
|
|
}
|
|
return 3;
|
|
};
|
|
|
|
// Gọi khi người chơi trả lời xong (chỉ gọi 1 lần khi đang đếm giờ)
|
|
tdv_sdk.onAnswered = function () {
|
|
// Chỉ xử lý nếu đang ở state 2 (đang đếm giờ)
|
|
if (tdv_sdk.questionState !== 2) {
|
|
console.log("⚠️ onAnswered skipped - already processed");
|
|
return tdv_sdk.questionState;
|
|
}
|
|
gameTimer.stopTimer();
|
|
tdv_sdk.questionState = 3;
|
|
console.log("📝 Answered! Press Space to see answer.");
|
|
return 3;
|
|
};
|
|
|
|
// Check xem câu hỏi hiện tại có phải dạng NGHE không (audio là mảng)
|
|
// Trả về 1 nếu là Listening Question (Q21-Q30), 0 nếu là câu hỏi thường
|
|
tdv_sdk.isListeningQuestion = function () {
|
|
if (!tdv_sdk.curQuestion) return 0;
|
|
return Array.isArray(tdv_sdk.curQuestion.audio) ? 1 : 0;
|
|
};
|
|
|
|
tdv_sdk.getCurQuestion = function () {
|
|
return tdv_sdk.curQuestion.question;
|
|
};
|
|
|
|
tdv_sdk.getCurOptions = function (index) {
|
|
if (!tdv_sdk.curQuestion.options) return "";
|
|
return tdv_sdk.curQuestion.options[index];
|
|
};
|
|
|
|
|
|
// Tính scale phù hợp dựa trên độ dài text đáp án
|
|
// Trả về giá trị scale từ 0.5 đến 1.0
|
|
// maxLength: Độ dài tối đa trước khi bắt đầu thu nhỏ (mặc định 12)
|
|
tdv_sdk.getOptionScale = function (index, maxLength) {
|
|
var text = tdv_sdk.curQuestion.options[index] || "";
|
|
var maxLen = maxLength || 12; // Bắt đầu thu nhỏ khi > 12 ký tự
|
|
var minScale = 0.65; // Scale nhỏ nhất
|
|
var maxScale = 1; // Scale lớn nhất
|
|
|
|
var len = text.length;
|
|
|
|
if (len <= maxLen) {
|
|
return maxScale; // Giữ nguyên scale = 1 nếu text ngắn
|
|
}
|
|
|
|
// Tính toán: giảm dần từ 1.0 đến 0.5 theo độ dài
|
|
var ratio = Math.max(0, 1 - (len - maxLen) / 25);
|
|
var newScale = minScale + (maxScale - minScale) * ratio;
|
|
|
|
// Làm tròn 2 chữ số thập phân
|
|
return Math.round(Math.max(minScale, newScale) * 100) / 100;
|
|
};
|
|
|
|
// Phiên bản linh hoạt hơn - tính scale tuyến tính
|
|
// Điều chỉnh scale mạnh hơn cho text dài
|
|
tdv_sdk.getAnswerScale = function (index, maxLen) {
|
|
// Sử dụng getCurOptions thay vì getAnswerByIndex
|
|
var answer = tdv_sdk.getCurOptions(index);
|
|
if (!answer) return 1;
|
|
|
|
var standardLen = maxLen || 8; // Độ dài chuẩn (giảm từ 10 xuống 8)
|
|
var len = String(answer).length;
|
|
|
|
// Scale mạnh hơn cho text dài
|
|
if (len <= standardLen) return 1; // <= 8 ký tự: scale 1.0
|
|
if (len <= 10) return 0.9; // 9-10 ký tự
|
|
if (len <= 12) return 0.85; // 11-12 ký tự
|
|
if (len <= 14) return 0.8; // 13-14 ký tự (Lunar New Year)
|
|
if (len <= 18) return 0.75; // 15-18 ký tự
|
|
if (len <= 22) return 0.7; // 19-22 ký tự
|
|
return 0.65; // > 22 ký tự: scale tối thiểu
|
|
};
|
|
|
|
// HÀM MỚI: Nhận TEXT trực tiếp thay vì index (tránh lỗi LoopIndex)
|
|
// Sử dụng: tdv_sdk.getTextScale("Lunar New Year")
|
|
tdv_sdk.getTextScale = function (text, maxLen) {
|
|
if (!text) return 1;
|
|
|
|
var standardLen = maxLen || 8;
|
|
var len = String(text).length;
|
|
|
|
// Scale mạnh hơn cho text dài
|
|
if (len <= standardLen) return 1; // <= 8 ký tự: scale 1.0
|
|
if (len <= 10) return 0.85; // 9-10 ký tự
|
|
if (len <= 12) return 0.75; // 11-12 ký tự
|
|
if (len <= 14) return 0.65; // 13-14 ký tự
|
|
if (len <= 18) return 0.55; // 15-18 ký tự
|
|
if (len <= 22) return 0.5; // 19-22 ký tự
|
|
return 0.45; // > 22 ký tự: scale tối thiểu
|
|
};
|
|
|
|
tdv_sdk.getCurCorrectOption = function () {
|
|
return tdv_sdk.correctAnswer;
|
|
};
|
|
|
|
tdv_sdk.getCorrectCount = function () {
|
|
return tdv_sdk.answers;
|
|
};
|
|
|
|
tdv_sdk.getCurImageUrl = function () {
|
|
return tdv_sdk.curQuestion.url;
|
|
};
|
|
|
|
tdv_sdk.nextQuestion = function () {
|
|
tdv_sdk.currentIndex++;
|
|
};
|
|
|
|
tdv_sdk.getCurIndex = function () {
|
|
return tdv_sdk.currentIndex;
|
|
};
|
|
|
|
// Alias cho getCurIndex (tương thích với các game khác)
|
|
tdv_sdk.getCurrentLevel = function () {
|
|
return tdv_sdk.currentIndex;
|
|
};
|
|
|
|
tdv_sdk.getTotalQuestion = function () {
|
|
return tdv_sdk.totalquestion;
|
|
};
|
|
|
|
// Check xem còn câu hỏi không (trả về 1 nếu còn, 0 nếu hết)
|
|
tdv_sdk.hasMoreQuestions = function () {
|
|
return tdv_sdk.currentIndex < tdv_sdk.totalquestion ? 1 : 0;
|
|
};
|
|
|
|
// Check xem đây có phải câu hỏi cuối cùng không (trả về 1 nếu đúng)
|
|
tdv_sdk.isLastQuestion = function () {
|
|
return tdv_sdk.currentIndex >= tdv_sdk.totalquestion - 1 ? 1 : 0;
|
|
};
|
|
|
|
// Check xem game đã kết thúc chưa (trả về 1 nếu hết câu hỏi, 0 nếu còn)
|
|
// Dùng trong Construct: If Browser.ExecJS("tdv_sdk.isGameOver()") = 1 → Game Over
|
|
tdv_sdk.isGameOver = function () {
|
|
return tdv_sdk.currentIndex >= tdv_sdk.totalquestion ? 1 : 0;
|
|
};
|
|
|
|
// Lấy số câu hỏi còn lại
|
|
tdv_sdk.getRemainingQuestions = function () {
|
|
return Math.max(0, tdv_sdk.totalquestion - tdv_sdk.currentIndex);
|
|
};
|
|
|
|
// Reset lại từ đầu (shuffle lại câu hỏi)
|
|
tdv_sdk.reloadQuestions = function () {
|
|
tdv_sdk.currentIndex = 0;
|
|
tdv_sdk.listquestion = [];
|
|
for (let i = 0; i < tdv_sdk.totalquestion; i++) {
|
|
tdv_sdk.listquestion.push(tdv_sdk.list[i]);
|
|
}
|
|
console.log("🔄 Questions reloaded and shuffled!");
|
|
return 1;
|
|
};
|
|
|
|
tdv_sdk.getId = function (index) {
|
|
return tdv_sdk.list[index].id;
|
|
};
|
|
|
|
tdv_sdk.getAnswers = function (index) {
|
|
return tdv_sdk.answers[index];
|
|
};
|
|
|
|
// --- AUDIO: Hỗ trợ cả string đơn và mảng audio ---
|
|
tdv_sdk.currentAudioQueue = [];
|
|
tdv_sdk.currentAudioIndex = 0;
|
|
|
|
tdv_sdk.playSound = function (name) {
|
|
console.log(`Play sound: ${name}`);
|
|
const audioSrc = `https://audio.senaai.vn/audio/en_female_1_${name.toLowerCase()}.mp3`;
|
|
const audio = new Audio(audioSrc);
|
|
audio.play();
|
|
};
|
|
|
|
// Phát audio câu hỏi (hỗ trợ cả string đơn và mảng)
|
|
tdv_sdk.playSoundQuestion = function (rate) {
|
|
// Dừng audio cũ nếu đang chạy
|
|
if (window.audio && !window.audio.paused) {
|
|
window.audio.pause();
|
|
window.audio.currentTime = 0;
|
|
}
|
|
|
|
tdv_sdk.currentAudioQueue = [];
|
|
tdv_sdk.currentAudioIndex = 0;
|
|
|
|
var audioSource = tdv_sdk.curQuestion.audio;
|
|
var playbackRate = rate || 1;
|
|
|
|
if (!audioSource) {
|
|
console.log("Không có audio cho câu hỏi này.");
|
|
return;
|
|
}
|
|
|
|
if (Array.isArray(audioSource)) {
|
|
// Mảng audio (Hội thoại: context + question)
|
|
tdv_sdk.currentAudioQueue = audioSource;
|
|
tdv_sdk.playNextInQueue(playbackRate);
|
|
} else {
|
|
// Audio đơn
|
|
tdv_sdk.playSingleAudio(audioSource, playbackRate);
|
|
}
|
|
};
|
|
|
|
tdv_sdk.playSingleAudio = function (src, rate) {
|
|
var audio = new Audio(src);
|
|
audio.playbackRate = rate;
|
|
window.audio = audio;
|
|
audio.play().catch(e => console.error("Lỗi phát audio:", e));
|
|
console.log(`Đang phát: ${src}`);
|
|
};
|
|
|
|
tdv_sdk.playNextInQueue = function (rate) {
|
|
if (tdv_sdk.currentAudioIndex >= tdv_sdk.currentAudioQueue.length) {
|
|
console.log("Đã phát hết đoạn hội thoại.");
|
|
return;
|
|
}
|
|
|
|
var src = tdv_sdk.currentAudioQueue[tdv_sdk.currentAudioIndex];
|
|
var audio = new Audio(src);
|
|
audio.playbackRate = rate;
|
|
window.audio = audio;
|
|
|
|
audio.onended = function () {
|
|
tdv_sdk.currentAudioIndex++;
|
|
setTimeout(function () {
|
|
tdv_sdk.playNextInQueue(rate);
|
|
}, 300);
|
|
};
|
|
|
|
audio.play().catch(e => console.error("Lỗi phát audio:", e));
|
|
console.log(`Đang phát đoạn ${tdv_sdk.currentAudioIndex + 1}: ${src}`);
|
|
};
|
|
|
|
tdv_sdk.stopSound = function () {
|
|
if (window.audio && !window.audio.paused) {
|
|
window.audio.pause();
|
|
window.audio.currentTime = 0;
|
|
}
|
|
tdv_sdk.currentAudioQueue = [];
|
|
tdv_sdk.currentAudioIndex = 0;
|
|
};
|
|
|
|
// Tất cả 4 đáp án sẽ có cùng kích thước chữ
|
|
tdv_sdk.getUniformScale = function () {
|
|
if (!tdv_sdk.curQuestion) return 1;
|
|
|
|
var options = tdv_sdk.curQuestion.options;
|
|
var maxLen = 0;
|
|
|
|
// Tìm độ dài của đáp án dài nhất
|
|
for (var i = 0; i < options.length; i++) {
|
|
var len = String(options[i] || "").length;
|
|
if (len > maxLen) maxLen = len;
|
|
}
|
|
|
|
// Tính scale dựa trên đáp án dài nhất
|
|
if (maxLen <= 8) return 1;
|
|
if (maxLen <= 10) return 0.95;
|
|
if (maxLen <= 12) return 0.9;
|
|
if (maxLen <= 14) return 0.85;
|
|
if (maxLen <= 18) return 0.8;
|
|
if (maxLen <= 22) return 0.75;
|
|
return 0.7;
|
|
};
|
|
|
|
|
|
tdv_sdk.goHome = function () {
|
|
window.location.href = "../";
|
|
};
|
|
|
|
// ==================== QUESTION TIMER (Mỗi câu hỏi 10 giây) ====================
|
|
var gameTimer = {};
|
|
gameTimer.questionTime = 10; // Thời gian mỗi câu hỏi (giây)
|
|
gameTimer.currentTime = gameTimer.questionTime;
|
|
gameTimer.isRunning = false;
|
|
gameTimer.intervalId = null;
|
|
|
|
// Bắt đầu đếm ngược cho câu hỏi hiện tại
|
|
gameTimer.startTimer = function () {
|
|
if (gameTimer.isRunning) {
|
|
console.warn("Timer is already running.");
|
|
return 0;
|
|
}
|
|
|
|
gameTimer.isRunning = true;
|
|
gameTimer.intervalId = setInterval(function () {
|
|
if (gameTimer.currentTime > 0) {
|
|
gameTimer.currentTime--;
|
|
} else {
|
|
gameTimer.stopTimer();
|
|
console.log("⏰ Question time is up!");
|
|
}
|
|
}, 1000);
|
|
|
|
console.log("⏱️ Question timer started:", gameTimer.questionTime, "seconds.");
|
|
return 1;
|
|
};
|
|
|
|
gameTimer.stopTimer = function () {
|
|
if (gameTimer.intervalId) {
|
|
clearInterval(gameTimer.intervalId);
|
|
gameTimer.intervalId = null;
|
|
gameTimer.isRunning = false;
|
|
console.log("Timer stopped.");
|
|
}
|
|
};
|
|
|
|
gameTimer.resetTimer = function () {
|
|
gameTimer.stopTimer();
|
|
gameTimer.currentTime = gameTimer.questionTime;
|
|
console.log("⏱️ Timer reset to:", gameTimer.questionTime, "seconds.");
|
|
};
|
|
|
|
// Reset timer cho câu hỏi mới (gọi khi loadquestion) - CHỈ RESET, KHÔNG START
|
|
gameTimer.prepareQuestionTimer = function () {
|
|
gameTimer.stopTimer();
|
|
gameTimer.currentTime = gameTimer.questionTime;
|
|
console.log("⏱️ Timer prepared:", gameTimer.questionTime, "seconds. Press Space to start.");
|
|
return 1;
|
|
};
|
|
|
|
// Reset VÀ start timer (gọi khi bấm Space)
|
|
gameTimer.resetQuestionTimer = function () {
|
|
gameTimer.stopTimer();
|
|
gameTimer.currentTime = gameTimer.questionTime;
|
|
gameTimer.startTimer();
|
|
console.log("🔄 Timer started:", gameTimer.questionTime, "seconds.");
|
|
return 1;
|
|
};
|
|
|
|
// Set thời gian mỗi câu hỏi (mặc định 10 giây)
|
|
gameTimer.setQuestionTime = function (seconds) {
|
|
gameTimer.questionTime = seconds || 10;
|
|
console.log("⚙️ Question time set to:", gameTimer.questionTime, "seconds.");
|
|
return gameTimer.questionTime;
|
|
};
|
|
|
|
gameTimer.getFormattedTime = function () {
|
|
if (gameTimer.currentTime < 0) return "0:00";
|
|
|
|
const minutes = Math.floor(gameTimer.currentTime / 60);
|
|
const seconds = gameTimer.currentTime % 60;
|
|
const formattedSeconds = seconds < 10 ? '0' + seconds : seconds;
|
|
|
|
return minutes + ':' + formattedSeconds;
|
|
};
|
|
|
|
gameTimer.getCurrentTimeValue = function () {
|
|
return gameTimer.currentTime;
|
|
};
|
|
|
|
// Trả về thời gian hiển thị (luôn = 0 nếu đã hết giờ)
|
|
gameTimer.getDisplayTime = function () {
|
|
// Nếu đã hết giờ (state >= 3), luôn trả về 0
|
|
if (tdv_sdk.questionState >= 3) {
|
|
return 0;
|
|
}
|
|
return Math.max(0, gameTimer.currentTime);
|
|
};
|
|
|
|
gameTimer.pauseTimer = function () {
|
|
if (gameTimer.isRunning) {
|
|
clearInterval(gameTimer.intervalId);
|
|
gameTimer.intervalId = null;
|
|
gameTimer.isRunning = false;
|
|
console.log("Timer paused at:", gameTimer.getFormattedTime());
|
|
return 1;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
gameTimer.resumeTimer = function () {
|
|
if (!gameTimer.isRunning && gameTimer.currentTime > 0) {
|
|
gameTimer.isRunning = true;
|
|
gameTimer.intervalId = setInterval(function () {
|
|
if (gameTimer.currentTime > 0) {
|
|
gameTimer.currentTime--;
|
|
} else {
|
|
gameTimer.stopTimer();
|
|
console.log("Time is up!");
|
|
}
|
|
}, 1000);
|
|
|
|
console.log("Timer resumed from:", gameTimer.getFormattedTime());
|
|
return 1;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
// ==================== GAME SCORE ====================
|
|
var gameScore = {};
|
|
gameScore.currentScore = 0;
|
|
|
|
gameScore.addScore = function (points) {
|
|
const pts = parseInt(points) || 0;
|
|
if (pts > 0) {
|
|
gameScore.currentScore += pts;
|
|
console.log(`Score added: ${pts}. New score: ${gameScore.currentScore}`);
|
|
}
|
|
return gameScore.currentScore;
|
|
};
|
|
|
|
gameScore.resetScore = function () {
|
|
gameScore.currentScore = 0;
|
|
console.log("Score reset to 0.");
|
|
return 0;
|
|
};
|
|
|
|
gameScore.getScore = function () {
|
|
return gameScore.currentScore;
|
|
};
|
|
|
|
gameScore.deductScore = function (points) {
|
|
const pts = parseInt(points) || 0;
|
|
if (gameScore.currentScore >= pts) {
|
|
gameScore.currentScore -= pts;
|
|
console.log(`Score deducted: ${pts}. New score: ${gameScore.currentScore}`);
|
|
} else {
|
|
gameScore.currentScore = 0;
|
|
console.log(`Score deducted. New score is 0.`);
|
|
}
|
|
return gameScore.currentScore;
|
|
};
|
|
|
|
// ==================== GAME LIVES ====================
|
|
var gameLives = {};
|
|
gameLives.maxLives = 3;
|
|
gameLives.currentLives = gameLives.maxLives;
|
|
|
|
gameLives.resetLives = function () {
|
|
gameLives.currentLives = gameLives.maxLives;
|
|
console.log("Lives reset to:", gameLives.maxLives);
|
|
return gameLives.currentLives;
|
|
};
|
|
|
|
gameLives.loseLife = function () {
|
|
if (gameLives.currentLives > 0) {
|
|
gameLives.currentLives--;
|
|
console.log("Lost 1 life. Remaining:", gameLives.currentLives);
|
|
} else {
|
|
console.log("No lives left. Game Over condition.");
|
|
}
|
|
return gameLives.currentLives;
|
|
};
|
|
|
|
gameLives.getLives = function () {
|
|
return gameLives.currentLives;
|
|
};
|
|
|
|
// ==================== INSTRUCTIONS ====================
|
|
tdv_sdk.getQuizInstructions = function () {
|
|
const instructions =
|
|
" 🌟 HƯỚNG DẪN GAME: HÀNH TRÌNH CỦA THỎ 🌟\n\n" +
|
|
"🎯 MỤC TIÊU:\n" +
|
|
" Giúp chú thỏ đi hết hành trình và đến đích! Trả lời đúng các câu hỏi để ghi thật nhiều điểm trên đường đi.\n\n" +
|
|
"🌀 CÁCH CHƠI:\n" +
|
|
" 1. Lắc xúc xắc: Chạm vào xúc xắc để quay.\n" +
|
|
" 2. Di chuyển: Chú thỏ sẽ đi theo số chấm xuất hiện trên xúc xắc.\n" +
|
|
" 3. Trả lời câu hỏi: Khi chú thỏ dừng lại, chọn đáp án đúng hiển thị trên màn hình.\n" +
|
|
" 4. Tiếp tục hành trình: Sau khi trả lời, bạn có thể quay lại xúc xắc ngay để đi tiếp.\n\n" +
|
|
"💡 ĐIỂM SỐ VÀ THỬ THÁCH:\n" +
|
|
" ✅ Đúng: +100 điểm.\n" +
|
|
" ❌ Sai: Không bị trừ điểm hay phạt.\n" +
|
|
" 🐺 Nguy hiểm: Nếu dừng ở ô **'SÓI'** (Wolf), bạn sẽ bị trừ 100 điểm ngay lập tức.\n\n" +
|
|
"🍀 Cùng chú thỏ phiêu lưu, trả lời câu hỏi và ghi thật nhiều điểm trên hành trình nhé!";
|
|
|
|
return instructions;
|
|
};
|
|
|
|
tdv_sdk.hasAudio = function () {
|
|
if (!tdv_sdk.curQuestion) return 0;
|
|
var audio = tdv_sdk.curQuestion.audio;
|
|
// Check nếu là mảng và có item
|
|
if (Array.isArray(audio) && audio.length > 0) return 1;
|
|
// Check nếu là string và không rỗng
|
|
if (typeof audio === 'string' && audio.trim() !== '') return 1;
|
|
return 0;
|
|
}; |