Files
rustkeep/.scratch/rustkeep-1.0/issues/01-effekt-vokabular.md

129 lines
5.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 01 — Effekt-Vokabular
Type: grilling
Status: resolved
Blocked by: —
## Question
Was kann ein Effekt ausdrücken, und wie sieht er in TOML aus?
Das Effekt-Vokabular ist die Mod-API: ein Modder kann exakt das bauen, was hier definiert wird.
Zu klären:
- Welche Wirkungen gibt es? Stat-Modifikator (flach, prozentual), Sofortschaden/Heilung,
Ressourcenverbrauch, Statuseffekt anwenden/entfernen, Event auslösen.
- Zeitlichkeit: permanent (Rasse), solange ausgerüstet (Item), N Runden (Statuseffekt), einmalig (Trank).
- Wie werden Effekte gestapelt und in welcher Reihenfolge verrechnet? Erst flach, dann prozentual?
- Wie referenziert ein Effekt sein Ziel — Träger, Gegner, alle Gegner?
- 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") |
### Nachtrag aus Ticket 08: `start_quest`
Der Katalog hat **sieben** Aktionen, nicht sechs. `start_quest` kam mit
[Ticket 08](08-event-trigger-system.md) dazu, weil eine Quest sonst ab dem ersten Zug mitzählte und
Questketten beim Betreten des Kellers bereits erfüllt wären.
```toml
{ action = "start_quest", quest = "core:rattenplage", target = "self" }
```
Das hier angeforderte Bedingungsvokabular steht ebenfalls in 08, zusammen mit dem **Trigger** als
vierter Wirkungsform.
### Nachtrag aus Ticket 11: `symbol` trägt das Zeichen, nicht einen Schlüssel
Oben steht, `symbol` sei ein Schlüssel und die Zuordnung mache `ui/theme.rs`. Darin steckt eine Lücke:
**`ui/theme.rs` ist Code.** Ein Modder, der `meinmod:frostbite` anlegt, kann dort nichts eintragen —
sein Statuseffekt hätte weder Zeichen noch Farbe.
Stattdessen trägt die TOML beides selbst, die Farbe als Name aus fester Liste:
```toml
symbol = "†"
color = "cyan"
```
`data/` kennt nur `char` und ein Farbnamen-Enum, `ui/theme.rs` übersetzt in `ratatui::Color` — `game/`
und `data/` bleiben damit weiterhin ratatui-frei.
### 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`).