pet_data/core/adventure-system.js

289 lines
9.4 KiB
JavaScript
Raw Permalink Normal View History

2025-11-24 13:45:09 +00:00
// 冒險系統核心
import { apiService } from './api-service.js'
import { ADVENTURES } from '../data/adventures.js'
import { ENEMIES } from '../data/enemies.js'
export class AdventureSystem {
constructor(petSystem, inventorySystem, api = apiService) {
this.petSystem = petSystem
this.inventorySystem = inventorySystem
this.api = api
this.currentAdventure = null
this.adventureTimer = null
this.logs = []
}
// 獲取所有冒險區域
getAdventures() {
return ADVENTURES
}
// 開始冒險
async startAdventure(adventureId) {
const adventure = ADVENTURES.find(a => a.id === adventureId)
if (!adventure) return { success: false, message: '找不到該冒險區域' }
const state = this.petSystem.getState()
// 1. 檢查條件
if (state.isSick || state.isDead || state.isSleeping) {
return { success: false, message: '寵物狀態不適合冒險' }
}
// 檢查等級/階段要求 (這裡簡化為檢查階段)
// 實際應根據 levelRequirement 檢查
// 檢查屬性要求
if (adventure.statsRequirement) {
for (const [stat, value] of Object.entries(adventure.statsRequirement)) {
if ((state[stat] || 0) < value) {
return { success: false, message: `屬性不足:需要 ${stat.toUpperCase()} ${value}` }
}
}
}
// 2. 檢查消耗
if (state.hunger < adventure.cost.hunger) {
return { success: false, message: '飢餓度不足' }
}
if (state.happiness < adventure.cost.happiness) {
return { success: false, message: '快樂度不足' }
}
// 3. 扣除消耗
await this.petSystem.updateState({
hunger: state.hunger - adventure.cost.hunger,
happiness: state.happiness - adventure.cost.happiness
})
// 4. 初始化冒險狀態
this.currentAdventure = {
id: adventureId,
startTime: Date.now(),
duration: adventure.duration * 1000, // 轉為毫秒
endTime: Date.now() + adventure.duration * 1000,
logs: [],
rewards: { items: [], coins: 0 },
encounters: []
}
this.addLog(`出發前往 ${adventure.name}`)
// 5. 啟動計時器
this.startAdventureLoop()
return { success: true, adventure: this.currentAdventure }
}
// 冒險循環
startAdventureLoop() {
if (this.adventureTimer) clearInterval(this.adventureTimer)
this.adventureTimer = setInterval(async () => {
if (!this.currentAdventure) {
this.stopAdventureLoop()
return
}
const now = Date.now()
const adventure = ADVENTURES.find(a => a.id === this.currentAdventure.id)
// 檢查是否結束
if (now >= this.currentAdventure.endTime) {
await this.completeAdventure()
return
}
// 隨機遭遇敵人
if (Math.random() < 0.1) { // 每秒 10% 機率遭遇
await this.encounterEnemy(adventure)
}
}, 1000)
}
stopAdventureLoop() {
if (this.adventureTimer) {
clearInterval(this.adventureTimer)
this.adventureTimer = null
}
}
// 遭遇敵人
async encounterEnemy(adventure) {
if (!adventure.enemyPool || adventure.enemyPool.length === 0) return
// 隨機選擇敵人
const enemyId = adventure.enemyPool[Math.floor(Math.random() * adventure.enemyPool.length)]
const enemyConfig = ENEMIES[enemyId]
if (!enemyConfig) return
this.addLog(`遭遇了 ${enemyConfig.name}!準備戰鬥!`)
// 執行戰鬥
const combatResult = this.calculateCombat(enemyConfig)
// 記錄戰鬥過程
combatResult.logs.forEach(log => this.addLog(log))
if (combatResult.win) {
this.addLog(`戰鬥勝利!`)
// 計算掉落
if (enemyConfig.drops) {
for (const drop of enemyConfig.drops) {
if (Math.random() < drop.chance) {
// 檢查是否為金幣
if (drop.itemId === 'gold_coin') {
// 金幣直接加到獎勵中
if (!this.currentAdventure.rewards.coins) {
this.currentAdventure.rewards.coins = 0
}
this.currentAdventure.rewards.coins += drop.count || 1
this.addLog(`獲得金幣:${drop.count || 1} 💰`)
} else {
// 其他道具加到物品列表
this.currentAdventure.rewards.items.push({
itemId: drop.itemId,
count: drop.count || 1,
name: drop.itemId // 暫時用 ID實際應查表
})
this.addLog(`獲得戰利品:${drop.itemId} x${drop.count || 1}`)
}
}
}
}
} else {
this.addLog(`戰鬥失敗... 寵物受傷逃跑了。`)
// 扣除健康
const state = this.petSystem.getState()
await this.petSystem.updateState({
health: Math.max(0, state.health - 10)
})
}
}
// 計算戰鬥 (簡化版回合制)
calculateCombat(enemy) {
const state = this.petSystem.getState()
const petStats = {
hp: state.health, // 用健康度當 HP
attack: state.attack || 10,
defense: state.defense || 0,
speed: state.speed || 10
}
const enemyStats = { ...enemy.stats }
const logs = []
let round = 1
let win = false
while (round <= 10) { // 最多 10 回合
// 速度決定先手
const petFirst = petStats.speed >= enemyStats.speed
// 雙方攻擊
const attacker = petFirst ? petStats : enemyStats
const defender = petFirst ? enemyStats : petStats
const attackerName = petFirst ? '你' : enemy.name
const defenderName = petFirst ? enemy.name : '你'
// 第一擊
let damage = Math.max(1, attacker.attack - defender.defense)
// 隨機浮動 0.8 ~ 1.2
damage = Math.floor(damage * (0.8 + Math.random() * 0.4))
defender.hp -= damage
logs.push(`[回合${round}] ${attackerName}${defenderName} 造成 ${damage} 點傷害`)
if (defender.hp <= 0) {
win = petFirst
break
}
// 第二擊
damage = Math.max(1, defender.attack - attacker.defense)
damage = Math.floor(damage * (0.8 + Math.random() * 0.4))
attacker.hp -= damage
logs.push(`[回合${round}] ${defenderName}${attackerName} 造成 ${damage} 點傷害`)
if (attacker.hp <= 0) {
win = !petFirst
break
}
round++
}
if (round > 10) {
logs.push('戰鬥超時,雙方平手(視為失敗)')
win = false
}
return { win, logs }
}
// 完成冒險
async completeAdventure() {
this.stopAdventureLoop()
const adventure = ADVENTURES.find(a => a.id === this.currentAdventure.id)
this.addLog('冒險結束!')
// 發放基礎獎勵
if (adventure.rewards) {
if (adventure.rewards.items) {
for (const reward of adventure.rewards.items) {
if (Math.random() < reward.chance) {
this.currentAdventure.rewards.items.push({
itemId: reward.itemId,
count: 1,
name: reward.itemId
})
}
}
}
}
// 實際發放道具到背包
if (this.inventorySystem) {
for (const item of this.currentAdventure.rewards.items) {
await this.inventorySystem.addItem(item.itemId, item.count)
}
}
// 發放金幣
if (this.currentAdventure.rewards.coins > 0) {
const state = this.petSystem.getState()
await this.petSystem.updateState({
coins: (state.coins || 0) + this.currentAdventure.rewards.coins
})
this.addLog(`獲得金幣:${this.currentAdventure.rewards.coins} 💰`)
}
// 觸發完成回調(如果有 UI 監聽)
if (this.onAdventureComplete) {
this.onAdventureComplete(this.currentAdventure)
}
this.currentAdventure = null
}
// 添加日誌
addLog(message) {
if (this.currentAdventure) {
const time = new Date().toLocaleTimeString()
this.currentAdventure.logs.push(`[${time}] ${message}`)
// 觸發更新回調
if (this.onLogUpdate) {
this.onLogUpdate(this.currentAdventure.logs)
}
}
}
// 獲取當前冒險狀態
getCurrentAdventure() {
return this.currentAdventure
}
}