pet_data/app/components/pixel/GodSystemOverlay.vue

615 lines
25 KiB
Vue
Raw Normal View History

2025-11-26 06:53:44 +00:00
<template>
<div class="flex flex-col h-full gap-4">
<!-- Header: Deity System Title -->
<div class="text-xl font-bold tracking-widest text-[#2ce8f4] border-b-2 border-[#4a3b5e] pb-2">
2025-11-27 08:42:55 +00:00
神明系統
2025-11-26 06:53:44 +00:00
</div>
<!-- Top Action Buttons Grid -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-2">
<PixelButton
v-for="action in TAB_ACTIONS"
:key="action.id"
@click="activeTab = action.id"
:variant="activeTab === action.id ? 'primary' : 'secondary'"
class="text-xs md:text-sm flex items-center justify-center gap-2"
>
<component :is="action.icon" :size="16" />
{{ action.label }}
</PixelButton>
<PixelButton :variant="activeTab === 'LIST' ? 'primary' : 'secondary'" @click="activeTab = 'LIST'" class="text-xs md:text-sm">
2025-11-27 08:42:55 +00:00
神明列表
2025-11-26 06:53:44 +00:00
</PixelButton>
</div>
<!-- Main Content Area -->
<div class="flex-grow bg-[#150c1f] border border-[#4a3b5e] p-4 relative overflow-hidden">
<!-- Background Decor -->
<div class="absolute inset-0 opacity-20 pointer-events-none flex items-center justify-center">
<div class="w-64 h-64 border-[20px] border-[#2b193f] rounded-full"></div>
</div>
<!-- --- VIEW: PRAY --- -->
2025-11-27 08:42:55 +00:00
<div v-if="activeTab === 'PRAY'" class="flex flex-col h-full gap-4 overflow-y-auto custom-scrollbar">
<!-- Deity Avatar & Basic Info -->
<div class="flex flex-col items-center gap-3">
<div class="relative">
<PixelAvatar
:deityId="currentDeity"
:stageLevel="activeDeityState?.stageLevel || 1"
class="w-32 h-32"
/>
</div>
<div class="text-center">
<h2 class="text-2xl text-[#f6b26b] font-bold">{{ activeStage?.name || activeDeity.name }}</h2>
<div class="text-[#99e550] text-sm tracking-wider mb-1">{{ activeStage?.title || activeDeity.personality }}</div>
<p class="text-[#8f80a0] text-xs max-w-md italic leading-relaxed">"{{ activeStage?.description }}"</p>
</div>
2025-11-26 06:53:44 +00:00
</div>
2025-11-27 08:42:55 +00:00
<!-- Progress Section -->
<div class="bg-[#1b1026] border border-[#4a3b5e] p-3 rounded">
<!-- Max Level Badge -->
<div v-if="isMaxLevel" class="text-center mb-3">
<span class="text-[#f6b26b] font-bold text-sm border border-[#f6b26b] px-3 py-1 rounded bg-[#2b193f] inline-block">
已達最高階
</span>
</div>
<!-- Favor -->
<div>
<div class="flex justify-between text-xs text-[#8f80a0] mb-1">
<span>好感度</span>
<span>{{ activeDeityFavor }}/100</span>
</div>
<div class="h-2 bg-[#2b193f] border border-[#4a3b5e] rounded-full overflow-hidden relative">
<div
class="h-full bg-[#d95763] transition-all duration-500"
:style="{ width: `${activeDeityFavor}%` }"
></div>
</div>
2025-11-26 06:53:44 +00:00
</div>
2025-11-27 08:42:55 +00:00
</div>
<!-- Current Stage Buffs -->
<div class="bg-[#1b1026] border border-[#4a3b5e] p-3 rounded">
<div class="text-[#f6b26b] text-sm font-bold mb-2 border-b border-[#4a3b5e] pb-1">
神力
</div>
<div class="grid grid-cols-2 gap-2 text-xs">
2025-11-26 06:53:44 +00:00
<div
2025-11-27 08:42:55 +00:00
v-for="(value, key) in currentStageBuffs"
:key="key"
class="bg-[#0f0816] border border-[#4a3b5e] px-2 py-1 rounded"
>
<span class="text-[#99e550]">{{ formatBuffKey(key) }}:</span>
<span class="text-[#e0d8f0] ml-1">{{ formatBuffValue(value) }}</span>
</div>
2025-11-26 06:53:44 +00:00
</div>
</div>
2025-11-27 08:42:55 +00:00
<!-- Quests for Current Stage -->
<div v-if="!isMaxLevel && currentStageQuests.length > 0" class="bg-[#1b1026] border border-[#4a3b5e] p-3 rounded">
<div class="text-[#2ce8f4] text-sm font-bold mb-2 border-b border-[#4a3b5e] pb-1">
修行當前階段任務
</div>
<div class="space-y-2">
<div
v-for="quest in currentStageQuests"
:key="quest.id"
class="bg-[#0f0816] border border-[#4a3b5e] p-2 rounded"
>
<div class="flex justify-between items-center mb-1">
<span class="text-[#e0d8f0] text-xs">{{ quest.description }}</span>
<span
class="text-xs font-bold"
:class="questProgress(quest.id) >= quest.target ? 'text-[#99e550]' : 'text-[#8f80a0]'"
>
{{ questProgress(quest.id) }}/{{ quest.target }}
</span>
</div>
<div class="h-1 bg-[#2b193f] rounded-full overflow-hidden">
<div
class="h-full transition-all duration-500"
:class="questProgress(quest.id) >= quest.target ? 'bg-[#99e550]' : 'bg-[#8f80a0]'"
:style="{ width: `${Math.min(100, (questProgress(quest.id) / quest.target) * 100)}%` }"
></div>
</div>
</div>
</div>
<!-- Evolve Button (when all quests completed) -->
<div v-if="canEvolveDeity" class="mt-3 text-center">
<PixelButton
class="w-full py-2 text-sm bg-[#2ce8f4] hover:bg-[#1ad4e0] animate-pulse"
@click="handleEvolve"
>
進化到下一階段
</PixelButton>
</div>
</div>
<!-- Lot Types -->
<div class="bg-[#1b1026] border border-[#4a3b5e] p-3 rounded">
<div class="text-[#ffe762] text-sm font-bold mb-2 border-b border-[#4a3b5e] pb-1">
求籤
</div>
<div class="flex flex-wrap gap-2">
<span
v-for="lotType in activeDeity.lotTypes"
:key="lotType"
class="bg-[#0f0816] border border-[#4a3b5e] px-3 py-1 rounded text-xs text-[#e0d8f0]"
>
{{ formatLotType(lotType) }}
</span>
</div>
</div>
<!-- Deity Dialogue (Random One) -->
<div class="bg-[#1b1026] border border-[#4a3b5e] p-3 rounded">
<div class="text-[#d95763] text-sm font-bold mb-2 border-b border-[#4a3b5e] pb-1">
神諭
</div>
<div class="bg-[#0f0816] border-l-2 border-[#d95763] px-3 py-2 text-sm text-[#e0d8f0] italic text-center">
"{{ randomDialogue }}"
</div>
</div>
<!-- Pray Button -->
<div class="flex flex-col items-center gap-2 mt-2 mb-4">
<PixelButton
class="w-48 py-3 text-base"
:class="{ 'animate-pulse': canPray }"
:disabled="!canPray"
@click="$emit('addFavor', 10)"
>
🙏 祈福 ({{ dailyPrayerCount || 0 }}/3)
</PixelButton>
<p v-if="(dailyPrayerCount || 0) >= 3" class="text-xs text-[#8f80a0]">今日祈福次數已用完</p>
<p v-else-if="activeDeityFavor >= 100" class="text-xs text-[#8f80a0]">好感度已滿</p>
<p v-else class="text-xs text-[#8f80a0]">增加好感度與修煉值 (剩餘 {{ 3 - (dailyPrayerCount || 0) }} )</p>
</div>
2025-11-26 06:53:44 +00:00
</div>
2025-11-27 08:42:55 +00:00
<!-- --- VIEW: JIAOBEI (Free Toss) --- -->
2025-11-26 06:53:44 +00:00
<!-- --- VIEW: JIAOBEI (Free Toss) --- -->
<div v-else-if="activeTab === 'JIAOBEI'" class="flex flex-col items-center justify-center h-full gap-8">
2025-11-27 08:42:55 +00:00
<h3 class="text-[#f6b26b] text-lg uppercase tracking-widest">擲筊問事</h3>
<div class="flex flex-col items-center gap-4">
<JiaobeiBlocks :result="lastResult" :isTossing="isTossing" />
<div v-if="lastResult && !isTossing" class="text-xl font-bold text-[#e0d8f0]">
{{ getJiaobeiResultText(lastResult) }}
</div>
</div>
2025-11-26 06:53:44 +00:00
<div class="mt-8">
<PixelButton @click="handleToss(false)" :disabled="isTossing" class="w-40">
2025-11-27 08:42:55 +00:00
{{ isTossing ? '擲筊中...' : '開始擲筊' }}
2025-11-26 06:53:44 +00:00
</PixelButton>
</div>
</div>
<!-- --- VIEW: LOT (Draw & Verify) --- -->
<div v-else-if="activeTab === 'LOT'" class="flex flex-col items-center justify-center h-full gap-4 text-center w-full">
<!-- Phase: Idle -->
<template v-if="lotPhase === LotPhase.Idle">
<Scroll :size="64" class="text-[#ffe762] mb-4" />
2025-11-27 08:42:55 +00:00
<h3 class="text-xl text-[#e0d8f0] mb-2">誠心求籤</h3>
2025-11-26 06:53:44 +00:00
<p class="text-sm text-[#8f80a0] max-w-xs mb-6">
2025-11-27 08:42:55 +00:00
搖動籤筒求出一支籤並需連續三個聖杯確認
2025-11-26 06:53:44 +00:00
</p>
<PixelButton @click="handleDrawLot" class="w-48">
2025-11-27 08:42:55 +00:00
開始求籤
2025-11-26 06:53:44 +00:00
</PixelButton>
</template>
<!-- Phase: Drawing (Animation) -->
<div v-else-if="lotPhase === LotPhase.Drawing" class="animate-bounce">
<div class="w-16 h-24 bg-[#4a2e18] border-2 border-[#f6b26b] mx-auto mb-4 relative rounded-sm">
<div class="absolute top-0 left-0 w-full h-full flex items-center justify-center text-[#f6b26b] font-bold">
...
</div>
</div>
2025-11-27 08:42:55 +00:00
<span class="text-[#f6b26b] tracking-widest">搖籤中...</span>
2025-11-26 06:53:44 +00:00
</div>
<!-- Phase: Verify -->
<template v-else-if="lotPhase === LotPhase.PendingVerify || lotPhase === LotPhase.Verifying">
<div class="text-2xl font-bold text-[#e0d8f0] border-2 border-[#f6b26b] px-4 py-2 mb-4 bg-[#2b193f]">
2025-11-27 08:42:55 +00:00
{{ drawnLot?.no }}
2025-11-26 06:53:44 +00:00
</div>
<p class="text-sm text-[#8f80a0] mb-4">
2025-11-27 08:42:55 +00:00
需連續三個聖杯確認
2025-11-26 06:53:44 +00:00
</p>
<div class="flex gap-2 mb-6 justify-center">
<div
v-for="i in 3"
:key="i"
class="w-4 h-4 rounded-full border border-[#4a3b5e]"
:class="i <= saintCupCount ? 'bg-[#d95763] shadow-[0_0_10px_#d95763]' : 'bg-[#1b1026]'"
/>
</div>
<JiaobeiBlocks :result="lastResult" :isTossing="isTossing" />
<div class="mt-8">
<PixelButton @click="handleToss(true)" :disabled="isTossing" class="w-40">
2025-11-27 08:42:55 +00:00
擲筊確認 ({{ saintCupCount }}/3)
2025-11-26 06:53:44 +00:00
</PixelButton>
</div>
</template>
<!-- Phase: Failed -->
<template v-else-if="lotPhase === LotPhase.Failed">
<div class="text-[#d95763] text-4xl mb-4"></div>
2025-11-27 08:42:55 +00:00
<h3 class="text-lg text-[#d95763] mb-2">笑杯/陰杯</h3>
2025-11-26 06:53:44 +00:00
<p class="text-sm text-[#8f80a0] mb-6">
2025-11-27 08:42:55 +00:00
神明指示此籤不對<br/>請重新求籤
2025-11-26 06:53:44 +00:00
</p>
<PixelButton @click="resetLot" variant="danger">
2025-11-27 08:42:55 +00:00
重新求籤
2025-11-26 06:53:44 +00:00
</PixelButton>
</template>
<!-- Phase: Success - Detailed Result -->
2025-11-27 08:42:55 +00:00
<div v-else-if="lotPhase === LotPhase.Result && drawnLot" class="w-full h-full overflow-y-auto custom-scrollbar p-2">
2025-11-26 06:53:44 +00:00
<PixelFrame class="bg-[#1b1026] border-4 border-[#f6b26b] relative shadow-[0_0_20px_rgba(246,178,107,0.3)]">
<!-- Header -->
<div class="text-center border-b-2 border-[#4a3b5e] pb-3 mb-3 bg-[#231533] p-2">
<div class="text-[#99e550] text-sm md:text-lg font-bold mb-1 flex items-center justify-center gap-2 animate-pulse">
<Sparkles :size="16" />
<span>三聖筊{{ activeDeity.name }}允准解籤</span>
<Sparkles :size="16" />
</div>
<div class="text-[#f6b26b] text-xl md:text-3xl font-bold tracking-widest mt-2 font-serif">
2025-11-27 08:42:55 +00:00
{{ drawnLot.no }} {{ drawnLot.grade }}
2025-11-26 06:53:44 +00:00
</div>
</div>
<!-- Poem (Block) -->
<div class="bg-[#2b193f] p-4 text-center mb-4 border-l-4 border-[#f6b26b] mx-2 shadow-inner">
2025-11-27 08:42:55 +00:00
<div class="text-lg md:text-xl text-[#e0d8f0] tracking-[0.2em] leading-loose font-serif drop-shadow-md whitespace-pre-line">
{{ drawnLot.poem1 }}
2025-11-26 06:53:44 +00:00
</div>
</div>
<!-- Details Grid -->
<div class="flex flex-col gap-4 text-left px-2">
<!-- Meaning -->
<div class="bg-[#0f0816] p-2 border border-[#4a3b5e]">
<span class="text-[#f6b26b] font-bold text-sm block mb-1 border-b border-[#4a3b5e] pb-1 w-full">
2025-11-27 08:42:55 +00:00
聖意 Meaning
2025-11-26 06:53:44 +00:00
</span>
2025-11-27 08:42:55 +00:00
<p class="text-[#e0d8f0] text-sm leading-relaxed mt-1">{{ drawnLot.meaning }}</p>
2025-11-26 06:53:44 +00:00
</div>
<!-- Interpretation -->
<div class="bg-[#0f0816] p-2 border border-[#4a3b5e]">
<span class="text-[#99e550] font-bold text-sm block mb-1 border-b border-[#4a3b5e] pb-1 w-full">
2025-11-27 08:42:55 +00:00
解曰 Interpretation
2025-11-26 06:53:44 +00:00
</span>
2025-11-27 08:42:55 +00:00
<p class="text-[#e0d8f0] text-sm leading-relaxed mt-1">{{ drawnLot.explanation }}</p>
</div>
<!-- Oracle -->
<div class="bg-[#0f0816] p-2 border border-[#4a3b5e]">
<span class="text-[#2ce8f4] font-bold text-sm block mb-1 border-b border-[#4a3b5e] pb-1 w-full">
仙機 Oracle
</span>
<div class="text-[#e0d8f0] text-sm leading-relaxed mt-1 whitespace-pre-wrap">
{{ drawnLot.oracle }}
</div>
2025-11-26 06:53:44 +00:00
</div>
<!-- Story -->
<div class="bg-[#0f0816] p-2 border border-[#4a3b5e]">
<span class="text-[#2ce8f4] font-bold text-sm block mb-1 border-b border-[#4a3b5e] pb-1 w-full">
2025-11-27 08:42:55 +00:00
典故 Story
2025-11-26 06:53:44 +00:00
</span>
<div class="text-[#8f80a0] text-xs leading-relaxed mt-1">
2025-11-27 08:42:55 +00:00
{{ getFirstStory(drawnLot.story) }}
2025-11-26 06:53:44 +00:00
</div>
</div>
</div>
<div class="mt-6 flex justify-center mb-2">
<PixelButton @click="resetLot" class="w-full md:w-auto px-8 py-3">
2025-11-27 08:42:55 +00:00
收下
2025-11-26 06:53:44 +00:00
</PixelButton>
</div>
</PixelFrame>
</div>
</div>
<!-- --- VIEW: LIST/SWITCH --- -->
<div v-else-if="activeTab === 'LIST' || activeTab === 'VERIFY'" class="flex flex-col gap-4">
2025-11-27 08:42:55 +00:00
<div class="text-xs text-[#8f80a0] uppercase mb-2"> 切換神明</div>
2025-11-26 06:53:44 +00:00
<div class="grid grid-cols-2 gap-4">
<button
v-for="deity in Object.values(deities)"
:key="deity.id"
@click="$emit('switchDeity', deity.id)"
class="border-2 p-3 flex items-center gap-3 transition-all relative"
:class="currentDeity === deity.id ? 'border-[#99e550] bg-[#2b193f]' : 'border-[#4a3b5e] bg-[#0f0816] hover:bg-[#150c1f]'"
>
<div class="w-10 h-10 relative">
2025-11-27 08:42:55 +00:00
<PixelAvatar :deityId="deity.id" :stageLevel="getDeityStageLevel(deity.id)" />
2025-11-26 06:53:44 +00:00
</div>
<div class="flex flex-col items-start">
<span class="font-bold" :class="currentDeity === deity.id ? 'text-[#99e550]' : 'text-[#e0d8f0]'">
{{ deity.name }}
</span>
<span class="text-[10px] text-[#8f80a0]">{{ deity.title }}</span>
</div>
<div v-if="currentDeity === deity.id" class="absolute top-2 right-2 w-2 h-2 bg-[#99e550] rounded-full shadow-[0_0_5px_#99e550]"></div>
</button>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
2025-11-26 09:53:03 +00:00
import { ref, computed, watch } from 'vue';
import { Heart, Sparkles, Scroll, Repeat, CheckCircle2, Gift } from 'lucide-vue-next';
2025-11-26 06:53:44 +00:00
import PixelButton from './PixelButton.vue';
import PixelAvatar from './PixelAvatar.vue';
import PixelFrame from './PixelFrame.vue';
import JiaobeiBlocks from './JiaobeiBlocks.vue';
2025-11-27 08:42:55 +00:00
import guanyinLots from '../../../guanyin_100_lots.json';
2025-11-26 09:53:03 +00:00
type Deity = any;
2025-11-26 06:53:44 +00:00
interface Props {
2025-11-26 09:53:03 +00:00
currentDeity: string;
deities: Record<string, Deity>;
2025-11-27 08:42:55 +00:00
deitySystemState?: any;
petSystemState?: any;
dailyPrayerCount?: number;
2025-11-26 06:53:44 +00:00
}
const props = defineProps<Props>();
2025-11-27 08:42:55 +00:00
const emit = defineEmits(['switchDeity', 'addFavor', 'onJiaobei', 'evolve']);
2025-11-26 06:53:44 +00:00
const activeTab = ref('PRAY');
const isTossing = ref(false);
2025-11-26 09:53:03 +00:00
const lastResult = ref<string | null>(null);
const LotPhase = {
Idle: 'idle',
Drawing: 'drawing',
Verifying: 'verifying',
Result: 'result',
PendingVerify: 'pending_verify',
Success: 'success',
Failed: 'failed'
};
const JiaobeiResult = {
Saint: 'Saint',
Smile: 'Smile',
Cry: 'Cry'
};
const lotPhase = ref<string>(LotPhase.Idle);
2025-11-27 08:42:55 +00:00
const drawnLot = ref<any>(null);
2025-11-26 06:53:44 +00:00
const saintCupCount = ref(0);
const TAB_ACTIONS = [
2025-11-27 08:42:55 +00:00
{ id: 'PRAY', label: '祈禱', icon: Sparkles },
{ id: 'LOT', label: '求籤', icon: Scroll },
{ id: 'JIAOBEI', label: '擲筊', icon: Repeat },
2025-11-26 06:53:44 +00:00
];
2025-11-27 08:42:55 +00:00
const activeDeity = computed(() => props.deities[props.currentDeity] || Object.values(props.deities)[0]);
// Computed for Stage Logic
const activeDeityState = computed(() => {
if (!props.deitySystemState?.collectedDeities) return null;
return props.deitySystemState.collectedDeities.find((d: any) => d.id === props.currentDeity);
});
const activeStage = computed(() => {
if (!activeDeity.value || !activeDeityState.value) return null;
return activeDeity.value.stages.find((s: any) => s.level === activeDeityState.value.stageLevel);
});
const nextStageExp = computed(() => {
if (!activeDeity.value || !activeDeityState.value) return 100;
const nextStage = activeDeity.value.stages.find((s: any) => s.level === activeDeityState.value.stageLevel + 1);
return nextStage ? nextStage.requiredExp : 9999;
});
const isMaxLevel = computed(() => {
if (!activeDeity.value || !activeDeityState.value) return false;
return activeDeityState.value.stageLevel >= activeDeity.value.stages.length;
});
const expPercentage = computed(() => {
if (!activeDeityState.value) return 0;
if (isMaxLevel.value) return 100;
return Math.min(100, (activeDeityState.value.exp / nextStageExp.value) * 100);
});
const activeDeityFavor = computed(() => {
if (!props.petSystemState?.deityFavors) return 0;
return props.petSystemState.deityFavors[props.currentDeity] || 0;
});
const canPray = computed(() => {
const prayCount = props.dailyPrayerCount || 0;
return prayCount < 3 && activeDeityFavor.value < 100;
});
const questProgress = (questId: string | number) => {
return activeDeityState.value?.quests?.[questId] || 0;
2025-11-26 06:53:44 +00:00
};
2025-11-27 08:42:55 +00:00
const getDeityStageLevel = (deityId: string) => {
if (!props.deitySystemState?.collectedDeities) return 1;
const deity = props.deitySystemState.collectedDeities.find((d: any) => d.id === deityId);
return deity ? deity.stageLevel : 1;
};
2025-11-26 06:53:44 +00:00
2025-11-27 08:42:55 +00:00
const canEvolveDeity = computed(() => {
if (!activeDeityState.value || !activeDeity.value) return false;
if (isMaxLevel.value) return false;
// Check if all current stage quests are completed
const quests = currentStageQuests.value;
if (!quests || quests.length === 0) return false;
return quests.every((q: any) => questProgress(q.id) >= q.target);
});
const handleEvolve = () => {
if (canEvolveDeity.value) {
emit('evolve');
}
2025-11-26 06:53:44 +00:00
};
2025-11-27 08:42:55 +00:00
const currentStageBuffs = computed(() => {
return activeStage.value?.buffs || {};
});
const currentStageQuests = computed(() => {
if (!activeDeity.value || !activeDeityState.value) return [];
// Get current stage quests (quests to complete this stage)
const currentStage = activeDeity.value.stages.find((s: any) => s.level === activeDeityState.value.stageLevel);
return currentStage?.quests || [];
});
const formatBuffKey = (key: string | number): string => {
const keyStr = String(key);
const keyMap: Record<string, string> = {
luck: '幸運',
gameSuccessRate: '遊戲成功率',
sicknessReduction: '抗病',
evolutionSpeed: '進化速度',
cleanlinessRetention: '清潔保持',
moodRetention: '心情保持',
trainingExp: '訓練經驗',
workGold: '工作金幣',
happinessRecovery: '快樂恢復',
healthRecovery: '健康恢復',
sicknessImmune: '免疫生病',
dropRate: '掉落率',
resourceGain: '資源獲得',
intGain: '智力成長',
miniGameBonus: '小遊戲獎勵',
breedingSuccess: '繁殖成功率',
badEventReduction: '壞事件減免'
};
return keyMap[keyStr] || keyStr;
};
const formatBuffValue = (value: any): string => {
if (typeof value === 'boolean') return value ? '是' : '否';
if (typeof value === 'number') {
if (value < 1) return `+${(value * 100).toFixed(0)}%`;
return `+${value}`;
}
return String(value);
};
const getJiaobeiResultText = (result: string): string => {
switch (result) {
case 'Saint': return '聖杯 (允杯)';
case 'Smile': return '笑杯';
case 'Cry': return '陰杯 (怒杯)';
default: return result;
}
};
const formatLotType = (lotType: string): string => {
const typeMap: Record<string, string> = {
guanyin_100: '觀音一百籤',
mazu_60: '媽祖六十甲子籤',
moon_blocks: '擲筊',
tarot_major: '塔羅大牌占卜'
};
return typeMap[lotType] || lotType;
};
// Random dialogue - stable until deity changes
const randomDialogue = ref('');
watch(() => props.currentDeity, () => {
if (!activeDeity.value?.dialogues || activeDeity.value.dialogues.length === 0) {
randomDialogue.value = '';
} else {
const randomIndex = Math.floor(Math.random() * activeDeity.value.dialogues.length);
randomDialogue.value = activeDeity.value.dialogues[randomIndex];
2025-11-26 06:53:44 +00:00
}
2025-11-27 08:42:55 +00:00
}, { immediate: true });
const getFirstStory = (storyText: string) => {
if (!storyText) return '';
const parts = storyText.split(/2\./);
return parts[0].trim();
2025-11-26 06:53:44 +00:00
};
2025-11-27 08:42:55 +00:00
// --- Methods ---
2025-11-26 06:53:44 +00:00
const handleDrawLot = () => {
2025-11-27 08:42:55 +00:00
lotPhase.value = LotPhase.Drawing;
setTimeout(() => {
const randomIndex = Math.floor(Math.random() * guanyinLots.length);
drawnLot.value = guanyinLots[randomIndex];
lotPhase.value = LotPhase.PendingVerify;
saintCupCount.value = 0;
}, 2000);
};
const handleToss = (isVerifying: boolean) => {
if (isTossing.value) return;
isTossing.value = true;
2025-11-26 06:53:44 +00:00
lastResult.value = null;
2025-11-27 08:42:55 +00:00
setTimeout(() => {
const rand = Math.random();
let result = '';
if (rand < 0.5) result = JiaobeiResult.Saint;
else if (rand < 0.75) result = JiaobeiResult.Smile;
else result = JiaobeiResult.Cry;
lastResult.value = result;
isTossing.value = false;
if (activeTab.value === 'JIAOBEI') {
emit('onJiaobei', result);
}
if (isVerifying) {
if (result === JiaobeiResult.Saint) {
saintCupCount.value++;
if (saintCupCount.value >= 3) {
lotPhase.value = LotPhase.Result;
}
} else {
saintCupCount.value = 0;
lotPhase.value = LotPhase.Failed;
}
}
}, 1500);
2025-11-26 06:53:44 +00:00
};
const resetLot = () => {
2025-11-27 08:42:55 +00:00
lotPhase.value = LotPhase.Idle;
drawnLot.value = null;
saintCupCount.value = 0;
lastResult.value = null;
2025-11-26 06:53:44 +00:00
};
</script>