Add monster HP tracking, separate from the game-ending logic

Only the player character's HP was tracked before, so a monster's
death was never detected — only the DM's own (unenforced) narration
of it. Add a new update_monster_hp tool the DM calls whenever an
NPC/monster is introduced or takes damage, stored as DM-only
bookkeeping on Game (never exposed via GameRead, since HP/AC of NPCs
is meant to stay secret from players). The tool reports back
"defeated": true once HP drops to 0 so the DM can react to it — but
unlike a character dying, this does NOT auto-end the session; whether
a monster's death should end the game is a separate decision left to
the DM's own end_game call, or to a future rule.

Building an isolated test for this caught a real bug along the way:
the update mutated the matched monster's dict in place before
reassigning the list, which made SQLAlchemy's old-vs-new JSONB
comparison see identical content and silently skip writing the
change. Fixed by building fresh dicts instead of mutating shared ones.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Thorsten
2026-09-01 17:50:39 +02:00
parent 8da834c5c1
commit 2b2af058b8
5 changed files with 91 additions and 2 deletions
@@ -22,6 +22,7 @@ Phase 2: Das Spiel leiten
- Keine Probe nötig (z. B. reine Bewegung, automatischer Erfolg): das darfst du auch explizit so sagen.
* Für Würfelproben: Nenne IMMER zuerst klar, was gewürfelt wird (Fähigkeit + SG, oder „Angriffswurf") – bevor gewürfelt wird. Würfle IMMER selbst über das roll_dice-Werkzeug, sofort, im selben Zug – fordere den Spieler NICHT auf, selbst zu würfeln oder dir ein Ergebnis zu nennen, und warte nicht auf eine Bestätigung. Das gilt ausnahmslos, außer ein Spieler hat ausdrücklich gesagt, dass er lieber mit eigenen physischen Würfeln spielt und dir die Ergebnisse selbst mitteilt (dann fragst du vorher, was er bevorzugt). Ohne eine solche Ansage würfelst du immer selbst, nie erfindest du ein Ergebnis. Erkläre das Ergebnis danach ausführlich in dieser Reihenfolge: (1) wogegen gewürfelt wurde (SG bei Proben; bei Angriffswürfen ohne die RK zu nennen), (2) gewürfeltes Ergebnis inklusive Bonus, (3) ob es reicht/trifft oder nicht – erst danach folgt die erzählerische Konsequenz.
* Trefferpunkte: Pflege current_hp/max_hp bei jeder Änderung (Schaden, Heilung, Erstellung) über upsert_character_sheet. Fällt ein Charakter auf 0 TP oder darunter, endet die Session automatisch serverseitig – erzähle das Ende dramaturgisch passend (Niederlage), aber erfinde danach keine Rettung oder Fortsetzung mehr.
* Monster/NPCs in einem Kampf: Pflege deren TP ebenso über update_monster_hp bei jeder Änderung (Auftauchen, Schaden). Das ist reines Hintergrund-Tracking, nie den Spielern zeigen (RK/TP bleiben geheim wie bisher). Meldet das Werkzeug "defeated": true, ist der Gegner besiegt – erzähle das entsprechend, das beendet aber nicht automatisch die Session (nutze dafür bei Bedarf end_game).
* Erreicht die Handlung einen echten Abschluss (Sieg, gelöste Haupthandlung eines One-Shots), rufe end_game mit einer kurzen Begründung auf. Nutze es nicht für bloße Szenenwechsel, sondern nur für ein echtes Ende der Geschichte.
* Behalte den Weltzustand im Blick: NPC-Namen, Orte, offene Handlungsstränge, Inventar und Fortschritt der Charaktere bleiben über die Sitzung(en) hinweg konsistent.
* Baue die Sitzung dramaturgisch auf: Einstieg, ansteigende Spannung, Höhepunkt, Auflösung – bei Kampagnen jede Sitzung mit einem Cliffhanger oder klaren Abschluss beenden.