feat(kampf): verbindliche Gegner-Ansage und Zielcursor

Am Zugende legt jeder Gegner fest, was er im naechsten Zug tut; der
Kampf-Screen zeigt es unter dem Lebensbalken. Verbindlich statt Vorschau,
denn nur so entsteht ein Fenster: Wer dem Gegner zwischen Ansage und
Ausfuehrung die Ausdauer nimmt, kostet ihn den Zug.

Zielwahl bekommt einen eigenen Cursor, Tab schaltet zwischen Gegner- und
Faehigkeitsliste um — dieselbe Bedienung wie im Laden. Die Ziffern
springen nur noch aufs Ziel, ausgeloest wird mit Enter.
This commit is contained in:
2026-08-12 20:49:24 +02:00
parent 7963df5236
commit 6014471c33
8 changed files with 233 additions and 47 deletions

View File

@@ -233,3 +233,22 @@ und `data/` bleiben ratatui-frei, weil ein Farbname eine Zeichenkette ist.
Kulisse.
- **14 Kampfformeln**: `core:attack` und `core:flee` müssen als Fähigkeiten im Kernspiel existieren —
ohne sie hat `UseAbility` weder Basisangriff noch Flucht.
### Nachtrag — zwei Cursor im Kampf-Screen (nach M4)
Ticket 11 hatte die Zielwahl den Zifferntasten überlassen: `Enter` traf den ersten Gegner, `1`–`9`
feuerten sofort auf den n-ten. Das reicht, solange man nur zuschlägt, und bricht, sobald die Wahl des
Ziels eine Entscheidung ist — dieselbe Taste hätte je nach Absicht zwei Bedeutungen.
Der Screen trägt jetzt **zwei Cursor**, `pick` für die Fähigkeit und `target` für den Gegner, und ein
`targeting: bool` sagt, welcher aktiv ist. `Tab` schaltet um, der Titel des aktiven Rahmens trägt
`· aktiv`. Das ist dieselbe Bedienung wie im Laden — **eine** Umschaltregel für alle zweispaltigen
Screens statt einer je Screen.
Die Ziffern bleiben, aber sie *springen* nur noch aufs Ziel, statt zu feuern; ausgelöst wird
ausschließlich mit `Enter`. Zwei gleichzeitig sichtbare Cursor mit Pfeilen auf beiden Achsen wären die
Alternative gewesen — weniger Tastendrücke, aber eine Bedienung, die es sonst nirgends im Spiel gibt.
Dazu zeigt die Gegnerliste unter jedem Lebensbalken die **Ansage** aus Ticket 14 (`↳ Wuchtschlag →
dich`, sonst `↳ zögert`). Sie steht bewusst als eigene Zeile und nicht als Kürzel hinter dem Namen:
Sie ist die Information, auf der die Entscheidung dieses Zuges beruht.

View File

@@ -259,3 +259,28 @@ verschieben, wenn später jemand die Liste wieder füllt.
Damit ist die Regel dieses Tickets vollständig: Die Reihenfolge steht vor dem Zug fest, *und* sie
endet, sobald ihre Grundlage weg ist.
### Nachtrag — die Ansage (Taktik-Ebene, nach M4)
Der Zugablauf bekommt einen **siebten Schritt**: Am Ende jedes Zuges legt jeder lebende Gegner fest,
was er im nächsten tun wird. Ausgewertet wird dieselbe `ai`-Liste nach derselben Regel — erster
passender *und verfügbarer* Eintrag —, nur eine Runde früher. Das Ergebnis steht als `intent` am
`Creature` und wird im Kampf-Screen unter dem Lebensbalken angezeigt.
**Verbindlich, nicht als Vorschau.** Der Gegner führt genau das aus, was dasteht. Die Alternative wäre
gewesen, die `ai`-Liste bei jedem Bild neu auszuwerten und das Ergebnis als Vermutung anzuzeigen — das
hätte keinen Zustand gekostet, aber auch keine Taktik erzeugt: Eine Anzeige, die sich mit der Lage
mitdreht, sagt nur, was *jetzt* gälte, und ist genau dann falsch, wenn der Spieler etwas unternimmt.
Der Gewinn liegt im **Fenster zwischen Ansage und Ausführung**. Vor dem Ausführen wird `ability_block`
erneut geprüft; schlägt es an, verliert der Gegner den Zug (`„X kommt nicht dazu — Nicht genug
Ausdauer."`). Damit wird jede Wirkung auf Ausdauer, Abklingzeit oder Bedingung zu einem *Konter*, und
die Sperrgründe, die Ticket 14 ohnehin schon berechnet, bekommen einen zweiten Nutzen.
Eine Ansage wird beim Ausführen verbraucht (`take`). Wer ohne Ansage an die Reihe kommt, tut nichts —
das trifft nur Gegner, die mitten im Zug auftauchen, und die stehen ohnehin nicht in der
Initiativreihenfolge dieses Zuges. **Ein** Ansagepunkt, kein zweiter beim Kampfbeginn.
Ausdrücklich **nicht** dazugekommen ist ein Ziel an der Ansage: Die `ai` greift ausschließlich den
Helden an, `intent` trägt deshalb nur die Fähigkeits-ID. Ein Zielfeld käme mit dem ersten Gegner, der
seine Verbündeten heilt.

View File

@@ -118,6 +118,20 @@ leerer `enemies` bricht den Zug jetzt ab.
Dazu **eine bewusst offene Stelle**: `Npc.triggers` ist nicht gebaut, weil `triggers_for` NPCs nicht
einsammelt — ein Feld ohne Leser wäre eine Zusage, die niemand einlöst. TODO steht im Code.
**Nach M4 — die Ansage** (58 Tests)
Kein Meilenstein, eine Nachforderung aus dem Spielen: Gegner sagen am Zugende an, was sie im nächsten
tun, und der Spieler wählt sein Ziel mit einem eigenen Cursor. Zwei Entscheidungen dahinter, beide in
die Tickets zurückgetragen:
| Frage | Entschieden | Warum |
|---|---|---|
| Ansage verbindlich oder Vorschau? | **verbindlich** (14) | Eine Anzeige, die sich mit der Lage mitdreht, ist genau dann falsch, wenn der Spieler handelt. Verbindlich heißt störbar — das Fenster zwischen Ansage und Ausführung *ist* die Taktik |
| Zielwahl mit Pfeilen auf zwei Achsen oder mit Tab? | **Tab** (11) | Dieselbe Umschaltregel wie im Laden. Eine Bedienung für alle zweispaltigen Screens statt einer je Screen |
Der Zugablauf aus **14** hat damit einen siebten Schritt, `Creature` ein Feld `intent`, und die
Sperrgründe, die `ability_block` ohnehin berechnete, haben einen zweiten Nutzen bekommen.
**Drei Befunde aus M1, die nur der Compiler liefern konnte** — alle in die Tickets zurückgetragen:
- **11**: Der Grenztest in seiner wörtlichen Fassung schlägt beim eigenen Doc-Kommentar an. Muss Kommentarzeilen ausnehmen.