216 lines
8.0 KiB
Vue
216 lines
8.0 KiB
Vue
|
|
<template>
|
||
|
|
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm" @click.self="$emit('close')">
|
||
|
|
<div class="relative w-full max-w-md bg-[#1b1026] border-4 border-[#4a3b5e] shadow-2xl p-4 m-4 max-h-[90vh] overflow-y-auto custom-scrollbar">
|
||
|
|
|
||
|
|
<!-- Close Button -->
|
||
|
|
<button
|
||
|
|
@click="$emit('close')"
|
||
|
|
class="absolute top-2 right-2 text-[#8f80a0] hover:text-white"
|
||
|
|
>
|
||
|
|
<X :size="24" />
|
||
|
|
</button>
|
||
|
|
|
||
|
|
<!-- Header -->
|
||
|
|
<div class="text-center mb-6">
|
||
|
|
<h2 class="text-2xl font-bold text-[#f6b26b] font-mono tracking-wider">守護神明</h2>
|
||
|
|
<div class="h-1 w-24 bg-[#f6b26b] mx-auto mt-2"></div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div v-if="currentDeity && currentStage" class="flex flex-col gap-6">
|
||
|
|
<!-- Deity Portrait & Info -->
|
||
|
|
<div class="flex flex-col items-center">
|
||
|
|
<div class="w-32 h-32 bg-[#0f0816] border-4 border-[#f6b26b] rounded-full flex items-center justify-center mb-4 relative overflow-hidden group">
|
||
|
|
<!-- Glow Effect -->
|
||
|
|
<div class="absolute inset-0 bg-[#f6b26b] opacity-10 animate-pulse"></div>
|
||
|
|
|
||
|
|
<!-- Icon Placeholder (Replace with actual image later) -->
|
||
|
|
<div class="text-6xl">{{ getDeityIcon(String(currentDeity.id)) }}</div>
|
||
|
|
|
||
|
|
<!-- Stage Badge -->
|
||
|
|
<div class="absolute bottom-0 bg-[#f6b26b] text-[#1b1026] text-xs font-bold px-3 py-1 rounded-full border-2 border-[#1b1026]">
|
||
|
|
Lv.{{ currentStage.level }}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<h3 class="text-xl font-bold text-[#e0d8f0]">{{ currentStage.name }}</h3>
|
||
|
|
<p class="text-[#f6b26b] text-sm font-mono mb-2">{{ currentStage.title }}</p>
|
||
|
|
<p class="text-[#8f80a0] text-xs text-center max-w-[80%]">{{ currentStage.description }}</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Evolution Progress -->
|
||
|
|
<div class="bg-[#0f0816] p-4 border-2 border-[#4a3b5e] rounded-lg">
|
||
|
|
<div class="flex justify-between items-center mb-2">
|
||
|
|
<span class="text-[#e0d8f0] text-sm font-bold">進化進度</span>
|
||
|
|
<span class="text-[#8f80a0] text-xs">{{ currentDeityState.exp }} / {{ nextStageExp }} EXP</span>
|
||
|
|
</div>
|
||
|
|
<div class="w-full h-4 bg-[#2b193f] rounded-full overflow-hidden border border-[#4a3b5e]">
|
||
|
|
<div
|
||
|
|
class="h-full bg-gradient-to-r from-[#f6b26b] to-[#d95763] transition-all duration-500"
|
||
|
|
:style="{ width: `${expPercentage}%` }"
|
||
|
|
></div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Evolve Button -->
|
||
|
|
<button
|
||
|
|
v-if="canEvolve"
|
||
|
|
@click="$emit('evolve')"
|
||
|
|
class="w-full mt-4 py-2 bg-[#f6b26b] text-[#1b1026] font-bold rounded hover:bg-[#ffe762] transition-colors animate-pulse"
|
||
|
|
>
|
||
|
|
✨ 立即進化 ✨
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Active Buffs -->
|
||
|
|
<div class="bg-[#0f0816] p-4 border-2 border-[#4a3b5e] rounded-lg">
|
||
|
|
<h4 class="text-[#2ce8f4] text-sm font-bold mb-3 border-b border-[#2ce8f4]/30 pb-1">神力加成</h4>
|
||
|
|
<div class="grid grid-cols-2 gap-2">
|
||
|
|
<div v-for="(value, key) in currentStage.buffs" :key="key" class="flex items-center gap-2 text-xs text-[#e0d8f0]">
|
||
|
|
<span class="w-1.5 h-1.5 bg-[#2ce8f4] rounded-full"></span>
|
||
|
|
{{ formatBuff(key, value) }}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Quests -->
|
||
|
|
<div class="bg-[#0f0816] p-4 border-2 border-[#4a3b5e] rounded-lg">
|
||
|
|
<h4 class="text-[#99e550] text-sm font-bold mb-3 border-b border-[#99e550]/30 pb-1">進化任務</h4>
|
||
|
|
<div class="space-y-3">
|
||
|
|
<div v-for="quest in currentDeity.quests" :key="quest.id" class="relative">
|
||
|
|
<div class="flex justify-between items-start mb-1">
|
||
|
|
<span class="text-[#e0d8f0] text-xs">{{ quest.description }}</span>
|
||
|
|
<span class="text-[#99e550] text-xs font-mono">
|
||
|
|
{{ getQuestProgress(quest.id) }} / {{ quest.target }}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div class="w-full h-1.5 bg-[#2b193f] rounded-full overflow-hidden">
|
||
|
|
<div
|
||
|
|
class="h-full bg-[#99e550]"
|
||
|
|
:style="{ width: `${Math.min(100, (getQuestProgress(quest.id) / quest.target) * 100)}%` }"
|
||
|
|
></div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Actions -->
|
||
|
|
<div class="grid grid-cols-2 gap-4">
|
||
|
|
<button
|
||
|
|
@click="$emit('divination')"
|
||
|
|
class="py-3 bg-[#2b193f] border-2 border-[#2ce8f4] text-[#2ce8f4] font-bold rounded hover:bg-[#3d2459] transition-colors flex items-center justify-center gap-2"
|
||
|
|
>
|
||
|
|
<Sparkles :size="18" />
|
||
|
|
{{ currentDeity.origin === 'western' ? '塔羅占卜' : '每日求籤' }}
|
||
|
|
</button>
|
||
|
|
|
||
|
|
<button
|
||
|
|
@click="$emit('switch')"
|
||
|
|
class="py-3 bg-[#2b193f] border-2 border-[#8f80a0] text-[#8f80a0] font-bold rounded hover:bg-[#3d2459] transition-colors flex items-center justify-center gap-2"
|
||
|
|
>
|
||
|
|
<RefreshCw :size="18" />
|
||
|
|
更換神明
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Empty State -->
|
||
|
|
<div v-else class="text-center py-12 text-[#8f80a0]">
|
||
|
|
<p>尚未供奉任何神明</p>
|
||
|
|
<button
|
||
|
|
@click="$emit('encounter')"
|
||
|
|
class="mt-4 px-6 py-2 bg-[#f6b26b] text-[#1b1026] font-bold rounded hover:bg-[#ffe762]"
|
||
|
|
>
|
||
|
|
尋找緣分
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup lang="ts">
|
||
|
|
import { computed } from 'vue';
|
||
|
|
import { X, Sparkles, RefreshCw } from 'lucide-vue-next';
|
||
|
|
|
||
|
|
const props = defineProps<{
|
||
|
|
currentDeity: any;
|
||
|
|
currentDeityState: any;
|
||
|
|
currentStage: any;
|
||
|
|
}>();
|
||
|
|
|
||
|
|
defineEmits(['close', 'evolve', 'divination', 'switch', 'encounter']);
|
||
|
|
|
||
|
|
const nextStageExp = computed(() => {
|
||
|
|
if (!props.currentDeity || !props.currentStage) return 100;
|
||
|
|
const nextStage = props.currentDeity.stages.find((s: any) => s.level === props.currentStage.level + 1);
|
||
|
|
return nextStage ? nextStage.requiredExp : props.currentStage.requiredExp;
|
||
|
|
});
|
||
|
|
|
||
|
|
const expPercentage = computed(() => {
|
||
|
|
if (!props.currentDeityState) return 0;
|
||
|
|
return Math.min(100, (props.currentDeityState.exp / nextStageExp.value) * 100);
|
||
|
|
});
|
||
|
|
|
||
|
|
const canEvolve = computed(() => {
|
||
|
|
if (!props.currentDeity || !props.currentDeityState) return false;
|
||
|
|
// Check max level
|
||
|
|
if (props.currentStage.level >= props.currentDeity.stages.length) return false;
|
||
|
|
|
||
|
|
// Check EXP
|
||
|
|
if (props.currentDeityState.exp < nextStageExp.value) return false;
|
||
|
|
|
||
|
|
// Check Quests
|
||
|
|
return props.currentDeity.quests.every((q: any) => {
|
||
|
|
return (props.currentDeityState.quests[q.id] || 0) >= q.target;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
function getQuestProgress(questId: string) {
|
||
|
|
return props.currentDeityState?.quests?.[questId] || 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
function formatBuff(key: string, value: any) {
|
||
|
|
const map: Record<string, string> = {
|
||
|
|
gameSuccessRate: '遊戲成功率',
|
||
|
|
sicknessReduction: '生病機率',
|
||
|
|
happinessRecovery: '快樂恢復',
|
||
|
|
dropRate: '掉寶率',
|
||
|
|
resourceGain: '資源獲得',
|
||
|
|
intGain: '智力成長',
|
||
|
|
miniGameBonus: '小遊戲獎勵',
|
||
|
|
healthRecovery: '健康恢復',
|
||
|
|
badEventReduction: '壞事機率',
|
||
|
|
defense: '防禦力',
|
||
|
|
attack: '攻擊力',
|
||
|
|
luck: '運氣',
|
||
|
|
str: '力量',
|
||
|
|
int: '智力',
|
||
|
|
dex: '敏捷',
|
||
|
|
health: '最大健康',
|
||
|
|
sicknessImmune: '免疫生病'
|
||
|
|
};
|
||
|
|
|
||
|
|
const label = map[key] || key;
|
||
|
|
|
||
|
|
if (key === 'sicknessImmune') return label;
|
||
|
|
|
||
|
|
const isPercent = typeof value === 'number' && value < 1 && value > -1;
|
||
|
|
const valStr = isPercent ? `${Math.round(value * 100)}%` : value;
|
||
|
|
const prefix = value > 0 ? '+' : '';
|
||
|
|
|
||
|
|
return `${label} ${prefix}${valStr}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
function getDeityIcon(id: string) {
|
||
|
|
const icons: Record<string, string> = {
|
||
|
|
mazu: '🌊',
|
||
|
|
earthgod: '🏮',
|
||
|
|
yuelao: '❤️',
|
||
|
|
wenchang: '📜',
|
||
|
|
guanyin: '🪷',
|
||
|
|
athena: '🦉'
|
||
|
|
};
|
||
|
|
return icons[id] || '✨';
|
||
|
|
}
|
||
|
|
</script>
|