feat: initialize TRXTD browser tower defense

This commit is contained in:
Tronax 2026-08-15 16:07:09 +02:00
commit c4347f8420
Signed by: Tronax
SSH key fingerprint: SHA256:2pKKXDZucWvaF/GzXNz0FY53EAO1YDLN80bqS+TTz/o
34 changed files with 8302 additions and 0 deletions

View file

@ -0,0 +1,144 @@
<script setup lang="ts">
import { store } from '@/game/store'
import { engine } from '@/game/engine'
import { mpgame } from '@/game/mpgame'
function restart(): void {
engine.startGame(store.difficulty)
}
function endless(): void {
engine.continueEndless()
}
function menu(): void {
if (store.mp.active) {
mpgame.leave()
} else {
store.screen = 'menu'
store.result = null
}
}
</script>
<template>
<div v-if="store.result" class="overlay" :class="store.result.win ? 'win' : 'lose'">
<div class="card">
<div class="emoji">{{ store.result.win ? '🏆' : '💀' }}</div>
<h2 v-if="store.mp.active">{{ store.result.win ? 'Sieg!' : 'Verloren' }}</h2>
<h2 v-else-if="store.result.win">Sieg!</h2>
<h2 v-else>Game Over</h2>
<p v-if="store.mp.active" class="msg">{{ store.mp.resultMsg }}</p>
<p v-else-if="store.result.win" class="msg">Alle 20 Wellen abgewehrt die Basis steht!</p>
<p v-else class="msg">Die Basis wurde überrannt. In Welle {{ store.result.wave }}.</p>
<div v-if="!store.mp.active" class="stats">
<div class="stat"><span>Punkte</span><b>{{ store.result.score }}</b></div>
<div class="stat"><span>Wellen</span><b>{{ store.result.wave }}</b></div>
<div class="stat"><span>Abschüsse</span><b>{{ store.result.kills }}</b></div>
<div class="stat">
<span>Rekord</span>
<b>{{ store.result.best }}<template v-if="store.result.score >= store.result.best && store.result.bestBefore < store.result.score"> 🎉 neu!</template></b>
</div>
</div>
<div class="btns">
<template v-if="store.mp.active">
<button class="btn primary" @click="menu">🚪 Zurück zum Menü</button>
</template>
<template v-else>
<button v-if="store.result.win" class="btn primary" @click="endless"> Endlos weiterspielen</button>
<button class="btn" @click="restart">🔁 Nochmal spielen</button>
<button class="btn" @click="menu">🚪 Hauptmenü</button>
</template>
</div>
</div>
</div>
</template>
<style scoped>
.overlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(8, 11, 15, 0.72);
backdrop-filter: blur(3px);
border-radius: 10px;
z-index: 10;
}
.card {
background: var(--panel);
border: 1px solid var(--panel-border);
border-radius: 16px;
padding: 28px 36px;
text-align: center;
max-width: 420px;
animation: pop 0.3s ease;
transform: scale(var(--ui-scale, 1));
}
@keyframes pop {
from { opacity: 0; }
}
.emoji {
font-size: 52px;
}
h2 {
margin: 6px 0 4px;
font-size: 30px;
}
.win h2 { color: #ffd23e; }
.lose h2 { color: #ff7a6e; }
.msg {
color: var(--text-dim);
font-size: 14px;
margin: 0 0 16px;
}
.stats {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
margin-bottom: 18px;
}
.stat {
background: var(--panel-inset);
border-radius: 10px;
padding: 10px;
display: flex;
flex-direction: column;
gap: 2px;
}
.stat span {
font-size: 11px;
color: var(--text-dim);
}
.stat b {
font-size: 18px;
}
.btns {
display: flex;
gap: 8px;
justify-content: center;
flex-wrap: wrap;
}
.btn {
background: var(--panel-inset);
border: 1px solid var(--panel-border);
color: var(--text);
font-family: inherit;
font-weight: 700;
font-size: 13px;
border-radius: 10px;
padding: 10px 16px;
cursor: pointer;
}
.btn:hover {
border-color: var(--accent);
}
.btn.primary {
background: linear-gradient(180deg, #e0a83f, #c5832a);
border: none;
color: #fff;
}
</style>