212 lines
10 KiB
Markdown
212 lines
10 KiB
Markdown
# Game Design
|
||
|
||
Alle Werte stehen zentral in `app/static/js/config.js`. Die Tabellen hier geben den
|
||
Stand zum Zeitpunkt des Schreibens wieder. Bei Abweichungen gilt `config.js`.
|
||
Einheiten: Pixel (px), px/s, Millisekunden (ms), Lebenspunkte (LP).
|
||
|
||
## Welt und Ton
|
||
|
||
- **Setting:** Die fiktive „Vereinigte Erde“ wird von zwei außerirdischen Fraktionen
|
||
angegriffen. Präsident Maximilian Valor verteidigt „den ewigen Frieden“ persönlich.
|
||
- **Satire:** Durchsagen des „Ministeriums für Zuversicht“ zwischen den Wellen,
|
||
Briefings, Game-Over-Texte. Der Spott gilt Militarismus und Propaganda im
|
||
Allgemeinen, nicht realen Personen, Parteien oder Ländern. Namen und Begriffe sind
|
||
eigenständig. Ein Test (`tests/test_assets.py`) verhindert Begriffe aus bekannten
|
||
Vorbildern.
|
||
- **Arena:** 2400 × 1600 px, größer als der Bildschirm (1280 × 720). Die Kamera folgt
|
||
dem Präsidenten. Gegner außerhalb des Bildes zeigt das HUD als Randpfeile an.
|
||
|
||
## Der Präsident
|
||
|
||
| Wert | |
|
||
|---|---|
|
||
| Leben | 100 LP |
|
||
| Tempo | 240 px/s (diagonal gleich schnell) |
|
||
| Hitbox | Kreis, Radius 18 px |
|
||
| Unverwundbarkeit nach Treffer | 500 ms (sonst tötet ein Schwarm in einem Frame) |
|
||
| Ausweichrolle | 640 px/s für 320 ms, unverwundbar, Abklingzeit 1500 ms. Ohne Bewegung in Blickrichtung. |
|
||
| Heilung nach jeder Welle | 15 LP |
|
||
|
||
Treffer am Präsidenten beenden die Punkteserie. Gegnerprojektile fliegen während der
|
||
Rolle hindurch, statt verschluckt zu werden.
|
||
|
||
## Waffen
|
||
|
||
| | Karabiner »Zuversicht« | Schrotflinte »Überzeugungskraft« | Dienstpistole »Anstand« |
|
||
|---|---|---|---|
|
||
| Taste | 1 | 2 | 3 |
|
||
| Modus | Dauerfeuer | Einzelschuss | Einzelschuss |
|
||
| Schaden | 14 | 8 × 11 (Schrot) | 16 |
|
||
| Feuerpause | 110 ms | 650 ms | 260 ms |
|
||
| Magazin / Reserve (Start, max.) | 30 / 180, 270 | 6 / 24, 48 | 12 / unbegrenzt |
|
||
| Nachladen | 1,5 s | 1,9 s | 1,1 s |
|
||
| Streuung | 3° | 24° Fächer | 2° |
|
||
| Reichweite | 820 px | 420 px | 700 px |
|
||
| Schaden/s (Feuerstoß / mit Nachladen) | 127 / 88 | 135 / 91 | 62 / 45 |
|
||
|
||
- Leeres Magazin lädt automatisch nach. Ein Waffenwechsel bricht das Nachladen ab.
|
||
- Sind Magazin und Reserve leer, wechselt das Spiel automatisch zur Dienstpistole.
|
||
Ohne Munition ist man also nie wehrlos.
|
||
- Die Nachschubkapsel füllt die Reserve aller Waffen auf das Maximum.
|
||
|
||
## Gegner
|
||
|
||
### Die Schwärmer (insektoid, Nahkampf)
|
||
|
||
| | Krabbler (klein) | Sprungkralle (mittel) | Brutmutter (Elite) |
|
||
|---|---|---|---|
|
||
| Leben | 20 | 60 | 450 |
|
||
| Tempo | 175 | 125 | 58 |
|
||
| Kontaktschaden (Abklingzeit) | 6 (700 ms) | 14 (800 ms) | 28 (1000 ms) |
|
||
| Punkte | 10 | 30 | 250 |
|
||
| Budgetkosten | 1 | 3 | 15 |
|
||
| Gruppengröße | 4–8 | 1–3 | 1 |
|
||
| Verhalten | Umzingeln | Sprungangriff | Brüten |
|
||
|
||
- **Umzingeln:** Jeder Krabbler bekommt einen eigenen Anflugwinkel auf einem Kreis
|
||
(130 px) um den Präsidenten. Ab 170 px Abstand greift er direkt an. Ein Rudel
|
||
kommt dadurch von mehreren Seiten.
|
||
- **Sprungangriff:** Verfolgen. Ab 260 px setzt die Sprungkralle 450 ms an: sie steht
|
||
still, färbt sich rot und wird größer. Dann springt sie mit 560 px/s für 380 ms in
|
||
die beim Ansetzen festgelegte Richtung. Wer auf die Vorwarnung reagiert, kann
|
||
ausweichen. Abklingzeit 2,4 s.
|
||
- **Brüten:** Langsames Verfolgen, alle 5 s schlüpfen bis zu 3 Krabbler, höchstens 6
|
||
gleichzeitig lebende Nachkommen.
|
||
|
||
### Die Blechlegion (Roboter, Fernkampf)
|
||
|
||
| | Nieter-Drohne (klein) | Blechsoldat (mittel) | Walzmeister (Elite) |
|
||
|---|---|---|---|
|
||
| Leben | 30 | 90 | 700 |
|
||
| Tempo | 95 | 78 | 44 |
|
||
| Wunschabstand | 220–340 px | 200–380 px | 260–460 px |
|
||
| Angriff | Einzelschuss 7, alle 1,5 s | 3er-Salve à 8, alle 2,3 s | Fächer aus 7 × 10 (50°), alle 2,7 s + Mörser |
|
||
| Projektiltempo | 330 | 400 | 290 |
|
||
| Punkte | 20 | 50 | 400 |
|
||
| Budgetkosten | 2 | 4 | 18 |
|
||
| Gruppengröße | 2–3 | 1–3 | 1 |
|
||
| Verhalten | Abstand halten | Flankieren | Belagern |
|
||
|
||
- **Abstand halten:** Zu weit weg → annähern, zu nah → zurückweichen, dazwischen seitlich
|
||
ausweichen. Die Richtung wechselt zufällig alle 1,4–3,2 s. So sind Fernkämpfer
|
||
kein stehendes Ziel.
|
||
- **Flankieren:** Ziel ist ein Punkt, der gegenüber der Linie Präsident→Gegner um 70°
|
||
gedreht ist (Abstand 290 px). Der Blechsoldat schwenkt also seitlich ein, statt
|
||
frontal anzulaufen. Dort angekommen, hält er Abstand.
|
||
- **Mörser (Walzmeister):** Alle 5,2 s zielt er auf die aktuelle Position des
|
||
Präsidenten. Eine rote Bodenmarkierung (Radius 90 px) füllt sich 1,4 s lang, dann
|
||
folgt der Einschlag (26 Schaden). Stehenbleiben ist keine Option.
|
||
- Frisch gespawnte Gegner schießen frühestens nach etwa 0,5–1,6 s. Das ist fair,
|
||
weil sonst Salven aus dem Nichts kämen.
|
||
|
||
### Allgemeine KI
|
||
|
||
Alle Bewegungen sind Steuerungsvektoren (`logic/steering.js`), die sich überlagern.
|
||
Eine Separation (Radius 34 px + Gegnerradius) schiebt Gegner auseinander und
|
||
verhindert Klumpen. Die Geschwindigkeit wird weich nachgeführt (18 % pro Frame),
|
||
damit Richtungswechsel nicht ruckeln. Nahkämpfer bleiben am Rand des Präsidenten
|
||
stehen, statt sich auf seinen Mittelpunkt zu drängen.
|
||
|
||
## Orbital-Befehle
|
||
|
||
Eingabe: **Q gedrückt halten** und die Richtungsfolge mit Pfeiltasten oder WASD
|
||
eingeben. Während der Eingabe steht der Präsident still. Das Ziel ist die
|
||
Mausposition, begrenzt auf 560 px Entfernung und die Arena. Falsche Eingaben leeren
|
||
den Puffer, man kann sofort neu ansetzen. Keine Folge ist der Anfang einer anderen,
|
||
und jede beginnt mit einer anderen Richtung (wird getestet). Die Codes sind eigene
|
||
Erfindungen. Der Orbitalschlag-Code ↑ → ↓ ↓ stammt aus der Projektvorgabe. Ein Test
|
||
stellt sicher, dass keiner der Codes einem Code aus einem bekannten Spiel mit
|
||
ähnlicher Mechanik entspricht.
|
||
|
||
| Befehl | Code | Verzögerung | Abklingzeit | Wirkung |
|
||
|---|---|---|---|---|
|
||
| Orbitalschlag »Morgenröte« | ↑ → ↓ ↓ | 2,5 s | 30 s | Radius 150 px, 260 Schaden an Gegnern, **40 am Präsidenten**, falls er im Radius steht |
|
||
| Nachschubkapsel »Fürsorgepaket« | ← ← ↓ → | 3 s | 45 s | Einschlag: Radius 70 px, 120 Schaden (20 am Präsidenten). Danach liegt 30 s eine Kapsel: +50 LP, volle Reserve. |
|
||
| Geschütz »Wachsamer Nachbar« | → ← → ↑ ↑ | 3 s | 60 s | Einschlag: Radius 60 px, 80 Schaden (15 am Präsidenten). Danach 25 s Geschütz: zielt auf den nächsten Gegner (480 px), 12 Schaden alle 150 ms |
|
||
|
||
Bis zum Einschlag zeigt eine Bodenmarkierung den genauen Wirkungsradius, einen
|
||
Strahl aus dem Orbit und einen Countdown. Kapsel und Geschütz blinken in ihren
|
||
letzten 3 Sekunden.
|
||
|
||
## Wellen
|
||
|
||
- **Budget:** `B(n) = 8 + 5 · (n − 1)^1,15`, gerundet. Gegner „kosten“ Budget
|
||
(Tabellen oben).
|
||
- **Fraktionen:** Wellen 1–2 nur Schwärmer, 3–4 nur Blechlegion, ab 5 gemischt.
|
||
- **Eliten:** jede 5. Welle, Anzahl = Welle / 5 (max. 4). Die erste Elite ist eine
|
||
Brutmutter, danach wechselt die Fraktion.
|
||
- **Zusammenstellung:** Zuerst werden Eliten gekauft (mindestens 30 % des Budgets
|
||
bleiben für Fußvolk). Dann gehen `10 % + 4 % · (n − 1)` des Restbudgets
|
||
(max. 50 %) in mittlere Gegner, der Rest in kleine. Gruppengrößen je Typ.
|
||
- **Ablauf:** Gruppen erscheinen nacheinander (1,3–3 s Abstand, in späten Wellen bis
|
||
zu 55 % dichter) an zufälligen Arenarändern, nie näher als 420 px am Präsidenten.
|
||
Leben mehr als 60 Gegner, wartet der Spawner.
|
||
- **Skalierung ab Welle 6:** +7 % Leben und +1,2 % Tempo pro Welle (Tempo max. +30 %).
|
||
- **Pause:** 8 s zwischen den Wellen mit Propaganda-Durchsage (ohne direkte
|
||
Wiederholung), Wellenbonus und Heilung.
|
||
|
||
| Welle | Budget | Eliten | Leben × | Tempo × | Ø Gegner |
|
||
|---|---|---|---|---|---|
|
||
| 1 | 8 | 0 | 1,00 | 1,00 | 8 |
|
||
| 3 | 19 | 0 | 1,00 | 1,00 | 9 |
|
||
| 5 | 33 | 1 | 1,00 | 1,00 | 14 |
|
||
| 10 | 71 | 2 | 1,35 | 1,06 | 23 |
|
||
| 15 | 112 | 3 | 1,70 | 1,12 | 37 |
|
||
| 20 | 156 | 4 | 2,05 | 1,18 | 52 |
|
||
|
||
(Ø Gegner ohne ausgebrütete Krabbler, gemittelt über 50 Zufalls-Seeds.)
|
||
|
||
## Punkte
|
||
|
||
- Abschuss: Punkte des Gegnertyps × Multiplikator
|
||
- **Serie:** Jeder Abschuss innerhalb von 3 s nach dem letzten setzt die Serie fort.
|
||
Alle 5 Abschüsse steigt der Multiplikator um 0,5, bis maximal ×4.
|
||
- Ein Treffer am Präsidenten beendet die Serie.
|
||
- **Wellenbonus:** 100 × Wellennummer (ohne Multiplikator)
|
||
|
||
### Plausibilitätsgrenzen im Backend
|
||
|
||
`app/config.py` (`GAME_RULE_DEFAULTS`) lehnt Einreichungen ab, wenn
|
||
|
||
1. die gemeldete Spieldauer länger ist als die Zeit seit Ausgabe des Run-Tokens
|
||
(+30 s Toleranz). Pausen zählen nicht zur Spieldauer, daher darf sie kürzer sein.
|
||
2. die Welle in der Spieldauer nicht erreichbar ist: `Dauer ≥ (Welle − 1) · 5 s`,
|
||
denn jede Pause dauert 8 s.
|
||
3. die Punkte über `2000 + 200 · Dauer in s` liegen.
|
||
|
||
Herleitung der 200 Punkte/s: Testläufe (Bot mit perfektem Zielen) liegen bei etwa
|
||
15–20 Punkten/s. Eine grobe Abschätzung für eine sehr starke Runde (Welle 25 nach
|
||
20 Minuten, Multiplikator dauerhaft hoch) ergibt 80–120 Punkte/s im Schnitt. 200/s
|
||
im **Durchschnitt über die ganze Runde** lässt also Luft, schneidet aber
|
||
Fantasiewerte ab. Der Sockel von 2000 deckt kurze Runden mit Glückstreffern ab. Wer
|
||
Punktwerte in `config.js` stark erhöht, muss diese Grenze mit anpassen.
|
||
|
||
Wie jede Prüfung im Backend verhindert das kein gezieltes Cheaten (die Spiellogik
|
||
läuft im Browser). Für Ausreißer gibt es die Moderationsbefehle (siehe
|
||
`docs/DEPLOYMENT_CPANEL.md`).
|
||
|
||
## Schwierigkeit
|
||
|
||
Ein Testbot (perfektes Zielen, weicht nur zurück, ohne Rolle, Orbital-Befehle und
|
||
Nachschub) erreicht Welle 5 nach etwa 2 Minuten. Die erste Elite-Welle mit Brutmutter
|
||
ist bewusst die erste echte Hürde. Wer Rolle, Orbitalschlag und Nachschub nutzt,
|
||
kommt deutlich weiter. Stellschrauben, wenn das Spiel zu schwer oder zu leicht wirkt:
|
||
|
||
- `WAVES.budgetGrowth` / `budgetExponent`: Größe der Wellen
|
||
- `WAVES.hpScalePerWave`: Zähigkeit in späten Wellen
|
||
- `PLAYER.waveClearHeal`, `ORBITAL.commands[supply].heal`: Heilung
|
||
- `ENEMY_TYPES.*.contactDamage` / `attack.damage`: Schaden der Gegner
|
||
|
||
## Rückmeldung (Feedback)
|
||
|
||
- Trefferblitz (weiß), Funken in Fraktionsfarbe, Punkte als schwebender Text
|
||
- neue Multiplikatorstufe als „SERIE ×2“ über dem Präsidenten
|
||
- Explosionen mit Feuer, Rauch, Lichtblitz, Brandspur und Wirkungsring (zeigt den Radius)
|
||
- Bildschirmwackeln bei Treffern und Explosionen, rote Vignette bei Schaden,
|
||
pulsierender Rand unter 30 % Leben
|
||
- Ausweichrolle mit Nachbild
|
||
- Randpfeile für Gegner außerhalb des Bildes (Eliten in Gold)
|
||
- Ton: Kenney-Klänge mit leichter Tonhöhenstreuung, synthetischer Ersatz,
|
||
Marschmusik (in der Pause gedämpft), Jingles für Wellenstart, Wellenende,
|
||
Elite-Alarm und Game Over
|