266 lines
8.6 KiB
TypeScript
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,
|
|
}
|
|
})
|