347 lines
15 KiB
HTML
347 lines
15 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Wackelpeter</title>
|
||
<style>
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
html, body { width: 100%; height: 100%; overflow: hidden; background: #000; }
|
||
canvas {
|
||
display: block;
|
||
cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill='none' stroke='%23140d02' stroke-width='4.5' stroke-linecap='round'%3E%3Ccircle cx='20' cy='20' r='13'/%3E%3Cpath d='M20 2v5M20 33v5M2 20h5M33 20h5'/%3E%3C/g%3E%3Cg fill='none' stroke='%23ffc83d' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='20' cy='20' r='13'/%3E%3Cpath d='M20 2v5M20 33v5M2 20h5M33 20h5'/%3E%3C/g%3E%3Cg fill='%23ffc83d' stroke='%23140d02' stroke-width='1'%3E%3Cpath d='M20 0l1.6 3.4L18.4 3.4Z'/%3E%3Cpath d='M20 40l1.6-3.4L18.4 36.6Z'/%3E%3Cpath d='M0 20l3.4-1.6L3.4 21.6Z'/%3E%3Cpath d='M40 20l-3.4-1.6L36.6 21.6Z'/%3E%3C/g%3E%3Cg fill='%23ffc83d' stroke='%23140d02' stroke-width='1'%3E%3Crect x='8.2' y='8.2' width='3.6' height='3.6' transform='rotate(45 10 10)'/%3E%3Crect x='28.2' y='8.2' width='3.6' height='3.6' transform='rotate(45 30 10)'/%3E%3Crect x='8.2' y='28.2' width='3.6' height='3.6' transform='rotate(45 10 30)'/%3E%3Crect x='28.2' y='28.2' width='3.6' height='3.6' transform='rotate(45 30 30)'/%3E%3C/g%3E%3Ccircle cx='20' cy='20' r='2.6' fill='%23ffe9a8' stroke='%23140d02' stroke-width='1'/%3E%3C/svg%3E") 20 20, crosshair;
|
||
}
|
||
#ui-overlay {
|
||
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
||
pointer-events: none; font-family: monospace; z-index: 10;
|
||
}
|
||
#damage-vignette {
|
||
position: absolute; inset: 0; opacity: 0; pointer-events: none;
|
||
background: radial-gradient(ellipse at center,
|
||
rgba(255,0,0,0) 40%, rgba(255,0,0,0.35) 100%);
|
||
box-shadow: inset 0 0 120px 40px rgba(255,0,0,0.5);
|
||
}
|
||
#damage-vignette.hurt { animation: hurt-flash 0.45s ease-out; }
|
||
@keyframes hurt-flash {
|
||
0% { opacity: 1; }
|
||
100% { opacity: 0; }
|
||
}
|
||
#low-hp-vignette {
|
||
position: absolute; inset: 0; opacity: 0; pointer-events: none;
|
||
background: radial-gradient(ellipse at center,
|
||
rgba(255,0,0,0.05) 0%, rgba(255,0,0,0.15) 55%, rgba(220,0,0,0.7) 100%);
|
||
box-shadow: inset 0 0 160px 60px rgba(220,0,0,0.55);
|
||
}
|
||
#low-hp-vignette.active { animation: low-hp-pulse 1.1s ease-in-out infinite; }
|
||
@keyframes low-hp-pulse {
|
||
0%, 100% { opacity: 0.25; }
|
||
50% { opacity: 0.6; }
|
||
}
|
||
#health-bar-bg {
|
||
position: absolute; top: 16px; left: 16px; width: 250px; height: 20px;
|
||
background: rgba(0,0,0,0.6); border: 2px solid #555;
|
||
}
|
||
#health-bar {
|
||
position: absolute; top: 16px; left: 16px; width: 250px; height: 20px;
|
||
background: #cc0000;
|
||
transition: width 0.1s linear;
|
||
}
|
||
#health-text {
|
||
position: absolute; top: 16px; left: 16px; width: 250px; height: 20px;
|
||
text-align: center; line-height: 20px; color: #fff; font-size: 12px;
|
||
}
|
||
#wave-label {
|
||
position: absolute; top: 48px; left: 16px; color: #ffcc00; font-size: 18px;
|
||
font-family: monospace; text-shadow: 2px 2px 4px #000;
|
||
}
|
||
#kills-label {
|
||
position: absolute; top: 72px; left: 16px; color: #ffcc00; font-size: 16px;
|
||
font-family: monospace; text-shadow: 2px 2px 4px #000;
|
||
}
|
||
.cooldown-container {
|
||
position: absolute; left: 16px; width: 200px; height: 16px;
|
||
}
|
||
.cooldown-bg {
|
||
width: 100%; height: 100%; background: rgba(0,0,0,0.6); border: 1px solid #555;
|
||
}
|
||
.cooldown-fill {
|
||
height: 100%; background: #2266dd; transition: width 0.05s linear;
|
||
}
|
||
.cooldown-label {
|
||
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
||
text-align: left; line-height: 16px; color: #fff; font-size: 11px;
|
||
padding-left: 4px; font-family: monospace;
|
||
}
|
||
#fireball-cooldown { bottom: 72px; }
|
||
#sword-cooldown { bottom: 48px; }
|
||
#teleport-cooldown { bottom: 24px; }
|
||
#lightning-cooldown { bottom: 96px; }
|
||
#trap-cooldown { bottom: 120px; }
|
||
#gas-cooldown { bottom: 144px; }
|
||
#wave-bar-container {
|
||
position: absolute; top: 16px; right: 16px; width: 250px; height: 16px;
|
||
}
|
||
#wave-bar-bg {
|
||
width: 100%; height: 100%; background: rgba(0,0,0,0.6); border: 1px solid #555;
|
||
}
|
||
#wave-bar-fill {
|
||
height: 100%; background: #ccaa00; transition: width 0.1s linear;
|
||
}
|
||
#wave-bar-label {
|
||
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
||
text-align: center; line-height: 16px; color: #fff; font-size: 11px;
|
||
font-family: monospace;
|
||
}
|
||
#game-over {
|
||
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
|
||
font-size: 100px; color: #fff; font-family: monospace; opacity: 0;
|
||
text-shadow: 4px 4px 8px #000;
|
||
transition: opacity 2s ease-in;
|
||
}
|
||
#game-over-panel {
|
||
position: absolute; top: 62%; left: 50%; transform: translate(-50%, -50%);
|
||
display: flex; flex-direction: column; align-items: center; gap: 12px;
|
||
pointer-events: none; opacity: 0; visibility: hidden;
|
||
transition: opacity 0.8s ease-in 1.5s;
|
||
font-family: monospace;
|
||
}
|
||
#game-over-stats {
|
||
color: #ffcc00; font-size: 20px; text-shadow: 2px 2px 4px #000;
|
||
}
|
||
.menu-button {
|
||
pointer-events: auto; cursor: pointer;
|
||
background: rgba(0,0,0,0.7); color: #fff; font-family: monospace;
|
||
font-size: 18px; padding: 10px 28px; border: 2px solid #888;
|
||
}
|
||
.menu-button:hover { background: #333; border-color: #ffcc00; color: #ffcc00; }
|
||
#main-menu {
|
||
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||
gap: 18px; pointer-events: auto; background: rgba(0,0,0,0.55);
|
||
transition: opacity 0.6s ease; font-family: monospace;
|
||
}
|
||
#main-menu h1 {
|
||
color: #fff; font-size: 72px; text-shadow: 4px 4px 8px #000;
|
||
}
|
||
#main-menu .subtitle {
|
||
color: #ffcc00; font-size: 20px; text-shadow: 2px 2px 4px #000;
|
||
}
|
||
#main-menu .menu-controls {
|
||
color: rgba(255,255,255,0.8); font-size: 13px; text-align: center;
|
||
line-height: 1.7;
|
||
}
|
||
#btn-start { font-size: 24px; padding: 14px 48px; }
|
||
#btn-confirm { font-size: 18px; padding: 10px 36px; }
|
||
#btn-confirm:disabled { opacity: 0.35; cursor: default; }
|
||
#instructions {
|
||
position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%);
|
||
color: rgba(255,255,255,0.5); font-size: 11px; font-family: monospace;
|
||
text-align: center;
|
||
}
|
||
#seed-input {
|
||
background: rgba(0,0,0,0.7); border: 2px solid #555; color: #ffcc00;
|
||
font-family: monospace; font-size: 16px; padding: 6px 10px; width: 180px;
|
||
text-align: center; outline: none;
|
||
}
|
||
#seed-input:focus { border-color: #ffcc00; }
|
||
#level-label {
|
||
position: absolute; top: 96px; left: 16px; color: #88ff88; font-size: 16px;
|
||
font-family: monospace; text-shadow: 2px 2px 4px #000;
|
||
}
|
||
#seed-label {
|
||
position: absolute; top: 96px; right: 16px; color: rgba(255,255,255,0.6);
|
||
font-size: 12px; font-family: monospace; text-shadow: 1px 1px 2px #000;
|
||
}
|
||
#xp-bar-container {
|
||
position: absolute; top: 120px; left: 16px; width: 250px; height: 12px;
|
||
}
|
||
#xp-bar-bg {
|
||
width: 100%; height: 100%; background: rgba(0,0,0,0.6); border: 1px solid #555;
|
||
}
|
||
#xp-bar-fill {
|
||
height: 100%; background: #44cc44; transition: width 0.1s linear;
|
||
}
|
||
#xp-bar-label {
|
||
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
||
text-align: center; line-height: 12px; color: #fff; font-size: 10px;
|
||
font-family: monospace;
|
||
}
|
||
#shield-bar-bg {
|
||
position: absolute; top: 44px; left: 16px; width: 250px; height: 10px;
|
||
background: rgba(0,0,0,0.6); border: 1px solid #555; display: none;
|
||
}
|
||
#shield-bar {
|
||
position: absolute; top: 44px; left: 16px; width: 250px; height: 10px;
|
||
background: #3399ff; transition: width 0.1s linear; display: none;
|
||
}
|
||
#shield-text {
|
||
position: absolute; top: 44px; left: 16px; width: 250px; height: 10px;
|
||
text-align: center; line-height: 10px; color: #fff; font-size: 9px;
|
||
font-family: monospace; display: none;
|
||
}
|
||
#level-up {
|
||
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||
gap: 24px; background: rgba(0,0,0,0.7); opacity: 0; pointer-events: none;
|
||
visibility: hidden; transition: opacity 0.3s ease; font-family: monospace;
|
||
}
|
||
#pause-overlay {
|
||
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||
gap: 18px; background: rgba(0,0,0,0.6); opacity: 0; pointer-events: none;
|
||
visibility: hidden; transition: opacity 0.2s ease; font-family: monospace;
|
||
}
|
||
#pause-overlay h2 {
|
||
color: #fff; font-size: 48px; text-shadow: 3px 3px 6px #000;
|
||
}
|
||
#level-up h2 {
|
||
color: #ffcc00; font-size: 44px; text-shadow: 3px 3px 6px #000;
|
||
}
|
||
#offer-row {
|
||
display: flex; gap: 20px;
|
||
}
|
||
.offer-card {
|
||
width: 230px; min-height: 220px; background: rgba(20,20,30,0.9);
|
||
border: 2px solid #888; padding: 14px; cursor: pointer;
|
||
display: flex; flex-direction: column; gap: 10px;
|
||
transition: transform 0.1s ease, border-color 0.1s ease;
|
||
}
|
||
.offer-card:hover { border-color: #ffcc00; background: rgba(40,40,50,0.95); }
|
||
.offer-card.selected {
|
||
border-color: #ffcc00; background: rgba(60,50,20,0.95);
|
||
transform: scale(1.04); box-shadow: 0 0 18px rgba(255,204,0,0.4);
|
||
}
|
||
.offer-icon {
|
||
width: 76px; height: 76px; margin: 2px auto 0;
|
||
filter: drop-shadow(0 3px 6px rgba(0,0,0,0.55));
|
||
transition: filter 0.1s ease;
|
||
}
|
||
.offer-icon svg { width: 100%; height: 100%; display: block; }
|
||
.offer-card:hover .offer-icon, .offer-card.selected .offer-icon {
|
||
filter: drop-shadow(0 0 9px rgba(255,204,0,0.5));
|
||
}
|
||
.offer-title {
|
||
color: #ffcc00; font-size: 18px; font-weight: bold; text-align: center;
|
||
}
|
||
.offer-desc {
|
||
color: rgba(255,255,255,0.85); font-size: 13px; line-height: 1.5;
|
||
}
|
||
.offer-hint {
|
||
color: rgba(255,255,255,0.4); font-size: 12px; margin-top: auto;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="ui-overlay">
|
||
<div id="damage-vignette"></div>
|
||
<div id="low-hp-vignette"></div>
|
||
<div id="health-bar-bg"></div>
|
||
<div id="health-bar"></div>
|
||
<div id="health-text">100</div>
|
||
<div id="shield-bar-bg"></div>
|
||
<div id="shield-bar"></div>
|
||
<div id="shield-text"></div>
|
||
<div id="wave-label">Wave 0</div>
|
||
<div id="kills-label">Kills: 0</div>
|
||
<div id="level-label">Level 0</div>
|
||
<div id="xp-bar-container">
|
||
<div id="xp-bar-bg"></div>
|
||
<div id="xp-bar-fill"></div>
|
||
<div id="xp-bar-label">XP: 0/20</div>
|
||
</div>
|
||
<div id="seed-label"></div>
|
||
|
||
<div id="fireball-cooldown" class="cooldown-container" style="display: none">
|
||
<div class="cooldown-bg"></div>
|
||
<div class="cooldown-fill"></div>
|
||
<div class="cooldown-label">Fireball</div>
|
||
</div>
|
||
<div id="sword-cooldown" class="cooldown-container">
|
||
<div class="cooldown-bg"></div>
|
||
<div class="cooldown-fill"></div>
|
||
<div class="cooldown-label">Sword</div>
|
||
</div>
|
||
<div id="teleport-cooldown" class="cooldown-container" style="display: none">
|
||
<div class="cooldown-bg"></div>
|
||
<div class="cooldown-fill"></div>
|
||
<div class="cooldown-label">Teleport</div>
|
||
</div>
|
||
<div id="lightning-cooldown" class="cooldown-container" style="display: none">
|
||
<div class="cooldown-bg"></div>
|
||
<div class="cooldown-fill"></div>
|
||
<div class="cooldown-label">Chain Lightning</div>
|
||
</div>
|
||
<div id="trap-cooldown" class="cooldown-container" style="display: none">
|
||
<div class="cooldown-bg"></div>
|
||
<div class="cooldown-fill"></div>
|
||
<div class="cooldown-label">Falle</div>
|
||
</div>
|
||
<div id="gas-cooldown" class="cooldown-container" style="display: none">
|
||
<div class="cooldown-bg"></div>
|
||
<div class="cooldown-fill"></div>
|
||
<div class="cooldown-label">Gaswolke</div>
|
||
</div>
|
||
|
||
<div id="wave-bar-container">
|
||
<div id="wave-bar-bg"></div>
|
||
<div id="wave-bar-fill"></div>
|
||
<div id="wave-bar-label">Next Wave...</div>
|
||
</div>
|
||
|
||
<div id="game-over">Verloren!</div>
|
||
<div id="game-over-panel">
|
||
<div id="game-over-stats"></div>
|
||
<button id="btn-restart" class="menu-button">Nochmal spielen</button>
|
||
<button id="btn-menu" class="menu-button">Hauptmenü</button>
|
||
</div>
|
||
|
||
<div id="level-up">
|
||
<h2>Level Up!</h2> <div id="offer-row">
|
||
<div id="offer-0" class="offer-card">
|
||
<div id="offer-icon-0" class="offer-icon"></div>
|
||
<div id="offer-title-0" class="offer-title"></div>
|
||
<div id="offer-desc-0" class="offer-desc"></div>
|
||
<div class="offer-hint">[1] auswählen</div>
|
||
</div>
|
||
<div id="offer-1" class="offer-card">
|
||
<div id="offer-icon-1" class="offer-icon"></div>
|
||
<div id="offer-title-1" class="offer-title"></div>
|
||
<div id="offer-desc-1" class="offer-desc"></div>
|
||
<div class="offer-hint">[2] auswählen</div>
|
||
</div>
|
||
<div id="offer-2" class="offer-card">
|
||
<div id="offer-icon-2" class="offer-icon"></div>
|
||
<div id="offer-title-2" class="offer-title"></div>
|
||
<div id="offer-desc-2" class="offer-desc"></div>
|
||
<div class="offer-hint">[3] auswählen</div>
|
||
</div>
|
||
</div>
|
||
<button id="btn-confirm" class="menu-button" disabled>Bestätigen (Enter)</button>
|
||
</div>
|
||
|
||
<div id="pause-overlay">
|
||
<h2>Pausiert</h2>
|
||
<button id="btn-resume" class="menu-button">Weiter (ESC)</button>
|
||
<button id="btn-pause-menu" class="menu-button">Hauptmenü</button>
|
||
</div>
|
||
|
||
<div id="main-menu">
|
||
<h1>WACKELPETER</h1>
|
||
<div class="subtitle">Ein Blob kämpft ums Überleben</div>
|
||
<div class="menu-controls">
|
||
WASD: Bewegen · Space: Springen · Maus: Zielen · ESC: Pause<br>
|
||
Linksklick: Schwert · Rechtsklick: Feuerball (per Skill)<br>
|
||
Q, E, 1–4: Skills (werden nach Erwerb belegt)
|
||
</div>
|
||
<input id="seed-input" type="text" placeholder="Seed (leer = zufällig)" />
|
||
<button id="btn-start" class="menu-button">Start</button>
|
||
</div>
|
||
|
||
<div id="instructions">
|
||
WASD: Move · Space: Jump · Mouse: Aim · Left Click: Sword · Right Click: Fireball · Q/E/1-4: Skills · ESC: Pause
|
||
</div>
|
||
</div>
|
||
<script type="module" src="/src/main.ts"></script>
|
||
</body>
|
||
</html>
|