diff --git a/docs/spec-vertical-slice.md b/docs/spec-vertical-slice.md new file mode 100644 index 0000000..4673fd8 --- /dev/null +++ b/docs/spec-vertical-slice.md @@ -0,0 +1,525 @@ +# Vertical-Slice-Spec: InfiniTower + +- **Status:** Angenommen +- **Datum:** 2026-08-10 +- **Betrifft:** Den vollständigen Funktionsumfang des Vertical Slice — was gebaut wird und woran + wir erkennen, dass es fertig ist +- **Baut auf:** [ADR-0001](adr/0001-balancing-daten-als-rust-konstanten.md) (Balancing-Daten), + [ADR-0002](adr/0002-stat-und-modifier-pipeline.md) (Stat- und Modifier-Pipeline), + [ADR-0003](adr/0003-save-format-ort-und-migration.md) (Save-Format), `CONTEXT.md` (Glossar und + Slice-Scope), Karte in Issue #1 +- **Vokabular:** verbindlich aus `CONTEXT.md`. Diese Spec führt keine neuen Begriffe ein, außer den + beiden in Abschnitt „Zwei Grenzwerte, zwei Begriffe" ausgewiesenen. + +Diese Spec sagt, **was** gebaut wird. Die ADRs sagen, **warum es so** gebaut wird — ihre Argumente +werden hier nicht wiederholt, sondern verlinkt. Wo eine Zahl noch nicht feststeht, steht sie als +‹Platzhalter›; sie lebt dann in `Balance` (ADR-0001) und wird durch Spielen gefunden, nicht hier. + +--- + +## Der Loop + +Der Spieler startet einen Run. Der Turm steht in der Mitte der Arena und schießt von selbst auf +Gegner, die in Wellen radial von außen anlaufen; jeder Kill gibt Coins, und aus Coins kauft der +Spieler jederzeit In-Run-Upgrades, die den Turm für diesen Run stärker machen. Die Wellen wachsen +schneller als das, was er sich leisten kann — nach sechs bis neun Minuten überrennen sie ihn, der +Turm stirbt, und alle In-Run-Upgrades verfallen mit ihm. Was bleibt, ist die Meta-Währung, die die +Gegner unterwegs gedroppt haben, und was der Boss auf Welle 10 fallen gelassen hat. Damit kauft er +zwischen den Runs permanente Workshop-Upgrades und rüstet gedroppte Cards aus. Der nächste Run +beginnt mit einem stärkeren Turm, kommt tiefer, wirft mehr ab — und endet wieder. Das ist das +Spiel: sterben ist der Fortschrittsmechanismus, nicht sein Gegenteil. + +--- + +## Zwei Grenzwerte, zwei Begriffe + +Die Karte nennt beides „Cap", meint aber zwei verschiedene Dinge. Diese Spec trennt sie, und der +Code tut es auch: + +| Begriff | Code | Bedeutung | +|---|---|---| +| **Harte Obergrenze** | `HARD_ENEMY_CAP` | 10 000 gleichzeitige Gegner. Ein Perf-Grenzwert aus #4, kein Design-Werkzeug. Wird nie überschritten, von nichts. | +| **Soll-Population** | `target_population(wave)` | Die für die aktuelle Welle angestrebte Zahl lebender Gegner. Wächst mit dem Wellenzähler und ist selbst Teil der Schwierigkeitskurve. Bindet ständig — sie ist die Design-Zielgröße. | + +Ein Effekt, der „mehr Gegner" verspricht, hebt die **Soll-Population** an, nie eine Spawn-Zahl +(Begründung: Cap-Analyse in Issue #1 — bei bindender Soll-Population wäre ein Spawn-Multiplikator +exakt wirkungslos). Die harte Obergrenze bleibt davon unberührt. + +--- + +## Feststehende Zahlen + +Alles hier ist entschieden. Alles andere ist ‹Platzhalter› oder steht unter „Offen". + +| Größe | Wert | Quelle | +|---|---|---| +| Wellen-Takt | ‹26 s› Spawn-Phase + ‹9 s› Cooldown-Phase = ‹35 s› bei Normalgeschwindigkeit | Primärtext, als Startwert übernommen (#8) | +| Wellen pro Spielzeit | 10 min ≈ 17 Wellen · 20 min ≈ 34 · 30 min ≈ 51 | Folge des Takts (#8) | +| Boss-Welle | jede 10. Welle | Primärtext (#3), übernommen | +| Ziel für Run 1 | Tod zwischen **Welle 10 und 15** — genau ein Boss gesehen, kurz danach tot; 6–9 Minuten | #8 | +| Wachstumsform | konstant exponentiell pro Welle, plus ein Multiplikator auf Boss-Wellen | #8 | +| Kosten- vs. HP-Verlauf | Kosten wachsen anfangs langsamer als Gegner-HP, ab ca. zwei Dritteln der Runlänge überholt die HP-Kurve. Entsteht von selbst, wenn der Kosten-Exponent das Einkommenswachstum übersteigt — **kein separater Knick** | #8 | +| Meta-Ertrag | Drop-basiert: Chance je Normalgegner, **garantiert je Boss**; gedroppte Menge wellenabhängig | #8 | +| Workshop-Kosten | exponentiell pro Level | #8 | +| Tuning-Zielgröße im Run | Zeit zwischen zwei bezahlbaren Käufen: früh ‹10–20 s›, später seltener | #8 | +| Harte Gegner-Obergrenze | 10 000 gleichzeitig (gemessener Bruch bei ~70 000, ohne Texturen/UI/Audio) | #4, Issue #1 | +| Perf-Budget bei 10 000 | Gameplay-Logik 0,114 ms von 16,67 ms; Rendering 96–98 % | #4 | +| In-Run-Shop-Struktur | vier Tabs: **Attack Shop · Defence Shop · Utility Shop · Ultimates** | HUD-Mockup, #10 | +| Shop-Kapazität | ~8 Zeilen je Tab ohne Scrollen → Größenordnung **~24 In-Run-Upgrades** | HUD-Mockup, #10 | +| Kauf-Modus | Buy x1, Kosten pro Kauf, **jederzeit** im Run — kein Wellenende, keine Freigabe | Issue #1, #8 | +| Card-Seltenheiten | drei: **Common / Rare / Epic** | #11 | +| Card-Slots | Start **1**, Wachstum auf **5**; die Slot-Zahl ist selbst Progression | #11 | +| Card-Quelle | Drop aus Fortschritt (Boss-Kill, neuer Wellen-Rekord). Kein Kauf, keine dritte Währung | #11 | +| Card-Randbedingungen | Slot 2 fällt **früh** (erste paar Runs); **mindestens zwei Epics** | #11 | +| Ultimate | genau eine: **Death Wave**, radialer Sweep, automatisch ausgelöst | #9 | +| Auslöse-Regel | **Cooldown UND ein Weltzustand**, je Fähigkeit fest verdrahtet, nicht einstellbar; feuern mehrere gleichzeitig, feuern alle | #12 | +| Währungen | zwei: `Coins` (In-Run, verfällt) und die Meta-Währung (Workshop). Nicht ineinander konvertierbar | Issue #1, #11 | +| Turm-Stats | 12, siehe Tabelle in ADR-0002 §3 | ADR-0002 | + +**Prüfkriterium für die fertige Kurve** (#8, gilt für die vier freien Zahlen): + +1. Run 1 endet zwischen Welle 10 und 15. +2. Jeder Run trägt mindestens ein Workshop-Level ein. +3. Die Run-Tiefe wächst über die ersten zehn Runs monoton, ohne dass ein Run mehr als etwa das + Doppelte des vorigen erreicht. + +--- + +## Was im Slice ist + +### 1. Arena, Turm und Kamera + +2D, `bevy_sprite`, orthographische Kamera. Ein `Tower` fest in der Mitte, Programmer-Art. Kein +Scrollen, kein Zoom, keine Turm-Platzierung. + +**Akzeptanz** +- Nach Programmstart und Run-Start ist der Turm sichtbar in der Bildmitte des Gameplay-Fensters, und + die gesamte Spawn-Peripherie liegt innerhalb des sichtbaren Bereichs. +- Die Turm-Entity wird beim Run-Start gespawnt und beim Run-Ende despawnt (ADR-0002 §6); zwischen + zwei Runs existiert keine Entity mit `EffectiveStats`. + +### 2. Wellen-Takt + +Eine `Wave` besteht aus zwei separat getakteten Phasen. Die nächste Welle beginnt, wenn **beide** +Timer abgelaufen sind — nicht wenn alle Gegner tot sind. Eine einzige endlose Kurve, keine Tiers. + +**Akzeptanz** +- Während der Spawn-Phase erscheinen Gegner; nach ‹26 s› hören Spawns auf, während bereits + vorhandene Gegner weiter laufen und angreifen; nach weiteren ‹9 s› beginnt Welle N+1. +- Wird Welle N+1 gestartet, während noch Gegner aus Welle N leben, laufen diese unverändert weiter + und werden nicht entfernt. +- Der aktuelle Wellenzähler ist im HUD ablesbar und stimmt mit dem Telemetrie-Log überein. +- Auf jeder Welle mit `wave % 10 == 0` spawnt genau ein Boss. + +### 3. Gegner und Population + +Drei bis vier Normal-Archetypen plus ein Boss (#3): ein Tempo/HP-Tradeoff-Paar, ein Fernkämpfer und +**eine** Sondermechanik, die Ziel-Priorisierung erzwingt (Splitter oder Schutz-Aura). Der Boss ist +ein einzelner schwerer, langsamer Meilenstein-Gegner. Keine Elite-Klasse, keine Fleet-Klasse, keine +Immunitätsmatrix. + +Der Spawner ist **cap-getrieben, nicht plan-getrieben**: er füllt bis zur `target_population(wave)` +auf, statt N Gegner nach Zeitplan zu setzen (Cap-Analyse, Issue #1). Gegner laufen radial von außen +auf den Turm zu und greifen ihn im Nahbereich an. + +**Akzeptanz** +- Bei laufender Spawn-Phase pendelt die Zahl lebender Gegner um `target_population(wave)`, mit einer + Abweichung von höchstens ‹±10 %› über ein 5-Sekunden-Fenster. +- Die Zahl lebender Gegner überschreitet **nie** `HARD_ENEMY_CAP` — auch nicht bei einem + Sprung-zu-Welle auf die höchste im Debug-Panel erreichbare Welle. +- Bei 10 000 gleichzeitigen Gegnern bleibt die Frametime unter 16,67 ms (Nachmessung mit dem Aufbau + aus `examples/perf_spike.rs`, nach dem Wechsel auf echte Sprites zu wiederholen). +- Jeder Archetyp ist an Sprite-Farbe oder -Form ohne Text unterscheidbar. + +### 4. Turm-Dauerfeuer und geteilter Reichweiten-Scan + +Der Turm schießt selbstständig auf Gegner in Reichweite. Genau **ein** System ermittelt pro Frame +den Reichweiten-Zustand; `tower_fire` und **alle** Auslöse-Bedingungen (Feature 7) lesen dessen +Ergebnis. Das ist keine Optimierung für später, sondern die Bedingung, unter der die +Auslöse-Entscheidung aus #12 tragfähig ist. + +**Akzeptanz** +- Bei mindestens einem Gegner in Reichweite feuert der Turm ohne jede Eingabe innerhalb von + `EffectiveStats.AttackInterval` Sekunden. +- Ohne Gegner in Reichweite feuert er nicht. +- Es existiert genau ein System, das die Gegnermenge in Turm-Reichweite bestimmt; ein `grep` nach + einem zweiten Reichweiten-Scan über die Gegner-Query findet keinen. + +### 5. Stat- und Modifier-Pipeline + +Vollständig nach [ADR-0002](adr/0002-stat-und-modifier-pipeline.md): drei Akkumulatoren (`flat`, +`points`, `mult`), ein `Direct`/`Interval`-Bit je Stat, Clamp einmal auf die Summe, `EffectiveStats` +als `Component` an der Turm-Entity, Neuberechnung bei Änderung. `type Stat = f32`. Alle Zahlen aus +`Res` (ADR-0001). + +**Akzeptanz** +- Das durchgerechnete Beispiel aus ADR-0002 („Durchgerechnetes Beispiel") ist als Test hinterlegt + und grün — mit den dort genannten Platzhalterwerten, nicht mit den späteren echten. +- Nach einer Änderung an `Workshop`, `EquippedCards` oder `RunUpgrades` läuft die Neuberechnung + genau einmal; ohne Änderung läuft sie nicht (nachweisbar über einen Zähler im Debug-Panel). +- `sync_tower_abilities` ist der einzige Schreiber von Fähigkeits-Components; sein `debug_assert` + am Ende des Abgleichs ist vorhanden und greift im Debug-Build. +- Jeder Modifikator, der in den Slice aufgenommen wird, hat die Sichtbarkeitsanforderung aus + ADR-0002 §11 vor dem Merge durchlaufen — inklusive Punkt 3 (beobachtbare Folge in der + Run-Telemetrie). + +### 6. Coins und In-Run-Upgrades + +`Coins` fallen bei jedem Kill an und werden **beim Tod gutgeschrieben** — kein einsammelbares Objekt, +keine Entity (Cap-Analyse, Issue #1: bei tausenden Kills pro Welle wäre das ein Entity-Sturm). Damit +kauft der Spieler In-Run-Upgrades in drei Tabs (Attack / Defence / Utility), jederzeit, einzeln +(Buy x1). Alle verfallen am Run-Ende, weil sie als `RunUpgrades`-Component an der Turm-Entity hängen +(ADR-0002 §6). + +**Akzeptanz** +- Ein Kauf ist zu jedem Zeitpunkt eines laufenden Runs möglich, auch mitten in der Spawn-Phase, ohne + dass die Simulation anhält. +- Ein Klick auf „Buy x1" zieht genau die angezeigten Kosten ab, erhöht das Upgrade um eine Stufe, + und der betroffene Wert in `EffectiveStats` ändert sich im selben Frame ablesbar. +- Ist der Coin-Stand kleiner als die Kosten, ist die Zeile nicht klickbar und als solche erkennbar. +- Nach einem Run-Ende und Run-Start stehen alle In-Run-Upgrades wieder auf Stufe 0, ohne dass + irgendein System sie zurücksetzt. +- Kosten und Wirkung unterscheiden sich zwischen den drei Tabs merklich genug, dass die + Telemetrie über zehn Runs **nicht** dieselbe Kaufreihenfolge zeigt (#8: sonst ist die + Kaufreihenfolge eine Sortierung, keine Entscheidung). + +### 7. Auslöse-System für Fähigkeiten + +**Ein** System wertet die Auslöse-Bedingungen aller aktiven Fähigkeiten aus — der Ultimate und jeder +Fähigkeits-Card. Eine Bedingung ist **Cooldown UND ein Weltzustand** (z. B. „‹N› Gegner in +Reichweite"), je Fähigkeit fest verdrahtet und nicht vom Spieler einstellbar. Die Werte kommen wie +alle Zahlen aus `Balance`. Feuern mehrere im selben Frame, feuern alle — keine Sperre, keine +Priorität. + +**Akzeptanz** +- Eine Fähigkeit feuert erst, wenn beide Teile der Bedingung erfüllt sind; ein abgelaufener Cooldown + allein löst nachweislich nicht aus (prüfbar, indem man die Arena leerräumt und wartet). +- Sind zwei Fähigkeiten im selben Frame auslösebereit, feuern beide im selben Frame. +- Die Bedingungswerte stehen in `Balance` und sind über das Debug-Panel zur Laufzeit änderbar; keine + Schwelle steht als Literal im Gameplay-Code (ADR-0001 §4). +- Das System liest den Reichweiten-Zustand aus Feature 4 und führt keinen eigenen Scan aus. + +### 8. Ultimate: Death Wave + +Ein radialer Sweep von der Turmmitte nach außen, automatisch ausgelöst über Feature 7. Kein +Zielsystem, kein Knopf, kein Eingabepfad. Die Systemanforderung, die sie aufdeckt, ist der +**gebatchte Massentod**: ein Sweep kann in einem Tick tausende Gegner treffen. + +**Akzeptanz** +- Bei erfüllter Bedingung startet der Sweep ohne Eingabe; ein sichtbarer Ring wandert von der + Turmmitte nach außen und trifft Gegner in der Reihenfolge ihres Abstands. +- Ein Sweep, der ‹5 000› Gegner gleichzeitig tötet, erzeugt keinen Frame über 16,67 ms — der + Massentod wird gebatcht, nicht als tausende Einzelereignisse abgearbeitet. +- Der verbleibende Cooldown ist im Ultimates-Tab ablesbar. +- Flächenwirkung ist über ein **Ziel-Limit pro Auslösung** gedeckelt, nicht über einen schrumpfenden + Radius (Cap-Analyse, Issue #1). + +### 9. Cards, Slots und Loadout + +Cards fallen als Drop aus Fortschritt: **Boss-Kill** oder **neuer Wellen-Rekord**. Sie sind nicht +kaufbar und haben keine eigene Währung. Eine Card ist entweder ein Stat-Modifikator oder eine +**Fähigkeit** (`CardEffect::Modifier` / `CardEffect::Ability`, ADR-0002 §8) — Fähigkeits-Cards feuern +über dasselbe System wie die Ultimate. Drei Seltenheiten, Slots von 1 auf 5. + +Das **Loadout steht vor dem Run fest**. Im laufenden Run sind Cards über den Pause-Button nur +einsehbar, nicht wechselbar (Issue #1). Damit wird im laufenden Run nie eine Fähigkeits-Component +entfernt (ADR-0002 §10, Nachtrag zu #6). + +**Akzeptanz** +- Nach einem Boss-Kill oder einem neuen Wellen-Rekord ist die Card-Ausbeute des Runs auf dem + Meta-Screen sichtbar, spätestens beim ersten Betreten nach dem Run-Ende. +- Der Spieler kann vor dem Run so viele Cards ausrüsten, wie er Slots hat, und keine mehr. +- Eine ausgerüstete Fähigkeits-Card erzeugt beim Run-Start genau eine Fähigkeits-Component am Turm; + eine abgelegte erzeugt keine. +- Während eines Runs ändert sich `EquippedCards` nicht — kein Pfad in der UI erlaubt es. +- Der Card-Pool enthält mindestens zwei Epics, und Slot 2 ist innerhalb der ersten ‹drei› Runs + erreichbar (#11; beide Bedingungen sind an das Abnahmekriterium des Slice gebunden). + +### 10. Meta-Währung und Workshop + +Die zweite Währung fällt aus denselben Kill-Events wie `Coins`, ist aber nicht in sie konvertierbar. +Drop-Chance je Normalgegner, garantiert je Boss, Menge wellenabhängig. Gutschrift beim Tod des +Gegners, kein Pickup. Der `Workshop` kauft davon permanente Stat-Upgrades mit exponentiell +wachsenden Kosten. + +**Akzeptanz** +- Eine Ausgabe von `Coins` im Run verringert den Meta-Währungs-Stand nicht, und umgekehrt. +- Ein Boss-Kill schreibt garantiert Meta-Währung gut; die gutgeschriebene Menge auf Welle 20 ist + höher als auf Welle 10. +- Ein Workshop-Kauf erhöht den `flat`- bzw. `mult`-Beitrag des betroffenen Stats sofort und + überlebt ein Run-Ende sowie einen Programm-Neustart. +- Über die ersten zehn Runs trägt jeder Run mindestens ein Workshop-Level ein (#8, Prüfkriterium 2). + +### 11. Run-Ende und Meta-Übergang + +Fällt die Turm-HP auf 0, endet der Run. **Genau ein System** überführt am Run-Ende die aus dem Run +abgeleiteten Meta-Werte (`highest_wave`, verdiente Meta-Währung, Card-Ausbeute) in die persistierten +Resources (ADR-0003 §6). Danach wird die Turm-Entity despawnt; alles Run-gebundene verschwindet mit +ihr, ohne Aufräum-Code. + +**Akzeptanz** +- Bei HP ≤ 0 endet der Run innerhalb eines Frames; danach existiert keine Entity mit + `EffectiveStats`, `RunUpgrades` oder einer Fähigkeits-Component mehr. +- `highest_wave` wächst nur, wenn die erreichte Welle den bisherigen Stand übersteigt, und wird + genau einmal pro Run geschrieben. +- Kein anderes System als dieses eine schreibt aus Run-Zustand in eine persistierte `Resource` + (prüfbar über die Schreibstellen der `SettingsGroup`-Resources). +- Der Spieler landet nach dem Run-Ende auf dem Meta-Screen, ohne Zwischenschritt und ohne dass ein + weiterer Run automatisch startet. + +### 12. In-Run-HUD und Pause + +Links das Gameplay-Fenster, rechts ein vertikales Panel über die volle Höhe. Das Panel trägt oben +den Namen des aktiven Tabs, darunter ~8 Zeilen im Schema `` / `` links und +`Buy x1` / `` rechts. Unten vier Tabs: **Attack Shop · Defence Shop · Utility Shop · +Ultimates**. Der Ultimates-Tab trägt die Cooldown-Anzeige (#12). Ein Pause-Button friert die +**gesamte** Simulation ein und gibt Einsicht in die ausgerüsteten Cards. + +Das Mockup (`docs/design/hud-in-run.png`) legt Panel und Tabs fest, zeigt aber weder Turm-HP, +Wellenzähler, Währungsstände noch den Pause-Button. Diese vier gehören ins Gameplay-Fenster oder +dessen Rand; ihre Platzierung ist frei, ihre Existenz nicht. + +**Akzeptanz** +- Die vier Tabs sind vorhanden und schaltbar; ein Tab-Wechsel hält die Simulation nicht an. +- Turm-HP, aktuelle Welle, `Coins`-Stand und Meta-Währungs-Stand sind während des Runs jederzeit + ohne Tab-Wechsel ablesbar. +- Der Pause-Button friert Gegnerbewegung, Turmfeuer, Wellen-Timer und Fähigkeits-Cooldowns + gleichzeitig ein; nach dem Fortsetzen laufen alle vier von genau ihrem Stand weiter. +- Im Pause-Zustand sind die ausgerüsteten Cards einsehbar und **nicht** wechselbar. +- Es gibt **keine** „Gespeichert"-Bestätigung — das Programm kann sie nicht belegen (ADR-0003 §8). + +### 13. Meta-Screen zwischen den Runs + +Der Zustand zwischen zwei Runs. Er trägt Workshop-Käufe, das Card-Loadout, den Slot-Fortschritt und +den Start-Knopf für den nächsten Run. **Sein Aufbau ist offen** (siehe „Offen"); was hier steht, ist +seine Funktion, nicht sein Layout. + +**Akzeptanz** +- Ein neuer Run ist nur von hier aus startbar. +- Workshop-Käufe, Card-Loadout und Slot-Stand sind von hier aus erreichbar und änderbar. +- Beim Betreten nach einem Run zeigt der Screen, was dieser Run eingebracht hat: erreichte Welle, + verdiente Meta-Währung, gedroppte Cards. +- Steht `version` nach dem Laden auf `0`, erscheint hier die Meldung aus ADR-0003 §8 — und bis zur + ersten bewussten Aktion des Spielers wird nicht geschrieben. + +### 14. Save/Load + +Vollständig nach [ADR-0003](adr/0003-save-format-ort-und-migration.md): `progress.toml` über +`bevy_settings`, `version` als Sentinel, Feldnamen als Vertrag, namensbasierte Ablage. Persistiert +werden nur Quellen, nie berechnete Werte (ADR-0002 §5). Kein laufender Run, kein `Balance`, kein +Zeitstempel. + +**Akzeptanz** +- Nach einem Programmneustart stehen Workshop-Level, Card-Bestand, Loadout, Slot-Zahl, + Meta-Währungsstand und `highest_wave` unverändert da. +- Ein von Hand beschädigtes `progress.toml` führt zur Meldung aus ADR-0003 §8 und **nicht** zu einem + Schreibvorgang, bevor der Spieler etwas tut. Die beschädigte Datei liegt danach unverändert da. +- Ein `progress.toml` mit `version` größer als `CURRENT` sperrt alle Schreibvorgänge für die Sitzung + und lässt die Datei unangetastet. +- Ein Umbenennen eines Feldes lässt den restlichen Spielstand intakt und setzt genau einen Wert auf + `Default`. +- Die Datei ist in einem Texteditor lesbar und von Hand editierbar — Schummeln ist ausdrücklich + akzeptiert, nicht übersehen. + +### 15. Debug-Panel und Run-Telemetrie + +**Kein Nice-to-have.** ADR-0001 und #8 benennen dieses Werkzeug als den eigentlichen Hebel, um die +vier freien Zahlen überhaupt finden zu können: ohne Sprung-zu-Welle kostet jeder Datenpunkt einen +Run von Welle 1 an, bei ‹35 s› pro Welle also Minuten. Das Panel mutiert `Balance` im laufenden +Prozess und nutzt dieselbe Naht wie der spätere Asset-Ladepfad (ADR-0001 §3). + +Umfang: Sprung zu einer beliebigen Welle · Live-Mutation der `Balance`-Werte · Anzeige von +`EffectiveStats` samt der **ungeclampten** Summen (ADR-0002 §2) · Herkunfts-Aufschlüsselung pro Stat +(ADR-0002 §6) · Run-Telemetrie: Zeit bis Tod, erreichte Welle, Coins pro Minute, Kills pro Welle, +DPS-Verlauf, Zeit zwischen zwei bezahlbaren Käufen. + +**Akzeptanz** +- Ein Sprung zu Welle N versetzt den laufenden Run in Welle N mit der für N vorgesehenen + Soll-Population und Gegner-Skalierung, ohne Programmneustart, in unter ‹2 s›. +- Eine Änderung an einem `Balance`-Wert im Panel wirkt ohne Neustart auf die nächste Neuberechnung + von `EffectiveStats`. +- Am Run-Ende liegt ein Telemetrie-Datensatz vor, der alle oben genannten Größen enthält und sich + maschinenlesbar exportieren lässt. +- **Ein Run, in dem das Debug-Panel benutzt wurde, schreibt nichts in `progress.toml`.** Weder + `highest_wave` noch Meta-Währung noch Card-Drops. Ein Sprung zu Welle 500 darf keinen + Wellen-Rekord und keinen Card-Drop erzeugen. +- Das Panel ist im Release-Build nicht erreichbar, ohne dass ein Schalter dafür umgelegt wird. + +--- + +## Was ausdrücklich nicht drin ist + +| Nicht im Slice | Warum | +|---|---| +| Pfadfindung, Turm-Platzierung, Maze-Building | die Arena ist radial und hat genau einen Turm — es gibt nichts zu platzieren und keinen Pfad zu finden. | +| Tiers | wir haben uns bewusst für **eine** endlose Kurve entschieden; Tier-Resets sind das Langzeit-Muster des Originals, nicht unser Slice-Problem. | +| Labs, Modules, Perks | dritte, vierte und fünfte Meta-Achse neben Workshop und Cards — der Slice soll zeigen, dass **eine** Progressionsschleife trägt, nicht dass fünf sich addieren. | +| Offline-Progress | braucht einen Zeitstempel im Save, und ein Feld ohne Leser ist genau der Fehler, den ADR-0002 §5 verbietet. | +| Elite- und Fleet-Klasse | ihre Mechanik im Original ist eine Anti-Cheese-Antwort auf ein Fähigkeiten-Arsenal, das wir gar nicht haben (#3). | +| Immunitätsmatrix | dieselbe Begründung — sie schützt vor Fähigkeiten, die der Slice nicht kennt. | +| Wall als zweiter HP-Pool | ein zweiter HP-Pool verdoppelt die Schadenslogik, ohne eine neue Frage zu beantworten (#3). | +| Coin- und Card-Pickups als Entities | bei tausenden Kills pro Welle ist ein einsammelbares Objekt pro Drop ein Entity-Sturm (Cap-Analyse #1). | +| Coin Decay, Heat-up, Enemy-Mass-Wachstum | Coin Decay und Mass sind dichte-neutral, aber ohne Nutzen im Slice; Heat-up ist bei 13-facher Angreiferzahl schlicht nicht übertragbar und müsste neu erfunden statt übernommen werden (Cap-Analyse #1). | +| Gacha-Kopien, Card-Mastery, Pity-System | das Original kauft Cards mit einer Währung, die es bei uns nicht gibt (Ads, IAP) — Drop-Verteilung ersetzt beides ersatzlos (#11). | +| Manuelle Ultimate-Auslösung | ein Knopf wäre der einzige Moment aktiver Kontrolle im ganzen Spiel und würde das Kern-Gefühl „Idle" brechen statt bestätigen (#9). | +| Einstellbare Auslöse-Bedingungen | die Bedingungen liegen bereits als Daten in `Balance`; sie einstellbar zu machen ist reine UI-Arbeit und kauft im Slice nichts (#12). | +| Buy x10 / Buy Max | das HUD-Schema lässt Platz dafür, ohne das Layout zu ändern — der Slice braucht es nicht (#10). | +| Spielgeschwindigkeits-Multiplikator | nicht entschieden und nicht im HUD; das Debug-Panel deckt den Zeitraffer-Bedarf beim Tunen ab (siehe „Lücken"). | +| Bots, Wave Skip, Recovery Packages | Systeme, die eine bereits laufende Schleife garnieren — der Slice muss erst zeigen, dass die Schleife läuft. | +| Guilds, Tournaments, Cloud-Saves, Accounts, IAP, Leaderboards | alles Server-seitige ist out of scope; ein Vergleichswert, der das Gerät verlässt, würde außerdem ADR-0003 §1 (Klartext-Save) neu aufmachen. | +| Mobile- und Web-Port | `bevy_settings` persistiert auf Android und iOS **nichts** und meldet es nur als `warn!` — der Port braucht eigene Arbeit (ADR-0003, Revisions-Auslöser 2). | +| Art-Direction, Audio | Programmer-Art ist eine Entscheidung, kein Zwischenstand; ein Art-Strang beantwortet keine der offenen Fragen. | +| Hot-Reload für Balancing-Daten | der Edit-to-see-Loop kostet gemessene ~11 s, und der teure Teil eines Tuning-Zyklus ist das Spielen (ADR-0001). | +| „Gespeichert"-Bestätigung | das Programm kann sie nicht belegen — es gibt in Bevy 0.19 keinen Rückkanal (ADR-0003 §8). | + +--- + +## Abnahmekriterium für den Slice + +Genau eines, überprüfbar, ohne Debug-Panel: + +> **In einer ununterbrochenen Sitzung von höchstens 60 Minuten auf einem frisch angelegten +> Spielstand spielt ein Spieler Runs, bis er einen zweiten Card-Slot besitzt und zwischen +> mindestens zwei Cards wählen kann, startet danach einen weiteren Run und erreicht darin eine +> höhere Welle als in Run 1; nach einem Neustart des Programms steht derselbe Meta-Stand wieder da.** + +Warum genau dieses: Es prüft alle vier Takte des Loops in einer Beobachtung — Run starten, sterben, +aufwerten, stärker starten — und bindet zusätzlich die Randbedingung aus #11 ein, dass der Slice das +Card-System nicht nur enthalten, sondern **zeigen** muss. Ein Slice, in dem Slot 2 ein Fernziel +bleibt, hat Cards gebaut und nie vorgeführt. Der Neustart am Ende prüft Feature 14 dort, wo es zählt. + +--- + +## Offen — bewusst nicht entschieden + +Für keinen dieser Punkte wird hier eine Antwort erfunden. + +| Punkt | Wer entscheidet | Wann | +|---|---|---| +| **Die vier freien Zahlen**: Wachstumsfaktor pro Welle, Boss-Multiplikator, Drop-Chance mal Wellenwert, Kosten-Exponent des Workshops | Der Entwickler beim Tunen. Form und Prüfkriterien stehen in #8, die Werte findet nur Spielen | Nach Feature 15 (Debug-Panel), vor dem Abnahmekriterium | +| **Name der Meta-Währung** | `CONTEXT.md` — der Glossar-Eintrag ist der Vertrag, der Save-Feldname folgt ihm | Bevor der erste Workshop-Preis geschrieben wird. `Coins` ist an die In-Run-Währung vergeben; ADR-0003 lässt das Feld unbenannt, weil ein vorläufiger Name nach der Migrationsregel (§4) teuer zu korrigieren wäre | +| **Aufbau des Meta-Screens** (Workshop, Cards, Slot-Fortschritt) | Ein eigenes Design-Ticket, analog zum HUD-Mockup | Vor Feature 13. Nur das In-Run-HUD ist entworfen | +| **`MaxHealth` mitten im Run erhöht** — wächst die aktuelle HP mit, behält sie ihren Anteil, oder bleibt sie unverändert? | Das Health-System, nicht die Pipeline (ADR-0002, „Offene Punkte") | **Vor dem ersten Defence-Shop-Upgrade.** Die ADR-0002-Stat-Tabelle weist `MaxHealth` ausdrücklich `flat` aus In-Run-Upgrades zu — der Fall tritt bei jedem Health-Kauf ein, nicht theoretisch | +| **`SlowAura`** — modifiziert Gegner statt den Turm und ist deshalb kein Stat | Fällt mit der Card-Liste; ADR-0002 §9 legt die Form fest (Component am Turm, das das Gegner-Bewegungssystem liest), nicht den Inhalt | Mit der Card-Liste | +| **Zusammensetzung der Card-Liste**: Anzahl, Wirkungen, Verteilung auf die drei Seltenheiten, Drop-Wahrscheinlichkeiten je Stufe, Stufenzahl je Card | Ein Card-Inhalts-Ticket, gebunden an #8 (Zahlen) und #11 (Randbedingungen) | Vor Feature 9. **Zwei Randbedingungen sind bereits verbindlich**: Slot 2 muss früh fallen, und es braucht mindestens zwei Epics — sonst ist die Epic-Stufe eine Behauptung statt einer Mechanik | +| **Slot-Kurve**: wodurch ein Card-Slot freigeschaltet wird | Niemand — siehe „Lücken", Punkt 2 | offen | + +--- + +## Widersprüche und Lücken + +Beim Zusammentragen aller Entscheidungen sind Stellen aufgefallen, an denen zwei Quellen sich +widersprechen oder an denen eine Frage niemandem gehört. Sie stehen hier, statt geglättet zu werden. + +### Widersprüche + +1. **Card-Drops überqueren die Run-Grenze, aber ADR-0003 kennt sie nicht.** ADR-0003 §6 nennt + ausdrücklich **genau eine** Ausnahme von der Regel „während eines Runs ändert sich keine + persistierte Quelle": `highest_wave` und die verdiente Meta-Währung, überführt genau einmal am + Run-Ende. `card_levels` steht nicht in dieser Ausnahme — obwohl #11 (entschieden 12:48, also vor + ADR-0003 um 13:46) Cards aus **Boss-Kills und neuen Wellen-Rekorden** droppen lässt, beides + Ereignisse *im* Run. Die Spec löst das oben nach ADR-0003 auf: Card-Drops werden im Run gepuffert + und zusammen mit den übrigen Meta-Werten am Run-Ende überführt. Wer das anders bauen will, muss + zuerst die Ausnahmeliste in ADR-0003 §6 erweitern — nicht stillschweigend ein zweites System + schreiben lassen. + +2. **Die Slot-Kurve gehört niemandem, ist aber Abnahmebedingung.** #11 entscheidet „Start bei 1, + wächst auf 5, die Slot-Zahl ist selbst Progression" und bindet Slot 2 ausdrücklich ans + Abnahmekriterium des Slice. **Wodurch** ein Slot freigeschaltet wird, sagt niemand: nicht #11 + (schiebt es an #8/#10), nicht #8 (die vier freien Zahlen enthalten keine Slot-Kurve), nicht die + Karte (der Fog nennt nur den Meta-Screen-Aufbau). `card_slots: u8` ist in ADR-0003 persistiert, + aber es gibt keinen Mechanismus, der ihn erhöht. Das ist keine Zahl, die man beim Tunen findet — + es ist eine unentschiedene Mechanik: Kauf aus Meta-Währung? Wellen-Meilenstein? Boss-Zahl? Sie + blockiert das Abnahmekriterium und muss vor Feature 9 entschieden werden. + +3. **Die Ticket-Überschrift von #8 verspricht 10–20 Minuten, die Entscheidung liefert 6–9.** #8 + heißt „Wellen- und Economy-Kurve für einen **10–20-Minuten-Run**", sein erster Kommentar + verlangt Tod „um Welle 20–40", und die Entscheidung im zweiten Kommentar setzt Run 1 auf **Welle + 10–15 = 6–9 Minuten**. Die Karte hat die letzte Fassung übernommen, die frühere steht unwidersprochen + daneben. Wahrscheinlich gemeint: 10–20 Minuten gilt für den **eingespielten** Run nach einigen + Workshop-Leveln, 6–9 Minuten für Run 1. Das steht so aber nirgends, und die Kurve wird gegen die + Zahl getunt, die man liest. Diese Spec folgt der Entscheidung (Welle 10–15) und hält fest, dass + für Run *n* keine Ziel-Runlänge existiert. + +4. **Die Cap-Analyse balanciert Sub-Caps für Gegnerklassen, die #3 abgeschafft hat.** Der + #1-Kommentar teilt die Sub-Caps sorgfältig in Modifikator-Caps (Protector 8, **Elite pro Typ 8**) + und Event-Caps (Boss 10, **Elite gesamt 20**). #3 wirft Elite und Fleet aber komplett aus dem + Slice. Damit ist die Hälfte der Analyse gegenstandslos: übrig bleiben genau **ein** mitskalierendes + Modifikator-Cap (die eine Sondermechanik-Einheit, Protector-artig) und **ein** absolutes + Event-Cap (Boss). Die Regel bleibt richtig, ihr Anwendungsbereich ist ein Viertel so groß wie + beschrieben — wer sie liest, baut sonst eine Klassifizierung für Klassen, die es nicht gibt. + +5. **~24 Shop-Zeilen stehen gegen 12 Stats.** Der HUD-Kommentar in #10 leitet aus 8 Zeilen × 3 Tabs + „etwa 24 In-Run-Upgrades" ab und macht daraus eine Design-Aussage („der Spieler kann in einem Run + nicht alles kaufen"). ADR-0002 §3 kennt aber insgesamt **12** Stats, und davon gehören + `UltimateCooldown` und `WaveCooldown` nicht in die drei Shop-Tabs. Die Aufteilung ergibt grob + Attack 5 (`Damage`, `AttackInterval`, `Range`, `CritChance`, `CritFactor`), Defence 4 + (`MaxHealth`, `DefensePercent`, `DefenseFlat`, `HealthRegen`) und **Utility 1** (`CoinGain`). Ein + Utility-Tab mit einer Zeile ist kein Tab. Entweder das Panel füllt nur die Hälfte der Zeilen — + dann trägt die Folgerung „kann nicht alles kaufen" nicht mehr —, oder es braucht In-Run-Upgrades, + die keine Stats aus ADR-0002 sind, und dann ist ADR-0002 §3 unvollständig. Beides ist eine + Entscheidung, keine Detailfrage. + Verschärfend: #3 empfiehlt für Utility ausdrücklich „stark vereinfachen", weil das Utility-System + des Originals an Labs und Perks hängt — beides im Nebel. Der Utility-Tab ist damit der schwächste + Teil der HUD-Struktur. + +6. **Die „12–17 Kaufmomente" sind zweimal überholt, stehen aber noch in der Kette.** Der + HUD-Kommentar (13:38) rechnet mit 12–17 Kaufmomenten aus einer 20-Minuten-Session, #8 (13:51) + verwirft die Rechnung ausdrücklich („die trägt nicht mehr", weil jederzeit gekauft wird) **und** + verkürzt Run 1 auf 10–15 Wellen. Was aus dem HUD-Kommentar überlebt, ist allein die Zahl 24 — + sie kommt aus dem Layout, nicht aus der Session-Rechnung. Die Tuning-Zielgröße ist die **Zeit + zwischen zwei bezahlbaren Käufen** (‹10–20 s› früh), nicht eine Kaufzahl pro Run. + +### Lücken, die niemandem gehören + +7. **Das Debug-Panel kann den echten Spielstand zerstören, und niemand hat es benannt.** Feature 15 + springt zu Welle N. Feature 11 schreibt am Run-Ende `highest_wave` und die Meta-Währung in die + persistierte Resource, und #11 macht „neuer Wellen-Rekord" zu einer **Card-Drop-Quelle**. Ein + Sprung zu Welle 500 beendet einen Run also mit `highest_wave = 500`, einem gewaltigen Card-Drop + und einem Meta-Währungsstand, der den ganzen Slice trivialisiert. Weder ADR-0001 noch #8 noch + ADR-0003 erwähnen das. Diese Spec zieht die Konsequenz oben als Akzeptanzkriterium ein: ein Run + mit benutztem Debug-Panel schreibt **nichts**. Wer das Panel baut, muss die Schreibsperre + zuerst bauen. + +8. **Die Card-Nachschubquelle „neuer Wellen-Rekord" versiegt eingebaut.** Beide Card-Quellen hängen + an Fortschritt: Boss-Kill und neuer Wellen-Rekord. Solange die Run-Tiefe monoton wächst (#8, + Prüfkriterium 3, gilt für die **ersten zehn** Runs), fließt Nachschub. Danach ist unbestimmt, was + passiert — ein Spieler, der zehn Runs lang auf derselben Welle hängen bleibt, bekommt keine neue + Card mehr und hat gleichzeitig keinen anderen Hebel, tiefer zu kommen als den Workshop. Ob das + ein Feature ist (Cards folgen dem Fortschritt) oder eine Sackgasse (Fortschritt braucht Cards), + hat niemand entschieden. Bei einem Run 1, der auf Welle 10–15 endet, ist außerdem der + **eine** Boss-Kill pro Run in der Frühphase der einzige garantierte Drop überhaupt — er trägt + Meta-Währung und Card-Chance gleichzeitig. + +9. **Gegner-gegen-Gegner-Kollision ist seit #4 offen und steht auf keiner Liste.** #4 und die + Cap-Analyse nennen sie als „offene Architekturfrage": Stapeln zulassen oder Spatial Grid mit + weicher Separation. Bei tausenden radial konvergierenden Körpern kommen O(n²) und ein Stau am + Turmring zusammen, den keine DPS-Menge auflöst. Sie steht **nicht** im Fog der Karte, in keiner + ADR und in keinem der offenen Punkte, die diese Spec zugewiesen bekommen hat. Sie entscheidet + aber, ob 10 000 Gegner überhaupt spielbar sind, und sie ist teuer nachzurüsten. + *Vorschlag zur Auflösung, nicht Entscheidung:* Stapeln zulassen — bei Programmer-Art in 2D + vertretbar, und der Spatial Grid ist der teure Weg, der jederzeit nachrüstbar bleibt. + +10. **Ziel-Limit für Flächeneffekte und gebatchter Massentod haben keine ADR.** Die Cap-Analyse + ordnet beides ausdrücklich „der Architektur" zu, aber ADR-0002 regelt Stats und + Fähigkeits-Components, nicht Massenwirkung. Death Wave (#9) trifft beide Punkte sofort. Diese + Spec hat sie deshalb als Akzeptanzkriterien in Feature 8 aufgenommen — das ersetzt keine ADR, + macht sie aber wenigstens prüfbar. + +11. **Ein Spielgeschwindigkeits-Multiplikator ist weder entschieden noch verworfen.** Die + Cap-Analyse wirft ihn auf („ein Idle-Spiel mit 35-Sekunden-Wellen will fast sicher einen") und + entschärft ihn nur perf-seitig; das Referenzspiel hat ihn; das HUD-Mockup zeigt ihn nicht. + Diese Spec listet ihn oben unter „nicht drin", weil das Debug-Panel den Zeitraffer-Bedarf beim + Tunen abdeckt — aber das ist eine Entscheidung, die hier zum ersten Mal getroffen wird und + jederzeit umkehrbar ist. + +12. **`WaveCooldown` hat einen Cap, aber im Slice keine Quelle.** ADR-0002 §3 führt den Stat samt + `caps.wave_cooldown_reduction`; im Original liefert ihn die Epic-Card „Wave Accelerator". Enthält + die noch offene Card-Liste keine entsprechende Card, sind Stat und Cap toter Code. Kein Fehler, + aber ein Punkt, der bei der Card-Liste mitentschieden werden sollte. + +13. **Die Fehlermeldung aus ADR-0003 hat keinen Ort.** ADR-0003 §3 und §8 verlangen bei `version == 0` + und bei `version > CURRENT` eine Meldung an den Spieler, bevor irgendetwas geschrieben wird. Der + Slice hat nur das In-Run-HUD (entworfen) und den Meta-Screen (offen). Diese Spec hängt die + Meldung an den Meta-Screen — womit der offene Meta-Screen-Entwurf eine Anforderung erbt, die + aus einer ganz anderen Ecke kommt.