feat(sasch40): improve Act III, add state persistence and fix portraits
- Fix character portrait crops and version assets to portrait_v2, ensuring correct identities (resolving Nat/Verena mismatch) - Update Schankraum scene image and configure Nginx cache-control to prevent stale asset caching - Make secret beer tap completely invisible in tavern until clicked - Reposition room hotspots in Act III to eliminate overlapping click targets - Add exit button [✕] to Bavarian Gstanzl duel minigame - Implement localStorage persistence in gameStore to maintain progress across page reloads - Enable clean game state and storage reset when clicking "Nochmal spielen" - Expand automated playtest script to cover Nat dialogue, duel exit, reload persistence, and game restart
This commit is contained in:
@@ -17,8 +17,12 @@ export interface GameState {
|
||||
soundMuted: boolean
|
||||
}
|
||||
|
||||
export const useGameStore = defineStore('game', {
|
||||
state: (): GameState => ({
|
||||
export const STORAGE_KEY = 'sasch40_game_save_v1'
|
||||
|
||||
const VALID_ACTS: GameAct[] = ['intro', 'prologue', 'platformer', 'tavern', 'party_express', 'finale']
|
||||
|
||||
function getInitialState(): GameState {
|
||||
const defaults: GameState = {
|
||||
currentAct: 'intro',
|
||||
kronkorken: 0,
|
||||
beers: 0,
|
||||
@@ -30,7 +34,66 @@ export const useGameStore = defineStore('game', {
|
||||
startTime: Date.now(),
|
||||
elapsedSeconds: 0,
|
||||
soundMuted: false,
|
||||
}),
|
||||
}
|
||||
|
||||
if (typeof window === 'undefined' || !window.localStorage) {
|
||||
return defaults
|
||||
}
|
||||
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY)
|
||||
if (!raw) return defaults
|
||||
const parsed = JSON.parse(raw)
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
const state: GameState = {
|
||||
currentAct: VALID_ACTS.includes(parsed.currentAct) ? parsed.currentAct : 'intro',
|
||||
kronkorken: typeof parsed.kronkorken === 'number' && !isNaN(parsed.kronkorken) ? parsed.kronkorken : 0,
|
||||
beers: typeof parsed.beers === 'number' && !isNaN(parsed.beers) ? parsed.beers : 0,
|
||||
guestsServed: typeof parsed.guestsServed === 'number' && !isNaN(parsed.guestsServed) ? parsed.guestsServed : 0,
|
||||
gstanzlWon: Boolean(parsed.gstanzlWon),
|
||||
partyMood: typeof parsed.partyMood === 'number' && !isNaN(parsed.partyMood) ? parsed.partyMood : 20,
|
||||
inventory: Array.isArray(parsed.inventory) ? parsed.inventory : defaults.inventory,
|
||||
unlockedEasterEggs: Array.isArray(parsed.unlockedEasterEggs) ? parsed.unlockedEasterEggs : [],
|
||||
startTime: typeof parsed.startTime === 'number' ? parsed.startTime : defaults.startTime,
|
||||
elapsedSeconds: typeof parsed.elapsedSeconds === 'number' ? parsed.elapsedSeconds : 0,
|
||||
soundMuted: Boolean(parsed.soundMuted)
|
||||
}
|
||||
if (state.soundMuted) {
|
||||
sound.setMuted(true)
|
||||
}
|
||||
return state
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to parse saved game state:', e)
|
||||
}
|
||||
|
||||
return defaults
|
||||
}
|
||||
|
||||
export function saveStateToStorage(state: GameState) {
|
||||
if (typeof window === 'undefined' || !window.localStorage) return
|
||||
try {
|
||||
const dataToSave = {
|
||||
currentAct: state.currentAct,
|
||||
kronkorken: state.kronkorken,
|
||||
beers: state.beers,
|
||||
guestsServed: state.guestsServed,
|
||||
gstanzlWon: state.gstanzlWon,
|
||||
partyMood: state.partyMood,
|
||||
inventory: state.inventory,
|
||||
unlockedEasterEggs: state.unlockedEasterEggs,
|
||||
startTime: state.startTime,
|
||||
elapsedSeconds: state.elapsedSeconds,
|
||||
soundMuted: state.soundMuted
|
||||
}
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(dataToSave))
|
||||
} catch (e) {
|
||||
console.warn('Failed to save game state to localStorage:', e)
|
||||
}
|
||||
}
|
||||
|
||||
export const useGameStore = defineStore('game', {
|
||||
state: (): GameState => getInitialState(),
|
||||
|
||||
getters: {
|
||||
isArcadeMode(state): boolean {
|
||||
@@ -135,6 +198,13 @@ export const useGameStore = defineStore('game', {
|
||||
},
|
||||
|
||||
resetGame() {
|
||||
if (typeof window !== 'undefined' && window.localStorage) {
|
||||
try {
|
||||
localStorage.removeItem(STORAGE_KEY)
|
||||
} catch (e) {
|
||||
console.warn('Failed to clear saved state', e)
|
||||
}
|
||||
}
|
||||
this.currentAct = 'intro'
|
||||
this.kronkorken = 0
|
||||
this.beers = 0
|
||||
@@ -145,6 +215,7 @@ export const useGameStore = defineStore('game', {
|
||||
this.unlockedEasterEggs = []
|
||||
this.startTime = Date.now()
|
||||
this.elapsedSeconds = 0
|
||||
saveStateToStorage(this.$state)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user