pet_data/core/event-system.js

324 lines
8.6 KiB
JavaScript
Raw Normal View History

2025-11-23 18:03:56 +00:00
// 事件系統核心 - 與 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
}
}
// 啟動事件檢查循環(每 10 秒檢查一次)
startEventCheck() {
if (this.eventCheckInterval) this.stopEventCheck()
this.eventCheckInterval = setInterval(() => {
this.checkTriggers()
}, 10000) // 每 10 秒
}
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
// 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(`[EventSystem] 事件 ${eventId} 條件不滿足`)
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) {
const updates = {}
for (const [key, value] of Object.entries(payload)) {
if (key === 'isSleeping' || key === 'isSick' || key === 'isDead') {
updates[key] = value
} else {
const current = petState[key] || 0
const newValue = Math.max(0, Math.min(100, current + value))
updates[key] = newValue
console.log(`[效果] ${key} ${value > 0 ? '+' : ''}${value} → 新值: ${newValue}`)
}
}
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
}
}
// 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 }
}
}