import { defineStore } from 'pinia' import { ref, shallowRef } from 'vue' import type { SceneNode, Choice, QTEDefinition, Hotspot, ChapterInfo, AchievementDef, EndingDef, LocalesConfig } from '@engine/types' export interface SlotInfo { slot: number timestamp: number sceneLabel: string thumbnail?: string } export const useGameStore = defineStore('game', () => { const currentScene = shallowRef(null) const choices = ref([]) const gameEnded = ref(false) const timerTotal = ref(0) const timerRemaining = ref(0) const saves = ref([]) const qteActive = ref(false) const qteDef = shallowRef(null) const qteTotal = ref(0) const qteRemaining = ref(0) const qteResult = ref<'none' | 'success' | 'fail'>('none') const videoTime = ref(0) const hotspots = ref([]) const isImageScene = ref(false) const inputMode = ref<'mouse' | 'keyboard'>('mouse') const showChapterSelect = ref(false) const chapters = ref([]) const unlockedChapterIds = ref>(new Set()) const showAchievements = ref(false) const achievementDefs = ref([]) const unlockedAchievementIds = ref>(new Set()) const toastAchievementId = ref('') const showEndingGallery = ref(false) const endings = ref([]) const visitedSceneIds = ref>(new Set()) const storyLocales = ref({ path: '', languages: ['zh'] }) const subFontSize = ref(Number(localStorage.getItem('subFontSize') || 20)) const subBgAlpha = ref(Number(localStorage.getItem('subBgAlpha') || 0)) const qteTimeRelax = ref(localStorage.getItem('qteTimeRelax') === 'true') const qteSingleKey = ref(localStorage.getItem('qteSingleKey') === 'true') const antiMistap = ref(localStorage.getItem('antiMistap') !== 'false') const pauseEnabled = ref(localStorage.getItem('pauseEnabled') !== 'false') const showSettings = ref(false) const showBattleResult = ref(false) const battleResultData = ref(null) const variables = ref>({}) const preferredQuality = ref(localStorage.getItem('preferredQuality') || '') const introVideo = ref('') const menuVideo = ref('') function setScene(scene: SceneNode) { currentScene.value = scene } function setChoices(list: Choice[]) { choices.value = list } function clearChoices() { choices.value = [] } function setGameEnded(val: boolean) { gameEnded.value = val } function setTimer(total: number, remaining: number) { timerTotal.value = total timerRemaining.value = remaining } function clearTimer() { timerTotal.value = 0 timerRemaining.value = 0 } function setSaves(list: SlotInfo[]) { saves.value = list } function showQTE(qte: QTEDefinition) { qteActive.value = true qteDef.value = qte qteTotal.value = qte.timeLimit qteRemaining.value = qte.timeLimit qteResult.value = 'none' } function updateQTE(remaining: number) { qteRemaining.value = remaining } function resolveQTE(success: boolean) { qteResult.value = success ? 'success' : 'fail' setTimeout(() => { qteActive.value = false qteDef.value = null qteResult.value = 'none' }, 1000) } function clearQTE() { qteActive.value = false qteDef.value = null qteResult.value = 'none' qteTotal.value = 0 qteRemaining.value = 0 } function setVideoTime(t: number) { videoTime.value = t } function setHotspots(list: Hotspot[]) { hotspots.value = list } function clearHotspots() { hotspots.value = [] } function setIsImageScene(val: boolean) { isImageScene.value = val } function setInputMode(mode: 'mouse' | 'keyboard') { inputMode.value = mode } function setChapters(list: ChapterInfo[]) { chapters.value = list } function setUnlockedChapters(ids: string[]) { unlockedChapterIds.value = new Set(ids) } function addUnlockedChapter(id: string) { unlockedChapterIds.value.add(id) unlockedChapterIds.value = new Set(unlockedChapterIds.value) } function setShowChapterSelect(val: boolean) { showChapterSelect.value = val } function setShowAchievements(val: boolean) { showAchievements.value = val } function setAchievementDefs(list: AchievementDef[]) { achievementDefs.value = list } function setUnlockedAchievementIds(ids: string[]) { unlockedAchievementIds.value = new Set(ids) } function addUnlockedAchievement(id: string) { unlockedAchievementIds.value.add(id) unlockedAchievementIds.value = new Set(unlockedAchievementIds.value) toastAchievementId.value = id } function clearToastAchievement() { toastAchievementId.value = '' } function setEndings(list: EndingDef[]) { endings.value = list } function setShowEndingGallery(val: boolean) { showEndingGallery.value = val } function setVisitedSceneIds(ids: string[]) { visitedSceneIds.value = new Set(ids) } function addVisitedSceneId(id: string) { visitedSceneIds.value.add(id) visitedSceneIds.value = new Set(visitedSceneIds.value) } function setStoryLocales(locales: LocalesConfig | undefined, assetBase?: string) { if (locales) { const base = (assetBase || '') const p = locales.path.startsWith('/') || locales.path.startsWith('http') ? locales.path : base + locales.path storyLocales.value = { ...locales, path: p } } } function setSubFontSize(v: number) { subFontSize.value = v; localStorage.setItem('subFontSize', String(v)) } function setSubBgAlpha(v: number) { subBgAlpha.value = v; localStorage.setItem('subBgAlpha', String(v)) } function setQteTimeRelax(v: boolean) { qteTimeRelax.value = v; localStorage.setItem('qteTimeRelax', String(v)) } function setQteSingleKey(v: boolean) { qteSingleKey.value = v; localStorage.setItem('qteSingleKey', String(v)) } function setAntiMistap(v: boolean) { antiMistap.value = v; localStorage.setItem('antiMistap', String(v)) } function setPauseEnabled(v: boolean) { pauseEnabled.value = v; localStorage.setItem('pauseEnabled', String(v)) } function setShowSettings(v: boolean) { showSettings.value = v } function variable(name: string): number { return variables.value[name] ?? 0 } function syncVariables(vars: Record) { variables.value = { ...vars } } function setBattleResult(data: any) { battleResultData.value = data showBattleResult.value = true } function setShowBattleResult(v: boolean) { showBattleResult.value = v } function setPreferredQuality(q: string) { preferredQuality.value = q; localStorage.setItem('preferredQuality', q) } function setIntroVideo(url: string) { introVideo.value = url } function setMenuVideo(url: string) { menuVideo.value = url } function dump() { console.group('GameStore') console.log('currentScene:', currentScene.value?.id) console.log('videoTime:', videoTime.value) console.log('choices:', choices.value) console.log('timer:', { total: timerTotal.value, remaining: timerRemaining.value }) console.log('gameEnded:', gameEnded.value) console.log('qte:', { active: qteActive.value, result: qteResult.value, total: qteTotal.value, remaining: qteRemaining.value }) console.log('saves:', saves.value) console.groupEnd() } return { currentScene, choices, gameEnded, timerTotal, timerRemaining, saves, qteActive, qteDef, qteTotal, qteRemaining, qteResult, videoTime, hotspots, isImageScene, showChapterSelect, chapters, unlockedChapterIds, inputMode, showAchievements, achievementDefs, unlockedAchievementIds, toastAchievementId, showEndingGallery, endings, visitedSceneIds, storyLocales, subFontSize, subBgAlpha, qteTimeRelax, qteSingleKey, antiMistap, pauseEnabled, showSettings, introVideo, menuVideo, showBattleResult, battleResultData, variables, preferredQuality, setScene, setChoices, clearChoices, setGameEnded, setTimer, clearTimer, setSaves, showQTE, updateQTE, resolveQTE, clearQTE, setVideoTime, setHotspots, clearHotspots, setIsImageScene, setInputMode, setChapters, setUnlockedChapters, addUnlockedChapter, setShowChapterSelect, setShowAchievements, setAchievementDefs, setUnlockedAchievementIds, addUnlockedAchievement, clearToastAchievement, setEndings, setShowEndingGallery, setVisitedSceneIds, addVisitedSceneId, setStoryLocales, setSubFontSize, setSubBgAlpha, setQteTimeRelax, setQteSingleKey, setAntiMistap, setPauseEnabled, setShowSettings, setIntroVideo, setMenuVideo, variable, setBattleResult, setShowBattleResult, syncVariables, setPreferredQuality, dump, } })