feat(handel): NPC-Registry, Dialog, Laden und Stapelregel
Vierzehnte Registry: NPCs sind keine Wesen — kein Kampfzustand, keine Initiative, keine Attribute. Ihre Antwortliste ist flach; was erst nach einer Antwort erscheint, ist eine Option mit einer Bedingung. - open_shop als elfte Aktion (game/ setzt eine Absicht, die UI schiebt) - Talk/Choose/Buy/Sell, Talk wirkt auf das eigene Feld wie PickUp - Preisspanne statt Goldkonto beim Haendler, Charisma in der Preisfunktion - Warenkorb einmal bei der Etagenerzeugung gezogen - Stapelregel aus Ticket 07 endlich gebaut: 50-120 Gold war 120 Eintraege - Dialog- und Shop-Screen, NPC-Symbol im Grid
This commit is contained in:
@@ -91,6 +91,28 @@ Lücke**: Ein Trigger kann die Nutzlast des Events, das ihn ausgelöst hat, **ni
|
||||
sieht nur Wesen. „Dornenpanzer reflektiert nur Feuer" ist damit nicht formulierbar. Zu entscheiden vor
|
||||
M4, weil dort Affix- und Gegenstands-Trigger kommen.
|
||||
|
||||
**M4 — Beute, Inventar, Affixe und Handel** (`feat/m4-beute`, `feat/m4-handel`, 56 Tests)
|
||||
|
||||
| Zusage | Aus | Befund |
|
||||
|---|---|---|
|
||||
| Eine Maschinerie für Gegenstände *und* Affixe | 16 | **bestätigt** — dieselben Gewichte, dieselbe Tabelle-in-Tabelle |
|
||||
| Beute erst beim Aufheben auflösen, ein Symbol für alles | 16 | **bestätigt** — die Anzeige verrät nichts, was noch nicht gewürfelt ist |
|
||||
| Affix ist eine benannte Modifikatorliste am Exemplar | 07 | **bestätigt** — strukturell dasselbe wie eine Charakteroption, `attribute()` blieb unverändert |
|
||||
| Speicherstand bleibt eine ID-Liste | 07 | **bestätigt** — `ItemInstance` trägt `def`, `affixes`, `count` |
|
||||
| Stapelregel: gleiche `def` **und** gleiche `affixes` | 07 | **war nie umgesetzt** — siehe unten |
|
||||
| Gold ist ein gewöhnlicher Gegenstand | 09 | **bestätigt** — Bezahlen läuft durch `take("core:gold", …)`, kein Sonderfeld |
|
||||
| Flache Dialogliste statt Knotengraph | M4 | **bestätigt** — die bedingte Option ersetzt den zweiten Knoten, ohne Knoten-IDs im Save |
|
||||
| `open_shop` als elfte Aktion, nicht als Sonderfeld | 01 | **bestätigt** — `game/` setzt eine Absicht, die Schleife schiebt den Screen |
|
||||
| Warenkorb einmal bei der Erzeugung ziehen | M4 | **bestätigt** — Schließen und Öffnen liefert dasselbe Angebot |
|
||||
|
||||
Ein Befund nachgetragen: **07/01/09** — die Stapelregel stand seit Ticket 07 auf dem Papier, aber
|
||||
niemand hatte sie gebaut. Der Beutezieher schob für `count = "50-120"` bis zu **120 einzelne Einträge**
|
||||
ins Inventar. Gefunden nicht beim Nachdenken, sondern beim Entwerfen des Handels: „Gold abziehen"
|
||||
braucht einen Stapel, sonst ist Bezahlen eine Schleife über Einträge.
|
||||
|
||||
Dazu **eine bewusst offene Stelle**: `Npc.triggers` ist nicht gebaut, weil `triggers_for` NPCs nicht
|
||||
einsammelt — ein Feld ohne Leser wäre eine Zusage, die niemand einlöst. TODO steht im Code.
|
||||
|
||||
**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.
|
||||
@@ -150,11 +172,65 @@ auch über Ticket 13.
|
||||
- [15 — Progression und Level-up](issues/15-progression-und-levelup.md) ([#16](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/16)) — Ein Aufstieg gibt **genau einen** frei verteilbaren Punkt auf die fuenf Grundwerte; `AssignPoints` ist **ein** Command mit allen Punkten (drei Stufen waeren sonst drei Zuege im Menue). **Keine Obergrenze** — `clamp(1, 50)` faellt, die Kurve begrenzt sich ueber steigende Kosten (`exp_base`, `exp_exponent` in `[balance]`). Erfahrung aus Toetungen (`exp_reward` am Wesen) und Quests (`give_exp`, zehnte Aktion), **nicht** fuers Betreten einer Etage — das belohnte das Durchrennen. **Die Zuwachs-Regel bleibt eng**: nur Aufstieg und `AssignPoints` heben den Lebensstand mit `max_health`, Ausruestung nie — sonst „heilt ein Ring beim Anlegen" (01). Rasse und Klasse bleiben **flach**, `per_level` entfaellt ersatzlos; was sie traegt, sind Faehigkeiten. `level` darf modifiziert werden, aber Punkte haengen an `base.level` — ein `+1 level`-Ring schenkt keinen. Vier Nachtraege: `give_exp` an 01, `current_exp`/`unspent_points` an **`Game`** statt ans Wesen (07 hatte die Platzierung hierher delegiert), `AssignPoints` an 11, zwei Balance-Knoepfe plus `exp_reward` an 14.
|
||||
- [16 — Loot-Tabellen](issues/16-loot-tabellen.md) ([#17](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/17)) — Zwoelfte Registry `[[loot_tables]]`, **eine Maschinerie fuer Gegenstaende und Affixe**. **Gewichte statt Prozent**, weil Prozente sich auf 100 summieren muessen und ein hinzugefuegter Mod-Eintrag die Summe kaputt macht. Nieten sind gewoehnliche Eintraege (kein `drop_chance`), Tabelle-in-Tabelle liefert Seltenheitsstufen, ohne dass „Seltenheit" ein Begriff wird. **Affix-Stufen statt Affix-Werte** — eine Staerke je Exemplar haette Save-Format, Preisformel und Stapelregel aus 07 auf einmal gekostet. **`luck` hat genau eine Regel**: Chance auf einen zusaetzlichen Zug auf jeder Tabelle — wirkt dreifach (mehr Gegenstaende, mehr Affixe, haeufiger die staerkere Stufe), ohne dreimal geschrieben zu werden. Der **Mod-Einhaengepunkt existiert schon**: Tabelle-in-Tabelle plus zwei Ueberschreibungen, kein zweiter Mechanismus. Bodenbeute wird **erst beim Aufheben** gezogen (`Room` haelt eine `loot_table` plus Positionen), moeglich nur weil alle Haufen dasselbe Symbol zeigen — dadurch wirkt ein Gluecksring auch auf das, was schon liegt. `guaranteed = true` fuer Bosse, Mehrfachziehung erlaubt. Nachtraege: `Room`-Umbau und optionales Prefab-`loot` an 10, `LUCK_FACTOR` an 14.
|
||||
|
||||
## Nachentscheidungen
|
||||
|
||||
Entscheidungen, die nach dem Schließen aller Tickets fällig wurden — beim Bauen, nicht beim Planen.
|
||||
|
||||
### NPC- und Handelsmodell (während M4)
|
||||
|
||||
Der letzte Punkt aus „Not yet specified". Er hing an nichts Offenem mehr: `Talk` stand in Ticket 11s
|
||||
Command-Liste, `npc_talked` in Ticket 08s Eventliste, `Dialog` und `Shop` unter den elf Screens, und
|
||||
Ticket 10 ließ das Prefab seine NPCs nennen. Was fehlte, waren die Definitionen dahinter.
|
||||
|
||||
**NPCs sind die vierzehnte Registry.** Nicht `creatures` mit `hostile = false`: Ein Händler trüge dann
|
||||
`health`, `initiative`, `cooldowns`, `ai` und `exp_reward` als dauerhaft toten Ballast, und die Frage
|
||||
„kann ich den Händler erschlagen" wäre beantwortet, ohne dass sie jemand gestellt hat. Vereinheitlichen
|
||||
lohnt, wenn Felder *geteilt* werden, nicht wenn sie mitgeschleppt werden.
|
||||
|
||||
**Der Warenbestand ist eine Beutetabelle.** `shop = "core:blacksmith_stock"` verweist auf
|
||||
`[[loot_tables]]` — dieselben Gewichte, dieselbe Tabelle-in-Tabelle, dieselben Affixe. Kein neuer
|
||||
„Waren"-Begriff, und ein Mod hängt Waren mit demselben Handgriff ein wie Beute. Gezogen wird **einmal
|
||||
beim Erzeugen der Etage**: Bei jedem `Talk` neu wäre ausnutzbar (weggehen, wiederkommen, bis das gute
|
||||
Stück im Regal liegt) — dieselbe Klasse wie Save-Scumming, die Ticket 14 geschlossen hat. Der
|
||||
Unterschied zur Bodenbeute, die *doch* erst beim Aufheben zieht: Dort war das Argument **Glück**, und
|
||||
bei einem Laden hat Glück nichts zu suchen — ein Kauf ist kein Fund.
|
||||
|
||||
**Preise mit Spanne**, sonst ist Handel ein Exploit oder ein No-op:
|
||||
|
||||
```
|
||||
kauf = item_price × (1 − price_modifier/100)
|
||||
verkauf = item_price × VERKAUF × (1 + price_modifier/100) # VERKAUF ≈ 0.4
|
||||
```
|
||||
|
||||
`charisma` speist `price_modifier` über eine Formel, die in der **Preisfunktion** lebt, nicht in
|
||||
`Game::attribute` — dort wäre es das einzige Attribut mit einem Sonderfall, und ein generischer Pfad
|
||||
mit einer Ausnahme ist die Stelle, an der später jemand rät. Der Händler kauft **alles und hat
|
||||
unbegrenzt Gold**: Die Spanne verhindert die Geldmaschine bereits, ein Goldvorrat wäre eine zweite
|
||||
Regel gegen dasselbe Problem.
|
||||
|
||||
**Dialoge sind eine flache Optionsliste**, kein Knotengraph. Jede Option trägt Text, `condition` und
|
||||
`actions` — damit sind Questvergabe, bedingte Optionen und Ladenzugang abgedeckt. Was erst ein Graph
|
||||
könnte, ist **Erzählung**, und das Story-Modul steht ausdrücklich unter *Out of scope*. Der Ausbau ist
|
||||
additiv: `goto` an der Option plus eine Knotenebene, die vorhandenen Optionen werden der Startknoten.
|
||||
|
||||
**`open_shop` wird die elfte Aktion** statt eines Sonderfelds an der Option — sie steht dann in
|
||||
derselben Liste wie `start_quest` und läuft über denselben Eingang.
|
||||
|
||||
**Angesprochen wird auf dem eigenen Feld.** Eine Regel für drei Kommandos: `g` hebt auf, was hier
|
||||
liegt, `>` steigt ab, wo hier eine Treppe ist, `t` spricht an, wer hier steht. Ein NPC blockiert nicht
|
||||
— er steht in einem Laden, nicht in einer Tür.
|
||||
|
||||
**Befund nebenbei: `stackable` war nie implementiert.** Ticket 02 gab Gegenständen das Feld, Ticket 07
|
||||
die Stapelregel, Ticket 09 erklärte Gold zum gewöhnlichen Gegenstand — und `loot.rs` schob für
|
||||
`count = "50-120"` bis zu 120 einzelne Einträge ins Inventar. `ItemInstance` bekommt deshalb ein
|
||||
`count`, und die Regel aus 07 (`stackable` **und** gleiche `def` **und** gleiche `affixes`) wird zum
|
||||
ersten Mal ausgeführt statt nur beschrieben.
|
||||
|
||||
## Not yet specified
|
||||
|
||||
- **Balancing** — konkrete Zahlen für Attribute, Schaden, Preise und Erfahrung über fünf Etagen. Wartet auf Kampfformeln (14), Progression (15) und Loot (16); vorher gibt es nichts zu balancieren.
|
||||
- **Boss-Design** — ein Boss ist derzeit ein Wesen mit `ai`-Liste (14) in einem Prefab mit `core:boss`-Tag (10). Was fehlt, sind **Phasen**: „ab 50 % Leben ein anderes Verhalten" wäre mit der `ai`-Bedingungsliste sogar ausdrückbar, „ab 50 % ändern sich die Werte" nicht. Berührt Stufe (c) des Mod-Supports.
|
||||
- **NPC- und Handelsmodell** — Warenbestand, Dialogdaten. Wartet auf das Event-System (08). Die Preisformel steht bereits in 07; weil 07 Backtracking ausgeschlossen hat, muss ein Händler auf **jeder** Etage erreichbar sein.
|
||||
- ~~**NPC- und Handelsmodell**~~ — **entschieden während M4**, siehe unten.
|
||||
- **Inventar-UX** — Gewicht oder Kapazität (`carry_capacity` ist seit 01 ein Attribut ohne Regel), Sortierung, Vergleichsansicht. 11 hat nur den Screen und die Commands festgelegt, nicht was darin steht.
|
||||
- **Mod-Verteilung** — durch 03 auf „Ordner ins Profil entpacken" geschrumpft, ohne Versionsprüfung. Offen ist nur noch, ob 1.0 mehr braucht.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user