- 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
435 lines
9.7 KiB
Vue
435 lines
9.7 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted, ref } from 'vue'
|
|
import { useGameStore } from '../stores/gameStore'
|
|
import confetti from 'canvas-confetti'
|
|
|
|
const store = useGameStore()
|
|
const certificateRef = ref<HTMLDivElement | null>(null)
|
|
|
|
onMounted(() => {
|
|
// Fire celebratory party confetti
|
|
confetti({
|
|
particleCount: 100,
|
|
spread: 70,
|
|
origin: { y: 0.6 }
|
|
})
|
|
})
|
|
|
|
function restart() {
|
|
store.resetGame()
|
|
}
|
|
|
|
function printOrSave() {
|
|
window.print()
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="certificate-container">
|
|
<div ref="certificateRef" class="certificate-paper">
|
|
<div class="royal-seal">👑 40 👑</div>
|
|
|
|
<h1 class="cert-title">KÖNIGLICHE THRON-URKUNDE</h1>
|
|
<h2 class="cert-subtitle">Gratulation zu 40 Jahren Regentschaft!</h2>
|
|
|
|
<div class="king-portrait-wrapper">
|
|
<img
|
|
src="/assets/characters/sascha/portrait.jpg"
|
|
alt="König Sascha I."
|
|
class="king-portrait"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Party Competition Highscore Banner -->
|
|
<div class="score-banner" :style="{ borderColor: store.scoreRank.color }">
|
|
<div class="score-rank-title" :style="{ color: store.scoreRank.color }">
|
|
★ {{ store.scoreRank.rank }} ★
|
|
</div>
|
|
<div class="score-number">
|
|
{{ store.totalScore.toLocaleString('de-DE') }} PUNKTE
|
|
</div>
|
|
<div class="score-subtitle">
|
|
„{{ store.scoreRank.title }}“
|
|
</div>
|
|
</div>
|
|
|
|
<div class="cert-body">
|
|
<p class="decree-text">
|
|
Hiermit bekundet das gesamte Herzogtum Haumdaucher, dass
|
|
</p>
|
|
<h3 class="honoree-name">KÖNIG SASCHA I.</h3>
|
|
<p class="decree-details">
|
|
die 40 Kronkorken des Reiches glorreich vereint und den Bass auf unsterbliche 135 BPM gehoben hat!
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Stats Grid -->
|
|
<div class="cert-stats">
|
|
<div class="stat-card">
|
|
<span class="stat-val">👑 {{ store.kronkorken }}</span>
|
|
<span class="stat-lbl">KRONKORKEN</span>
|
|
</div>
|
|
<div class="stat-card">
|
|
<span class="stat-val">🍻 {{ store.beers }}</span>
|
|
<span class="stat-lbl">KRÜGE HELLES</span>
|
|
</div>
|
|
<div class="stat-card">
|
|
<span class="stat-val">👥 {{ store.guestsServed }}</span>
|
|
<span class="stat-lbl">GEFOLGE VERSORGT</span>
|
|
</div>
|
|
<div class="stat-card">
|
|
<span class="stat-val">🔊 135</span>
|
|
<span class="stat-lbl">TECHNO BPM</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Point Breakdown Table -->
|
|
<div class="breakdown-card">
|
|
<div class="breakdown-header">📊 SCORE-AUFSCHLÜSSELUNG</div>
|
|
<div class="breakdown-row">
|
|
<span>Kronkorken ({{ store.kronkorken }}x)</span>
|
|
<span class="breakdown-pts">+{{ store.kronkorken * 100 }}</span>
|
|
</div>
|
|
<div class="breakdown-row">
|
|
<span>Helles gezapft ({{ store.beers }}x)</span>
|
|
<span class="breakdown-pts">+{{ store.beers * 250 }}</span>
|
|
</div>
|
|
<div class="breakdown-row">
|
|
<span>Gefolge glücklich ({{ store.guestsServed }}x)</span>
|
|
<span class="breakdown-pts">+{{ store.guestsServed * 300 }}</span>
|
|
</div>
|
|
<div class="breakdown-row">
|
|
<span>Gstanzl-Battle Sieg</span>
|
|
<span class="breakdown-pts">{{ store.gstanzlWon ? '+1500' : '0' }}</span>
|
|
</div>
|
|
<div class="breakdown-row">
|
|
<span>Geheimnisse ({{ store.unlockedEasterEggs.length }}x)</span>
|
|
<span class="breakdown-pts">+{{ store.unlockedEasterEggs.length * 500 }}</span>
|
|
</div>
|
|
<div class="breakdown-row total-row">
|
|
<span>GESAMT-ERGEBNIS</span>
|
|
<span class="total-pts">{{ store.totalScore.toLocaleString('de-DE') }}</span>
|
|
</div>
|
|
<div class="compare-callout">
|
|
📱 Zeig deinen Score an der Bar & vergleiche mit anderen Gästen!
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Royal Postscript from Verena -->
|
|
<div class="queen-ps">
|
|
<span class="queen-signature">Königin Verena bemerkt:</span>
|
|
<p>„Ich hab dich unendlich lieb mein Schatz... aber geputzt wird nach der Party fei trotzdem ned!“ 🧹</p>
|
|
</div>
|
|
|
|
<!-- Easter Eggs Unlocked -->
|
|
<div v-if="store.unlockedEasterEggs.length" class="eggs-list">
|
|
<span>Gefundene Geheimnisse:</span>
|
|
<div class="egg-tags">
|
|
<span v-for="egg in store.unlockedEasterEggs" :key="egg" class="egg-badge">
|
|
🌟 {{ egg.toUpperCase() }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div class="cert-actions">
|
|
<button class="save-btn" @click="printOrSave">
|
|
📸 URKUNDE DRUCKEN / SCREENSHOT
|
|
</button>
|
|
<button class="restart-btn" @click="restart">
|
|
🔄 NOCHMAL SPIELEN
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.certificate-container {
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #1a0f0a;
|
|
overflow-y: auto;
|
|
padding: 12px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.certificate-paper {
|
|
background: #fdf6e2;
|
|
border: 6px double #854d0e;
|
|
border-radius: 12px;
|
|
padding: 16px 14px;
|
|
width: 100%;
|
|
max-width: 330px;
|
|
text-align: center;
|
|
color: #451a03;
|
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.7);
|
|
position: relative;
|
|
}
|
|
|
|
.royal-seal {
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
color: #b45309;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.cert-title {
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 9px;
|
|
color: #78350f;
|
|
margin: 0 0 6px 0;
|
|
}
|
|
|
|
.cert-subtitle {
|
|
font-family: 'MedievalSharp', serif;
|
|
font-size: 17px;
|
|
font-weight: bold;
|
|
color: #b91c1c;
|
|
margin: 0 0 10px 0;
|
|
}
|
|
|
|
.king-portrait-wrapper {
|
|
margin: 0 auto 10px auto;
|
|
width: 90px;
|
|
height: 90px;
|
|
border: 3px solid #d4af37;
|
|
border-radius: 50%;
|
|
overflow: hidden;
|
|
box-shadow: 0 4px 10px rgba(0,0,0,0.3);
|
|
}
|
|
|
|
.king-portrait {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.decree-text {
|
|
font-family: 'MedievalSharp', serif;
|
|
font-size: 13px;
|
|
margin: 4px 0;
|
|
}
|
|
|
|
.honoree-name {
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 12px;
|
|
color: #991b1b;
|
|
margin: 6px 0 2px 0;
|
|
}
|
|
|
|
.honoree-title {
|
|
font-family: 'MedievalSharp', serif;
|
|
font-size: 14px;
|
|
font-style: italic;
|
|
font-weight: bold;
|
|
color: #b45309;
|
|
margin: 0 0 6px 0;
|
|
}
|
|
|
|
.decree-details {
|
|
font-family: 'MedievalSharp', serif;
|
|
font-size: 13px;
|
|
line-height: 1.3;
|
|
margin: 0 0 10px 0;
|
|
}
|
|
|
|
.cert-stats {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 6px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.stat-card {
|
|
background: rgba(217, 119, 6, 0.15);
|
|
border: 1px solid #d97706;
|
|
border-radius: 6px;
|
|
padding: 4px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.stat-val {
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 9px;
|
|
color: #92400e;
|
|
}
|
|
|
|
.stat-lbl {
|
|
font-size: 9px;
|
|
color: #78350f;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.score-banner {
|
|
background: #1e1b18;
|
|
border: 3px solid #ffd700;
|
|
border-radius: 8px;
|
|
padding: 10px 8px;
|
|
margin-bottom: 12px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
|
|
}
|
|
|
|
.score-rank-title {
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 9px;
|
|
margin-bottom: 4px;
|
|
text-shadow: 0 0 8px currentColor;
|
|
}
|
|
|
|
.score-number {
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 14px;
|
|
color: #fff;
|
|
letter-spacing: 1px;
|
|
margin: 4px 0;
|
|
}
|
|
|
|
.score-subtitle {
|
|
font-family: 'MedievalSharp', serif;
|
|
font-size: 13px;
|
|
font-style: italic;
|
|
color: #fef08a;
|
|
}
|
|
|
|
.breakdown-card {
|
|
background: rgba(254, 243, 199, 0.7);
|
|
border: 1px solid #d97706;
|
|
border-radius: 6px;
|
|
padding: 8px;
|
|
margin-bottom: 10px;
|
|
font-family: 'MedievalSharp', serif;
|
|
font-size: 12px;
|
|
text-align: left;
|
|
}
|
|
|
|
.breakdown-header {
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 8px;
|
|
color: #78350f;
|
|
margin-bottom: 6px;
|
|
text-align: center;
|
|
border-bottom: 1px dashed #b45309;
|
|
padding-bottom: 4px;
|
|
}
|
|
|
|
.breakdown-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 2px 0;
|
|
color: #451a03;
|
|
}
|
|
|
|
.breakdown-pts {
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 8px;
|
|
color: #15803d;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.total-row {
|
|
border-top: 1px solid #b45309;
|
|
margin-top: 4px;
|
|
padding-top: 4px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.total-pts {
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 9px;
|
|
color: #b45309;
|
|
}
|
|
|
|
.compare-callout {
|
|
margin-top: 6px;
|
|
padding: 4px;
|
|
background: #fef08a;
|
|
border: 1px solid #eab308;
|
|
border-radius: 4px;
|
|
font-size: 10px;
|
|
color: #713f12;
|
|
text-align: center;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.queen-ps {
|
|
background: #fef3c7;
|
|
border-left: 3px solid #ec4899;
|
|
padding: 6px 8px;
|
|
border-radius: 4px;
|
|
margin-bottom: 8px;
|
|
font-family: 'MedievalSharp', serif;
|
|
text-align: left;
|
|
}
|
|
|
|
.queen-signature {
|
|
font-size: 11px;
|
|
font-weight: bold;
|
|
color: #be185d;
|
|
}
|
|
|
|
.queen-ps p {
|
|
margin: 2px 0 0 0;
|
|
font-size: 12px;
|
|
color: #831843;
|
|
}
|
|
|
|
.eggs-list {
|
|
font-size: 11px;
|
|
color: #78350f;
|
|
margin-top: 6px;
|
|
}
|
|
|
|
.egg-tags {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 4px;
|
|
flex-wrap: wrap;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
.egg-badge {
|
|
background: #f59e0b;
|
|
color: #fff;
|
|
font-size: 8px;
|
|
padding: 2px 6px;
|
|
border-radius: 4px;
|
|
font-family: 'Press Start 2P', monospace;
|
|
}
|
|
|
|
.cert-actions {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
width: 100%;
|
|
max-width: 330px;
|
|
}
|
|
|
|
.save-btn {
|
|
background: #15803d;
|
|
color: #fff;
|
|
border: 2px solid #86efac;
|
|
border-radius: 8px;
|
|
padding: 10px;
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 8px;
|
|
cursor: pointer;
|
|
box-shadow: 0 4px 10px rgba(0,0,0,0.5);
|
|
}
|
|
|
|
.restart-btn {
|
|
background: #78350f;
|
|
color: #fef08a;
|
|
border: 1px solid #b45309;
|
|
border-radius: 8px;
|
|
padding: 8px;
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 8px;
|
|
cursor: pointer;
|
|
}
|
|
</style>
|