docs: m3-befunde in tickets 01, 08 und 14 zurueckgetragen, dreizehnte registry ins glossar
This commit is contained in:
@@ -153,6 +153,32 @@ Fähigkeiten. Das Vokabular bleibt hier unverändert.
|
|||||||
`damage` · `change_attribute` · `apply_modifier` · `remove_modifier` · `give_item` · `remove_item` ·
|
`damage` · `change_attribute` · `apply_modifier` · `remove_modifier` · `give_item` · `remove_item` ·
|
||||||
`start_quest` (08) · `flee` (14) · `run_script` (13) · `give_exp` (15) — **zehn**.
|
`start_quest` (08) · `flee` (14) · `run_script` (13) · `give_exp` (15) — **zehn**.
|
||||||
|
|
||||||
|
### Nachtrag aus M3: benannte Modifikatoren brauchen eine Registry
|
||||||
|
|
||||||
|
Oben steht `{ action = "apply_modifier", modifier = "core:poisoned", … }` — eine Aktion referenziert
|
||||||
|
einen Modifikator **per ID**. Aufgefallen beim Bauen von M3: **Keine der zwölf Registries definiert
|
||||||
|
benannte Modifikatoren.** `core:poisoned` hatte kein Zuhause.
|
||||||
|
|
||||||
|
Das ist die **dreizehnte Registry**, `[[modifiers]]`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[modifiers]]
|
||||||
|
id = "poisoned"
|
||||||
|
name = "Vergiftet"
|
||||||
|
symbol = "☠"
|
||||||
|
turns = 4
|
||||||
|
attributes = [ { attribute = "damage", percent = -15 } ]
|
||||||
|
triggers = [ { on = "turn_started",
|
||||||
|
actions = [ { action = "damage", amount = 2, damage_type = "poison", target = "self" } ] } ]
|
||||||
|
```
|
||||||
|
|
||||||
|
Das innere Feld heißt bewusst `attributes` und nicht `modifiers` — ein Modifikator, der Modifikatoren
|
||||||
|
enthält, liest sich wie ein Fehler. Und `effects` wäre der Begriff, den dieses Ticket ausdrücklich
|
||||||
|
verworfen hat.
|
||||||
|
|
||||||
|
Ein Modifikator ist damit ein **Bündel**: mehrere Umrechnungen plus Trigger plus Dauer. Gift senkt den
|
||||||
|
Schaden *und* tickt — das wäre mit einer einzelnen Umrechnung nicht ausdrückbar.
|
||||||
|
|
||||||
### Bewusst nicht entschieden
|
### Bewusst nicht entschieden
|
||||||
|
|
||||||
Das **Bedingungsvokabular** für `condition`. Es kommt aus Ticket 08, damit Quests und Modifikatoren
|
Das **Bedingungsvokabular** für `condition`. Es kommt aus Ticket 08, damit Quests und Modifikatoren
|
||||||
|
|||||||
@@ -71,6 +71,28 @@ Level ≥ 3" wird zu zwei Einträgen dupliziert — oder der Modder hängt beide
|
|||||||
Bedingungen werden an **zwei** Stellen ausgewertet: beim Feuern eines Triggers und beim Auslesen eines
|
Bedingungen werden an **zwei** Stellen ausgewertet: beim Feuern eines Triggers und beim Auslesen eines
|
||||||
Attributs (bedingte Modifikatoren aus 01). Letzteres erzwingt den Nachtrag an Ticket 07, siehe unten.
|
Attributs (bedingte Modifikatoren aus 01). Letzteres erzwingt den Nachtrag an Ticket 07, siehe unten.
|
||||||
|
|
||||||
|
### Nachträge aus M3
|
||||||
|
|
||||||
|
Beim Bauen kamen zwei Prüfungen dazu, die oben fehlten:
|
||||||
|
|
||||||
|
- **`health_below`** mit einem Anteil (0.0–1.0). Die `ai`-Listen aus 14 brauchen „unter 30 % Leben", und
|
||||||
|
das ist mit `attribute` nicht ausdrückbar: `health` ist **Zustand**, kein Attribut (01), und ein
|
||||||
|
*Verhältnis* lässt sich mit `at_least`/`below` auf einem absoluten Wert nicht formulieren.
|
||||||
|
- **`chance`** am Trigger. Dieses Ticket nennt „Flammendes Schwert: 20 % Chance, Brennen auszulösen" als
|
||||||
|
Motivbeispiel, hat aber kein Feld dafür festgelegt. Ohne es bräuchte jeder Wahrscheinlichkeitseffekt
|
||||||
|
ein Script — und Scripting liegt laut 13 hinter 1.0.
|
||||||
|
|
||||||
|
### Offene Lücke aus M3: ein Trigger sieht sein Event nicht
|
||||||
|
|
||||||
|
Die Events oben tragen Nutzlast (Schadenstyp, Prefab-ID, Menge) — **die Bedingungsgrammatik kann sie
|
||||||
|
nicht prüfen.** `Check` sieht nur Wesen, nie das Ereignis. Damit ist „Dornenpanzer reflektiert nur
|
||||||
|
Feuer" oder „nur bei kritischen Treffern" derzeit nicht formulierbar.
|
||||||
|
|
||||||
|
In M3 wurden `Event.damage_type` und `Event.label` deshalb gestrichen: Felder, die niemand auslesen
|
||||||
|
kann, sind Kommentare in Feldform. Was fehlt, ist eine Prüfungsfamilie über die Nutzlast — etwa
|
||||||
|
`{ check = "damage_type", value = "fire" }`. Zu entscheiden, bevor Affixe und Gegenstands-Trigger
|
||||||
|
kommen (M4), denn dort werden solche Effekte erwartet.
|
||||||
|
|
||||||
### Neun Events, feste Liste
|
### Neun Events, feste Liste
|
||||||
|
|
||||||
| Event | Nutzlast über `source`/`target` hinaus |
|
| Event | Nutzlast über `source`/`target` hinaus |
|
||||||
@@ -144,6 +166,12 @@ Gegen Zyklen — Trigger A löst B aus, B löst A aus — ein schlichter Zähler
|
|||||||
Zug**, danach Abbruch mit Warnzeile. Kein Zyklenerkennungs-Graph; der Zähler fängt denselben Fall und
|
Zug**, danach Abbruch mit Warnzeile. Kein Zyklenerkennungs-Graph; der Zähler fängt denselben Fall und
|
||||||
ist eine Zeile.
|
ist eine Zeile.
|
||||||
|
|
||||||
|
**Befund aus M3: die Warteschlange war ein Stack.** Die erste Umsetzung nahm `Vec::pop()`, also LIFO —
|
||||||
|
ein Folge-Event drängelte sich vor die schon wartenden. Genau das sollte die Warteschlange verhindern
|
||||||
|
(„hängt es hinten an, statt den Stack zu vertiefen"). Jetzt `VecDeque` mit `pop_front`. Die Formulierung
|
||||||
|
oben war richtig, die Umsetzung nicht, und **kein Test hat es gemerkt** — Reihenfolge fällt erst auf,
|
||||||
|
wenn zwei Trigger um dasselbe Ziel konkurrieren.
|
||||||
|
|
||||||
Trigger werden bei jedem Event **gesucht, nicht indiziert** — dieselbe Entscheidung wie „kein
|
Trigger werden bei jedem Event **gesucht, nicht indiziert** — dieselbe Entscheidung wie „kein
|
||||||
Attribut-Cache" in 07 und aus demselben Grund: Ein Index müsste bei jedem An- und Ablegen, jedem Loot
|
Attribut-Cache" in 07 und aus demselben Grund: Ein Index müsste bei jedem An- und Ablegen, jedem Loot
|
||||||
und jedem Affix-Wechsel gepflegt werden, also genau das Invalidierungsproblem, das 07 vermieden hat.
|
und jedem Affix-Wechsel gepflegt werden, also genau das Invalidierungsproblem, das 07 vermieden hat.
|
||||||
|
|||||||
@@ -102,6 +102,15 @@ p_flucht = clamp(0.5 + (dexterity(Held) - dexterity(schnellster Gegner)) * FLUCH
|
|||||||
geminderten multipliziert, ist mathematisch belanglos: `roh × kf × (1−r)` ist dasselbe wie
|
geminderten multipliziert, ist mathematisch belanglos: `roh × kf × (1−r)` ist dasselbe wie
|
||||||
`roh × (1−r) × kf`. Festzulegen war nur, dass beide multiplikativ *bleiben*.
|
`roh × (1−r) × kf`. Festzulegen war nur, dass beide multiplikativ *bleiben*.
|
||||||
|
|
||||||
|
**Befund aus M3: die Trefferformel war toter Code.** `hit_chance` existierte, war getestet — und wurde
|
||||||
|
nie aufgerufen. **Jeder Angriff traf.** Gemeldet hat es nur der Compiler
|
||||||
|
(`warning: function 'hit_chance' is never used`); kein Test schlug an, weil alle Tests die Formel
|
||||||
|
*direkt* prüften statt über einen Angriff.
|
||||||
|
|
||||||
|
Lehre für die Formeln unten: Eine Formel, die nur von ihrem eigenen Unit-Test aufgerufen wird, ist
|
||||||
|
nicht verdrahtet. Der Test, der das jetzt abfängt, führt 200 Angriffe gegen einen absurd flinken
|
||||||
|
Gegner und verlangt, dass mindestens einer verfehlt *und* mindestens einer trifft.
|
||||||
|
|
||||||
Drei Klemmbereiche, jeder mit Grund:
|
Drei Klemmbereiche, jeder mit Grund:
|
||||||
|
|
||||||
- **Resistenz bei `0.8`** — bei `1.0` wäre ein Wesen immun, und Immunität ist keine Zahl, sondern ein
|
- **Resistenz bei `0.8`** — bei `1.0` wäre ein Wesen immun, und Immunität ist keine Zahl, sondern ein
|
||||||
|
|||||||
@@ -66,6 +66,31 @@ Wandfelder; zwei L-Varianten reichen nicht, es braucht eine Wegsuche über den f
|
|||||||
(das Grid braucht einen mitlaufenden Bildausschnitt, weil Etage 5 breiter ist als ein
|
(das Grid braucht einen mitlaufenden Bildausschnitt, weil Etage 5 breiter ist als ein
|
||||||
80-Spalten-Terminal — das stand in keinem Ticket).
|
80-Spalten-Terminal — das stand in keinem Ticket).
|
||||||
|
|
||||||
|
**M3 — Kampf, Events und Trigger** (`feat/m3-kampf`, 43 Tests)
|
||||||
|
|
||||||
|
| Zusage | Aus | Befund |
|
||||||
|
|---|---|---|
|
||||||
|
| Trigger werden **gesucht, nicht indiziert** | 08 | **bestätigt** — die letzte offene Papierzusage. Gift tickt über einen `turn_started`-Trigger, ohne Script |
|
||||||
|
| Warteschlange statt Rekursion | 08 | **erst nach Korrektur** — die Umsetzung war ein Stack |
|
||||||
|
| Zug = Spieler plus alle Gegner, Initiative am Wesen | 14 | **bestätigt**, Gleichstand geht an den Spieler |
|
||||||
|
| Tote erst am Zugende entfernen | 14 | **bestätigt** |
|
||||||
|
| Gesperrte Fähigkeit ⇒ `Rejected`, kein Zug | 14 | **bestätigt** |
|
||||||
|
| Resistenz typ-indiziert, bei 0.8 gedeckelt | 01/14 | **bestätigt**, Verwundbarkeit bei −1.0 ausdrückbar |
|
||||||
|
| Krit-Reihenfolge ist belanglos | 14 | **bestätigt**, direkt nachgerechnet |
|
||||||
|
| Gegner gehören zum Raum, verschoben nicht kopiert | 10 | **bestätigt** |
|
||||||
|
| Trefferformel | 14 | **war toter Code** — jeder Angriff traf, siehe unten |
|
||||||
|
|
||||||
|
Drei Befunde nachgetragen: **14** (die Trefferformel wurde nie aufgerufen — nur der Compiler hat es
|
||||||
|
gemeldet, weil alle Tests sie *direkt* prüften statt über einen Angriff), **08** (die Warteschlange war
|
||||||
|
`Vec::pop`, also LIFO — die Formulierung war richtig, die Umsetzung nicht, und kein Test hat es
|
||||||
|
gemerkt) und **01** (benannte Modifikatoren wie `core:poisoned` hatten keine Registry; jetzt die
|
||||||
|
**dreizehnte**).
|
||||||
|
|
||||||
|
Dazu zwei Ergänzungen am Bedingungsvokabular (`health_below`, `chance` am Trigger) und **eine offene
|
||||||
|
Lücke**: Ein Trigger kann die Nutzlast des Events, das ihn ausgelöst hat, **nicht prüfen** — `Check`
|
||||||
|
sieht nur Wesen. „Dornenpanzer reflektiert nur Feuer" ist damit nicht formulierbar. Zu entscheiden vor
|
||||||
|
M4, weil dort Affix- und Gegenstands-Trigger kommen.
|
||||||
|
|
||||||
**Drei Befunde aus M1, die nur der Compiler liefern konnte** — alle in die Tickets zurückgetragen:
|
**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.
|
- **11**: Der Grenztest in seiner wörtlichen Fassung schlägt beim eigenen Doc-Kommentar an. Muss Kommentarzeilen ausnehmen.
|
||||||
|
|||||||
12
CONTEXT.md
12
CONTEXT.md
@@ -33,6 +33,11 @@ Klasse, ausgerüstete Gegenstände und befristete Zustände.
|
|||||||
|
|
||||||
Beispiele: „Zwerg: +2 Konstitution", „Eisenschwert: +5 Schaden", „Segen: +10 % Kritische Chance".
|
Beispiele: „Zwerg: +2 Konstitution", „Eisenschwert: +5 Schaden", „Segen: +10 % Kritische Chance".
|
||||||
|
|
||||||
|
Ein **benannter** Modifikator (`core:poisoned`) ist ein Bündel: mehrere Umrechnungen, eigene
|
||||||
|
[Trigger](#trigger) und eine Dauer in [Zügen](#zug). Er lebt in der Registry `[[modifiers]]` und wird
|
||||||
|
von der [Aktion](#aktion) `apply_modifier` aufgelegt. Er **wohnt beim Träger** — stirbt der, verschwindet
|
||||||
|
er mit ihm.
|
||||||
|
|
||||||
## Aktion
|
## Aktion
|
||||||
|
|
||||||
Eine einmalige Zustandsänderung. Sie feuert, wirkt, ist vorbei. Quellen sind Angriffe,
|
Eine einmalige Zustandsänderung. Sie feuert, wirkt, ist vorbei. Quellen sind Angriffe,
|
||||||
@@ -232,9 +237,9 @@ Es gibt **keinen Seltenheitsbegriff**: Abstufungen sind eigene Einträge mit kle
|
|||||||
|
|
||||||
## Registry
|
## Registry
|
||||||
|
|
||||||
Eine benannte Sammlung moddbarer Definitionen, geschlüsselt nach namespaced ID. Es gibt **zwölf**, und
|
Eine benannte Sammlung moddbarer Definitionen, geschlüsselt nach namespaced ID. Es gibt **dreizehn**,
|
||||||
das hier ist die kanonische Liste — sie ist über sieben Tickets gewachsen und stand sonst nirgends
|
und das hier ist die kanonische Liste — sie ist über sieben Tickets und drei Meilensteine gewachsen und
|
||||||
vollständig:
|
stand sonst nirgends vollständig:
|
||||||
|
|
||||||
| Registry | TOML-Tabelle |
|
| Registry | TOML-Tabelle |
|
||||||
|---|---|
|
|---|---|
|
||||||
@@ -249,6 +254,7 @@ vollständig:
|
|||||||
| [Prefabs](#prefab) | `[[prefabs]]` |
|
| [Prefabs](#prefab) | `[[prefabs]]` |
|
||||||
| [Etagen](#etage) | `[[floors]]` |
|
| [Etagen](#etage) | `[[floors]]` |
|
||||||
| [Loot-Tabellen](#loot-tabelle) | `[[loot_tables]]` |
|
| [Loot-Tabellen](#loot-tabelle) | `[[loot_tables]]` |
|
||||||
|
| Benannte [Modifikatoren](#modifikator) | `[[modifiers]]` |
|
||||||
| Scripts | `[[scripts]]` |
|
| Scripts | `[[scripts]]` |
|
||||||
|
|
||||||
Jede dieser Tabellen darf in jeder beliebigen `*.toml` eines [Mods](#mod) stehen.
|
Jede dieser Tabellen darf in jeder beliebigen `*.toml` eines [Mods](#mod) stehen.
|
||||||
|
|||||||
Reference in New Issue
Block a user