Lashtw commited on
Commit
5ce0f9e
·
verified ·
1 Parent(s): dc9ab84

Upload 41 files

Browse files
Files changed (1) hide show
  1. spring.js +184 -458
spring.js CHANGED
@@ -1,11 +1,11 @@
1
- document.addEventListener(\'DOMContentLoaded\', function() {
2
  // 檢查是否有玩家資料
3
  const currentPlayerId = localStorage.getItem('currentPlayerId');
4
- const playerName = localStorage.getItem('playerName');
5
- const playerProfession = localStorage.getItem('playerProfession');
6
 
7
  // 如果沒有玩家資料,重定向到首頁
8
- if (!currentPlayerId || !playerName || !playerProfession) {
9
  alert('請先登入遊戲!');
10
  window.location.href = 'index.html';
11
  return;
@@ -18,515 +18,241 @@ document.addEventListener(\'DOMContentLoaded\', function() {
18
  const startChallengeBtn = document.getElementById('start-challenge');
19
  const questionText = document.getElementById('question-text');
20
  const optionsContainer = document.getElementById('options-container');
21
- const resultFeedback = document.getElementById('result-feedback');
22
- const progressCount = document.getElementById('progress-count');
23
- const progressFill = document.getElementById('progress-fill');
24
  const backToMapBtn = document.getElementById('back-to-map');
25
- const nextTrialBtn = document.getElementById('next-trial');
26
- const bgmAudio = document.getElementById('bgm');
27
- const correctSound = document.getElementById('correct-sound');
28
- const wrongSound = document.getElementById('wrong-sound');
29
- const toggleBgmBtn = document.getElementById('toggle-bgm');
30
-
31
- // 音樂控制
32
- let isBgmPlaying = false;
33
-
34
- // 播放背景音樂
35
- function playBgm() {
36
- bgmAudio.volume = 0.3; // 設置音量
37
- bgmAudio.play().catch(e => console.log('自動播放被阻止:', e));
38
- isBgmPlaying = true;
39
- }
40
-
41
- // 嘗試自動播放背景音樂(大多數瀏覽器會阻止)
42
- playBgm();
43
-
44
- // 音樂開關按鈕
45
- toggleBgmBtn.addEventListener('click', function() {
46
- if (isBgmPlaying) {
47
- bgmAudio.pause();
48
- isBgmPlaying = false;
49
- toggleBgmBtn.textContent = '音樂開';
50
- } else {
51
- bgmAudio.play();
52
- isBgmPlaying = true;
53
- toggleBgmBtn.textContent = '音樂關';
54
- }
55
- });
56
-
57
- // 問題集
58
- const questions = [
59
- {
60
- question: "Q1. 8 的平方是多少?",
61
- options: ["(A) 56", "(B) 64", "(C) 72", "(D) 81"],
62
- correctIndex: 1
63
- },
64
- {
65
- question: "Q2. 哪個數的平方是 121?",
66
- options: ["(A) 10", "(B) 11", "(C) 12", "(D) 13"],
67
- correctIndex: 1
68
- },
69
- {
70
- question: "Q3. 5 的平方是多少?",
71
- options: ["(A) 20", "(B) 30", "(C) 25", "(D) 35"],
72
- correctIndex: 2
73
- },
74
- {
75
- question: "Q4. 哪個數的平方是 36?",
76
- options: ["(A) 6", "(B) 7", "(C) 5", "(D) 8"],
77
- correctIndex: 0
78
- },
79
- {
80
- question: "Q5. 12 的平方是多少?",
81
- options: ["(A) 124", "(B) 132", "(C) 144", "(D) 154"],
82
- correctIndex: 2
83
- },
84
- {
85
- question: "Q6. 哪個數的平方是 49?",
86
- options: ["(A) 6", "(B) 8", "(C) 7", "(D) 9"],
87
- correctIndex: 2
88
- }
89
- ];
90
 
 
91
  let currentQuestionIndex = 0;
92
- let correctAnswers = 0;
93
- let correctStreak = 0;
94
- let maxCorrectStreak = 0;
95
- let startTime = null;
96
- let questionStartTime = null;
97
- let fastestQuestionTime = 999;
98
- let errors = 0; // 開始考驗按鈕點擊事件
99
- startChallengeBtn.addEventListener(\'click\', function() {
100
- console.log(\'開始考驗按鈕被點擊\');
101
- storySection.style.display = \'none\';
102
- quizSection.style.display = \'block\';
103
- startTime = new Date();
104
- questionStartTime = new Date();
105
- showQuestion(currentQuestionIndex);
106
- });tion(currentQuestionIndex);
107
- });
108
 
109
- // 預先載入成就系統
110
- function loadAchievementSystem() {
111
- console.log('預先載入成就系統');
112
- if (!window.achievementSystem) {
113
- const script = document.createElement('script');
114
- script.src = 'achievements.js';
115
- script.onload = function() {
116
- console.log('成就系統腳本載入完成');
117
- };
118
- document.head.appendChild(script);
119
 
120
- // 確保成就系統容器存在
121
- if (!document.getElementById('toast-container')) {
122
- const toastContainer = document.createElement('div');
123
- toastContainer.className = 'toast-container';
124
- toastContainer.id = 'toast-container';
125
- document.body.appendChild(toastContainer);
 
126
  }
 
 
 
 
 
 
 
 
 
127
  }
128
  }
129
 
130
- // 顯示問題
131
- function showQuestion(index) {
132
- const question = questions[index];
 
 
 
 
 
133
  questionText.textContent = question.question;
134
 
135
  // 清空選項容器
136
  optionsContainer.innerHTML = '';
137
 
138
- // 添加選項
139
- question.options.forEach((option, i) => {
140
  const button = document.createElement('button');
141
- button.className = 'option-btn';
142
  button.textContent = option;
143
- button.dataset.index = i;
144
-
145
- button.addEventListener('click', function() {
146
- checkAnswer(i);
147
- });
148
-
149
  optionsContainer.appendChild(button);
150
  });
151
 
152
- // 清空結果反饋
153
- resultFeedback.textContent = '';
154
 
155
- // 記錄問題開始時間
156
- questionStartTime = new Date();
157
  }
158
 
159
- // 檢查答案
160
- function checkAnswer(selectedIndex) {
161
- const correctIndex = questions[currentQuestionIndex].correctIndex;
162
- const optionButtons = document.querySelectorAll('.option-btn');
163
-
164
- // 計算回答時間
165
- const now = new Date();
166
- const questionTime = (now - questionStartTime) / 1000; // 轉換為秒
167
-
168
- // 更新最快回答時間
169
- if (questionTime < fastestQuestionTime) {
170
- fastestQuestionTime = questionTime;
171
- }
172
 
173
  // 禁用所有選項按鈕
174
- optionButtons.forEach(button => {
175
- button.classList.add('disabled');
176
- button.disabled = true;
 
 
 
 
 
 
 
177
  });
178
 
179
- // 標記正確和錯誤的選項
180
- optionButtons[correctIndex].classList.add('correct');
181
-
182
- if (selectedIndex !== correctIndex) {
183
- optionButtons[selectedIndex].classList.add('incorrect');
184
- resultFeedback.textContent = '答錯了,再接再厲!';
185
- // 播放錯誤音效
186
- wrongSound.currentTime = 0;
187
- wrongSound.play().catch(e => console.log('音效播放失敗:', e));
188
- // 重置連續正確計數
189
- correctStreak = 0;
190
- // 增加錯誤計數
191
- errors++;
192
- } else {
193
- correctAnswers++;
194
- resultFeedback.textContent = '答對了,太棒了!';
195
  // 播放正確音效
196
- correctSound.currentTime = 0;
197
- correctSound.play().catch(e => console.log('音效播放失敗:', e));
198
- // 增加連續正確計數
199
- correctStreak++;
200
- // 更新最大連續正確計數
201
- if (correctStreak > maxCorrectStreak) {
202
- maxCorrectStreak = correctStreak;
203
- }
204
  }
205
 
206
- // 更新進度
207
- progressCount.textContent = correctAnswers;
208
- progressFill.style.width = (correctAnswers / questions.length * 100) + '%';
209
 
210
- // 延遲後進入下一題或完成
211
  setTimeout(() => {
212
- currentQuestionIndex++;
213
-
214
- if (currentQuestionIndex < questions.length) {
215
- showQuestion(currentQuestionIndex);
216
- } else {
217
- // 完成所有問題
218
- quizSection.style.display = 'none';
219
-
220
- // 檢查是否至少答對4題
221
- if (correctAnswers >= 4) {
222
- completionSection.style.display = 'block';
223
- // 更新遊戲進度
224
- updateGameProgress();
225
- } else {
226
- // 未達到通過標準,顯示重試訊息
227
- alert(`你只答對了${correctAnswers}題,需要至少答對4題才能通過試煉。請重新挑戰!`);
228
- // 重置問題
229
- currentQuestionIndex = 0;
230
- correctAnswers = 0;
231
- correctStreak = 0;
232
- errors = 0;
233
- progressCount.textContent = '0';
234
- progressFill.style.width = '0%';
235
- // 返回故事部分
236
- storySection.style.display = 'block';
237
- }
238
- }
239
- }, 2000);
240
  }
241
 
242
- // 更新遊戲進度
243
- function updateGameProgress() {
244
- console.log('更新遊戲進度');
245
- const gameProgress = JSON.parse(localStorage.getItem(`gameProgress_${currentPlayerId}`)) || {};
246
-
247
- if (!gameProgress.completedTrials) {
248
- gameProgress.completedTrials = {};
249
- }
250
-
251
- // 計算當前得分和星數
252
- const currentScore = (correctAnswers / questions.length) * 100;
253
- let currentStars = 0;
254
- if (correctAnswers >= 6) currentStars = 3;
255
- else if (correctAnswers >= 5) currentStars = 2;
256
- else if (correctAnswers >= 4) currentStars = 1;
257
-
258
- // 計算完成時間
259
- const endTime = new Date();
260
- const trialTime = (endTime - startTime) / 1000; // 轉換為秒
261
-
262
- // 檢查是否已有平方之泉的紀錄
263
- const existingTrial = gameProgress.completedTrials["平方之泉"];
264
- const isFirstCompletion = !existingTrial || !existingTrial.completed;
265
- const isFirstThreeStars = currentStars === 3 && (!existingTrial || !existingTrial.stars || existingTrial.stars < 3);
266
- const isPerfect = errors === 0;
267
-
268
- console.log(`試煉結果: 答對${correctAnswers}題,星數${currentStars},錯誤${errors}次,時間${trialTime}秒`);
269
- console.log(`是否首次完成: ${isFirstCompletion}, 是否首次3星: ${isFirstThreeStars}, 是否完美: ${isPerfect}`);
270
-
271
- // 如果沒有紀錄或當前星數更高,則更新
272
- if (!existingTrial || !existingTrial.stars || currentStars > existingTrial.stars) {
273
- gameProgress.completedTrials["平方之泉"] = {
274
- completed: true,
275
- score: currentScore,
276
- stars: currentStars,
277
- challengesCompleted: Array(questions.length).fill(false).map((_, i) => i < correctAnswers),
278
- noErrors: isPerfect,
279
- completionTime: trialTime
280
- };
281
- }
282
-
283
- gameProgress.currentLocation = "平方之泉";
284
- gameProgress.lastSaved = new Date().toISOString();
285
-
286
- localStorage.setItem(`gameProgress_${currentPlayerId}`, JSON.stringify(gameProgress));
287
-
288
- // 檢查成就
289
- checkAchievements(gameProgress, currentStars, trialTime, isPerfect);
290
  }
291
 
292
- // 檢查成就
293
- function checkAchievements(gameProgress, currentStars, trialTime, isPerfect) {
294
- console.log('檢查成就');
295
- // 構建遊戲狀態
296
- const gameState = {
297
- // 基本信息
298
- loginCount: parseInt(localStorage.getItem(\'loginCount\') || \'1\'),
299
- prologueCompleted: localStorage.getItem(\'prologueCompleted\') === \'true\'),
300
-
301
- // 試煉相關
302
- visitedTrials: [\'平方之泉\'],
303
- completedTrials: {
304
- "平方之泉": {
305
- completed: true,
306
- score: currentScore,
307
- stars: currentStars,
308
- challengesCompleted: Array(questions.length).fill(false).map((_, i) => i < correctAnswers),
309
- noErrors: isPerfect,
310
- completionTime: trialTime
311
- }
312
- },
313
-
314
- // 其他統計
315
- maxCorrectStreak: maxCorrectStreak,
316
- fastestTrialTime: trialTime,
317
- fastestQuestionTime: fastestQuestionTime,
318
- retriesAfterFailure: parseInt(localStorage.getItem(\'retriesAfterFailure\') || \'0\'),
319
- lastTrialCompletionTime: new Date(),
320
- lastTrialStartTime: startTime,
321
-
322
- // 特殊條件
323
- allThreeStarsSameDay: false,
324
- firstAttemptAllThreeStars: isFirstThreeStars,
325
- musicEnabledAllTrials: isBgmPlaying,
326
- musicDisabledAllTrials: !isBgmPlaying,
327
-
328
- // 額外資訊
329
- totalStars: currentStars,
330
- currentTrialTime: trialTime,
331
- currentTrialErrors: errors,
332
- currentTrialCombo: maxCorrectStreak
333
- }; // 檢查其他試煉的完成情況
334
- if (gameProgress.completedTrials && gameProgress.completedTrials["變換山谷"]?.completed) {
335
- gameState.visitedTrials.push('變換山谷');
336
- gameState.completedTrials["變換山谷"] = {
337
- completed: true,
338
- stars: gameProgress.completedTrials["變換山谷"].stars || 0,
339
- noErrors: gameProgress.completedTrials["變換山谷"].noErrors || false
340
- };
341
- }
342
-
343
- if (gameProgress.completedTrials && gameProgress.completedTrials["展開之塔"]?.completed) {
344
- gameState.visitedTrials.push('展開之塔');
345
- gameState.completedTrials["展開之塔"] = {
346
- completed: true,
347
- stars: gameProgress.completedTrials["展開之塔"].stars || 0,
348
- noErrors: gameProgress.completedTrials["展開之塔"].noErrors || false
349
- };
350
- }
351
-
352
- // 確保成就系統已載入
353
- ensureAchievementSystemLoaded(function() {
354
- console.log('成就系統已載入,開始檢查成就');
355
-
356
- // 使用全域函數檢查所有成就
357
- if (window.checkAllAchievements) {
358
- console.log('使用全域函數檢查所有成就');
359
- window.checkAllAchievements(gameState);
360
- }
361
- // 使用成就系統實例檢查所有成就
362
- else if (window.achievementSystem) {
363
- console.log('使用成就系統實例檢查所有成就');
364
- window.achievementSystem.checkAllAchievements(gameState);
365
- }
366
- // 直接解鎖特定成就
367
- else {
368
- console.log('成就系統未載入,直接解鎖特定成就');
369
- directUnlockAchievements(gameState);
370
- }
371
- });
372
  }
373
 
374
- // 確保成就系統已載入
375
- function ensureAchievementSystemLoaded(callback) {
376
- console.log('確保成就系統已載入');
377
-
378
- // 如果成就系統已載入,直接執行回調
379
- if (window.achievementSystem) {
380
- console.log('成就系統已載入,直接執行回調');
381
- callback();
382
- return;
383
- }
384
-
385
- console.log('成就系統尚未載入,重新載入並等待');
386
-
387
- // 如果成就系統尚未載入,重新載入並等待
388
- const script = document.createElement('script');
389
- script.src = 'achievements.js';
390
- script.onload = function() {
391
- console.log('成就系統腳本載入完成,執行回調');
392
- callback();
393
- };
394
- document.head.appendChild(script);
395
  }
396
 
397
- // 直接解鎖特定成就
398
- function directUnlockAchievements(gameState) {
399
- console.log('直接解鎖特定成就');
400
-
401
- // 首次完成平方之泉試煉
402
- if (gameState.completedTrials["平方之泉"].completed) {
403
- unlockAchievement('trial_1', '泉水初體驗', '首次完成平方之泉試煉', 'trial');
404
- }
405
-
406
- // 在平方之泉獲得3星
407
- if (gameState.completedTrials["平方之泉"].stars === 3) {
408
- unlockAchievement('trial_2', '泉水專家', '在平方之泉獲得3星', 'trial');
409
- }
410
-
411
- // 在平方之泉中不犯任何錯誤
412
- if (gameState.completedTrials["平方之泉"].noErrors) {
413
- unlockAchievement('trial_3', '泉水完美主義者', '在平方之泉中不犯任何錯誤', 'trial');
414
- }
415
-
416
- // 連續答對10題
417
- if (gameState.maxCorrectStreak >= 10) {
418
- unlockAchievement('trial_10', '連擊大師', '連續答對10題', 'trial');
419
- }
420
-
421
- // 連續答對20題
422
- if (gameState.maxCorrectStreak >= 20) {
423
- unlockAchievement('trial_11', '超級連擊', '連續答對20題', 'trial');
424
  }
 
425
 
426
- // 在30秒內完成一個試煉
427
- if (gameState.fastestTrialTime <= 30) {
428
- unlockAchievement('trial_12', '速度之王', '在30秒內完成一個試煉', 'trial');
429
- }
430
 
431
- // 在5秒內答對一題
432
- if (gameState.fastestQuestionTime <= 5) {
433
- unlockAchievement('trial_13', '閃電思考', '在5秒內答對一題', 'trial');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
434
  }
435
  }
436
 
437
- // 手動解鎖成就並顯示通知
438
- function unlockAchievement(id, title, description, type) {
439
- console.log(`手動解鎖成就: ${id} - ${title}`);
 
440
 
441
- // 檢查成就是否已解鎖
442
- const savedProgress = localStorage.getItem('userAchievements');
443
- const userAchievements = savedProgress ? JSON.parse(savedProgress) : {};
444
 
445
- // 如果成就已經解鎖,不做任何事
446
- if (userAchievements[id]?.unlocked) {
447
- console.log(`成就 "${title}" 已經解鎖過了`);
448
- return;
 
 
 
 
 
449
  }
450
 
451
- // 設定成就為已解鎖
452
- const now = new Date();
453
- const formattedDate = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
454
-
455
- userAchievements[id] = {
456
- unlocked: true,
457
- unlockedAt: formattedDate
458
- };
459
-
460
- // 儲存使用者成就進度
461
- localStorage.setItem('userAchievements', JSON.stringify(userAchievements));
462
-
463
- // 顯示成就解鎖通知
464
- showAchievementToast(title, description, type);
465
 
466
- console.log(`成就 "${title}" 已解鎖!`);
467
  }
468
 
469
- // 顯示成就解鎖通知
470
- function showAchievementToast(title, description, type) {
471
- console.log(`顯示成就解鎖通知: ${title}`);
472
-
473
- const toastContainer = document.getElementById('toast-container') || createToastContainer();
474
-
475
- // 創建通知元素
476
- const toast = document.createElement('div');
477
- toast.className = `toast ${type}`;
478
-
479
- // 設定成就圖示 (使用emoji)
480
- let icon = '🏆';
481
- switch (type) {
482
- case 'journey':
483
- icon = '🧭';
484
- break;
485
- case 'trial':
486
- icon = '⚔️';
487
- break;
488
- case 'secret':
489
- icon = '🔮';
490
- break;
491
- }
492
-
493
- // 通知內容
494
- toast.innerHTML = `
495
- <div class="toast-icon">${icon}</div>
496
- <div class="toast-content">
497
- <div class="toast-title">成就解鎖!</div>
498
- <div>【${title}】:${description}</div>
499
- </div>
500
- `;
501
-
502
- // 添加到通知容器
503
- toastContainer.appendChild(toast);
504
-
505
- // 等待動畫完成後移除通知
506
- setTimeout(() => {
507
- toast.remove();
508
- }, 5000);
509
  }
510
 
511
- // 創建通知容器
512
- function createToastContainer() {
513
- console.log('創建通知容器');
514
-
515
- const toastContainer = document.createElement('div');
516
- toastContainer.className = 'toast-container';
517
- toastContainer.id = 'toast-container';
518
- document.body.appendChild(toastContainer);
519
- return toastContainer;
520
  }
521
 
522
- // 返回王國地圖按鈕點擊事件
523
- backToMapBtn.addEventListener('click', function() {
524
- window.location.href = 'kingdom_map.html';
525
- });
 
 
526
 
527
- // 前往下一試煉按鈕點擊事件
528
- nextTrialBtn.addEventListener('click', function() {
529
- // 直接導向變換山谷
530
- window.location.href = 'valley.html';
531
- });
532
  });
 
 
1
+ document.addEventListener('DOMContentLoaded', function() {
2
  // 檢查是否有玩家資料
3
  const currentPlayerId = localStorage.getItem('currentPlayerId');
4
+ const playerName = localStorage.getItem('currentPlayerName');
5
+ const playerProfession = localStorage.getItem('currentPlayerProfession');
6
 
7
  // 如果沒有玩家資料,重定向到首頁
8
+ if (!currentPlayerId) {
9
  alert('請先登入遊戲!');
10
  window.location.href = 'index.html';
11
  return;
 
18
  const startChallengeBtn = document.getElementById('start-challenge');
19
  const questionText = document.getElementById('question-text');
20
  const optionsContainer = document.getElementById('options-container');
21
+ const nextQuestionBtn = document.getElementById('next-question');
 
 
22
  const backToMapBtn = document.getElementById('back-to-map');
23
+ const progressBar = document.getElementById('progress-bar');
24
+ const progressText = document.getElementById('progress-text');
25
+ const scoreDisplay = document.getElementById('score-display');
26
+ const finalScoreDisplay = document.getElementById('final-score');
27
+ const starsDisplay = document.getElementById('stars-display');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
+ // 遊戲狀態
30
  let currentQuestionIndex = 0;
31
+ let score = 0;
32
+ let totalQuestions = 10;
33
+ let questions = [];
34
+ let startTime = Date.now();
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ // 生成平方題目
37
+ function generateQuestions() {
38
+ questions = [];
39
+ for (let i = 0; i < totalQuestions; i++) {
40
+ const base = Math.floor(Math.random() * 10) + 1; // 1-10
41
+ const answer = base * base;
 
 
 
 
42
 
43
+ // 生成錯誤選項
44
+ const wrongAnswers = [];
45
+ while (wrongAnswers.length < 3) {
46
+ const wrong = answer + Math.floor(Math.random() * 20) - 10;
47
+ if (wrong !== answer && wrong > 0 && !wrongAnswers.includes(wrong)) {
48
+ wrongAnswers.push(wrong);
49
+ }
50
  }
51
+
52
+ // 隨機排列選項
53
+ const options = [answer, ...wrongAnswers].sort(() => Math.random() - 0.5);
54
+
55
+ questions.push({
56
+ question: `${base}² = ?`,
57
+ options: options,
58
+ correctAnswer: answer
59
+ });
60
  }
61
  }
62
 
63
+ // 顯示當前題目
64
+ function showQuestion() {
65
+ if (currentQuestionIndex >= questions.length) {
66
+ showCompletion();
67
+ return;
68
+ }
69
+
70
+ const question = questions[currentQuestionIndex];
71
  questionText.textContent = question.question;
72
 
73
  // 清空選項容器
74
  optionsContainer.innerHTML = '';
75
 
76
+ // 創建選項按鈕
77
+ question.options.forEach((option, index) => {
78
  const button = document.createElement('button');
 
79
  button.textContent = option;
80
+ button.className = 'option-btn';
81
+ button.addEventListener('click', () => selectAnswer(option, button));
 
 
 
 
82
  optionsContainer.appendChild(button);
83
  });
84
 
85
+ // 更新進度
86
+ updateProgress();
87
 
88
+ // 隱藏下一題按鈕
89
+ nextQuestionBtn.style.display = 'none';
90
  }
91
 
92
+ // 選擇答案
93
+ function selectAnswer(selectedAnswer, buttonElement) {
94
+ const question = questions[currentQuestionIndex];
95
+ const isCorrect = selectedAnswer === question.correctAnswer;
 
 
 
 
 
 
 
 
 
96
 
97
  // 禁用所有選項按鈕
98
+ const allButtons = optionsContainer.querySelectorAll('.option-btn');
99
+ allButtons.forEach(btn => btn.disabled = true);
100
+
101
+ // 標記正確和錯誤答案
102
+ allButtons.forEach(btn => {
103
+ if (parseInt(btn.textContent) === question.correctAnswer) {
104
+ btn.classList.add('correct');
105
+ } else if (btn === buttonElement && !isCorrect) {
106
+ btn.classList.add('incorrect');
107
+ }
108
  });
109
 
110
+ if (isCorrect) {
111
+ score++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  // 播放正確音效
113
+ const correctAudio = new Audio('bingo.mp3');
114
+ correctAudio.play().catch(e => console.log('音效播放失敗:', e));
115
+ } else {
116
+ // 播放錯誤音效
117
+ const wrongAudio = new Audio('wrong.mp3');
118
+ wrongAudio.play().catch(e => console.log('音效播放失敗:', e));
 
 
119
  }
120
 
121
+ // 更新分數顯示
122
+ updateScore();
 
123
 
124
+ // 顯示下一題按鈕
125
  setTimeout(() => {
126
+ nextQuestionBtn.style.display = 'block';
127
+ }, 1000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  }
129
 
130
+ // 更新進度
131
+ function updateProgress() {
132
+ const progress = ((currentQuestionIndex + 1) / totalQuestions) * 100;
133
+ progressBar.style.width = progress + '%';
134
+ progressText.textContent = `第 ${currentQuestionIndex + 1} 題 / 共 ${totalQuestions} 題`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  }
136
 
137
+ // 更新分數
138
+ function updateScore() {
139
+ scoreDisplay.textContent = `分數:${score}/${currentQuestionIndex + 1}`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
141
 
142
+ // 下一題
143
+ function nextQuestion() {
144
+ currentQuestionIndex++;
145
+ showQuestion();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  }
147
 
148
+ // 顯示完成畫面
149
+ function showCompletion() {
150
+ const endTime = Date.now();
151
+ const completionTime = Math.round((endTime - startTime) / 1000);
152
+
153
+ quizSection.style.display = 'none';
154
+ completionSection.style.display = 'block';
155
+
156
+ // 計算星級
157
+ const percentage = (score / totalQuestions) * 100;
158
+ let stars = 0;
159
+ if (percentage >= 90) stars = 3;
160
+ else if (percentage >= 70) stars = 2;
161
+ else if (percentage >= 50) stars = 1;
162
+
163
+ // 顯示最終分數和星級
164
+ finalScoreDisplay.textContent = `最終分數:${score}/${totalQuestions} (${percentage.toFixed(1)}%)`;
165
+
166
+ // 顯示星星
167
+ let starsHTML = '';
168
+ for (let i = 0; i < 3; i++) {
169
+ if (i < stars) {
170
+ starsHTML += '<span class="star filled">★</span>';
171
+ } else {
172
+ starsHTML += '<span class="star">☆</span>';
173
+ }
 
174
  }
175
+ starsDisplay.innerHTML = starsHTML;
176
 
177
+ // 保存進度
178
+ saveProgress(stars, score, completionTime);
 
 
179
 
180
+ // 檢查成就
181
+ if (window.achievementSystem) {
182
+ const gameState = {
183
+ currentTrial: 'spring',
184
+ totalStars: stars,
185
+ completedTrials: {
186
+ spring: {
187
+ score: score,
188
+ stars: stars,
189
+ challengesCompleted: 1,
190
+ noErrors: score === totalQuestions,
191
+ completionTime: completionTime,
192
+ firstAttemptAllThreeStars: stars === 3
193
+ }
194
+ }
195
+ };
196
+ window.achievementSystem.checkAllAchievements(gameState);
197
  }
198
  }
199
 
200
+ // 保存進度
201
+ function saveProgress(stars, score, completionTime) {
202
+ const currentPlayerId = localStorage.getItem('currentPlayerId');
203
+ if (!currentPlayerId) return;
204
 
205
+ // 獲取現有進度
206
+ let gameProgress = JSON.parse(localStorage.getItem(`gameProgress_${currentPlayerId}`)) || {};
 
207
 
208
+ // 更新平方之泉進度
209
+ if (!gameProgress.spring || gameProgress.spring.stars < stars) {
210
+ gameProgress.spring = {
211
+ completed: true,
212
+ stars: stars,
213
+ score: score,
214
+ completionTime: completionTime,
215
+ completedAt: new Date().toISOString()
216
+ };
217
  }
218
 
219
+ // 保存進度
220
+ localStorage.setItem(`gameProgress_${currentPlayerId}`, JSON.stringify(gameProgress));
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
+ console.log('平方之泉進度已保存:', gameProgress.spring);
223
  }
224
 
225
+ // 開始挑戰按鈕事件
226
+ if (startChallengeBtn) {
227
+ startChallengeBtn.addEventListener('click', function() {
228
+ console.log('開始平方之泉挑戰');
229
+ storySection.style.display = 'none';
230
+ quizSection.style.display = 'block';
231
+
232
+ // 生成題目並開始
233
+ generateQuestions();
234
+ currentQuestionIndex = 0;
235
+ score = 0;
236
+ startTime = Date.now();
237
+ showQuestion();
238
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  }
240
 
241
+ // 下一題按鈕事件
242
+ if (nextQuestionBtn) {
243
+ nextQuestionBtn.addEventListener('click', nextQuestion);
 
 
 
 
 
 
244
  }
245
 
246
+ // 返回地圖按鈕事件
247
+ if (backToMapBtn) {
248
+ backToMapBtn.addEventListener('click', function() {
249
+ window.location.href = 'kingdom_map.html';
250
+ });
251
+ }
252
 
253
+ // 初始化顯示
254
+ storySection.style.display = 'block';
255
+ quizSection.style.display = 'none';
256
+ completionSection.style.display = 'none';
 
257
  });
258
+