2025-11-23 18:03:56 +00:00
|
|
|
|
// 神明系統 - 與 API 整合
|
|
|
|
|
|
import { apiService } from './api-service.js'
|
2025-11-24 07:38:44 +00:00
|
|
|
|
import { JIAOBEI_CONFIG } from '../data/jiaobei-config.js'
|
2025-11-23 18:03:56 +00:00
|
|
|
|
|
|
|
|
|
|
export class TempleSystem {
|
2025-11-24 10:34:02 +00:00
|
|
|
|
constructor(petSystem, api = apiService, achievementSystem = null) {
|
2025-11-23 18:03:56 +00:00
|
|
|
|
this.petSystem = petSystem
|
|
|
|
|
|
this.api = api
|
2025-11-24 10:34:02 +00:00
|
|
|
|
this.achievementSystem = achievementSystem
|
2025-11-23 18:03:56 +00:00
|
|
|
|
this.deities = []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化(從 API 載入神明資料)
|
|
|
|
|
|
async initialize() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
this.deities = await this.api.getDeities()
|
|
|
|
|
|
console.log(`[TempleSystem] 載入 ${this.deities.length} 位神明`)
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('[TempleSystem] 載入神明失敗:', error)
|
|
|
|
|
|
// 降級到本地載入
|
|
|
|
|
|
const { DEITIES } = await import('../data/deities.js')
|
|
|
|
|
|
this.deities = DEITIES
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 獲取所有神明
|
|
|
|
|
|
getDeities() {
|
|
|
|
|
|
return [...this.deities]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 獲取當前神明
|
|
|
|
|
|
getCurrentDeity() {
|
|
|
|
|
|
const state = this.petSystem.getState()
|
|
|
|
|
|
return this.deities.find(d => d.id === state.currentDeityId) || this.deities[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 切換神明
|
|
|
|
|
|
async switchDeity(deityId) {
|
|
|
|
|
|
const deity = this.deities.find(d => d.id === deityId)
|
|
|
|
|
|
if (!deity) {
|
|
|
|
|
|
return { success: false, message: '找不到該神明' }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await this.petSystem.updateState({ currentDeityId: deityId })
|
2025-11-24 07:38:44 +00:00
|
|
|
|
|
|
|
|
|
|
// 重新計算屬性(新神明的加成)
|
|
|
|
|
|
this.petSystem.calculateCombatStats()
|
|
|
|
|
|
|
|
|
|
|
|
// 同步 effective 属性到状态
|
|
|
|
|
|
await this.petSystem.updateState({
|
|
|
|
|
|
effectiveStr: this.petSystem.state.effectiveStr,
|
|
|
|
|
|
effectiveInt: this.petSystem.state.effectiveInt,
|
|
|
|
|
|
effectiveDex: this.petSystem.state.effectiveDex,
|
|
|
|
|
|
effectiveLuck: this.petSystem.state.effectiveLuck
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-11-23 18:03:56 +00:00
|
|
|
|
return { success: true, deity }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 祈福(每日上限 3 次)
|
|
|
|
|
|
async pray() {
|
|
|
|
|
|
const state = this.petSystem.getState()
|
2025-11-24 07:38:44 +00:00
|
|
|
|
|
2025-11-23 18:03:56 +00:00
|
|
|
|
if (state.dailyPrayerCount >= 3) {
|
|
|
|
|
|
return { success: false, message: '今日祈福次數已用完' }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const result = await this.api.prayToDeity({
|
|
|
|
|
|
deityId: state.currentDeityId,
|
|
|
|
|
|
petState: state
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 更新好感度
|
|
|
|
|
|
const currentFavor = state.deityFavors[state.currentDeityId] || 0
|
|
|
|
|
|
const newFavor = Math.min(100, currentFavor + result.favorIncrease)
|
2025-11-24 07:38:44 +00:00
|
|
|
|
|
|
|
|
|
|
// 檢查是否等級提升或達到滿級
|
|
|
|
|
|
const deity = this.getCurrentDeity()
|
|
|
|
|
|
const oldLevel = deity.favorLevelBuffs ? Math.floor(currentFavor / deity.favorLevelBuffs.interval) : 0
|
|
|
|
|
|
const newLevel = deity.favorLevelBuffs ? Math.floor(newFavor / deity.favorLevelBuffs.interval) : 0
|
|
|
|
|
|
const levelUp = newLevel > oldLevel
|
|
|
|
|
|
const reachedMax = currentFavor < 100 && newFavor >= 100
|
|
|
|
|
|
|
2025-11-23 18:03:56 +00:00
|
|
|
|
await this.petSystem.updateState({
|
|
|
|
|
|
deityFavors: {
|
|
|
|
|
|
...state.deityFavors,
|
|
|
|
|
|
[state.currentDeityId]: newFavor
|
|
|
|
|
|
},
|
|
|
|
|
|
dailyPrayerCount: state.dailyPrayerCount + 1
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-11-24 07:38:44 +00:00
|
|
|
|
// 重新計算屬性(好感度變化影響加成)
|
|
|
|
|
|
this.petSystem.calculateCombatStats()
|
|
|
|
|
|
|
|
|
|
|
|
// 同步 effective 属性到状态
|
|
|
|
|
|
await this.petSystem.updateState({
|
|
|
|
|
|
effectiveStr: this.petSystem.state.effectiveStr,
|
|
|
|
|
|
effectiveInt: this.petSystem.state.effectiveInt,
|
|
|
|
|
|
effectiveDex: this.petSystem.state.effectiveDex,
|
|
|
|
|
|
effectiveLuck: this.petSystem.state.effectiveLuck
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-11-23 18:03:56 +00:00
|
|
|
|
// 獲取神明對話
|
|
|
|
|
|
const dialogue = deity.dialogues[Math.floor(Math.random() * deity.dialogues.length)]
|
|
|
|
|
|
|
2025-11-24 10:34:02 +00:00
|
|
|
|
// 記錄到成就系統
|
|
|
|
|
|
if (this.achievementSystem) {
|
|
|
|
|
|
await this.achievementSystem.recordAction('pray')
|
|
|
|
|
|
// 檢查神明好感度成就
|
|
|
|
|
|
await this.achievementSystem.checkAndUnlockAchievements()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-23 18:03:56 +00:00
|
|
|
|
return {
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
favorIncrease: result.favorIncrease,
|
|
|
|
|
|
newFavor,
|
2025-11-24 07:38:44 +00:00
|
|
|
|
oldLevel,
|
|
|
|
|
|
newLevel,
|
|
|
|
|
|
levelUp,
|
|
|
|
|
|
reachedMax,
|
2025-11-23 18:03:56 +00:00
|
|
|
|
dialogue,
|
2025-11-24 07:38:44 +00:00
|
|
|
|
message: result.message,
|
|
|
|
|
|
deity
|
2025-11-23 18:03:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('[TempleSystem] 祈福失敗:', error)
|
|
|
|
|
|
return { success: false, message: '祈福失敗' }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 獲取好感度星級(每 20 點一星)
|
|
|
|
|
|
getFavorStars(deityId) {
|
2025-11-24 13:45:09 +00:00
|
|
|
|
if (!deityId) return '☆☆☆☆☆'
|
2025-11-23 18:03:56 +00:00
|
|
|
|
const state = this.petSystem.getState()
|
2025-11-24 13:45:09 +00:00
|
|
|
|
if (!state || !state.deityFavors) return '☆☆☆☆☆'
|
2025-11-23 18:03:56 +00:00
|
|
|
|
const favor = state.deityFavors[deityId] || 0
|
|
|
|
|
|
const stars = Math.floor(favor / 20)
|
|
|
|
|
|
return '★'.repeat(stars) + '☆'.repeat(5 - stars)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 抽籤
|
2025-11-24 07:38:44 +00:00
|
|
|
|
|
2025-11-24 08:04:00 +00:00
|
|
|
|
// 求籤(需要三聖筊驗證)
|
|
|
|
|
|
async drawLot(lotType = 'guanyin_100') {
|
|
|
|
|
|
const state = this.petSystem.getState()
|
|
|
|
|
|
const deity = this.getCurrentDeity()
|
2025-11-24 07:38:44 +00:00
|
|
|
|
|
2025-11-24 08:04:00 +00:00
|
|
|
|
// 檢查神明是否支持此簽詩
|
|
|
|
|
|
if (!deity.lotTypes || !deity.lotTypes.includes(lotType)) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: `${deity.name}不提供${lotType}簽詩`
|
2025-11-23 18:03:56 +00:00
|
|
|
|
}
|
2025-11-24 08:04:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 載入簽詩資料
|
|
|
|
|
|
const lots = await this.loadLots(lotType)
|
|
|
|
|
|
|
|
|
|
|
|
// 隨機抽一支簽
|
|
|
|
|
|
const randomIndex = Math.floor(Math.random() * lots.length)
|
|
|
|
|
|
const lot = lots[randomIndex]
|
2025-11-24 07:38:44 +00:00
|
|
|
|
|
2025-11-24 10:34:02 +00:00
|
|
|
|
// 記錄到成就系統
|
|
|
|
|
|
if (this.achievementSystem) {
|
|
|
|
|
|
await this.achievementSystem.recordAction('drawFortune')
|
|
|
|
|
|
await this.achievementSystem.checkAndUnlockAchievements()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 08:04:00 +00:00
|
|
|
|
// 返回需要擲筊驗證的狀態
|
2025-11-23 18:03:56 +00:00
|
|
|
|
return {
|
|
|
|
|
|
success: true,
|
2025-11-24 08:04:00 +00:00
|
|
|
|
needVerification: true,
|
|
|
|
|
|
lot,
|
|
|
|
|
|
lotType,
|
|
|
|
|
|
deity: deity.name,
|
|
|
|
|
|
verificationCount: 0,
|
|
|
|
|
|
requiredHoly: 3 // 需要三個聖筊
|
2025-11-23 18:03:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('[TempleSystem] 抽籤失敗:', error)
|
|
|
|
|
|
return { success: false, message: '抽籤失敗' }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-24 07:38:44 +00:00
|
|
|
|
|
2025-11-24 08:04:00 +00:00
|
|
|
|
// 驗證簽詩(擲筊確認)
|
|
|
|
|
|
async verifyLot(lotData) {
|
|
|
|
|
|
// 擲筊
|
|
|
|
|
|
const jiaobeiResult = await this.throwJiaobei(`求問第${lotData.lot.no}籤`)
|
|
|
|
|
|
|
|
|
|
|
|
if (jiaobeiResult.result === 'holy') {
|
|
|
|
|
|
// 聖筊
|
|
|
|
|
|
const newCount = (lotData.verificationCount || 0) + 1
|
|
|
|
|
|
|
|
|
|
|
|
if (newCount >= lotData.requiredHoly) {
|
|
|
|
|
|
// 三聖筊,可以解簽
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
verified: true,
|
|
|
|
|
|
lot: lotData.lot,
|
|
|
|
|
|
jiaobeiResult,
|
|
|
|
|
|
message: `三聖筊!${lotData.deity}允准解籤`
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 還需要更多聖筊
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
verified: false,
|
|
|
|
|
|
needMore: true,
|
|
|
|
|
|
verificationCount: newCount,
|
|
|
|
|
|
requiredHoly: lotData.requiredHoly,
|
|
|
|
|
|
lot: lotData.lot,
|
|
|
|
|
|
jiaobeiResult,
|
|
|
|
|
|
message: `第${newCount}個聖筊,還需${lotData.requiredHoly - newCount}個聖筊`
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 笑筊或陰筊,需要重抽
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
verified: false,
|
|
|
|
|
|
needRedraw: true,
|
|
|
|
|
|
jiaobeiResult,
|
|
|
|
|
|
message: `${jiaobeiResult.result === 'laughing' ? '笑筊' : '陰筊'},請重新抽籤`
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 載入簽詩資料
|
|
|
|
|
|
async loadLots(lotType) {
|
|
|
|
|
|
if (lotType === 'guanyin_100') {
|
|
|
|
|
|
const data = await import('../data/guanyin_100_lots.json')
|
|
|
|
|
|
return data.default || data
|
|
|
|
|
|
}
|
|
|
|
|
|
throw new Error(`未知的簽詩類型: ${lotType}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 07:38:44 +00:00
|
|
|
|
// 擲筊
|
|
|
|
|
|
async throwJiaobei(question = '') {
|
|
|
|
|
|
const state = this.petSystem.getState()
|
|
|
|
|
|
const deity = this.getCurrentDeity()
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 計算實際概率
|
|
|
|
|
|
const probabilities = this.calculateJiaobeiProbabilities()
|
|
|
|
|
|
|
|
|
|
|
|
// 嘗試使用 API
|
|
|
|
|
|
const apiResult = await this.api.throwJiaobei({
|
|
|
|
|
|
petId: state.id,
|
|
|
|
|
|
deityId: deity.id,
|
|
|
|
|
|
question,
|
|
|
|
|
|
probabilities
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 如果 API 回傳本地降級標記,使用本地邏輯
|
|
|
|
|
|
if (!apiResult.localFallback) {
|
|
|
|
|
|
return apiResult
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.warn('[TempleSystem] 擲筊 API 失敗,使用本地邏輯', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 本地邏輯
|
|
|
|
|
|
const probabilities = this.calculateJiaobeiProbabilities()
|
|
|
|
|
|
const result = this.rollJiaobei(probabilities)
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
result,
|
|
|
|
|
|
deity: deity.name,
|
2025-11-24 10:34:02 +00:00
|
|
|
|
message: result === 'holy' ? '聖筊' : result === 'laughing' ? '笑筊' : '陰筊',
|
|
|
|
|
|
probabilities
|
2025-11-24 07:38:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 10:34:02 +00:00
|
|
|
|
// 取得當前神明可用的 lotTypes(可能有多個)
|
|
|
|
|
|
getCurrentDeityLotTypes() {
|
|
|
|
|
|
const deity = this.getCurrentDeity()
|
|
|
|
|
|
// 若未設定則回傳空陣列,避免錯誤
|
|
|
|
|
|
return deity?.lotTypes ?? []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 07:38:44 +00:00
|
|
|
|
// 計算擲筊概率(考慮運勢和好感度)
|
|
|
|
|
|
calculateJiaobeiProbabilities() {
|
|
|
|
|
|
const state = this.petSystem.getState()
|
|
|
|
|
|
const deity = this.getCurrentDeity()
|
|
|
|
|
|
|
|
|
|
|
|
// 基礎概率
|
|
|
|
|
|
let { holy, laughing, negative } = JIAOBEI_CONFIG.baseProbability
|
|
|
|
|
|
|
|
|
|
|
|
// 運勢影響:增加聖筊概率
|
|
|
|
|
|
const luck = state.luck || 10
|
|
|
|
|
|
const luckBonus = Math.min(
|
|
|
|
|
|
luck * JIAOBEI_CONFIG.luckModifier,
|
|
|
|
|
|
JIAOBEI_CONFIG.maxModifier
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 好感度影響:減少陰筊概率
|
|
|
|
|
|
const favor = state.deityFavors[deity.id] || 0
|
|
|
|
|
|
const favorBonus = Math.min(
|
|
|
|
|
|
favor * JIAOBEI_CONFIG.favorModifier,
|
|
|
|
|
|
JIAOBEI_CONFIG.maxModifier
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 調整概率
|
|
|
|
|
|
holy += luckBonus + favorBonus / 2
|
|
|
|
|
|
negative -= favorBonus
|
|
|
|
|
|
laughing -= luckBonus / 2
|
|
|
|
|
|
|
|
|
|
|
|
// 確保非負
|
|
|
|
|
|
holy = Math.max(0.1, holy)
|
|
|
|
|
|
laughing = Math.max(0.1, laughing)
|
|
|
|
|
|
negative = Math.max(0.1, negative)
|
|
|
|
|
|
|
|
|
|
|
|
// 歸一化(確保總和為1)
|
|
|
|
|
|
const total = holy + laughing + negative
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
holy: holy / total,
|
|
|
|
|
|
laughing: laughing / total,
|
|
|
|
|
|
negative: negative / total
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 投擲筊杯(隨機結果)
|
|
|
|
|
|
rollJiaobei(probabilities) {
|
|
|
|
|
|
const rand = Math.random()
|
|
|
|
|
|
|
|
|
|
|
|
if (rand < probabilities.holy) {
|
|
|
|
|
|
return 'holy'
|
|
|
|
|
|
} else if (rand < probabilities.holy + probabilities.laughing) {
|
|
|
|
|
|
return 'laughing'
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return 'negative'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Debug: 重置每日祈福次數
|
|
|
|
|
|
async debugResetDailyPrayer() {
|
|
|
|
|
|
console.log('[Debug] 重置每日祈福次數')
|
|
|
|
|
|
await this.petSystem.updateState({ dailyPrayerCount: 0 })
|
|
|
|
|
|
return { success: true, message: '已重置祈福次數' }
|
|
|
|
|
|
}
|
2025-11-23 18:03:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|