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

5.7 KiB
Raw Permalink Blame History

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 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

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

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 dazu, weil eine Quest sonst ab dem ersten Zug mitzählte und Questketten beim Betreten des Kellers bereits erfüllt wären.

{ 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:

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).