feat(sasch40): add retro birthday game subproject and k8s deployment
- Add Vue 3 + Vite + TypeScript retro game: 'Saschas Kronkorken Kreuzzug: 40 Jahre Bass & Gerstensaft' - Add dynamic GameBoy layout: controls visible only during arcade modes, fullscreen during dialogue and tavern - Add QR code welcome & prequel screen with lore, feature preview, and audio hints - Add competitive party highscore and ranking breakdown on royal certificate - Add dedicated individual 1:1 character portraits for Sascha, Verena, NAT, Hansi, Mop, Lutz, Armend, Amy, Mane, Pü, and Mario - Add Dockerfile, Makefile, and K8s deployment at sasch40.haumdaucher.de - Update openclaw timeout configuration
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { sound } from '../audio/synthAudio'
|
||||
|
||||
export type GameAct = 'intro' | 'prologue' | 'platformer' | 'tavern' | 'party_express' | 'finale'
|
||||
|
||||
export interface GameState {
|
||||
currentAct: GameAct
|
||||
kronkorken: number
|
||||
beers: number
|
||||
guestsServed: number
|
||||
gstanzlWon: boolean
|
||||
partyMood: number
|
||||
inventory: string[]
|
||||
unlockedEasterEggs: string[]
|
||||
startTime: number
|
||||
elapsedSeconds: number
|
||||
soundMuted: boolean
|
||||
}
|
||||
|
||||
export const useGameStore = defineStore('game', {
|
||||
state: (): GameState => ({
|
||||
currentAct: 'intro',
|
||||
kronkorken: 0,
|
||||
beers: 0,
|
||||
guestsServed: 0,
|
||||
gstanzlWon: false,
|
||||
partyMood: 20,
|
||||
inventory: ['Königliche Sonnenbrille', 'Leergutsack'],
|
||||
unlockedEasterEggs: [],
|
||||
startTime: Date.now(),
|
||||
elapsedSeconds: 0,
|
||||
soundMuted: false,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
isArcadeMode(state): boolean {
|
||||
return state.currentAct === 'platformer' || state.currentAct === 'party_express'
|
||||
},
|
||||
|
||||
totalScore(state): number {
|
||||
const capPoints = state.kronkorken * 100
|
||||
const beerPoints = state.beers * 250
|
||||
const guestPoints = state.guestsServed * 300
|
||||
const gstanzlBonus = state.gstanzlWon ? 1500 : 0
|
||||
const eggBonus = state.unlockedEasterEggs.length * 500
|
||||
const completionBonus = 2000
|
||||
return capPoints + beerPoints + guestPoints + gstanzlBonus + eggBonus + completionBonus
|
||||
},
|
||||
|
||||
scoreRank(): { rank: string; title: string; color: string } {
|
||||
const score = this.totalScore
|
||||
if (score >= 15000) {
|
||||
return {
|
||||
rank: 'S-RANG (LEGENDÄR)',
|
||||
title: 'Göttlicher Imperator des 135-BPM-Schalldrucks',
|
||||
color: '#ffd700'
|
||||
}
|
||||
} else if (score >= 12000) {
|
||||
return {
|
||||
rank: 'A-RANG (HERZOGLICH)',
|
||||
title: 'Großfürst des Gerstensafts & Rave-Legende',
|
||||
color: '#38bdf8'
|
||||
}
|
||||
} else if (score >= 9000) {
|
||||
return {
|
||||
rank: 'B-RANG (RITTERLICH)',
|
||||
title: 'Ehren-Ritter der Hopfen-Manufaktur',
|
||||
color: '#4ade80'
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
rank: 'C-RANG (KNAPPE)',
|
||||
title: 'Durstiger Party-Knappe von Haumdaucher',
|
||||
color: '#fbbf24'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
titleAward(state): string {
|
||||
return this.scoreRank.title
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
addKronkorken(amount: number = 1) {
|
||||
this.kronkorken += amount
|
||||
this.partyMood = Math.min(100, this.partyMood + 2 * amount)
|
||||
sound.playCoin()
|
||||
},
|
||||
|
||||
addBeer() {
|
||||
this.beers++
|
||||
this.partyMood = Math.min(100, this.partyMood + 10)
|
||||
sound.playGulp()
|
||||
},
|
||||
|
||||
serveGuest() {
|
||||
this.guestsServed++
|
||||
this.addBeer()
|
||||
this.addKronkorken(3)
|
||||
},
|
||||
|
||||
setGstanzlWon() {
|
||||
this.gstanzlWon = true
|
||||
this.addKronkorken(15)
|
||||
},
|
||||
|
||||
addItem(item: string) {
|
||||
if (!this.inventory.includes(item)) {
|
||||
this.inventory.push(item)
|
||||
}
|
||||
},
|
||||
|
||||
unlockEasterEgg(egg: string) {
|
||||
if (!this.unlockedEasterEggs.includes(egg)) {
|
||||
this.unlockedEasterEggs.push(egg)
|
||||
this.addKronkorken(5)
|
||||
}
|
||||
},
|
||||
|
||||
setAct(act: GameAct) {
|
||||
this.currentAct = act
|
||||
if (act === 'finale') {
|
||||
sound.playFanfare()
|
||||
}
|
||||
},
|
||||
|
||||
startGame() {
|
||||
this.currentAct = 'prologue'
|
||||
sound.startBGM()
|
||||
},
|
||||
|
||||
toggleMute() {
|
||||
this.soundMuted = sound.toggleMute()
|
||||
},
|
||||
|
||||
resetGame() {
|
||||
this.currentAct = 'intro'
|
||||
this.kronkorken = 0
|
||||
this.beers = 0
|
||||
this.guestsServed = 0
|
||||
this.gstanzlWon = false
|
||||
this.partyMood = 20
|
||||
this.inventory = ['Königliche Sonnenbrille', 'Leergutsack']
|
||||
this.unlockedEasterEggs = []
|
||||
this.startTime = Date.now()
|
||||
this.elapsedSeconds = 0
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user