Files
tianshu-engine/src/stores/gameStore.ts

266 lines
8.6 KiB
TypeScript

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<SceneNode | null>(null)
const choices = ref<Choice[]>([])
const gameEnded = ref(false)
const timerTotal = ref(0)
const timerRemaining = ref(0)
const saves = ref<SlotInfo[]>([])
const qteActive = ref(false)
const qteDef = shallowRef<QTEDefinition | null>(null)
const qteTotal = ref(0)
const qteRemaining = ref(0)
const qteResult = ref<'none' | 'success' | 'fail'>('none')
const videoTime = ref(0)
const hotspots = ref<Hotspot[]>([])
const isImageScene = ref(false)
const inputMode = ref<'mouse' | 'keyboard'>('mouse')
const showChapterSelect = ref(false)
const chapters = ref<ChapterInfo[]>([])
const unlockedChapterIds = ref<Set<string>>(new Set())
const showAchievements = ref(false)
const achievementDefs = ref<AchievementDef[]>([])
const unlockedAchievementIds = ref<Set<string>>(new Set())
const toastAchievementId = ref('')
const showEndingGallery = ref(false)
const endings = ref<EndingDef[]>([])
const visitedSceneIds = ref<Set<string>>(new Set())
const storyLocales = ref<LocalesConfig>({ 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<any>(null)
const variables = ref<Record<string, number>>({})
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<string, number>) {
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,
}
})