8.6 KiB
16 — Loot-Tabellen
Type: grilling Status: resolved Blocked by: 02
Question
Wie werden Beutefunde definiert, gewichtet und ausgewürfelt?
Die Gegenstands-Registry aus 02 steht, luck ist ein Attribut aus 01. Offen ist alles dazwischen:
- Wo hängt Beute? Am Gegner, am Raum-Prefab, an der Etage, oder an einer benannten Tabelle, die mehrere referenzieren können?
- Wie wird gewichtet? Gewichte pro Eintrag, Wahrscheinlichkeit in Prozent, oder Seltenheitsstufen mit fester Verteilung? Dürfen Tabellen andere Tabellen referenzieren?
- Wie wirkt
luck? Auf die Drop-Chance, auf die Seltenheitsstufe, auf die Menge — oder auf mehreres, und mit welcher Formel? - Mengen und Garantien: Gibt es „genau ein Gegenstand", „null bis drei", garantierte Drops für Bosse? Kann ein Eintrag mehrfach gezogen werden?
- Etagenskalierung: Fallen auf Etage 5 andere Gegenstände als auf Etage 1, und wird das über getrennte Tabellen ausgedrückt oder über eine Bedingung am Eintrag?
- Wie greifen Mods ein? Nur neue Tabellen hinzufügen, oder auch Einträge in fremde Tabellen einhängen — und wie sieht dieses Einhängen aus, ohne die fremde Datei zu überschreiben?
- Zufall: derselbe Generator wie im Kampf (Ticket 14), und gehört sein Zustand in den Speicherstand?
Ergebnis: Tabellenschema mit TOML-Beispiel, Gewichtungsregel, luck-Formel und die Mod-Einhängepunkte.
Vorgabe aus Ticket 07
Beute ist ItemInstance { def, affixes }, nicht bloß eine Gegenstands-ID. Damit kommt eine Frage
dazu, die es vor 07 nicht gab: Wer vergibt Affixe beim Loot, und mit welcher Gewichtung? Hängen
sie an der Tabelle, am Eintrag, an der Etage — und wirkt luck auf die Affix-Zahl, auf deren
Seltenheit, oder gar nicht?
Affixe sind eine eigene Registry (die sechste), also gilt für sie derselbe Mod-Einhängepunkt wie für Gegenstände.
Answer
Begriffe im Glossar. Der Zufall war bereits entschieden: derselbe gesetzte Generator aus Ticket 14, dessen Seed im Save liegt — Beute würfelt beim Nachladen nicht neu.
Eine Maschinerie für Gegenstände und Affixe
Zwölfte Registry [[loot_tables]]:
[[loot_tables]]
id = "core:weapon_affixes"
rolls = "0-1"
entries = [
{ affix = "core:flaming", weight = 5 },
{ affix = "core:greater_flaming", weight = 1 }, # Stufe, kein Wert
{ nothing = true, weight = 20 },
]
[[loot_tables]]
id = "core:floor_3_table"
rolls = "1-3"
entries = [
{ item = "core:health_potion", weight = 10, count = "1-2" },
{ item = "core:iron_sword", weight = 3, affixes = "core:weapon_affixes" },
{ table = "core:rare_table", weight = 1 },
{ nothing = true, weight = 20 },
{ item = "core:boss_blade", guaranteed = true },
]
Gewichte statt Prozent — keine Geschmacksfrage, sondern eine Modding-Frage: Prozentwerte müssen sich auf 100 summieren, und ein hinzugefügter Eintrag macht die Summe kaputt, woraufhin jemand alle anderen anpassen muss. Gewichte verdünnen sich anteilig, ohne dass irgendwer rechnet.
Nieten sind gewöhnliche Einträge, kein eigenes drop_chance-Feld. Ein Gegner, der selten etwas
fallen lässt, bekommt ein hohes nothing-Gewicht — die Engine kennt eine Mechanik statt zweier.
Tabelle-in-Tabelle ist eine Zeile und liefert Seltenheitsstufen, ohne dass „Seltenheit" ein Begriff werden muss.
guaranteed = true wird immer ausgegeben und nimmt an der Gewichtung nicht teil. Mit Gewichten
allein lässt sich „sicher" nicht ausdrücken, und Bosse stehen in der Destination; Questgegenstände sind
derselbe Fall.
Mehrfachziehung erlaubt, kein unique-Flag. Drei Heiltränke sind ein normales Ergebnis, und
stapelbare Gegenstände (02) tragen das ohne Zutun. Wer Einzelstücke will, gibt ihnen eine eigene
Tabelle mit rolls = "1-1". Die Decke: Falls „nie zweimal dasselbe Schwert" nötig wird, ist unique
ein Flag — jetzt wäre es eine Regel ohne Fall.
Affix-Stufen statt Affix-Werte
Ticket 07 hat festgelegt, dass eine ItemInstance nur Affix-IDs trägt. „Flammend" und „Stark
flammend" sind deshalb zwei Registry-Einträge mit unterschiedlichen Modifikatoren und Preisfaktoren,
keine Zahl am Exemplar.
Eine Stärke je Exemplar hätte drei Dinge auf einmal gekostet: das Save-Format (ID-Liste), die
Preisformel base_price × Π price_factor und die Stapelregel — zwei Schwerter „Flammend 3" und
„Flammend 4" stapeln nicht mehr, aber wie zeigt man den Unterschied an? Mit Stufen kann der Modder
seine Abstufungen benennen, statt eine Zahl auszuliefern, die keine Anzeige hat.
luck hat genau eine Regel
Eine Chance auf einen zusätzlichen Zug — auf jeder Tabelle.
p_extra = clamp(luck * LUCK_FACTOR, 0.0, 0.9)
Ein Knopf mehr in [balance]. Die Regel wirkt dreifach, ohne dreimal geschrieben zu werden: mehr
Gegenstände, mehr Affixe, und häufiger die stärkere Stufe — weil die als eigener Eintrag mit kleinem
Gewicht danebensteht.
Der Grund gegen „Glück verschiebt zur Seltenheit" ist ein Ausschluss: Es gibt keinen Seltenheitsbegriff. Das Schema kennt nur Gewichte; Seltenheit erst zu definieren und dann Gewichte umzurechnen wäre ein zweites Konzept für dasselbe Gefühl.
Der Mod-Einhängepunkt existiert bereits
Ticket 03 gilt unverändert: ganzer Eintrag wird ersetzt. Ein neuer Mechanismus wird trotzdem nicht gebraucht — Tabelle-in-Tabelle ist der Einhängepunkt, zwei gewöhnliche Überschreibungen und null neue Begriffe:
[[loot_tables]]
id = "meinmod:floor_3"
entries = [ { table = "core:floor_3_table", weight = 100 },
{ item = "meinmod:zauberstab", weight = 5 } ]
[[floors]]
id = "core:floor_3"
overrides = "core:floor_3"
loot = "meinmod:floor_3"
Decke: Zwei Mods, die dieselbe Etage umhängen, kollidieren — der letzte gewinnt. Das ist derselbe
Konflikt wie bei jeder anderen Überschreibung in 03. Falls er häufig wird, ist [[loot_additions]] der
Nachbau; ihn vorher zu bauen hieße, einen zweiten Mechanismus für etwas einzuführen, das der erste
schon kann.
Beute wird beim Aufheben gezogen
Room aus Ticket 10 bekommt eine loot_table und loot: Vec<Pos> statt fertiger Instanzen — alle
Haufen eines Raums ziehen ohnehin aus derselben Tabelle, die ID je Haufen zu wiederholen wäre
Redundanz. Aufgelöst wird erst beim Aufheben; der Save wird dadurch sogar kleiner.
Die Zahl der Haufen steht bei der Erzeugung fest (die l-Zeichen im Prefab), ihr Inhalt nicht.
Alle zeigen dasselbe generische Symbol — deshalb verrät die Anzeige nichts, und ein Glücksring
wirkt auch auf das, was auf dieser Etage bereits liegt. Bei Ziehung zur Erzeugungszeit wäre der Wurf
für diese Etage schon gefallen, bevor der Spieler den Ring findet.
Fällt der Wurf beim Aufheben auf eine Niete, verschwindet der Haufen mit einer Meldung. Kein
Neuwürfeln — das hängt sich bei einer reinen Nieten-Tabelle auf und bräuchte dann doch einen Zähler.
Keine Ladeprüfung „Tabellen für l-Plätze dürfen keine Nieten enthalten": Das wäre die Bevormundung,
die Ticket 02 abgeräumt hat. Wer leere Haufen nicht will, lässt Nieten aus der Tabelle weg.
Etagenskalierung — die Auflage aus 15 ist strukturell erfüllt
Eine Tabelle je Etage, wie Ticket 10 es mit dem loot-Feld bereits angelegt hat. Nirgends steht eine
Fünf: Etagen sind Registry-Einträge, jeder bringt seine Tabelle mit, ein Mod mit Etage 6 bringt ihre
gleich mit, und der Endlosmodus wiederholt mit der letzten Etage auch deren Tabelle.
Bedingungen am Eintrag (floor at_least 3 auf einer gemeinsamen Tabelle) klingen flexibler, lösen das
Endlos-Problem aber gerade nicht: Ein Eintrag mit at_least = 3 ist auf Etage 500 genauso gültig wie
auf Etage 3. Echte Tiefenskalierung bräuchte Gewichte als Funktion der Etage — eine Formel, keine
Daten, und die wird gebaut, wenn der Endlosmodus kommt.
Ein Prefab darf über ein optionales loot-Feld seine eigene Tabelle nennen. Sonst ist ein
Schatzkammer-Raum nur ein Raum mit mehr l-Zeichen — mehr vom Gleichen statt etwas Besserem. Es nennt
dabei eine Tabellen-ID, keine Gegenstände, und bleibt damit über alle Tiefen verwendbar; dieselbe
Begründung, mit der 10 festgelegt hat, dass ein e nicht sagt, welcher Gegner.
Wo Beute hängt
An der creatures-Registry (14), an der Etage (10) und optional am Prefab. Alle drei nennen schlicht
eine Tabellen-ID.
Zwei Nachträge an geschlossene Tickets
| Ticket | Nachtrag |
|---|---|
| 10 | Room hält loot_table: LootTableId plus loot: Vec<Pos> statt Vec<(Pos, ItemInstance)>; optionales loot-Feld am Prefab; generischer Beute-Marker im Grid |
| 14 | LUCK_FACTOR in [balance] |