pet_data/core/achievement-system.js

375 lines
11 KiB
JavaScript
Raw Permalink Normal View History

2025-11-24 10:34:02 +00:00
// 成就系統核心
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} 個已解鎖成就`)
2025-11-24 13:45:09 +00:00
2025-11-24 10:34:02 +00:00
// 重新應用已解鎖成就的加成
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 }
2025-11-24 13:45:09 +00:00
2025-11-24 10:34:02 +00:00
// 重新應用已解鎖成就的加成
await this.reapplyAchievementBuffs()
}
}
}
// 重新應用已解鎖成就的加成(初始化時使用)
async reapplyAchievementBuffs() {
if (!this.petSystem) return
2025-11-24 13:45:09 +00:00
2025-11-24 10:34:02 +00:00
const unlocked = this.achievements.filter(a => this.unlockedAchievements.includes(a.id))
const achievementBuffs = {}
2025-11-24 13:45:09 +00:00
2025-11-24 10:34:02 +00:00
// 累積所有已解鎖成就的加成
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
}
}
}
2025-11-24 13:45:09 +00:00
2025-11-24 10:34:02 +00:00
// 更新寵物狀態
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) {
2025-11-24 13:45:09 +00:00
return state.hunger >= 100 &&
state.happiness >= 100 &&
state.health >= 100
2025-11-24 10:34:02 +00:00
}
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 || {}
2025-11-24 13:45:09 +00:00
2025-11-24 10:34:02 +00:00
// 合併加成
for (const [key, value] of Object.entries(achievement.reward.buffs)) {
achievementBuffs[key] = (achievementBuffs[key] || 0) + value
}
await this.petSystem.updateState({ achievementBuffs })
2025-11-24 13:45:09 +00:00
2025-11-24 10:34:02 +00:00
// 重新計算戰鬥數值
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()
2025-11-24 13:45:09 +00:00
if (state.hunger >= 100 &&
state.happiness >= 100 &&
state.health >= 100 &&
!this.achievementStats.perfectStateReached) {
2025-11-24 10:34:02 +00:00
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
}
2025-11-24 13:45:09 +00:00
// 重置成就系統(刪除寵物時使用)
async reset() {
this.unlockedAchievements = []
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
try {
await this.api.saveAchievements({
unlocked: this.unlockedAchievements,
stats: this.achievementStats
})
} catch (error) {
console.warn('[AchievementSystem] API 同步失敗:', error)
// 降級到 localStorage
localStorage.removeItem('achievements')
}
console.log('[AchievementSystem] 成就已重置')
}
2025-11-24 10:34:02 +00:00
}