feat: m4 teil 1 — beute, inventar und affixe
- data/: [[loot_tables]] und [[affixes]] als Registries; LootEntry mit guaranteed, nothing, table-in-table, count und affixes - game/loot.rs: EINE Ziehmaschinerie fuer Gegenstaende und Affixe, Tiefendeckel gegen wechselseitigen Bezug - PickUp zieht erst beim Aufheben (Ticket 16) — moeglich nur, weil alle Haufen dasselbe Symbol zeigen - UseItem/Equip/Unequip/Drop, Inventar-Screen als Registry-Schleife - Affixe im Attributpfad, in der Resistenz und in der Trigger-Suche; item_label stellt Affixnamen voran, item_price multipliziert Faktoren - Room haelt eine loot_table (nicht je Haufen eine), Prefab-loot ueberschreibt die Etagentabelle 53 Tests. Offen aus M4: Handel.
This commit is contained in:
@@ -229,6 +229,90 @@ impl Default for Balance {
|
||||
}
|
||||
}
|
||||
|
||||
/// Eine benannte Modifikatorliste, die an einem **einzelnen Exemplar** haengt —
|
||||
/// „Flammendes Eisenschwert" (Ticket 07).
|
||||
///
|
||||
/// Abstufungen sind **eigene Eintraege** mit kleinerem Gewicht (`core:flaming`
|
||||
/// neben `core:greater_flaming`), keine Zahl am Exemplar: Eine Staerke je
|
||||
/// Exemplar haette Save-Format, Preisformel und Stapelregel auf einmal
|
||||
/// gekostet (Ticket 16).
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Affix {
|
||||
pub id: String,
|
||||
/// Wird dem Gegenstandsnamen vorangestellt: „Flammendes Eisenschwert".
|
||||
pub name: String,
|
||||
#[serde(default = "one_f32")]
|
||||
pub price_factor: f32,
|
||||
#[serde(default)]
|
||||
pub modifiers: Vec<Modifier>,
|
||||
#[serde(default)]
|
||||
pub triggers: Vec<Trigger>,
|
||||
#[serde(default)]
|
||||
pub overrides: Option<String>,
|
||||
}
|
||||
|
||||
fn one_f32() -> f32 {
|
||||
1.0
|
||||
}
|
||||
|
||||
/// Ein Eintrag einer Beutetabelle. Genau eine der vier Formen (Ticket 16).
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct LootEntry {
|
||||
#[serde(default = "one")]
|
||||
pub weight: u32,
|
||||
/// Wird **immer** ausgegeben und nimmt an der Gewichtung nicht teil — mit
|
||||
/// Gewichten allein laesst sich „sicher" nicht ausdruecken, und Bosse
|
||||
/// stehen in der Destination.
|
||||
#[serde(default)]
|
||||
pub guaranteed: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub item: Option<String>,
|
||||
/// Tabelle-in-Tabelle: liefert Seltenheitsstufen, ohne dass „Seltenheit"
|
||||
/// ein Begriff werden muss. Zugleich der **Mod-Einhaengepunkt** — ein Mod
|
||||
/// bindet `core:floor_3_table` als Untertabelle ein.
|
||||
#[serde(default)]
|
||||
pub table: Option<String>,
|
||||
/// Dieselbe Maschinerie zieht Gegenstaende *und* Affixe.
|
||||
#[serde(default)]
|
||||
pub affix: Option<String>,
|
||||
/// Niete. Ein gewoehnlicher Eintrag, kein eigenes `drop_chance`-Feld — die
|
||||
/// Engine kennt eine Mechanik statt zweier.
|
||||
#[serde(default)]
|
||||
pub nothing: bool,
|
||||
|
||||
/// Stapelmenge, als Bereich `"1-2"`.
|
||||
#[serde(default)]
|
||||
pub count: Option<String>,
|
||||
/// Affix-Tabelle fuer diesen Gegenstand.
|
||||
#[serde(default)]
|
||||
pub affixes: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct LootTable {
|
||||
pub id: String,
|
||||
/// Wie viele Zuege, als Bereich `"1-3"`.
|
||||
#[serde(default)]
|
||||
pub rolls: Option<String>,
|
||||
#[serde(default)]
|
||||
pub entries: Vec<LootEntry>,
|
||||
#[serde(default)]
|
||||
pub overrides: Option<String>,
|
||||
}
|
||||
|
||||
/// Bereichsangabe `"1-3"` oder `"2"`. Ein Zweizeiler statt einer Grammatik.
|
||||
pub fn parse_range(spec: Option<&String>) -> (u32, u32) {
|
||||
let Some(s) = spec else { return (1, 1) };
|
||||
match s.split_once('-') {
|
||||
Some((a, b)) => (a.trim().parse().unwrap_or(1), b.trim().parse().unwrap_or(1)),
|
||||
None => {
|
||||
let n = s.trim().parse().unwrap_or(1);
|
||||
(n, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Ein von Hand gezeichneter Raum als ASCII-Block (Ticket 10).
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Prefab {
|
||||
@@ -283,9 +367,11 @@ pub struct FloorDef {
|
||||
/// als bei Prefabs, weil eine Etage ihre Gegner benennen koennen soll.
|
||||
#[serde(default)]
|
||||
pub creatures: Vec<WeightedId>,
|
||||
/// Beutetabelle fuer die `l`-Plaetze (Ticket 16).
|
||||
#[serde(default)]
|
||||
pub loot: Option<String>,
|
||||
#[serde(default)]
|
||||
pub overrides: Option<String>,
|
||||
// TODO(M4): `loot` — die Beutetabelle fuer die `l`-Plaetze (Ticket 16).
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@@ -309,9 +395,11 @@ pub struct Registries {
|
||||
pub abilities: HashMap<String, Ability>,
|
||||
pub creatures: HashMap<String, CreatureDef>,
|
||||
pub modifiers: HashMap<String, ModifierDef>,
|
||||
pub affixes: HashMap<String, Affix>,
|
||||
pub loot_tables: HashMap<String, LootTable>,
|
||||
/// Keine Registry — ein Block mit festem Schema, feldweise verschmolzen.
|
||||
pub balance: Balance,
|
||||
// TODO(M4+): `affixes`, `quests`, `loot_tables`, `scripts`.
|
||||
// TODO(M5+): `quests` (Ticket 08) und `scripts` (Ticket 13).
|
||||
}
|
||||
|
||||
impl Registries {
|
||||
|
||||
Reference in New Issue
Block a user