287 lines
7.3 KiB
JavaScript
287 lines
7.3 KiB
JavaScript
// 寵物系統核心 - 與 API 整合
|
||
import { apiService } from './api-service.js'
|
||
import { PET_SPECIES } from '../data/pet-species.js'
|
||
|
||
export class PetSystem {
|
||
constructor(api = apiService) {
|
||
this.api = api
|
||
this.state = null
|
||
this.speciesConfig = null
|
||
this.tickInterval = null
|
||
this.eventCheckInterval = null
|
||
}
|
||
|
||
// 初始化寵物(從 API 載入或創建新寵物)
|
||
async initialize(speciesId = 'tinyTigerCat') {
|
||
try {
|
||
// 從 API 載入現有狀態
|
||
this.state = await this.api.getPetState()
|
||
|
||
if (!this.state) {
|
||
// 創建新寵物
|
||
this.state = this.createInitialState(speciesId)
|
||
await this.api.savePetState(this.state)
|
||
}
|
||
|
||
// 載入種族配置
|
||
this.speciesConfig = PET_SPECIES[this.state.speciesId] || PET_SPECIES[speciesId]
|
||
|
||
return this.state
|
||
} catch (error) {
|
||
console.error('[PetSystem] 初始化失敗:', error)
|
||
// 降級到本地狀態
|
||
this.state = this.createInitialState(speciesId)
|
||
this.speciesConfig = PET_SPECIES[speciesId]
|
||
return this.state
|
||
}
|
||
}
|
||
|
||
// 創建初始狀態
|
||
createInitialState(speciesId) {
|
||
const config = PET_SPECIES[speciesId]
|
||
return {
|
||
speciesId,
|
||
stage: 'baby',
|
||
hunger: 100,
|
||
happiness: 100,
|
||
health: 100,
|
||
weight: 500,
|
||
ageSeconds: 0,
|
||
poopCount: 0,
|
||
str: 0,
|
||
int: 0,
|
||
dex: 0,
|
||
luck: config.baseStats.luck || 10,
|
||
isSleeping: false,
|
||
isSick: false,
|
||
isDead: false,
|
||
currentDeityId: 'mazu',
|
||
deityFavors: {
|
||
mazu: 0,
|
||
earthgod: 0,
|
||
yuelao: 0,
|
||
wenchang: 0,
|
||
guanyin: 0
|
||
},
|
||
dailyPrayerCount: 0,
|
||
destiny: null,
|
||
buffs: [],
|
||
inventory: [],
|
||
generation: 1,
|
||
lastTickTime: Date.now()
|
||
}
|
||
}
|
||
|
||
// 更新狀態(同步到 API)
|
||
async updateState(updates) {
|
||
this.state = { ...this.state, ...updates }
|
||
|
||
try {
|
||
await this.api.updatePetState(updates)
|
||
} catch (error) {
|
||
console.warn('[PetSystem] API 更新失敗,使用本地狀態:', error)
|
||
}
|
||
|
||
return this.state
|
||
}
|
||
|
||
// 獲取當前狀態
|
||
getState() {
|
||
return { ...this.state }
|
||
}
|
||
|
||
// 刪除寵物
|
||
async deletePet() {
|
||
try {
|
||
// 停止所有循環
|
||
this.stopTickLoop()
|
||
|
||
// 從 API 刪除
|
||
await this.api.deletePetState()
|
||
|
||
// 重置狀態
|
||
this.state = null
|
||
this.speciesConfig = null
|
||
|
||
return { success: true, message: '寵物已刪除' }
|
||
} catch (error) {
|
||
console.error('[PetSystem] 刪除寵物失敗:', error)
|
||
// 即使 API 失敗,也清除本地狀態
|
||
this.state = null
|
||
this.speciesConfig = null
|
||
return { success: true, message: '寵物已刪除(本地)' }
|
||
}
|
||
}
|
||
|
||
// Tick 循環(每 3 秒)
|
||
startTickLoop(callback) {
|
||
if (this.tickInterval) this.stopTickLoop()
|
||
|
||
this.tickInterval = setInterval(async () => {
|
||
await this.tick()
|
||
if (callback) callback(this.getState())
|
||
}, 3000)
|
||
}
|
||
|
||
stopTickLoop() {
|
||
if (this.tickInterval) {
|
||
clearInterval(this.tickInterval)
|
||
this.tickInterval = null
|
||
}
|
||
}
|
||
|
||
// 單次 Tick 執行
|
||
async tick() {
|
||
if (!this.state || this.state.isDead) return
|
||
|
||
const now = Date.now()
|
||
const deltaTime = (now - (this.state.lastTickTime || now)) / 1000
|
||
this.state.lastTickTime = now
|
||
|
||
// 年齡增長
|
||
this.state.ageSeconds += deltaTime
|
||
|
||
// 檢查階段轉換
|
||
this.checkStageTransition()
|
||
|
||
// 基礎數值衰減
|
||
const config = this.speciesConfig.baseStats
|
||
this.state.hunger = Math.max(0, this.state.hunger - config.hungerDecayPerTick * 100)
|
||
this.state.happiness = Math.max(0, this.state.happiness - config.happinessDecayPerTick * 100)
|
||
|
||
// 便便機率
|
||
if (Math.random() < config.poopChancePerTick) {
|
||
this.state.poopCount = Math.min(4, this.state.poopCount + 1)
|
||
}
|
||
|
||
// 生病機率
|
||
if (!this.state.isSick && Math.random() < config.sicknessChance) {
|
||
this.state.isSick = true
|
||
await this.updateState({ isSick: true })
|
||
}
|
||
|
||
// 健康檢查
|
||
if (this.state.health <= 0) {
|
||
this.state.isDead = true
|
||
await this.updateState({ isDead: true })
|
||
}
|
||
|
||
// 同步到 API
|
||
await this.updateState({
|
||
ageSeconds: this.state.ageSeconds,
|
||
hunger: this.state.hunger,
|
||
happiness: this.state.happiness,
|
||
poopCount: this.state.poopCount,
|
||
isSick: this.state.isSick,
|
||
isDead: this.state.isDead
|
||
})
|
||
}
|
||
|
||
// 檢查階段轉換
|
||
checkStageTransition() {
|
||
const config = this.speciesConfig
|
||
const currentStage = this.state.stage
|
||
const ageSeconds = this.state.ageSeconds
|
||
|
||
for (const stageConfig of config.lifecycle) {
|
||
if (stageConfig.stage === currentStage) {
|
||
// 找到下一個階段
|
||
const currentIndex = config.lifecycle.findIndex(s => s.stage === currentStage)
|
||
if (currentIndex < config.lifecycle.length - 1) {
|
||
const nextStage = config.lifecycle[currentIndex + 1]
|
||
if (ageSeconds >= nextStage.durationSeconds && nextStage.durationSeconds > 0) {
|
||
this.state.stage = nextStage.stage
|
||
this.updateState({ stage: nextStage.stage })
|
||
}
|
||
}
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
// 餵食
|
||
async feed(amount = 20) {
|
||
if (this.state.isDead) return { success: false, message: '寵物已死亡' }
|
||
|
||
const newHunger = Math.min(100, this.state.hunger + amount)
|
||
const newWeight = this.state.weight + (amount * 0.5)
|
||
|
||
await this.updateState({
|
||
hunger: newHunger,
|
||
weight: newWeight
|
||
})
|
||
|
||
return { success: true, hunger: newHunger, weight: newWeight }
|
||
}
|
||
|
||
// 玩耍
|
||
async play(amount = 15) {
|
||
if (this.state.isDead || this.state.isSleeping) {
|
||
return { success: false, message: '寵物無法玩耍' }
|
||
}
|
||
|
||
const newHappiness = Math.min(100, this.state.happiness + amount)
|
||
const newDex = this.state.dex + 0.5
|
||
|
||
await this.updateState({
|
||
happiness: newHappiness,
|
||
dex: newDex
|
||
})
|
||
|
||
return { success: true, happiness: newHappiness, dex: newDex }
|
||
}
|
||
|
||
// 清理便便
|
||
async cleanPoop() {
|
||
if (this.state.poopCount === 0) {
|
||
return { success: false, message: '沒有便便需要清理' }
|
||
}
|
||
|
||
const newPoopCount = 0
|
||
const newHappiness = Math.min(100, this.state.happiness + 10)
|
||
|
||
await this.updateState({
|
||
poopCount: newPoopCount,
|
||
happiness: newHappiness
|
||
})
|
||
|
||
return { success: true, poopCount: newPoopCount, happiness: newHappiness }
|
||
}
|
||
|
||
// 治療
|
||
async heal(amount = 20) {
|
||
if (this.state.isDead) return { success: false, message: '寵物已死亡' }
|
||
|
||
const newHealth = Math.min(100, this.state.health + amount)
|
||
const wasSick = this.state.isSick
|
||
|
||
await this.updateState({
|
||
health: newHealth,
|
||
isSick: false
|
||
})
|
||
|
||
return {
|
||
success: true,
|
||
health: newHealth,
|
||
isSick: false,
|
||
cured: wasSick && !this.state.isSick
|
||
}
|
||
}
|
||
|
||
// 睡覺/起床
|
||
async toggleSleep() {
|
||
if (this.state.isDead) return { success: false, message: '寵物已死亡' }
|
||
|
||
const newIsSleeping = !this.state.isSleeping
|
||
const healthChange = newIsSleeping ? 5 : 0
|
||
|
||
await this.updateState({
|
||
isSleeping: newIsSleeping,
|
||
health: Math.min(100, this.state.health + healthChange)
|
||
})
|
||
|
||
return { success: true, isSleeping: newIsSleeping }
|
||
}
|
||
}
|
||
|