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:
@@ -16,7 +16,7 @@ use toml::Spanned;
|
||||
|
||||
use super::registries::{
|
||||
Ability, Affix, Category, CharacterOption, CreatureDef, FloorDef, Item, LootTable, ModifierDef,
|
||||
Prefab, Registries, Slot,
|
||||
Npc, Prefab, Registries, Slot,
|
||||
};
|
||||
|
||||
/// Genau drei harte Fehler (Ticket 04). Alles Uebrige ist Warnung plus
|
||||
@@ -261,6 +261,8 @@ struct ModFile {
|
||||
affixes: Vec<Spanned<toml::Value>>,
|
||||
#[serde(default)]
|
||||
loot_tables: Vec<Spanned<toml::Value>>,
|
||||
#[serde(default)]
|
||||
npcs: Vec<Spanned<toml::Value>>,
|
||||
/// **Keine** Tabelle mit `[[...]]`, sondern ein einzelner Block, der
|
||||
/// feldweise verschmilzt — die ausdrueckliche Ausnahme zu Ticket 03.
|
||||
#[serde(default)]
|
||||
@@ -300,6 +302,7 @@ impl_entry!(CreatureDef);
|
||||
impl_entry!(ModifierDef);
|
||||
impl_entry!(Affix);
|
||||
impl_entry!(LootTable);
|
||||
impl_entry!(Npc);
|
||||
|
||||
struct FileCtx<'a> {
|
||||
module: &'a str,
|
||||
@@ -510,6 +513,7 @@ pub fn load_mods() -> Result<(Registries, Vec<String>), LoadError> {
|
||||
parse_entries(parsed.modifiers, &ctx, &mut reg.modifiers, &mut warnings);
|
||||
parse_entries(parsed.affixes, &ctx, &mut reg.affixes, &mut warnings);
|
||||
parse_entries(parsed.loot_tables, &ctx, &mut reg.loot_tables, &mut warnings);
|
||||
parse_entries(parsed.npcs, &ctx, &mut reg.npcs, &mut warnings);
|
||||
|
||||
// `[balance]` verschmilzt **feldweise** (Ticket 14): Ein Mod, der
|
||||
// einen Knopf dreht, schreibt eine Zeile — und ein neuer Knopf in
|
||||
|
||||
@@ -6,5 +6,5 @@ pub mod registries;
|
||||
|
||||
pub use loader::{load_mods, write_log};
|
||||
pub use registries::{
|
||||
Balance, CreatureDef, FloorDef, LootEntry, Prefab, Registries, parse_range,
|
||||
Balance, CreatureDef, FloorDef, DialogOption, LootEntry, Npc, Prefab, Registries, parse_range,
|
||||
};
|
||||
|
||||
@@ -212,8 +212,14 @@ pub struct Balance {
|
||||
pub resistance_cap: f32,
|
||||
pub hit_floor: f32,
|
||||
pub hit_ceiling: f32,
|
||||
// TODO(M4/M5): `exp_base`, `exp_exponent` (Ticket 15) und `luck_factor`
|
||||
// (Ticket 16) — sie kommen mit ihren Lesern, nicht davor.
|
||||
/// Anteil des Preises, den ein Haendler beim Ankauf zahlt. **Die Spanne**:
|
||||
/// Ohne sie ist Handel ein Exploit oder ein No-op — kaufen und sofort
|
||||
/// zurueckverkaufen waere entweder gratis oder eine Geldmaschine.
|
||||
pub verkauf: f32,
|
||||
/// Wie stark `charisma` auf `price_modifier` wirkt (Ticket 02).
|
||||
pub charisma_preis: f32,
|
||||
// TODO(M5): `exp_base`, `exp_exponent` (Ticket 15) und `luck_factor`
|
||||
// (Ticket 16) — sie kommen mit ihren Lesern, nicht davor.
|
||||
}
|
||||
|
||||
impl Default for Balance {
|
||||
@@ -225,10 +231,54 @@ impl Default for Balance {
|
||||
resistance_cap: 0.8,
|
||||
hit_floor: 0.05,
|
||||
hit_ceiling: 0.95,
|
||||
verkauf: 0.4,
|
||||
charisma_preis: 1.5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Eine Wahlmoeglichkeit im Gespraech. **Flach, kein Knotengraph** — was erst
|
||||
/// ein Graph koennte, ist Erzaehlung, und das Story-Modul steht unter
|
||||
/// *Out of scope*.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct DialogOption {
|
||||
pub text: String,
|
||||
#[serde(default)]
|
||||
pub condition: Vec<Condition>,
|
||||
#[serde(default)]
|
||||
pub actions: Vec<Action>,
|
||||
}
|
||||
|
||||
/// Die **vierzehnte** Registry. Bewusst kein `creatures`-Eintrag mit
|
||||
/// `hostile = false`: Ein Haendler truege sonst `health`, `initiative`,
|
||||
/// `cooldowns`, `ai` und `exp_reward` als dauerhaft toten Ballast.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Npc {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
#[serde(default = "npc_symbol")]
|
||||
pub symbol: char,
|
||||
#[serde(default)]
|
||||
pub color: Option<String>,
|
||||
#[serde(default)]
|
||||
pub greeting: String,
|
||||
/// **Der Warenbestand ist eine Beutetabelle** — dieselben Gewichte,
|
||||
/// dieselbe Tabelle-in-Tabelle, dieselben Affixe. Kein neuer
|
||||
/// „Waren"-Begriff.
|
||||
#[serde(default)]
|
||||
pub shop: Option<String>,
|
||||
#[serde(default)]
|
||||
pub options: Vec<DialogOption>,
|
||||
// TODO(M5): `triggers` — erst wenn `triggers_for` NPCs einsammelt. Als
|
||||
// Feld ohne Leser waere es eine Zusage, die niemand einloest.
|
||||
#[serde(default)]
|
||||
pub overrides: Option<String>,
|
||||
}
|
||||
|
||||
fn npc_symbol() -> char {
|
||||
'n'
|
||||
}
|
||||
|
||||
/// Eine benannte Modifikatorliste, die an einem **einzelnen Exemplar** haengt —
|
||||
/// „Flammendes Eisenschwert" (Ticket 07).
|
||||
///
|
||||
@@ -323,6 +373,11 @@ pub struct Prefab {
|
||||
/// Ersetzt die Etagentabelle fuer die `l`-Plaetze dieses Raums (Ticket 16).
|
||||
#[serde(default)]
|
||||
pub loot: Option<String>,
|
||||
/// Wer auf den `n`-Plaetzen steht. Anders als bei `e` nennt das **Prefab**
|
||||
/// den NPC, nicht die Etage: NPCs skalieren nicht mit der Tiefe — ein
|
||||
/// Schmied auf Etage 5 ist derselbe wie auf Etage 1 (Ticket 10).
|
||||
#[serde(default)]
|
||||
pub npcs: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub overrides: Option<String>,
|
||||
}
|
||||
@@ -397,6 +452,7 @@ pub struct Registries {
|
||||
pub modifiers: HashMap<String, ModifierDef>,
|
||||
pub affixes: HashMap<String, Affix>,
|
||||
pub loot_tables: HashMap<String, LootTable>,
|
||||
pub npcs: HashMap<String, Npc>,
|
||||
/// Keine Registry — ein Block mit festem Schema, feldweise verschmolzen.
|
||||
pub balance: Balance,
|
||||
// TODO(M5+): `quests` (Ticket 08) und `scripts` (Ticket 13).
|
||||
|
||||
Reference in New Issue
Block a user