Add skill system, level-ups, and new enemy types

This commit is contained in:
2026-08-17 16:38:58 +02:00
parent 4751d428a7
commit 6f207ba1a0
23 changed files with 2192 additions and 83 deletions
+123 -6
View File
@@ -7,7 +7,10 @@
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; background: #000; }
canvas { display: block; }
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;
@@ -50,6 +53,7 @@
#fireball-cooldown { bottom: 72px; }
#sword-cooldown { bottom: 48px; }
#teleport-cooldown { bottom: 24px; }
#lightning-cooldown { bottom: 96px; }
#wave-bar-container {
position: absolute; top: 16px; right: 16px; width: 250px; height: 16px;
}
@@ -102,22 +106,107 @@
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;
transition: opacity 0.3s ease; font-family: monospace;
}
#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: 140px; 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-title {
color: #ffcc00; font-size: 18px; font-weight: bold;
}
.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="health-bar-bg"></div>
<div id="health-bar"></div>
<div id="health-text">100%</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">
<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>
@@ -127,11 +216,16 @@
<div class="cooldown-fill"></div>
<div class="cooldown-label">Sword</div>
</div>
<div id="teleport-cooldown" class="cooldown-container">
<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="wave-bar-container">
<div id="wave-bar-bg"></div>
@@ -146,18 +240,41 @@
<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-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-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-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="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<br>
Linksklick: Feuerball · Rechtsklick: Schwert · M3: Hände tauschen · E: Teleport
Linksklick: Schwert · Rechtsklick: Feuerball (per Skill) · Q: Kettenblitz (per Skill) · E: Teleport (per Skill)
</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: Fireball · Right Click: Sword · M3: Swap hands · E: Teleport
WASD: Move · Space: Jump · Mouse: Aim · Left Click: Sword · Right Click: Fireball · Q: Lightning · E: Teleport
</div>
</div>
<script type="module" src="/src/main.ts"></script>