diff --git a/.scratch/rustkeep-1.0/issues/01-effekt-vokabular.md b/.scratch/rustkeep-1.0/issues/01-effekt-vokabular.md index 42b1b97..750b450 100644 --- a/.scratch/rustkeep-1.0/issues/01-effekt-vokabular.md +++ b/.scratch/rustkeep-1.0/issues/01-effekt-vokabular.md @@ -1,7 +1,7 @@ # 01 — Effekt-Vokabular Type: grilling -Status: open +Status: resolved Blocked by: — ## Question @@ -19,3 +19,81 @@ Zu klären: - Wie sieht die TOML-Repräsentation aus, und bleibt sie lesbar genug für Modder ohne Doku? Ergebnis: eine Liste der Effekt-Varianten mit TOML-Beispiel je Variante. + +## Answer + +Begriffe sind im [Glossar](../../../CONTEXT.md) festgehalten. + +### Zwei Begriffe, nicht einer + +**Modifikator** rechnet ein Attribut um, solange er existiert — er wird nie ausgeführt, sondern beim +Auslesen aufsummiert. **Aktion** ändert Zustand einmalig. Getrennte Maschinen, getrennte TOML-Arrays. +Ein gemeinsamer Oberbegriff „Effekt" ist ausdrücklich *kein* kanonischer Begriff mehr. + +### Attributkatalog (Engine-Vokabular, ohne Namensraum) + +`strength` · `dexterity` · `constitution` · `charisma` · `luck` · `level` · `max_health` · +`max_stamina` · `damage` · `hit_chance` · `critical_chance` · `critical_factor` · +`resistance` (typ-indiziert) · `shop_price` · `carry_capacity` + +`max_health` ist ein Attribut und wird von Modifikatoren umgerechnet. Der aktuelle Lebensstand ist +**kein** Attribut, sondern Zustand — den ändern Aktionen. Diese Trennung muss scharf bleiben. + +### Modifikator + +```toml +modifiers = [ + { attribute = "damage", flat = 5 }, + { attribute = "strength", flat = 2, percent = 5 }, + { attribute = "critical_chance", percent = 10, duration = "turns", turns = 3, + target = "all_enemies", symbol = "curse", name = "Verflucht" }, +] +``` + +- `flat` und `percent` beide optional, mindestens eines Pflicht. +- `duration`: `permanent` · `while_equipped` · `turns` · `until_floor_end`. +- `target`: `self` · `target` · `all_enemies`. Der Modifikator wohnt **immer beim Träger** und wird + beim Auslesen des Ziels eingesammelt — stirbt der Träger, verschwindet die Aura von selbst. +- `symbol` und `name` nur bei befristeten Zuständen; Item-Boni erben beides vom Item. + `symbol` ist ein Schlüssel, keine Farbe — die Zuordnung macht `ui/theme.rs`. + +### Aktion + +```toml +actions = [ + { action = "damage", amount = 12, damage_type = "fire", target = "target" }, + { action = "change_attribute", attribute = "health", amount = 20, target = "self" }, + { action = "apply_modifier", modifier = "core:poisoned", target = "target" }, + { action = "remove_modifier", modifier = "core:poisoned", target = "self" }, + { action = "give_item", item = "core:gold", count = 50, target = "self" }, + { action = "remove_item", item = "core:torch", count = 1, target = "self" }, +] +``` + +Sechs Aktionen. `damage` bleibt eigenständig statt `change_attribute health -12`, weil Schaden durch +eine Kette läuft (Resistenz mindert, Krit vervielfacht, Bedingungen greifen) und „bei erlittenem +Schaden" ein Event ist. Flache Liste, keine verschachtelten Aktionen — Ketten laufen über das +Event-System. + +### Regeln + +| | | +|---|---| +| Stapeln | `(Basis + Σ flach) × (1 + Σ prozentual)`, intern `f32`, gerundet an genau einer Stelle | +| Uhr | Ein Zug. Ein Feld gehen = ein Zug, eine Kampfaktion = ein Zug. Debuffs ticken auch beim Laufen | +| Schadenstypen | `fire` `ice` `poison` `shock` `holy` `slash` `blunt` — fest, Engine-Vokabular | +| Minderung | Ein Mechanismus: `resistance` je Typ. `armor` am Item ist Kurzschreibweise für Resistenz gegen `slash` und `blunt` | +| Namensraum | Doppelpunkt = Modder-Inhalt (`core:poisoned`). Ohne = Engine-Vokabular (`strength`, `fire`) | +| Tags | Freie namespaced Strings am Wesen, Grundlage für Bedingungen | +| Sprache | Schadenstyp `poison` ≠ Modifikator `core:poisoned` („Vergiftet") | + +### Bewusst nicht entschieden + +Das **Bedingungsvokabular** für `condition`. Es kommt aus Ticket 08, damit Quests und Modifikatoren +dieselbe Grammatik benutzen statt zweier, die sich subtil unterscheiden. Ticket 01 fordert es nur an. + +### Folgen für bestehenden Code + +`ItemArmor.armor` fällt weg und wird ein Modifikator auf `resistance`. `Stats` trennt Attribute von +Zustand. Der Attributkatalog braucht abgeleitete Größen, die es heute gar nicht gibt (`hit_chance`, +`carry_capacity`). diff --git a/.scratch/rustkeep-1.0/issues/14-kampfformeln-und-rundenablauf.md b/.scratch/rustkeep-1.0/issues/14-kampfformeln-und-rundenablauf.md new file mode 100644 index 0000000..0feb763 --- /dev/null +++ b/.scratch/rustkeep-1.0/issues/14-kampfformeln-und-rundenablauf.md @@ -0,0 +1,27 @@ +# 14 — Kampfformeln und Rundenablauf + +Type: grilling +Status: open +Blocked by: 01 + +## Question + +Wie läuft ein Kampf ab, und mit welchen Formeln? + +Der Attributkatalog aus 01 liefert die Zutaten (`damage`, `hit_chance`, `critical_chance`, +`critical_factor`, `resistance`, `dexterity`, `luck`). Wie sie zusammenwirken, ist offen: + +- **Reihenfolge**: Was bestimmt, wer zuerst handelt — `dexterity`, ein Initiativwurf, oder immer der + Spieler zuerst? Ändert sich das während des Kampfes? +- **Trefferformel**: Wie berechnet sich, ob ein Angriff trifft? Ist `hit_chance` gegen Ausweichen + gerechnet, oder trifft immer und `dexterity` mindert nur den Schaden? +- **Schadensformel**: In welcher Reihenfolge greifen Waffe, `damage`-Modifikatoren, Krit und + `resistance`? Ist Resistenz prozentual oder flach, und gibt es eine Ober- oder Untergrenze? +- **Kritische Treffer**: Wie speist `luck` in `critical_chance`? Multipliziert `critical_factor` den + Rohschaden oder den geminderten? +- **Aktionen pro Zug**: Genau eine, oder gibt es Ausdauer als Budget? Wozu dient `max_stamina` sonst? +- **Flucht**: Möglich, mit welcher Chance, mit welchen Kosten? +- **Zufall**: Schadensstreuung ja oder nein, und woher kommt der Zufallsgenerator — braucht es einen + Seed im Speicherstand? + +Ergebnis: die Formeln als Pseudocode plus der Ablauf eines Zuges von Eingabe bis Ergebnis. diff --git a/.scratch/rustkeep-1.0/issues/15-progression-und-levelup.md b/.scratch/rustkeep-1.0/issues/15-progression-und-levelup.md new file mode 100644 index 0000000..a591948 --- /dev/null +++ b/.scratch/rustkeep-1.0/issues/15-progression-und-levelup.md @@ -0,0 +1,25 @@ +# 15 — Progression und Level-up + +Type: grilling +Status: open +Blocked by: 02 + +## Question + +Was passiert beim Aufstieg, und wie sieht die Kurve aus? + +`Player` hat bereits `current_exp` und `next_level_exp`, `Stats::level_up()` deckelt bei 50. Der +Attributkatalog aus 01 steht. Offen ist, was ein Level überhaupt gibt: + +- **Was gewährt ein Aufstieg?** Feste Modifikatoren aus der Klasse, frei verteilbare Attributpunkte, + oder beides? Freie Punkte heißen Zuweisungs-UI und die Gefahr, sich den Charakter zu verbauen. +- **Ist die Kurve Daten oder Formel?** Eine Tabelle je Level in TOML (moddbar, explizit) oder eine + Formel mit Parametern (kompakt, weniger schraubbar)? +- **Bleibt die Obergrenze bei 50**, wenn 1.0 aus fünf Etagen besteht? Passt das zusammen? +- **Woher kommt Erfahrung?** Nur Tötungen, auch Quests, auch erstmaliges Betreten einer Etage? +- **Skaliert Rasse oder Klasse mit?** „+2 Konstitution je Level" ist ein Modifikator mit Level-Bezug — + kann das Vokabular aus 01 das ausdrücken, oder braucht es dafür etwas Neues? +- **Werden Leben und Ausdauer beim Aufstieg aufgefüllt?** Das ist eine Balancing-Entscheidung mit + Folgen für die Etagen-Länge. + +Ergebnis: Aufstiegsregel, Kurvenform (Daten oder Formel), Erfahrungsquellen und die Obergrenze. diff --git a/.scratch/rustkeep-1.0/map.md b/.scratch/rustkeep-1.0/map.md index fc41903..7287eb2 100644 --- a/.scratch/rustkeep-1.0/map.md +++ b/.scratch/rustkeep-1.0/map.md @@ -14,7 +14,8 @@ dort als Konvention im Body. Zuordnung Ticket → Gitea-Issue: | 04 Fehlerstrategie | [#5](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/5) | 09 Save-Schema | [#10](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/10) | | 05 Research Script-Engine | [#6](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/6) | 10 Raum-Prefab-Format | [#11](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/11) | | 11 UI-Gerüst | [#12](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/12) | 12 Prototyp ratatui | [#13](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/13) | -| 13 Script-Engine wählen | [#14](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/14) | | | +| 13 Script-Engine wählen | [#14](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/14) | 14 Kampfformeln | [#15](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/15) | +| 15 Progression | [#16](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/16) | | | ## Destination @@ -26,6 +27,9 @@ Inventar und Ausrüstung, Quests, NPCs, Handel, Speichern/Laden, Mod-Support auf Domain: Rust-Terminal-Roguelike, moddbar. Repo: `MDietermann/rustkeep`. +Das Glossar liegt in [`CONTEXT.md`](../../CONTEXT.md) im Repo-Wurzelverzeichnis — kanonische Begriffe, +keine Implementierung. Jede Session, die einen Begriff schärft, schreibt ihn dort fest. + Jede Session konsultiert: `ponytail` (dauerhaft aktiv), `/grilling` und `/domain-modeling` für Grilling-Tickets, `/research` für Research-Tickets, `/prototype` für Prototype-Tickets. @@ -55,14 +59,13 @@ auch über Ticket 13. +- [01 — Effekt-Vokabular](issues/01-effekt-vokabular.md) ([#2](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/2)) — **Zwei Begriffe statt einem**: Modifikator (rechnet ein Attribut um, solange er existiert) und Aktion (ändert Zustand einmalig), getrennte Maschinen und getrennte TOML-Arrays. Fester Attributkatalog ohne Namensraum; `max_health` ist Attribut, der Lebensstand ist Zustand. Sechs Aktionen, `damage` eigenständig wegen der Minderungskette. Stapeln `(Basis + Σ flach) × (1 + Σ prozentual)`. Eine Uhr: der Zug. Sieben feste Schadenstypen, ein Minderungsmechanismus (`resistance`), `armor` nur Kurzschreibweise. Auren wohnen beim Träger. Bedingungsvokabular bewusst an Ticket 08 delegiert. Begriffe im [Glossar](../../CONTEXT.md). - [05 — Research: Script-Engine](issues/05-research-script-engine.md) ([#6](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/6)) — Empfehlung Rhai wegen Fehlermeldungen mit Zeile und Spalte, billiger Typ-Brücke, AST-Hot-Reload und Build ohne `cc`. Gemessen: mlua liest unter `StdLib::ALL_SAFE` per `io.open` echte Dateien — „safe" heißt dort speichersicher, nicht fähigkeitsbeschränkt. Lua gewinnt bei der Modder-Vertrautheit; WASM scheidet für 1.0 aus. **Kernfolge: reden Scripts nur über das Effekt-Vokabular, ist die Engine-Wahl umkehrbar.** Entscheidung offen in Ticket 13. - [06 — Research: ratatui-App-Architektur](issues/06-research-ratatui-architektur.md) ([#7](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/7)) — Screen-Stack über zentralem `Game`-State statt Elm oder Component-Trait; `game/` bleibt ratatui-frei; Popups per `Clear` auf Sub-`Rect` statt Widget-Stack; blockierendes `event::read()` ohne Tick; Dungeon-Grid ist Eigenbau, es gibt kein Widget dafür; ratatui 0.30.2 mit MSRV 1.88; `KeyEventKind::Press`-Filter unter Windows Pflicht. Voller Bericht in [research/06](research/06-ratatui-architektur.md). ## Not yet specified -- **Kampfmechanik im Detail** — Initiative, Aktionen pro Runde, Trefferformel, Krit, Flucht. Wartet auf das Effekt-Vokabular (01), weil Angriffe und Fähigkeiten Effekte sind. - **Loot-Tabellen** — wie Drops definiert und gewichtet werden, wie `luck` einwirkt. Wartet auf die Typ-Registry (02). -- **XP-Kurve und Progression** — was Level-ups geben, wie Rasse/Klasse mitskalieren. Wartet auf 01. - **Boss-Design** — ob Bosse nur Gegner mit besseren Werten sind oder eigene Mechanik brauchen (Phasen, Skripte). Berührt Stufe (c) des Mod-Supports. - **NPC- und Handelsmodell** — Warenbestand, Preisbildung über `charisma`, Dialogdaten. Wartet auf das Event-System (08). - **Inventar-UX** — Slots, Gewicht oder Kapazität, Sortierung, Vergleichsansicht. Wartet jetzt auf das Screen-Modell (11), nicht mehr auf 06. diff --git a/CONTEXT.md b/CONTEXT.md new file mode 100644 index 0000000..f173057 --- /dev/null +++ b/CONTEXT.md @@ -0,0 +1,68 @@ +# Glossar + +Kanonische Begriffe für rustkeep. Nur Sprache, keine Implementierung. + +## Attribut + +Eine benannte, veränderbare Größe an einem Wesen. Der Katalog ist fest und wird von der Engine +vorgegeben — er umfasst die Grundwerte (Stärke, Geschicklichkeit, Konstitution, Charisma, Glück, +Leben, Ausdauer, Level) *und* die abgeleiteten Kampfgrößen (Schaden, Rüstung, Trefferchance, +Kritische Chance, Kritischer Faktor, Shop-Preis, Tragfähigkeit). + +Ein Attribut ist kein Inhalt, den ein Mod anlegt: Ein Modifikator auf ein Attribut, das keine +Spiellogik ausliest, hätte keine Wirkung. Der Katalog darf wachsen — aber durch die Engine, +nicht durch eine TOML-Datei. + +## Modifikator + +Eine Umrechnung eines [Attributs](#attribut), die gilt, solange eine Bedingung erfüllt ist. +Er wird nie ausgeführt, sondern beim Auslesen des Attributs aufsummiert. Quellen sind Rasse, +Klasse, ausgerüstete Gegenstände und befristete Zustände. + +Beispiele: „Zwerg: +2 Konstitution", „Eisenschwert: +5 Schaden", „Segen: +10 % Kritische Chance". + +## Aktion + +Eine einmalige Zustandsänderung. Sie feuert, wirkt, ist vorbei. Quellen sind Angriffe, +Verbrauchsgegenstände, Questbelohnungen und Fallen. + +Beispiele: „12 Schaden zufügen", „20 Leben heilen", „50 Gold geben", „Gift anwenden". + +Eine Aktion kann einen befristeten [Modifikator](#modifikator) erzeugen — so hängen die beiden +Begriffe zusammen, ohne dasselbe zu sein. + +## Zustand + +Der veränderliche Istwert eines Wesens — aktuelles Leben, aktuelle Ausdauer, getragene Gegenstände, +aktive befristete [Modifikatoren](#modifikator). Kein [Attribut](#attribut) und nicht von +Modifikatoren umrechenbar: Ein Modifikator wirkt auf `max_health`, eine [Aktion](#aktion) ändert den +Lebensstand. Die Trennung muss scharf bleiben, sonst heilt ein Ring beim Anlegen. + +## Schadenstyp + +Eine von sieben festen Kennzeichnungen, wie Schaden gemindert wird: `fire`, `ice`, `poison`, `shock`, +`holy`, `slash`, `blunt`. Engine-Vokabular ohne Namensraum. Zu jedem Typ gehört eine Resistenz, und +Resistenz ist der *einzige* Minderungsmechanismus — Rüstung ist Kurzschreibweise für Resistenz gegen +`slash` und `blunt`, kein eigenes Konzept. + +Der Schadenstyp `poison` ist **nicht** der Modifikator `core:poisoned` („Vergiftet"). Der Typ sagt, +wie gemindert wird; der Modifikator ist ein Zustand, der über Züge tickt. + +## Tag + +Eine freie, namespaced Kennzeichnung an einem Wesen (`core:undead`, `meinmod:aquatisch`). Reiner +Inhalt: Die Engine kennt keine Tags, sie vergleicht nur Zeichenketten. Grundlage für Bedingungen +wie „+5 Schaden gegen Untote". Gegenpol zum [Attribut](#attribut) — der Doppelpunkt zeigt dem Modder, +auf welcher Seite er steht. + +## Zug + +Die einzige Zeiteinheit des Spiels. Ein Feld weitergehen ist ein Zug, eine Kampfaktion ist ein Zug. +Es gibt keine getrennte Kampfrunden-Uhr: Befristete [Modifikatoren](#modifikator) ticken auch beim +Erkunden, damit „ich warte den Debuff draußen ab" eine Entscheidung mit Kosten bleibt. + +## Effekt + +**Kein kanonischer Begriff.** Wird umgangssprachlich für [Modifikator](#modifikator) *und* +[Aktion](#aktion) benutzt; in Code, TOML und Doku ist stattdessen immer der genaue Begriff zu +verwenden. Das Wort überlebt nur noch in „Effekt-Vokabular" als Sammelname für beide zusammen.