pet_data/app/app.vue

2026 lines
54 KiB
Vue
Raw Normal View History

2025-11-23 18:03:56 +00:00
<template>
<div class="pet-system-container">
<!-- 名字輸入對話框 -->
<div v-if="showNameInput" class="name-input-modal">
<div class="modal-content">
2025-11-24 07:38:44 +00:00
<h2> 為你的寵物命名</h2>
2025-11-23 18:03:56 +00:00
<p>請為你的新寵物取一個名字</p>
<input
v-model="inputPetName"
@keyup.enter="confirmName"
type="text"
placeholder="輸入寵物名字..."
maxlength="20"
class="name-input"
/>
<div class="modal-buttons">
<button @click="confirmName" :disabled="!inputPetName || inputPetName.trim().length === 0">
確認
</button>
</div>
</div>
</div>
<div class="header">
2025-11-24 07:38:44 +00:00
<h1>{{ petState?.name || 'LOADING...' }}</h1>
2025-11-23 18:03:56 +00:00
<p class="subtitle">{{ systemStatus }}</p>
</div>
<!-- 寵物狀態顯示 -->
<div class="pet-status" v-if="petState">
<!-- 基礎屬性 -->
<div class="status-section">
<h3>基礎屬性</h3>
<div class="status-grid">
<div class="stat-item">
<span class="stat-label">飢餓</span>
<div class="stat-bar">
<div class="stat-fill" :style="{ width: `${petState.hunger || 0}%` }"></div>
</div>
2025-11-24 07:38:44 +00:00
<span class="stat-value">{{ Math.round(petState.hunger || 0) }}</span>
2025-11-23 18:03:56 +00:00
</div>
<div class="stat-item">
<span class="stat-label">快樂</span>
<div class="stat-bar">
<div class="stat-fill" :style="{ width: `${petState.happiness || 0}%` }"></div>
</div>
2025-11-24 07:38:44 +00:00
<span class="stat-value">{{ Math.round(petState.happiness || 0) }}</span>
2025-11-23 18:03:56 +00:00
</div>
<div class="stat-item">
<span class="stat-label">健康</span>
<div class="stat-bar">
2025-11-24 07:38:44 +00:00
<div class="stat-fill" :style="{ width: `${(petState.health / getMaxHealth(petState)) * 100 || 0}%` }"></div>
2025-11-23 18:03:56 +00:00
</div>
2025-11-24 07:38:44 +00:00
<span class="stat-value">{{ Math.round(petState.health || 0) }}/{{ getMaxHealth(petState) }}</span>
2025-11-23 18:03:56 +00:00
</div>
</div>
</div>
<!-- 寵物資料 -->
<div class="status-section">
<h3> 寵物資料 </h3>
<div class="pet-info-grid">
<div class="info-item">
<span class="info-label">名字</span>
<span class="info-value">{{ petState.name || '未命名' }}</span>
</div>
<div class="info-item">
<span class="info-label">階段</span>
<span class="info-value">{{ getStageName(petState.stage) }}</span>
</div>
<div class="info-item">
<span class="info-label">年齡</span>
<span class="info-value">{{ formatAge(petState.ageSeconds) }}</span>
</div>
<div class="info-item">
<span class="info-label">身高</span>
<span class="info-value">{{ Math.round(petState.height || 0) }} cm</span>
</div>
2025-11-24 07:38:44 +00:00
<div class="info-item">
<span class="info-label">身高</span>
<span class="info-value">{{ Math.round(petState.height || 0) }} cm</span>
</div>
2025-11-23 18:03:56 +00:00
<div class="info-item">
<span class="info-label">體重</span>
<span class="info-value">{{ Math.round(petState.weight || 0) }} g</span>
</div>
<div class="info-item">
<span class="info-label">命格</span>
2025-11-24 07:38:44 +00:00
<div class="info-value-group">
<span class="info-value highlight">{{ petState.destiny ? petState.destiny.name : '無' }}</span>
<span v-if="petState.destiny" class="info-sub">{{ petState.destiny.description }}</span>
</div>
2025-11-23 18:03:56 +00:00
</div>
<div class="info-item">
<span class="info-label">力量 (STR)</span>
2025-11-24 07:38:44 +00:00
<span class="info-value">{{ Math.round(petState.effectiveStr || petState.str || 0) }}</span>
2025-11-23 18:03:56 +00:00
</div>
<div class="info-item">
<span class="info-label">智力 (INT)</span>
2025-11-24 07:38:44 +00:00
<span class="info-value">{{ Math.round(petState.effectiveInt || petState.int || 0) }}</span>
2025-11-23 18:03:56 +00:00
</div>
<div class="info-item">
<span class="info-label">敏捷 (DEX)</span>
2025-11-24 07:38:44 +00:00
<span class="info-value">{{ Math.round(petState.effectiveDex || petState.dex || 0) }}</span>
</div>
<div class="info-item">
<span class="info-label">運勢 (LUCK)</span>
<span class="info-value">{{ Math.round(petState.effectiveLuck || petState.luck || 0) }}</span>
2025-11-23 18:03:56 +00:00
</div>
<div class="info-item">
<span class="info-label">世代</span>
<span class="info-value"> {{ petState.generation || 1 }} </span>
</div>
<div class="info-item">
<span class="info-label">神明好感</span>
<span class="info-value">{{ getDeityFavorDisplay(petState) }}</span>
</div>
<div class="info-item">
<span class="info-label">HP</span>
<span class="info-value">{{ Math.round(petState.hp || petState.health || 0) }}</span>
</div>
<div class="info-item">
<span class="info-label">攻擊</span>
<span class="info-value">{{ Math.round(petState.attack || 0) }}</span>
</div>
<div class="info-item">
<span class="info-label">防禦</span>
<span class="info-value">{{ Math.round(petState.defense || 0) }}</span>
</div>
<div class="info-item">
<span class="info-label">速度</span>
<span class="info-value">{{ Math.round(petState.speed || 0) }}</span>
</div>
</div>
</div>
2025-11-24 07:38:44 +00:00
<div class="status-section">
<h3> 加成與隱藏數值 </h3>
<div class="bonus-grid">
<div
class="bonus-item"
v-for="(value, key) in getAllBonuses(petState)"
:key="key"
:class="{ 'not-implemented': !isImplemented(key) }"
>
<span class="bonus-label">{{ getBonusName(key) }}</span>
<span class="bonus-value" :class="{ positive: value > 0, negative: value < 0 }">
{{ value > 0 ? '+' : '' }}{{ value }}
</span>
</div>
</div>
</div>
2025-11-23 18:03:56 +00:00
<!-- 狀態標籤 -->
<div class="status-badges">
2025-11-24 07:38:44 +00:00
<span v-if="petState.isSleeping" class="badge">[SLEEP] 睡覺中</span>
<span v-if="petState.isSick" class="badge sick">[SICK] 生病</span>
<span v-if="petState.poopCount > 0" class="badge">[POOP] 便便 x{{ petState.poopCount }}</span>
2025-11-23 18:03:56 +00:00
</div>
</div>
<!-- 操作按鈕區 -->
<div class="action-panel">
<div class="action-group">
2025-11-24 07:38:44 +00:00
<h3> 寵物互動</h3>
2025-11-23 18:03:56 +00:00
<div class="button-grid">
2025-11-24 07:38:44 +00:00
<button @click="handleFeed"
:disabled="!canDoAction('feed')"
:title="!canDoAction('feed') ? getDisabledReason('feed') : '增加飢餓值 (+體重)'">
[FEED] 餵食
</button>
<!-- 玩耍選項 -->
<div class="play-group" style="grid-column: span 2; display: flex; gap: 5px;">
<button @click="handlePlay('normal')"
:disabled="!canDoAction('play')"
:title="!canDoAction('play') ? getDisabledReason('play') : '一般玩耍 (體重 -1g)'"
style="flex: 1;">
[PLAY] 玩耍
</button>
<button @click="handlePlay('training')"
:disabled="!canDoAction('play')"
:title="!canDoAction('play') ? getDisabledReason('play') : '體能訓練 (體重 -3g)'"
style="flex: 1;">
[TRAIN] 訓練
</button>
<button @click="handlePlay('puzzle')"
:disabled="!canDoAction('play')"
:title="!canDoAction('play') ? getDisabledReason('play') : '益智遊戲 (體重不變)'"
style="flex: 1;">
[PUZZLE] 益智
</button>
</div>
<button @click="handleClean"
:disabled="!canDoAction('clean')"
:title="!canDoAction('clean') ? getDisabledReason('clean') : '清理便便'">
[CLEAN] 清理
</button>
<button @click="handleHeal"
:disabled="!canDoAction('heal')"
:title="!canDoAction('heal') ? getDisabledReason('heal') : '恢復健康'">
[HEAL] 治療
</button>
<button @click="handleSleep"
:disabled="!canDoAction('sleep')"
:title="!canDoAction('sleep') ? getDisabledReason('sleep') : '睡覺恢復健康'">
{{ petState?.isSleeping ? '[WAKE] 起床' : '[SLEEP] 睡覺' }}
2025-11-23 18:03:56 +00:00
</button>
2025-11-24 07:38:44 +00:00
<button @click="handleShowStatus" :disabled="!isReady">[STATUS] 查看狀態</button>
<button @click="handleCheckEvolution" :disabled="!isReady" title="檢查進化條件">[CHECK] 進化檢查</button>
<button @click="handleDeletePet" :disabled="!isReady" class="danger-button">[DEL] 刪除寵物</button>
2025-11-23 18:03:56 +00:00
</div>
</div>
<div class="action-group">
2025-11-24 07:38:44 +00:00
<h3>[ROLL] 事件系統</h3>
2025-11-23 18:03:56 +00:00
<div class="button-grid">
2025-11-24 07:38:44 +00:00
<button @click="handleStart" :disabled="!isReady || isRunning">[START] 啟動循環</button>
<button @click="handleStop" :disabled="!isRunning">[STOP] 停止循環</button>
<button @click="handleListEvents" :disabled="!isReady">[LIST] 事件列表</button>
<button @click="handleEventHistory" :disabled="!isReady">[HISTORY] 事件歷史</button>
<button @click="handleTestAllEvents" :disabled="!isReady">[TEST] 測試所有事件</button>
2025-11-23 18:03:56 +00:00
</div>
2025-11-24 07:38:44 +00:00
<!-- 快速觸發事件 -->
<details class="event-list">
<summary>* 快速觸發事件</summary>
<div class="button-grid small">
<button @click="handleTriggerEvent('lucky_find')" :disabled="!isReady">幸運發現</button>
<button @click="handleTriggerEvent('find_treat')" :disabled="!isReady">發現點心</button>
<button @click="handleTriggerEvent('playful_moment')" :disabled="!isReady">玩耍時光</button>
<button @click="handleTriggerEvent('deity_blessing')" :disabled="!isReady">神明祝福</button>
<button @click="handleTriggerEvent('over_eat')" :disabled="!isReady">吃太多</button>
<button @click="handleTriggerEvent('catch_cold')" :disabled="!isReady">感冒</button>
</div>
</details>
2025-11-23 18:03:56 +00:00
</div>
<div class="action-group">
2025-11-24 07:38:44 +00:00
<h3>[PRAY] 神明系統</h3>
2025-11-23 18:03:56 +00:00
<div class="button-grid">
2025-11-24 07:38:44 +00:00
<button @click="handlePray" :disabled="!isReady">[PRAY] 祈福</button>
<button @click="handleDrawFortune" :disabled="!isReady">[DRAW] 抽籤</button>
<button @click="handleThrowJiaobei" :disabled="!isReady">[JIAOBEI] 擲筊</button>
<button @click="handleListDeities" :disabled="!isReady">[LIST] 神明列表</button>
2025-11-23 18:03:56 +00:00
</div>
2025-11-24 07:38:44 +00:00
<!-- 切換神明 -->
<details class="deity-list">
<summary>[SWITCH] 切換神明</summary>
<div class="button-grid small">
<button @click="handleSwitchDeity('mazu')" :disabled="!isReady"
:class="{ active: petState?.currentDeityId === 'mazu' }">媽祖</button>
<button @click="handleSwitchDeity('earthgod')" :disabled="!isReady"
:class="{ active: petState?.currentDeityId === 'earthgod' }">土地公</button>
<button @click="handleSwitchDeity('yuelao')" :disabled="!isReady"
:class="{ active: petState?.currentDeityId === 'yuelao' }">月老</button>
<button @click="handleSwitchDeity('wenchang')" :disabled="!isReady"
:class="{ active: petState?.currentDeityId === 'wenchang' }">文昌</button>
<button @click="handleSwitchDeity('guanyin')" :disabled="!isReady"
:class="{ active: petState?.currentDeityId === 'guanyin' }">觀音</button>
</div>
</details>
2025-11-23 18:03:56 +00:00
</div>
</div>
2025-11-24 07:38:44 +00:00
<!-- Debug 面板 -->
<div class="debug-toggle" @click="showDebug = !showDebug">[DEBUG]</div>
<div v-if="showDebug" class="debug-panel">
<h3>[TOOLS] Debug 工具</h3>
<div class="debug-group">
<h4>神明系統</h4>
<button @click="debugResetPrayer">重置祈福次數</button>
<button @click="debugAddFavor(10)">好感度 +10</button>
<button @click="debugAddFavor(50)">好感度 +50</button>
</div>
<div class="debug-group">
<h4>事件系統</h4>
<button @click="debugTriggerEvent">隨機觸發事件</button>
</div>
<div class="debug-group">
<h4>寵物狀態</h4>
<button @click="debugFillStats">填滿飢餓/快樂</button>
<button @click="debugMaxAttributes">屬性全滿 (100)</button>
<button @click="debugAddPoop">[POOP] 便便 x4</button>
<button @click="debugKill">一鍵瀕死</button>
</div>
2025-11-23 18:03:56 +00:00
</div>
</div>
</template>
2025-11-24 07:38:44 +00:00
<style scoped>
/* Debug 面板樣式 */
.debug-toggle {
position: fixed;
bottom: 10px;
right: 10px;
width: 40px;
height: 40px;
background: rgba(0, 0, 0, 0.5);
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 9999;
font-size: 20px;
}
.debug-panel {
position: fixed;
bottom: 60px;
right: 10px;
background: rgba(0, 0, 0, 0.9);
color: white;
padding: 15px;
border-radius: 10px;
z-index: 9999;
width: 200px;
border: 1px solid #444;
}
.debug-panel h3 {
margin: 0 0 10px 0;
font-size: 16px;
border-bottom: 1px solid #444;
padding-bottom: 5px;
}
.debug-group {
margin-bottom: 15px;
}
.debug-group h4 {
margin: 0 0 5px 0;
font-size: 12px;
color: #aaa;
}
.debug-panel button {
display: block;
width: 100%;
margin-bottom: 5px;
padding: 5px;
background: #333;
border: 1px solid #555;
color: white;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
}
.debug-panel button:hover {
background: #555;
}
</style>
2025-11-23 18:03:56 +00:00
<script setup>
import { onMounted, onUnmounted, ref } from 'vue'
import { PetSystem } from '../core/pet-system.js'
import { EventSystem } from '../core/event-system.js'
import { TempleSystem } from '../core/temple-system.js'
import { ApiService } from '../core/api-service.js'
// 創建 API 服務
const apiService = new ApiService({
useMock: true,
baseUrl: 'http://localhost:3000/api',
mockDelay: 100
})
// 響應式狀態
const petState = ref(null)
const systemStatus = ref('正在初始化...')
const isReady = ref(false)
const isRunning = ref(false)
const showNameInput = ref(false)
const inputPetName = ref('')
// 系統實例
let petSystem, eventSystem, templeSystem
// 更新狀態顯示
function updatePetState() {
if (petSystem) {
petState.value = petSystem.getState()
}
}
2025-11-24 07:38:44 +00:00
// 檢查當前階段是否可以執行某個動作
function canDoAction(action) {
if (!isReady.value || !petSystem) return false
return petSystem.isActionAllowed(action)
}
// 獲取按鈕禁用的原因
function getDisabledReason(action) {
if (!isReady.value || !petSystem) return '系統尚未就緒'
if (!petSystem.isActionAllowed(action)) {
const stage = petState.value?.stage || 'unknown'
const stageNames = {
'egg': '蛋階段',
'baby': '幼體',
'child': '幼年',
'adult': '成年'
}
return `${stageNames[stage] || stage}不能執行此操作`
}
return ''
}
2025-11-23 18:03:56 +00:00
// 格式化年齡
function formatAge(ageSeconds) {
if (!ageSeconds) return '0 秒'
const days = Math.floor(ageSeconds / 86400)
const hours = Math.floor((ageSeconds % 86400) / 3600)
const minutes = Math.floor((ageSeconds % 3600) / 60)
const seconds = Math.floor(ageSeconds % 60)
if (days > 0) return `${days}${hours} 小時`
if (hours > 0) return `${hours} 小時 ${minutes} 分鐘`
if (minutes > 0) return `${minutes} 分鐘 ${seconds}`
return `${seconds}`
}
// 獲取階段名稱
function getStageName(stage) {
const stageNames = {
'egg': '蛋',
'baby': '幼體',
'child': '幼年',
'adult': '成年'
}
return stageNames[stage] || stage
}
// 獲取神明好感顯示
function getDeityFavorDisplay(state) {
if (!state || !state.currentDeityId) return '無'
const favor = state.deityFavors?.[state.currentDeityId] || 0
const deityNames = {
'mazu': '媽祖',
'earthgod': '土地公',
'yuelao': '月老',
'wenchang': '文昌',
'guanyin': '觀音'
}
return `${deityNames[state.currentDeityId] || state.currentDeityId}: ${favor}/100`
}
2025-11-24 07:38:44 +00:00
// 獲取所有加成
// 獲取所有加成
function getAllBonuses(state) {
if (!state) return {}
const bonuses = {}
// 1. 命格加成
if (state.destiny && state.destiny.buffs) {
for (const [key, value] of Object.entries(state.destiny.buffs)) {
bonuses[key] = (bonuses[key] || 0) + value
}
}
// 獲取當前神明(如果在神明系統範圍內)
let currentDeity = null
if (templeSystem) {
currentDeity = templeSystem.getCurrentDeity()
}
// 2. 神明基礎加成
if (currentDeity && currentDeity.buffs) {
for (const [key, value] of Object.entries(currentDeity.buffs)) {
bonuses[key] = (bonuses[key] || 0) + value
}
}
// 3. 臨時 Buff (需要從 eventSystem 獲取)
if (eventSystem) {
const activeBuffs = eventSystem.getBuffManager().getActiveBuffs()
for (const buff of activeBuffs) {
if (buff.effects) {
for (const [key, value] of Object.entries(buff.effects)) {
bonuses[key] = (bonuses[key] || 0) + value
}
}
}
}
// 4. 神明好感度等級加成
if (currentDeity && currentDeity.favorLevelBuffs) {
const favor = state.deityFavors?.[state.currentDeityId] || 0
const level = Math.floor(favor / currentDeity.favorLevelBuffs.interval)
if (level > 0 && currentDeity.favorLevelBuffs.buffsPerLevel) {
for (const [key, valuePerLevel] of Object.entries(currentDeity.favorLevelBuffs.buffsPerLevel)) {
bonuses[key] = (bonuses[key] || 0) + (valuePerLevel * level)
}
}
}
// 5. 神明滿級特殊 Buff
if (currentDeity && currentDeity.maxFavorBuff) {
const favor = state.deityFavors?.[state.currentDeityId] || 0
if (favor >= 100 && currentDeity.maxFavorBuff.effects) {
for (const [key, value] of Object.entries(currentDeity.maxFavorBuff.effects)) {
// 排除非數值效果(如 sicknessImmune
if (typeof value === 'number') {
bonuses[key] = (bonuses[key] || 0) + value
}
}
}
}
return bonuses
}
// 检查加成是否已实现
function isImplemented(key) {
const implemented = [
'str', 'int', 'dex', 'luck', 'health',
'strGain', 'intGain', 'dexGain',
'happinessRecovery', 'healthRecovery'
]
return implemented.includes(key)
}
// 獲取加成名稱
function getBonusName(key) {
const names = {
// 基礎屬性(影响战斗数值)
str: '力量',
int: '智力',
dex: '敏捷',
luck: '運勢',
health: '最大健康',
// 成長效率
strGain: '力量成長',
intGain: '智力成長',
dexGain: '敏捷成長',
// 状态恢复
happinessRecovery: '快樂恢復',
healthRecovery: '健康恢復',
// 未实现的加成
gameSuccessRate: '小遊戲成功率',
sicknessReduction: '生病抗性',
resourceGain: '資源獲得',
breedingSuccess: '繁殖成功率',
dropRate: '掉落率',
miniGameBonus: '小遊戲獎勵',
badEventReduction: '壞事件減少'
}
return names[key] || key
}
// 获取最大健康值
function getMaxHealth(state) {
if (!state) return 100
const bonuses = getAllBonuses(state)
return 100 + (bonuses.health || 0)
}
2025-11-23 18:03:56 +00:00
// 顯示狀態(簡潔版)
function showStatus() {
if (!petSystem || !eventSystem || !templeSystem) {
console.log('系統尚未初始化')
return
}
const state = petSystem.getState()
if (!state) {
console.log('狀態尚未載入')
return
}
updatePetState()
const buffs = eventSystem.getBuffManager().getActiveBuffs()
const currentDeity = templeSystem.getCurrentDeity()
const favorStars = templeSystem.getFavorStars(state.currentDeityId)
2025-11-24 07:38:44 +00:00
const buffNames = buffs.map(b => b.name)
// 檢查神明滿級 Buff
if (currentDeity && state.deityFavors?.[state.currentDeityId] >= 100 && currentDeity.maxFavorBuff) {
const buff = currentDeity.maxFavorBuff
buffNames.push(`*${buff.name}(${buff.description})`)
}
2025-11-23 18:03:56 +00:00
// 安全獲取數值,避免 undefined
const safeNum = (val) => (typeof val === 'number' && !isNaN(val) ? val.toFixed(0) : '0')
2025-11-24 07:38:44 +00:00
console.log(` 狀態 | 飢餓:${safeNum(state.hunger)} 快樂:${safeNum(state.happiness)} 健康:${safeNum(state.health)} | 力量:${safeNum(state.str)} 智力:${safeNum(state.int)} 敏捷:${safeNum(state.dex)} 運勢:${safeNum(state.luck)} | ${currentDeity?.name || '未知'}${favorStars} | Buff:${buffNames.length > 0 ? buffNames.join(', ') : '無'}`)
2025-11-23 18:03:56 +00:00
}
// 啟動遊戲循環
function start() {
if (isRunning.value) {
2025-11-24 07:38:44 +00:00
console.log('[WARN] 遊戲循環已在運行中')
2025-11-23 18:03:56 +00:00
return
}
isRunning.value = true
// 移除 tick 回調中的自動輸出,只在有事件時才輸出
petSystem.startTickLoop(() => {
// 更新狀態顯示
updatePetState()
})
eventSystem.startEventCheck()
2025-11-24 07:38:44 +00:00
// 初始化全局 Debug 工具
window.debug = {
// 重置祈福次數
resetPrayer: async () => {
await templeSystem.debugResetDailyPrayer()
console.log('[OK] 祈福次數已重置')
showStatus()
},
// 設置好感度
setFavor: async (deityId, amount) => {
const state = petSystem.getState()
await petSystem.updateState({
deityFavors: {
...state.deityFavors,
[deityId]: amount
}
})
console.log(`[OK] ${deityId} 好感度已設置為 ${amount}`)
showStatus()
},
// 觸發事件
triggerEvent: async (eventId) => {
await eventSystem.debugTriggerEvent(eventId)
showStatus()
},
// 設置屬性
setStat: async (stat, value) => {
await petSystem.debugSetStat(stat, value)
showStatus()
},
// 幫助
help: () => {
console.log(`
[TOOLS] Debug 工具列表:
- debug.resetPrayer() 重置每日祈福次數
- debug.setFavor(id, amount) 設置神明好感度 (例如: 'mazu', 99)
- debug.triggerEvent(id) 觸發事件 (不填 ID 則隨機)
- debug.setStat(stat, value) 設置屬性 (例如: 'hunger', 100)
`)
}
}
console.log('[DEBUG] Debug 工具已就緒,輸入 debug.help() 查看指令')
2025-11-23 18:03:56 +00:00
2025-11-24 07:38:44 +00:00
console.log('[OK] 遊戲循環已啟動(靜默模式,只在事件觸發時輸出)')
2025-11-23 18:03:56 +00:00
}
// 停止遊戲循環
function stop() {
if (!isRunning.value) {
2025-11-24 07:38:44 +00:00
console.log('[WARN] 遊戲循環未運行')
2025-11-23 18:03:56 +00:00
return
}
petSystem.stopTickLoop()
eventSystem.stopEventCheck()
isRunning.value = false
2025-11-24 07:38:44 +00:00
console.log('[STOP] 遊戲循環已停止')
2025-11-23 18:03:56 +00:00
}
// 餵食
async function feed(amount = 20) {
const result = await petSystem.feed(amount)
if (result.success) {
2025-11-24 07:38:44 +00:00
console.log(`[OK] 餵食 飢餓+${amount} 體重+${(amount * 0.5).toFixed(1)}g | STR+${result.strGain?.toFixed(2)}`)
2025-11-23 18:03:56 +00:00
showStatus()
} else {
2025-11-24 07:38:44 +00:00
console.log(`[ERR] ${result.message}`)
2025-11-23 18:03:56 +00:00
}
}
// 玩耍
async function play(amount = 15) {
const result = await petSystem.play(amount)
if (result.success) {
2025-11-24 07:38:44 +00:00
const baseAmount = amount
const actualGain = result.happinessGain
const bonusPercent = actualGain > baseAmount ? `+${((actualGain / baseAmount - 1) * 100).toFixed(0)}%` : ''
console.log(`[OK] 玩耍 快樂 ${actualGain.toFixed(1)} ${bonusPercent} | DEX+${result.dexGain.toFixed(2)} INT+${result.intGain.toFixed(2)}`)
2025-11-23 18:03:56 +00:00
showStatus()
} else {
2025-11-24 07:38:44 +00:00
console.log(`[ERR] ${result.message}`)
2025-11-23 18:03:56 +00:00
}
}
// 清理便便
async function clean() {
const result = await petSystem.cleanPoop()
if (result.success) {
2025-11-24 07:38:44 +00:00
console.log('[OK] 清理便便 +10 快樂')
2025-11-23 18:03:56 +00:00
showStatus()
} else {
2025-11-24 07:38:44 +00:00
console.log(`[ERR] ${result.message}`)
2025-11-23 18:03:56 +00:00
}
}
// 治療
async function heal(amount = 20) {
const result = await petSystem.heal(amount)
if (result.success) {
2025-11-24 07:38:44 +00:00
const actualHeal = result.healAmount?.toFixed(1) || amount
const bonusText = result.healAmount > amount ? ` (+${((result.healAmount / amount - 1) * 100).toFixed(0)}%)` : ''
console.log(`[OK] 治療 健康+${actualHeal}${bonusText}${result.cured ? ' (已治癒)' : ''}`)
2025-11-23 18:03:56 +00:00
showStatus()
} else {
2025-11-24 07:38:44 +00:00
console.log(`[ERR] ${result.message}`)
2025-11-23 18:03:56 +00:00
}
}
// 睡覺/起床
async function sleep() {
const result = await petSystem.toggleSleep()
if (result.success) {
2025-11-24 07:38:44 +00:00
if (result.message) {
console.log(`[OK] ${result.message}`)
} else {
console.log(`[OK] ${result.isSleeping ? '已入睡' : '已醒來'}`)
}
2025-11-23 18:03:56 +00:00
showStatus()
} else {
2025-11-24 07:38:44 +00:00
console.log(`[ERR] ${result.message}`)
2025-11-23 18:03:56 +00:00
}
}
// 觸發事件
async function triggerEvent(eventId) {
const result = await eventSystem.triggerEvent(eventId)
if (result) {
2025-11-24 07:38:44 +00:00
console.log(`[OK] 事件 ${eventId} 觸發`)
2025-11-23 18:03:56 +00:00
showStatus()
} else {
2025-11-24 07:38:44 +00:00
console.log(`[ERR] 事件 ${eventId} 條件不滿足`)
2025-11-23 18:03:56 +00:00
}
}
// 查看事件列表
async function listEvents() {
const events = await apiService.getEvents()
2025-11-24 07:38:44 +00:00
console.log('\n[LIST] 可用事件列表 (共 ' + events.length + ' 個):')
console.log('='.repeat(60))
// 按類型分組
const grouped = {
good: events.filter(e => e.type === 'good'),
bad: events.filter(e => e.type === 'bad'),
weird: events.filter(e => e.type === 'weird'),
rare: events.filter(e => e.type === 'rare')
}
for (const [type, list] of Object.entries(grouped)) {
if (list.length === 0) continue
const typeEmoji = {
good: '*',
bad: '💀',
weird: '👻',
rare: '🌟'
}
console.log(`\n${typeEmoji[type]} ${type.toUpperCase()} 事件 (${list.length}個):`)
list.forEach(e => {
const effectsDesc = e.effects.map(eff => {
if (eff.type === 'modifyStats') {
const stats = Object.entries(eff.payload)
.map(([k, v]) => `${k}${v > 0 ? '+' : ''}${v}`)
.join(', ')
return stats
}
return eff.type
}).join(' | ')
console.log(` ${e.id}`)
console.log(` 效果: ${effectsDesc}`)
console.log(` 測試: triggerEvent('${e.id}')`)
})
}
console.log('\n' + '='.repeat(60))
console.log('[TIP] 快速測試所有事件: testAllEvents()')
console.log('='.repeat(60) + '\n')
2025-11-23 18:03:56 +00:00
}
// 查看事件歷史
function eventHistory() {
const history = eventSystem.getHistory()
2025-11-24 07:38:44 +00:00
console.log('\n[HISTORY] 事件歷史:')
2025-11-23 18:03:56 +00:00
console.log('='.repeat(50))
if (history.length === 0) {
console.log(' (無)')
} else {
history.forEach((h, i) => {
const time = new Date(h.timestamp).toLocaleTimeString()
console.log(`${i + 1}. [${time}] ${h.eventId} (${h.eventType})`)
})
}
console.log('='.repeat(50) + '\n')
}
// 祈福
async function pray() {
const result = await templeSystem.pray()
if (result.success) {
2025-11-24 07:38:44 +00:00
let message = `[OK] 祈福 +${result.favorIncrease} 好感 → ${result.newFavor}/100 | ${result.dialogue}`
// 等级提升提示
if (result.levelUp) {
message += `\n🌟 好感度等級提升Lv.${result.oldLevel} → Lv.${result.newLevel}`
if (result.deity.favorLevelBuffs) {
const buffs = Object.entries(result.deity.favorLevelBuffs.buffsPerLevel)
.map(([key, value]) => `${key.toUpperCase()}+${value}`)
.join(', ')
message += ` (${buffs})`
}
}
// 滿級特殊 Buff 提示
if (result.reachedMax && result.deity.maxFavorBuff) {
message += `\n** 滿級祝福!獲得特殊 Buff: ${result.deity.maxFavorBuff.name}`
message += `\n ${result.deity.maxFavorBuff.description}`
}
console.log(message)
2025-11-23 18:03:56 +00:00
showStatus()
} else {
2025-11-24 07:38:44 +00:00
console.log(`[ERR] ${result.message}`)
2025-11-23 18:03:56 +00:00
}
}
// 抽籤
async function drawFortune() {
const result = await templeSystem.drawFortune()
if (result.success) {
2025-11-24 07:38:44 +00:00
console.log('\n[DRAW] 抽籤結果:')
2025-11-23 18:03:56 +00:00
console.log('='.repeat(50))
console.log(`等級: ${result.lot.grade}`)
console.log(`籤詩: ${result.lot.poem1}`)
console.log(` ${result.lot.poem2}`)
console.log(`解釋: ${result.lot.meaning}`)
if (result.buff) {
2025-11-24 07:38:44 +00:00
console.log(`\n* 獲得 Buff: ${result.buff.name}`)
2025-11-23 18:03:56 +00:00
}
console.log('='.repeat(50) + '\n')
} else {
2025-11-24 07:38:44 +00:00
console.log(`[ERR] ${result.message}`)
2025-11-23 18:03:56 +00:00
}
}
// 切換神明
async function switchDeity(deityId) {
const result = await templeSystem.switchDeity(deityId)
if (result.success) {
2025-11-24 07:38:44 +00:00
console.log(`[OK] 已切換到 ${result.deity.name}`)
2025-11-23 18:03:56 +00:00
} else {
2025-11-24 07:38:44 +00:00
console.log(`[ERR] ${result.message}`)
}
showStatus()
}
// 擲筊
async function handleThrowJiaobei() {
const result = await templeSystem.throwJiaobei()
if (result.success) {
const resultSymbols = {
holy: '⚪⚫', // 一正一反 - 聖筊
laughing: '⚪⚪', // 兩個正面 - 笑筊
negative: '⚫⚫' // 兩個反面 - 陰筊
}
const resultNames = {
holy: '聖筊',
laughing: '笑筊',
negative: '陰筊'
}
console.log('\n[JIAOBEI] 擲筊結果:')
console.log('='.repeat(50))
console.log(`神明: ${result.deity}`)
console.log(`結果: ${resultSymbols[result.result]} ${resultNames[result.result]}`)
console.log(`訊息: ${result.message}`)
console.log(`\n概率:`)
console.log(` 聖筊: ${(result.probabilities.holy * 100).toFixed(1)}%`)
console.log(` 笑筊: ${(result.probabilities.laughing * 100).toFixed(1)}%`)
console.log(` 陰筊: ${(result.probabilities.negative * 100).toFixed(1)}%`)
console.log('='.repeat(50) + '\n')
2025-11-23 18:03:56 +00:00
}
2025-11-24 07:38:44 +00:00
2025-11-23 18:03:56 +00:00
showStatus()
}
// 查看神明列表
function listDeities() {
const deities = templeSystem.getDeities()
2025-11-24 07:38:44 +00:00
console.log('\n[PRAY] 神明列表:')
2025-11-23 18:03:56 +00:00
console.log('='.repeat(50))
deities.forEach(d => {
const state = petSystem.getState()
const favor = state.deityFavors[d.id] || 0
const stars = templeSystem.getFavorStars(d.id)
console.log(`\n${d.id}: ${d.name}`)
console.log(` 個性: ${d.personality}`)
console.log(` 好感: ${stars} (${favor}/100)`)
console.log(` 加成: ${d.buffDescriptions.join(', ')}`)
})
console.log('='.repeat(50) + '\n')
}
// 應用 Buff
async function applyBuffs() {
await eventSystem.applyBuffs()
eventSystem.getBuffManager().tick()
2025-11-24 07:38:44 +00:00
console.log('[OK] Buff 已更新')
2025-11-23 18:03:56 +00:00
showStatus()
}
// 確認名字並初始化
async function confirmName() {
if (!inputPetName.value || inputPetName.value.trim().length === 0) {
return
}
showNameInput.value = false
const name = inputPetName.value.trim()
await init(name)
}
// 初始化系統
async function init(petName = null) {
petSystem = new PetSystem(apiService)
eventSystem = new EventSystem(petSystem, apiService)
templeSystem = new TempleSystem(petSystem, apiService)
try {
await petSystem.initialize('tinyTigerCat')
// 如果有提供名字,更新寵物名字
if (petName) {
await petSystem.updateState({ name: petName })
}
await eventSystem.initialize()
await templeSystem.initialize()
updatePetState()
isReady.value = true
2025-11-24 07:38:44 +00:00
systemStatus.value = '[OK] 系統已就緒'
console.log('[OK] 系統已初始化')
console.log('[SWITCH] 自動啟動遊戲循環...')
// 自動啟動遊戲循環
start()
2025-11-23 18:03:56 +00:00
showStatus()
} catch (error) {
// 如果沒有名字,顯示輸入對話框
if (error.message && error.message.includes('名字')) {
showNameInput.value = true
systemStatus.value = '請為寵物命名'
} else {
2025-11-24 07:38:44 +00:00
systemStatus.value = '[ERR] 初始化失敗: ' + error.message
2025-11-23 18:03:56 +00:00
console.error(error)
}
}
return { petSystem, eventSystem, templeSystem }
}
// 按鈕處理函數
async function handleFeed() {
await feed(20)
updatePetState()
}
2025-11-24 07:38:44 +00:00
async function handlePlay(gameType = 'normal') {
const result = await play({ amount: 15, gameType })
if (result && result.success) {
console.log(`${result.gameType} 體重變化: ${result.weightChange > 0 ? '+' : ''}${result.weightChange}g`)
}
2025-11-23 18:03:56 +00:00
updatePetState()
}
async function handleClean() {
await clean()
updatePetState()
}
async function handleHeal() {
await heal(20)
updatePetState()
}
async function handleSleep() {
await sleep()
updatePetState()
}
function handleShowStatus() {
showStatus()
}
2025-11-24 07:38:44 +00:00
function handleCheckEvolution() {
if (window.checkEvolution) {
window.checkEvolution()
}
}
function handleTestAllEvents() {
if (window.testAllEvents) {
window.testAllEvents()
}
}
2025-11-23 18:03:56 +00:00
function handleStart() {
start()
}
function handleStop() {
stop()
}
async function handleListEvents() {
await listEvents()
}
function handleEventHistory() {
eventHistory()
}
async function handleTriggerEvent(eventId) {
await triggerEvent(eventId)
updatePetState()
}
async function handlePray() {
await pray()
updatePetState()
}
async function handleDrawFortune() {
await drawFortune()
}
function handleListDeities() {
listDeities()
}
async function handleSwitchDeity(deityId) {
await switchDeity(deityId)
updatePetState()
}
// 刪除寵物
async function handleDeletePet() {
if (!confirm('確定要刪除當前寵物嗎?此操作無法復原!')) {
return
}
try {
// 停止遊戲循環
if (isRunning.value) {
stop()
}
// 刪除寵物
const result = await petSystem.deletePet()
if (result.success) {
2025-11-24 07:38:44 +00:00
console.log('[OK] ' + result.message)
2025-11-23 18:03:56 +00:00
// 重置所有狀態
petState.value = null
isReady.value = false
isRunning.value = false
systemStatus.value = '寵物已刪除,請重新建立'
// 清除事件系統歷史
if (eventSystem) {
eventSystem.eventHistory = []
eventSystem.getBuffManager().buffs = []
}
// 顯示名字輸入對話框
inputPetName.value = ''
showNameInput.value = true
} else {
2025-11-24 07:38:44 +00:00
console.log('[ERR] 刪除失敗')
2025-11-23 18:03:56 +00:00
}
} catch (error) {
console.error('刪除寵物時發生錯誤:', error)
alert('刪除寵物時發生錯誤,請重試')
}
}
// 幫助
function help() {
console.log('\n' + '='.repeat(50))
console.log('📖 可用命令列表')
console.log('='.repeat(50))
2025-11-24 07:38:44 +00:00
console.log('\n[PLAY] 遊戲控制:')
2025-11-23 18:03:56 +00:00
console.log(' start() - 啟動遊戲循環')
console.log(' stop() - 停止遊戲循環')
console.log(' showStatus() - 顯示當前狀態')
2025-11-24 07:38:44 +00:00
console.log('\n 寵物互動:')
2025-11-23 18:03:56 +00:00
console.log(' feed(amount) - 餵食(預設 +20')
console.log(' play(amount) - 玩耍(預設 +15')
console.log(' clean() - 清理便便')
console.log(' heal(amount) - 治療(預設 +20')
console.log(' sleep() - 睡覺/起床')
2025-11-24 07:38:44 +00:00
console.log('\n[ROLL] 事件系統:')
2025-11-23 18:03:56 +00:00
console.log(' triggerEvent(id) - 手動觸發事件')
console.log(' listEvents() - 查看所有事件')
console.log(' eventHistory() - 查看事件歷史')
console.log(' applyBuffs() - 手動應用 Buff')
2025-11-24 07:38:44 +00:00
console.log('\n[PRAY] 神明系統:')
2025-11-23 18:03:56 +00:00
console.log(' pray() - 祈福(每日 3 次)')
console.log(' drawFortune() - 抽籤')
console.log(' switchDeity(id) - 切換神明')
console.log(' listDeities() - 查看神明列表')
2025-11-24 07:38:44 +00:00
console.log('\n[TIP] 提示:')
2025-11-23 18:03:56 +00:00
console.log(' - 所有數值操作都會同步到 APImock 模式使用 localStorage')
console.log(' - 事件每 10 秒自動檢查10% 機率觸發)')
console.log(' - 遊戲循環每 3 秒執行一次 tick')
console.log(' - 輸入 help() 再次查看此列表')
console.log('='.repeat(50) + '\n')
}
2025-11-24 07:38:44 +00:00
// 測試加成系統
function testBonuses() {
if (!petSystem || !petState.value) {
console.log('[ERR] 系統尚未初始化')
return
}
console.log('\n' + '='.repeat(60))
console.log('[CHECK] 加成系統測試報告')
console.log('='.repeat(60))
const state = petSystem.getState()
// 1. 命格信息
console.log('\n[HISTORY] 命格信息:')
if (state.destiny) {
console.log(` 名稱: ${state.destiny.name}`)
console.log(` 描述: ${state.destiny.description}`)
console.log(` 加成:`, state.destiny.buffs)
} else {
console.log(' [ERR] 未分配命格')
}
// 1.5 神明信息
console.log('\n[PRAY] 當前神明:')
if (templeSystem) {
const deity = templeSystem.getCurrentDeity()
if (deity) {
console.log(` 名稱: ${deity.name}`)
console.log(` 加成:`, deity.buffs)
}
}
// 2. 所有加成(合計)
const bonuses = petSystem.getAllBonuses()
console.log('\n💫 總加成(命格+神明):')
if (Object.keys(bonuses).length === 0) {
console.log(' 無')
} else {
for (const [key, value] of Object.entries(bonuses)) {
const sign = value > 0 ? '+' : ''
const percent = (value * 100).toFixed(0)
console.log(` ${key}: ${sign}${percent}%`)
}
}
// 3. 當前屬性
console.log('\n[STATUS] 當前屬性:')
console.log(` STR: ${state.str.toFixed(1)} | INT: ${state.int.toFixed(1)} | DEX: ${state.dex.toFixed(1)}`)
console.log(` 攻擊: ${state.attack?.toFixed(1)} | 防禦: ${state.defense?.toFixed(1)} | 速度: ${state.speed?.toFixed(1)}`)
// 4. 計算示例
console.log('\n[TEST] 計算示例:')
const strGainBase = 0.5
const strGainWithBonus = strGainBase * (1 + (bonuses.strGain || 0))
console.log(` 餵食時 STR 增長: ${strGainBase}${strGainWithBonus.toFixed(2)} (${bonuses.strGain ? '+' + (bonuses.strGain * 100).toFixed(0) + '%' : '無加成'})`)
const intGainBase = 0.2
const intGainWithBonus = intGainBase * (1 + (bonuses.intGain || 0))
console.log(` 玩耍時 INT 增長: ${intGainBase}${intGainWithBonus.toFixed(2)} (${bonuses.intGain ? '+' + (bonuses.intGain * 100).toFixed(0) + '%' : '無加成'})`)
const happinessGainBase = 15
const happinessGainWithBonus = happinessGainBase * (1 + (bonuses.happinessRecovery || 0))
console.log(` 玩耍時快樂恢復: ${happinessGainBase}${happinessGainWithBonus.toFixed(1)} (${bonuses.happinessRecovery ? '+' + (bonuses.happinessRecovery * 100).toFixed(0) + '%' : '無加成'})`)
console.log('\n' + '='.repeat(60))
console.log('[TIP] 提示: 執行 feed() 或 play() 來驗證實際效果')
}
2025-11-23 18:03:56 +00:00
// 掛載到 window
2025-11-24 07:38:44 +00:00
// Debug UI 狀態
const showDebug = ref(false)
// Debug 方法
const debugResetPrayer = async () => {
await window.debug.resetPrayer()
}
const debugAddFavor = async (amount) => {
const state = petSystem.getState()
const currentFavor = state.deityFavors?.[state.currentDeityId] || 0
await window.debug.setFavor(state.currentDeityId, Math.min(100, currentFavor + amount))
}
const debugTriggerEvent = async () => {
await window.debug.triggerEvent()
}
const debugFillStats = async () => {
await window.debug.setStat('hunger', 100)
await window.debug.setStat('happiness', 100)
}
const debugMaxAttributes = async () => {
await window.debug.setStat('str', 100)
await window.debug.setStat('int', 100)
await window.debug.setStat('dex', 100)
}
const debugKill = async () => {
await window.debug.setStat('health', 0)
}
const debugAddPoop = async () => {
await window.debug.setStat('poopCount', 4)
}
// 處理鍵盤輸入(可選)
const handleKeydown = (e) => {
// Ctrl + Shift + D 開關 Debug 面板
if (e.ctrlKey && e.shiftKey && e.key === 'D') {
showDebug.value = !showDebug.value
}
}
2025-11-23 18:03:56 +00:00
onMounted(async () => {
2025-11-24 07:38:44 +00:00
window.addEventListener('keydown', handleKeydown)
2025-11-23 18:03:56 +00:00
// 檢查是否已有寵物
try {
const existingState = localStorage.getItem('petState')
if (existingState) {
// 已有寵物,直接初始化
systemStatus.value = '正在載入寵物...'
await init()
} else {
// 新寵物,顯示名字輸入
systemStatus.value = '歡迎!請為你的寵物命名'
showNameInput.value = true
}
// 將所有函數掛載到 window
window.petSystem = petSystem
window.eventSystem = eventSystem
window.templeSystem = templeSystem
window.showStatus = showStatus
window.start = start
window.stop = stop
window.feed = feed
window.play = play
window.clean = clean
window.heal = heal
window.sleep = sleep
window.triggerEvent = triggerEvent
window.listEvents = listEvents
window.eventHistory = eventHistory
window.pray = pray
window.drawFortune = drawFortune
window.switchDeity = switchDeity
window.listDeities = listDeities
window.applyBuffs = applyBuffs
window.help = help
window.init = init
2025-11-24 07:38:44 +00:00
window.testBonuses = testBonuses
// 事件測試函數
window.testEvent = async (eventId) => {
const events = await apiService.getEvents()
const event = events.find(e => e.id === eventId)
if (!event) {
console.log(`[ERR] 找不到事件: ${eventId}`)
return
}
console.log(`\n[TEST] 測試: ${event.id} (${event.type})`)
showStatus()
await triggerEvent(eventId)
await new Promise(r => setTimeout(r, 100))
showStatus()
}
window.testAllEvents = async () => {
const events = await apiService.getEvents()
console.log(`\n[TEST] 測試 ${events.length} 個事件...\n`)
for (const e of events) {
console.log(`[START] ${e.id}`)
await triggerEvent(e.id)
await new Promise(r => setTimeout(r, 50))
}
console.log('\n[OK] 完成')
showStatus()
}
// 檢查進化狀態
window.checkEvolution = () => {
const state = petSystem.getState()
const species = petSystem.speciesConfig
console.log('\n' + '='.repeat(60))
console.log('[CHECK] 進化系統檢查')
console.log('='.repeat(60))
console.log(`\n當前階段: ${state.stage}`)
console.log(`年齡: ${state.ageSeconds.toFixed(1)}`)
console.log(`屬性: STR ${state.str.toFixed(1)} | INT ${state.int.toFixed(1)} | DEX ${state.dex.toFixed(1)}`)
// 找到當前階段
const currentIdx = species.lifecycle.findIndex(s => s.stage === state.stage)
if (currentIdx < 0) {
console.log('\n[ERR] 找不到當前階段配置')
return
}
const currentStage = species.lifecycle[currentIdx]
if (currentIdx < species.lifecycle.length - 1) {
const nextStage = species.lifecycle[currentIdx + 1]
console.log(`\n下一階段: ${nextStage.stage}`)
// 檢查當前階段是否已達到結束時間
const timeRequirement = currentStage.durationSeconds
const timeMet = state.ageSeconds >= timeRequirement
if (timeRequirement === Infinity) {
console.log(`年齡條件: 已達到最終階段,無需再進化`)
} else {
console.log(`年齡條件: ${state.ageSeconds.toFixed(1)}/${timeRequirement}${timeMet ? '[OK]' : '[ERR]'}`)
}
// 檢查屬性條件
if (nextStage.conditions && Object.keys(nextStage.conditions).length > 0) {
console.log('屬性條件:')
if (nextStage.conditions.str) {
const met = state.str >= nextStage.conditions.str
console.log(` STR: ${state.str.toFixed(1)}/${nextStage.conditions.str} ${met ? '[OK]' : '[ERR]'}`)
}
if (nextStage.conditions.int) {
const met = state.int >= nextStage.conditions.int
console.log(` INT: ${state.int.toFixed(1)}/${nextStage.conditions.int} ${met ? '[OK]' : '[ERR]'}`)
}
if (nextStage.conditions.dex) {
const met = state.dex >= nextStage.conditions.dex
console.log(` DEX: ${state.dex.toFixed(1)}/${nextStage.conditions.dex} ${met ? '[OK]' : '[ERR]'}`)
}
} else {
console.log('屬性條件: 無')
}
// 顯示進化建議
if (timeMet && nextStage.conditions) {
const allStatsMet = Object.entries(nextStage.conditions).every(([key, value]) => state[key] >= value)
if (allStatsMet) {
console.log('\n* 條件已滿足!應該會自動進化')
} else {
console.log('\n[TIP] 提示: 年齡已足夠,再提升屬性即可進化')
}
} else if (!timeMet) {
const remaining = timeRequirement - state.ageSeconds
console.log(`\n[WAIT] 還需等待 ${remaining.toFixed(1)}`)
}
} else {
console.log('\n[DONE] 已達到最終階段')
}
console.log('='.repeat(60) + '\n')
}
2025-11-23 18:03:56 +00:00
} catch (error) {
2025-11-24 07:38:44 +00:00
systemStatus.value = '[ERR] 初始化失敗: ' + error.message
2025-11-23 18:03:56 +00:00
console.error(error)
}
})
onUnmounted(() => {
if (isRunning.value) {
stop()
}
})
</script>
<style scoped>
2025-11-24 07:38:44 +00:00
/* 像素字体 - Zpix 支持繁体中文 */
@import url('https://cdn.jsdelivr.net/npm/zpix-pixel-font@latest/dist/Zpix.css');
* {
font-family: 'Zpix', 'Noto Sans TC', monospace;
image-rendering: pixelated;
}
2025-11-23 18:03:56 +00:00
.pet-system-container {
min-height: 100vh;
2025-11-24 07:38:44 +00:00
background: #0a0a0a;
color: #00ff00;
padding: 15px;
2025-11-23 18:03:56 +00:00
}
.header {
text-align: center;
2025-11-24 07:38:44 +00:00
margin-bottom: 20px;
border: 3px solid #00ff00;
padding: 15px;
background: #000;
box-shadow: 0 0 15px #00ff00;
2025-11-23 18:03:56 +00:00
}
.header h1 {
2025-11-24 07:38:44 +00:00
color: #00ffff;
font-size: 18px;
margin: 0 0 10px 0;
text-shadow: 2px 2px 0 #000, 0 0 10px #00ffff;
2025-11-23 18:03:56 +00:00
}
.subtitle {
2025-11-24 07:38:44 +00:00
color: #00aa00;
font-size: 10px;
2025-11-23 18:03:56 +00:00
}
/* 寵物狀態顯示 */
.pet-status {
2025-11-24 07:38:44 +00:00
background: #000;
padding: 15px;
margin-bottom: 15px;
border: 3px solid #00ff00;
box-shadow: inset 0 0 20px rgba(0, 255, 0, 0.1);
2025-11-23 18:03:56 +00:00
}
.status-section {
2025-11-24 07:38:44 +00:00
margin-bottom: 20px;
2025-11-23 18:03:56 +00:00
}
.status-section h3 {
2025-11-24 07:38:44 +00:00
color: #00ffff;
margin-bottom: 10px;
font-size: 14px;
2025-11-23 18:03:56 +00:00
text-align: center;
2025-11-24 07:38:44 +00:00
padding-bottom: 8px;
border-bottom: 2px solid #00ff00;
text-shadow: 0 0 5px #00ffff;
2025-11-23 18:03:56 +00:00
}
.status-grid {
display: grid;
2025-11-24 07:38:44 +00:00
gap: 10px;
margin-bottom: 10px;
2025-11-23 18:03:56 +00:00
}
.stat-item {
display: flex;
align-items: center;
gap: 10px;
}
.stat-label {
2025-11-24 07:38:44 +00:00
min-width: 50px;
color: #00aa00;
2025-11-23 18:03:56 +00:00
font-weight: bold;
2025-11-24 07:38:44 +00:00
font-size: 10px;
2025-11-23 18:03:56 +00:00
}
.stat-bar {
flex: 1;
2025-11-24 07:38:44 +00:00
height: 12px;
background: #000;
border: 2px solid #00ff00;
2025-11-23 18:03:56 +00:00
position: relative;
overflow: hidden;
}
.stat-fill {
height: 100%;
2025-11-24 07:38:44 +00:00
background: #00ff00;
2025-11-23 18:03:56 +00:00
transition: width 0.3s ease;
2025-11-24 07:38:44 +00:00
box-shadow: 0 0 10px #00ff00;
2025-11-23 18:03:56 +00:00
}
.stat-value {
2025-11-24 07:38:44 +00:00
min-width: 40px;
text-align: right;
color: #ffffff;
font-size: 10px;
2025-11-23 18:03:56 +00:00
font-weight: bold;
}
2025-11-24 07:38:44 +00:00
.pet-info-grid,
.bonus-grid {
2025-11-23 18:03:56 +00:00
display: grid;
2025-11-24 07:38:44 +00:00
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 8px;
margin-bottom: 10px;
2025-11-23 18:03:56 +00:00
}
2025-11-24 07:38:44 +00:00
.info-item,
.bonus-item {
2025-11-23 18:03:56 +00:00
display: flex;
justify-content: space-between;
2025-11-24 07:38:44 +00:00
padding: 5px 8px;
background: #001100;
border: 1px solid #00ff00;
transition: all 0.2s;
2025-11-23 18:03:56 +00:00
}
2025-11-24 07:38:44 +00:00
.info-item:hover,
.bonus-item:hover {
background: #002200;
box-shadow: 0 0 5px #00ff00;
2025-11-23 18:03:56 +00:00
}
2025-11-24 07:38:44 +00:00
.info-label,
.bonus-label {
color: #00aa00;
font-size: 10px;
}
.info-value,
.bonus-value {
color: #ffffff;
font-size: 10px;
2025-11-23 18:03:56 +00:00
font-weight: bold;
2025-11-24 07:38:44 +00:00
}
.bonus-value.positive {
color: #00ff00;
}
.bonus-value.negative {
color: #ff0000;
}
.bonus-item.not-implemented {
opacity: 0.6;
border-color: #ff0000;
background: #110000;
box-shadow: inset 0 0 10px rgba(255, 0, 0, 0.1);
}
.bonus-item.not-implemented .bonus-label {
color: #ff0000;
text-decoration: line-through;
}
.bonus-item.not-implemented .bonus-value {
color: #ff0000 !important;
2025-11-23 18:03:56 +00:00
}
.status-badges {
display: flex;
2025-11-24 07:38:44 +00:00
gap: 8px;
2025-11-23 18:03:56 +00:00
flex-wrap: wrap;
2025-11-24 07:38:44 +00:00
margin-top: 10px;
2025-11-23 18:03:56 +00:00
}
.badge {
2025-11-24 07:38:44 +00:00
background: #000;
border: 2px solid #ffff00;
color: #ffff00;
padding: 4px 8px;
font-size: 10px;
animation: blink 1s infinite;
2025-11-23 18:03:56 +00:00
}
.badge.sick {
2025-11-24 07:38:44 +00:00
border-color: #ff0000;
color: #ff0000;
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0.5; }
2025-11-23 18:03:56 +00:00
}
/* 操作按鈕區 */
.action-panel {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 20px;
}
.action-group {
background: #252526;
padding: 20px;
border-radius: 8px;
border-left: 4px solid #4ec9b0;
}
.action-group h3 {
color: #4ec9b0;
margin-bottom: 15px;
font-size: 1.1em;
}
.button-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
2025-11-24 07:38:44 +00:00
gap: 8px;
2025-11-23 18:03:56 +00:00
}
button {
2025-11-24 07:38:44 +00:00
background: #000;
border: 2px solid #00ff00;
color: #00ff00;
padding: 10px;
2025-11-23 18:03:56 +00:00
cursor: pointer;
2025-11-24 07:38:44 +00:00
transition: all 0.1s;
font-size: 12px;
2025-11-23 18:03:56 +00:00
}
button:hover:not(:disabled) {
2025-11-24 07:38:44 +00:00
background: #00ff00;
color: #000;
box-shadow: 0 0 10px #00ff00;
2025-11-23 18:03:56 +00:00
}
button:active:not(:disabled) {
2025-11-24 07:38:44 +00:00
transform: translate(2px, 2px);
2025-11-23 18:03:56 +00:00
}
button:disabled {
2025-11-24 07:38:44 +00:00
border-color: #003300;
color: #003300;
2025-11-23 18:03:56 +00:00
cursor: not-allowed;
2025-11-24 07:38:44 +00:00
opacity: 0.5;
2025-11-23 18:03:56 +00:00
}
.danger-button {
background: #d32f2f !important;
}
.danger-button:hover:not(:disabled) {
background: #f44336 !important;
}
.console-output {
2025-11-24 07:38:44 +00:00
background: #000;
border: 3px solid #00ff00;
padding: 10px;
min-height: 200px;
max-height: 400px;
2025-11-23 18:03:56 +00:00
overflow-y: auto;
2025-11-24 07:38:44 +00:00
font-size: 10px;
box-shadow: inset 0 0 20px rgba(0, 255, 0, 0.1);
2025-11-23 18:03:56 +00:00
}
.log-entry {
2025-11-24 07:38:44 +00:00
margin: 3px 0;
padding: 3px;
border-left: 2px solid #00ff00;
padding-left: 8px;
color: #00ff00;
2025-11-23 18:03:56 +00:00
}
2025-11-24 07:38:44 +00:00
/* Debug 面板樣式 */
.debug-toggle {
position: fixed;
top: 10px;
right: 10px;
background: #000;
border: 2px solid #ff00ff;
color: #ff00ff;
padding: 5px 10px;
cursor: pointer;
font-size: 10px;
z-index: 100;
box-shadow: 0 0 10px #ff00ff;
}
.debug-toggle:hover {
background: #ff00ff;
color: #000;
}
.debug-panel {
position: fixed;
top: 50px;
right: 10px;
background: #000;
border: 3px solid #ff00ff;
padding: 15px;
max-width: 250px;
z-index: 99;
box-shadow: 0 0 20px #ff00ff;
}
.debug-panel h3 {
color: #ff00ff;
margin-bottom: 10px;
font-size: 12px;
text-shadow: 0 0 5px #ff00ff;
}
.debug-group {
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #330033;
}
.debug-group:last-child {
border-bottom: none;
}
.debug-group h4 {
color: #ff00ff;
margin-bottom: 5px;
font-size: 10px;
}
.debug-panel button {
width: 100%;
margin-bottom: 5px;
border-color: #ff00ff;
color: #ff00ff;
font-size: 9px;
}
.debug-panel button:hover:not(:disabled) {
background: #ff00ff;
2025-11-23 18:03:56 +00:00
}
.name-input-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
2025-11-24 07:38:44 +00:00
background: rgba(0, 0, 0, 0.95);
2025-11-23 18:03:56 +00:00
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
2025-11-24 07:38:44 +00:00
background: #000;
border: 3px solid #00ffff;
padding: 20px;
min-width: 300px;
box-shadow: 0 0 30px #00ffff;
}
.modal-content h2 {
color: #00ffff;
font-size: 14px;
margin-bottom: 10px;
text-shadow: 0 0 10px #00ffff;
text-align: center;
}
.modal-content p {
color: #00aa00;
font-size: 10px;
margin-bottom: 15px;
text-align: center;
}
.name-input {
width: 100%;
background: #000;
border: 2px solid #00ff00;
color: #00ff00;
padding: 10px;
font-size: 12px;
margin-bottom: 15px;
box-sizing: border-box;
}
.name-input:focus {
outline: none;
border-color: #00ffff;
box-shadow: 0 0 10px #00ffff;
}
.modal-buttons {
display: flex;
justify-content: center;
}
.modal-buttons button {
min-width: 100px;
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 12px;
height: 12px;
}
::-webkit-scrollbar-track {
background: #000;
border: 1px solid #00ff00;
}
::-webkit-scrollbar-thumb {
background: #00ff00;
border: 2px solid #000;
}
::-webkit-scrollbar-thumb:hover {
background: #00ffff;
box-shadow: 0 0 5px #00ffff;
}
/* 其他修正 */
.info-value-group {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.info-value.highlight {
color: #00ffff;
text-shadow: 0 0 5px #00ffff;
}
.info-sub {
color: #00aa00;
font-size: 8px;
margin-top: 2px;
}
button.active {
background: #00ff00;
color: #000;
box-shadow: 0 0 10px #00ff00;
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 12px;
height: 12px;
}
::-webkit-scrollbar-track {
background: #000;
border: 1px solid #00ff00;
}
::-webkit-scrollbar-thumb {
background: #00ff00;
border: 2px solid #000;
}
::-webkit-scrollbar-thumb:hover {
background: #00ffff;
box-shadow: 0 0 5px #00ffff;
}
/* 其他修正 */
.info-value-group {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.info-value.highlight {
color: #00ffff;
text-shadow: 0 0 5px #00ffff;
}
.info-sub {
color: #00aa00;
font-size: 8px;
margin-top: 2px;
}
.modal-content {
2025-11-23 18:03:56 +00:00
padding: 30px;
border-radius: 12px;
border: 2px solid #4ec9b0;
min-width: 400px;
max-width: 90%;
}
.modal-content h2 {
color: #4ec9b0;
margin-bottom: 10px;
text-align: center;
}
.modal-content p {
color: #d4d4d4;
margin-bottom: 20px;
text-align: center;
}
.name-input {
width: 100%;
padding: 12px;
background: #1e1e1e;
border: 2px solid #3c3c3c;
border-radius: 6px;
color: #d4d4d4;
font-size: 1.1em;
margin-bottom: 20px;
text-align: center;
}
.name-input:focus {
outline: none;
border-color: #4ec9b0;
}
.modal-buttons {
display: flex;
justify-content: center;
gap: 10px;
}
.modal-buttons button {
background: #007acc;
color: #fff;
border: none;
padding: 12px 24px;
border-radius: 6px;
cursor: pointer;
font-size: 1em;
font-weight: 500;
}
.modal-buttons button:hover:not(:disabled) {
background: #0098ff;
}
.modal-buttons button:disabled {
background: #3c3c3c;
color: #858585;
cursor: not-allowed;
opacity: 0.6;
}
@media (max-width: 768px) {
.action-panel {
grid-template-columns: 1fr;
}
.modal-content {
min-width: 90%;
padding: 20px;
}
}
2025-11-24 07:38:44 +00:00
/* 折疊面板樣式 */
details.event-list, details.deity-list {
margin-top: 10px;
border: 1px solid #3c3c3c;
border-radius: 4px;
padding: 10px;
}
details summary {
cursor: pointer;
user-select: none;
color: #4ec9b0;
font-weight: bold;
padding: 5px;
list-style-position: inside;
}
details summary:hover {
background: rgba(78, 201, 176, 0.1);
border-radius: 4px;
}
details[open] summary {
margin-bottom: 10px;
border-bottom: 1px solid #3c3c3c;
}
/* 小按鈕網格 */
.button-grid.small {
gap: 8px;
}
.button-grid.small button {
padding: 8px 12px;
font-size: 0.85em;
}
/* 激活狀態的按鈕 */
button.active {
background: #4ec9b0 !important;
color: #1e1e1e !important;
font-weight: bold;
border: 2px solid #6ee2c4;
}
button.active:hover {
background: #6ee2c4 !important;
}
2025-11-23 18:03:56 +00:00
</style>