// 事件系統核心 - 與 API 整合 import { apiService } from './api-service.js' export class EventSystem { constructor(petSystem, api = apiService) { this.petSystem = petSystem this.api = api this.events = [] this.buffManager = new BuffManager() this.eventHistory = [] this.eventCheckInterval = null this.lastEventCheckTime = 0 } // 初始化(從 API 載入事件配置) async initialize() { try { this.events = await this.api.getEvents() console.log(`[EventSystem] 載入 ${this.events.length} 個事件`) } catch (error) { console.error('[EventSystem] 載入事件失敗:', error) // 降級到本地載入 const { EVENT_CONFIG } = await import('../data/events.js') this.events = EVENT_CONFIG } } // 啟動事件檢查循環(从配置读取间隔) startEventCheck() { if (this.eventCheckInterval) this.stopEventCheck() // 从配置读取间隔时间 const petConfig = this.petSystem.speciesConfig const interval = petConfig?.baseStats?.eventCheckInterval || 10000 this.eventCheckInterval = setInterval(() => { this.checkTriggers() }, interval) } stopEventCheck() { if (this.eventCheckInterval) { clearInterval(this.eventCheckInterval) this.eventCheckInterval = null } } // 隨機選擇事件(依權重) selectRandomEvent() { const totalWeight = this.events.reduce((sum, e) => sum + e.weight, 0) let rand = Math.random() * totalWeight for (const event of this.events) { rand -= event.weight if (rand <= 0) return event } return this.events[0] // fallback } // 檢查觸發條件(10% 機率 + 條件檢查) async checkTriggers() { const petState = this.petSystem.getState() if (petState.isDead) return // 睡眠時不觸發事件(類似暫停) if (petState.isSleeping) return // 10% 機率觸發 if (Math.random() >= 0.1) return const event = this.selectRandomEvent() // 檢查條件 if (event.condition && !event.condition(petState)) { return } // 觸發事件 await this.triggerEvent(event.id, petState) } // 觸發事件(同步到 API) async triggerEvent(eventId, petState = null) { const event = this.events.find(e => e.id === eventId) if (!event) { console.warn(`[EventSystem] 找不到事件: ${eventId}`) return null } const currentState = petState || this.petSystem.getState() // 檢查條件 if (event.condition && !event.condition(currentState)) { console.log(`\n❌ 事件 ${event.id} 觸發失敗`) console.log(` 條件: ${event.conditionDescription || '未定義'}`) console.log(` 當前狀態:`) console.log(` - 飢餓: ${currentState.hunger.toFixed(1)}`) console.log(` - 快樂: ${currentState.happiness.toFixed(1)}`) console.log(` - 健康: ${currentState.health.toFixed(1)}`) console.log(` - 運勢: ${currentState.luck.toFixed(1)}`) console.log(` - 體重: ${currentState.weight.toFixed(1)}`) console.log(` - DEX: ${currentState.dex.toFixed(1)}`) console.log(` - INT: ${currentState.int.toFixed(1)}`) return null } console.log(`\n[事件觸發] ${event.id} (${event.type}): 機率檢查通過!`) // 執行效果 const results = [] for (const effect of event.effects) { const result = await this.executeEffect(effect, currentState) results.push(result) } // 記錄歷史 this.eventHistory.push({ timestamp: Date.now(), eventId: event.id, eventType: event.type, effects: results }) // 同步到 API try { await this.api.triggerEvent(eventId, currentState) } catch (error) { console.warn('[EventSystem] API 同步失敗:', error) } return { event, results } } // 執行效果 async executeEffect(effect, petState) { switch (effect.type) { case 'modifyStats': return await this.modifyStats(effect.payload, petState) case 'addBuff': return await this.addBuff(effect.payload) case 'spawnPoop': return await this.spawnPoop(effect.payload) case 'templeFavor': return await this.modifyTempleFavor(effect.payload) case 'logMessage': console.log(`[訊息] ${effect.payload}`) return { type: 'logMessage', message: effect.payload } default: console.warn(`[EventSystem] 未知效果類型: ${effect.type}`) return null } } // 修改屬性 async modifyStats(payload, petState) { // 獲取最新狀態(因為 petState 可能是舊的快照) const currentState = this.petSystem.getState() const updates = {} for (const [key, value] of Object.entries(payload)) { if (key === 'isSleeping' || key === 'isSick' || key === 'isDead') { updates[key] = value } else { const current = currentState[key] || 0 let newValue = current if (value > 0) { // 增加屬性:如果是自然增長(非道具),上限為 100 // 如果當前已經 >= 100,則不再增加(除非是道具,但這裡是事件系統) // 如果當前 < 100,則最多增加到 100 newValue = current < 100 ? Math.min(100, current + value) : current } else { // 減少屬性:總是生效,最低為 0 newValue = Math.max(0, current + value) } updates[key] = newValue console.log(`[效果] ${key} ${value > 0 ? '+' : ''}${value} (${current.toFixed(1)} → ${newValue.toFixed(1)})`) } } await this.petSystem.updateState(updates) return { type: 'modifyStats', updates } } // 添加 Buff async addBuff(buffData) { this.buffManager.addBuff(buffData) // 同步到 API try { await this.api.applyBuff(buffData) } catch (error) { console.warn('[EventSystem] Buff API 同步失敗:', error) } return { type: 'addBuff', buff: buffData } } // 生成便便 async spawnPoop(payload) { const count = payload?.count || 1 const currentPoop = this.petSystem.getState().poopCount const newPoop = Math.min(4, currentPoop + count) await this.petSystem.updateState({ poopCount: newPoop }) console.log(`[效果] 生成便便: ${count} 個,總數: ${newPoop}`) return { type: 'spawnPoop', count, total: newPoop } } // 修改神明好感度 async modifyTempleFavor(payload) { const { deityId, amount } = payload const currentState = this.petSystem.getState() const currentFavor = currentState.deityFavors[deityId] || 0 const newFavor = Math.max(0, Math.min(100, currentFavor + amount)) await this.petSystem.updateState({ deityFavors: { ...currentState.deityFavors, [deityId]: newFavor } }) console.log(`[效果] ${deityId} 好感度 ${amount > 0 ? '+' : ''}${amount} → ${newFavor}`) return { type: 'templeFavor', deityId, favor: newFavor } } // 應用 Buff 到狀態(每 tick 呼叫) async applyBuffs() { const petState = this.petSystem.getState() const buffs = this.buffManager.getActiveBuffs() // 計算最終屬性(考慮 Buff) const finalStats = this.calculateFinalStats(petState, buffs) // 更新狀態 await this.petSystem.updateState(finalStats) return finalStats } // 計算最終屬性(Base + Flat + Percent) calculateFinalStats(baseState, buffs) { const stats = { ...baseState } // 收集所有 Buff 的 flat 和 percent 加成 const flatMods = {} const percentMods = {} buffs.forEach(buff => { if (buff.flat) { Object.entries(buff.flat).forEach(([key, value]) => { flatMods[key] = (flatMods[key] || 0) + value }) } if (buff.percent) { Object.entries(buff.percent).forEach(([key, value]) => { percentMods[key] = (percentMods[key] || 0) + value }) } }) // 應用加成 Object.keys(stats).forEach(key => { if (typeof stats[key] === 'number' && key !== 'ageSeconds' && key !== 'weight' && key !== 'generation') { const base = stats[key] const flat = flatMods[key] || 0 const percent = percentMods[key] || 0 stats[key] = Math.max(0, Math.min(100, (base + flat) * (1 + percent))) } }) return stats } // 獲取事件歷史 getHistory() { return [...this.eventHistory] } // 獲取 Buff 管理器 getBuffManager() { return this.buffManager } // Debug: 強制觸發事件 async debugTriggerEvent(eventId = null) { let event if (eventId) { event = this.events.find(e => e.id === eventId) if (!event) { console.warn(`[Debug] 找不到事件: ${eventId}`) return } } else { event = this.selectRandomEvent() } console.log(`[Debug] 強制觸發事件: ${event.id}`) await this.triggerEvent(event.id) return event } } // Buff 管理器 class BuffManager { constructor() { this.buffs = [] } addBuff(buff) { // 檢查是否可堆疊 const existing = this.buffs.find(b => b.id === buff.id) if (existing && !buff.stacks) { // 不可堆疊,重置持續時間 existing.currentTicks = buff.durationTicks console.log(`[Buff] 重置: ${buff.name} (持續 ${buff.durationTicks} ticks)`) } else { // 可堆疊或新 Buff this.buffs.push({ ...buff, currentTicks: buff.durationTicks, currentStacks: (existing?.currentStacks || 0) + 1 }) console.log(`[Buff] 新增: ${buff.name} (持續 ${buff.durationTicks} ticks)`) } } tick() { this.buffs = this.buffs.filter(b => { if (b.durationTicks === Infinity) return true // 永久 Buff b.currentTicks-- if (b.currentTicks <= 0) { console.log(`[Buff] 過期: ${b.name}`) return false } return true }) } getActiveBuffs() { return this.buffs.filter(b => b.currentTicks > 0 || b.durationTicks === Infinity) } getFinalModifier(statKey) { const activeBuffs = this.getActiveBuffs() let flatTotal = 0 let percentTotal = 0 activeBuffs.forEach(b => { if (b.flat?.[statKey]) flatTotal += b.flat[statKey] if (b.percent?.[statKey]) percentTotal += b.percent[statKey] }) return { flat: flatTotal, percent: percentTotal } } }