// 成就系統核心 import { apiService } from './api-service.js' import { ACHIEVEMENTS } from '../data/achievements.js' export class AchievementSystem { constructor(petSystem, eventSystem, templeSystem, api = apiService) { this.petSystem = petSystem this.eventSystem = eventSystem this.templeSystem = templeSystem this.api = api this.achievements = ACHIEVEMENTS this.unlockedAchievements = [] // 已解鎖的成就 ID 列表 this.achievementStats = { // 動作計數 actionCounts: { feed: 0, play: 0, clean: 0, heal: 0, sleep: 0, pray: 0, drawFortune: 0 }, // 事件計數 eventCount: 0, eventTypeCounts: { good: 0, bad: 0, weird: 0, rare: 0 }, // 特殊狀態 recoveredFromDying: false, perfectStateReached: false } } // 初始化(從 API 載入已解鎖成就) async initialize() { try { const saved = await this.api.getAchievements() if (saved) { this.unlockedAchievements = saved.unlocked || [] this.achievementStats = { ...this.achievementStats, ...saved.stats } } console.log(`[AchievementSystem] 載入 ${this.unlockedAchievements.length} 個已解鎖成就`) // 重新應用已解鎖成就的加成 await this.reapplyAchievementBuffs() } catch (error) { console.error('[AchievementSystem] 載入成就失敗:', error) // 降級到本地載入 const saved = localStorage.getItem('achievements') if (saved) { const data = JSON.parse(saved) this.unlockedAchievements = data.unlocked || [] this.achievementStats = { ...this.achievementStats, ...data.stats } // 重新應用已解鎖成就的加成 await this.reapplyAchievementBuffs() } } } // 重新應用已解鎖成就的加成(初始化時使用) async reapplyAchievementBuffs() { if (!this.petSystem) return const unlocked = this.achievements.filter(a => this.unlockedAchievements.includes(a.id)) const achievementBuffs = {} // 累積所有已解鎖成就的加成 for (const achievement of unlocked) { if (achievement.reward && achievement.reward.buffs) { for (const [key, value] of Object.entries(achievement.reward.buffs)) { achievementBuffs[key] = (achievementBuffs[key] || 0) + value } } } // 更新寵物狀態 if (Object.keys(achievementBuffs).length > 0) { await this.petSystem.updateState({ achievementBuffs }) // 重新計算戰鬥數值 this.petSystem.calculateCombatStats() console.log(`[AchievementSystem] 已重新應用 ${unlocked.length} 個成就的加成`) } } // 檢查成就條件 checkCondition(achievement) { const condition = achievement.condition const state = this.petSystem.getState() switch (condition.type) { case 'age': return state.ageSeconds >= condition.value case 'stage': return state.stage === condition.value case 'stats': // 檢查所有指定屬性是否達到要求 for (const [stat, value] of Object.entries(condition.stats)) { if ((state[stat] || 0) < value) { return false } } return true case 'action_count': return this.achievementStats.actionCounts[condition.action] >= condition.value case 'deity_favor': // 檢查任一神明好感度 const favors = state.deityFavors || {} return Object.values(favors).some(favor => favor >= condition.value) case 'event_count': return this.achievementStats.eventCount >= condition.value case 'event_type_count': return this.achievementStats.eventTypeCounts[condition.eventType] >= condition.value case 'recovered_from_dying': return this.achievementStats.recoveredFromDying === condition.value case 'perfect_state': if (condition.value) { return state.hunger >= 100 && state.happiness >= 100 && state.health >= 100 } return false default: return false } } // 檢查並解鎖成就 async checkAndUnlockAchievements() { const newlyUnlocked = [] for (const achievement of this.achievements) { // 如果已經解鎖,跳過 if (this.unlockedAchievements.includes(achievement.id)) { continue } // 檢查條件 if (this.checkCondition(achievement)) { await this.unlockAchievement(achievement) newlyUnlocked.push(achievement) } } return newlyUnlocked } // 解鎖成就 async unlockAchievement(achievement) { if (this.unlockedAchievements.includes(achievement.id)) { return // 已經解鎖 } this.unlockedAchievements.push(achievement.id) // 應用成就獎勵(永久 Buff) if (achievement.reward && achievement.reward.buffs) { // 將成就加成添加到寵物狀態 const currentState = this.petSystem.getState() const achievementBuffs = currentState.achievementBuffs || {} // 合併加成 for (const [key, value] of Object.entries(achievement.reward.buffs)) { achievementBuffs[key] = (achievementBuffs[key] || 0) + value } await this.petSystem.updateState({ achievementBuffs }) // 重新計算戰鬥數值 this.petSystem.calculateCombatStats() } // 同步到 API try { await this.api.saveAchievements({ unlocked: this.unlockedAchievements, stats: this.achievementStats }) } catch (error) { console.warn('[AchievementSystem] API 同步失敗:', error) // 降級到 localStorage localStorage.setItem('achievements', JSON.stringify({ unlocked: this.unlockedAchievements, stats: this.achievementStats })) } // 顯示成就通知 console.log(`\n${'='.repeat(50)}`) console.log(`🏆 成就解鎖:${achievement.icon} ${achievement.name}`) console.log(`📝 ${achievement.description}`) if (achievement.reward && achievement.reward.buffs) { console.log(`✨ 獎勵:`) for (const [key, value] of Object.entries(achievement.reward.buffs)) { const sign = value > 0 ? '+' : '' if (typeof value === 'number' && value < 1 && value > 0) { console.log(` ${key}: ${sign}${(value * 100).toFixed(0)}%`) } else { console.log(` ${key}: ${sign}${value}`) } } } console.log('='.repeat(50) + '\n') return achievement } // 記錄動作 async recordAction(action) { if (this.achievementStats.actionCounts[action] !== undefined) { this.achievementStats.actionCounts[action]++ await this.checkAndUnlockAchievements() } } // 記錄事件 async recordEvent(event) { this.achievementStats.eventCount++ if (event.type && this.achievementStats.eventTypeCounts[event.type] !== undefined) { this.achievementStats.eventTypeCounts[event.type]++ } await this.checkAndUnlockAchievements() } // 記錄從瀕死恢復 recordRecoveryFromDying() { if (!this.achievementStats.recoveredFromDying) { this.achievementStats.recoveredFromDying = true this.checkAndUnlockAchievements() } } // 檢查完美狀態 checkPerfectState() { const state = this.petSystem.getState() if (state.hunger >= 100 && state.happiness >= 100 && state.health >= 100 && !this.achievementStats.perfectStateReached) { this.achievementStats.perfectStateReached = true this.checkAndUnlockAchievements() } } // 獲取已解鎖成就 getUnlockedAchievements() { return this.achievements.filter(a => this.unlockedAchievements.includes(a.id)) } // 獲取未解鎖成就 getLockedAchievements() { return this.achievements.filter(a => !this.unlockedAchievements.includes(a.id)) } // 獲取成就進度 getAchievementProgress(achievement) { const condition = achievement.condition const state = this.petSystem.getState() switch (condition.type) { case 'age': return { current: state.ageSeconds, target: condition.value, progress: Math.min(100, (state.ageSeconds / condition.value) * 100) } case 'action_count': return { current: this.achievementStats.actionCounts[condition.action] || 0, target: condition.value, progress: Math.min(100, ((this.achievementStats.actionCounts[condition.action] || 0) / condition.value) * 100) } case 'stats': // 返回最低進度 let minProgress = 100 for (const [stat, value] of Object.entries(condition.stats)) { const current = state[stat] || 0 const progress = Math.min(100, (current / value) * 100) minProgress = Math.min(minProgress, progress) } return { progress: minProgress } case 'deity_favor': const favors = state.deityFavors || {} const maxFavor = Math.max(...Object.values(favors), 0) return { current: maxFavor, target: condition.value, progress: Math.min(100, (maxFavor / condition.value) * 100) } case 'event_count': return { current: this.achievementStats.eventCount, target: condition.value, progress: Math.min(100, (this.achievementStats.eventCount / condition.value) * 100) } default: return { progress: 0 } } } // 獲取所有成就加成(用於顯示) getAllAchievementBonuses() { const bonuses = {} const unlocked = this.getUnlockedAchievements() for (const achievement of unlocked) { if (achievement.reward && achievement.reward.buffs) { for (const [key, value] of Object.entries(achievement.reward.buffs)) { bonuses[key] = (bonuses[key] || 0) + value } } } return bonuses } }