feat: m3 kampf, events und trigger
Der Dungeon hat jetzt Gegner, und man kann sterben.
- game/action.rs: sieben Schadenstypen, fuenf der zehn Aktionen, Target
- game/condition.rs: Bedingungsgrammatik (Liste = UND, not je Eintrag)
- game/event.rs: zwoelf Events, Trigger als vierte Wirkungsform
- game/combat.rs: Treffer- und Schadensformel mit drei Klemmbereichen
- Game::apply, drain_events (FIFO), Initiative, Rundenablauf aus Ticket 14
- data/: abilities-, creatures- und modifiers-Registry, [balance] feldweise
- ui/: Combat-Screen mit Faehigkeitsmenue und Sperrgrund
Drei Befunde:
- Die Trefferformel war toter Code — jeder Angriff traf. Nur der Compiler
hat es gemeldet ('hit_chance is never used'). Test haelt sie am Leben.
- Die Warteschlange war ein Stack (pop statt pop_front), obwohl Ticket 08
ausdruecklich 'haengt es hinten an' sagt. Jetzt VecDeque.
- Benannte Modifikatoren (core:poisoned) hatten keine Registry — Ticket 01
laesst apply_modifier per ID referenzieren, aber keine der zwoelf
definierte sie. Das ist die dreizehnte.
43 Tests.
This commit is contained in:
@@ -14,7 +14,10 @@ use serde::Deserialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
use toml::Spanned;
|
||||
|
||||
use super::registries::{Category, CharacterOption, FloorDef, Item, Prefab, Registries, Slot};
|
||||
use super::registries::{
|
||||
Ability, Category, CharacterOption, CreatureDef, FloorDef, Item, ModifierDef, Prefab,
|
||||
Registries, Slot,
|
||||
};
|
||||
|
||||
/// Genau drei harte Fehler (Ticket 04). Alles Uebrige ist Warnung plus
|
||||
/// Verwerfen des **einzelnen Eintrags**.
|
||||
@@ -248,6 +251,16 @@ struct ModFile {
|
||||
prefabs: Vec<Spanned<toml::Value>>,
|
||||
#[serde(default)]
|
||||
floors: Vec<Spanned<toml::Value>>,
|
||||
#[serde(default)]
|
||||
abilities: Vec<Spanned<toml::Value>>,
|
||||
#[serde(default)]
|
||||
creatures: Vec<Spanned<toml::Value>>,
|
||||
#[serde(default)]
|
||||
modifiers: Vec<Spanned<toml::Value>>,
|
||||
/// **Keine** Tabelle mit `[[...]]`, sondern ein einzelner Block, der
|
||||
/// feldweise verschmilzt — die ausdrueckliche Ausnahme zu Ticket 03.
|
||||
#[serde(default)]
|
||||
balance: Option<toml::Value>,
|
||||
}
|
||||
|
||||
/// Damit die vier Registry-Typen durch dieselbe Einlese-Schleife passen.
|
||||
@@ -278,6 +291,9 @@ impl_entry!(Category);
|
||||
impl_entry!(CharacterOption);
|
||||
impl_entry!(Prefab);
|
||||
impl_entry!(FloorDef);
|
||||
impl_entry!(Ability);
|
||||
impl_entry!(CreatureDef);
|
||||
impl_entry!(ModifierDef);
|
||||
|
||||
struct FileCtx<'a> {
|
||||
module: &'a str,
|
||||
@@ -451,6 +467,7 @@ pub fn load_mods() -> Result<(Registries, Vec<String>), LoadError> {
|
||||
|
||||
// Phase 2 — Einlesen in Ladereihenfolge
|
||||
let mut reg = Registries::default();
|
||||
let mut balance_raw = toml::value::Table::new();
|
||||
for id in &order {
|
||||
let Some(info) = found.iter().find(|m| &m.id == id) else { continue };
|
||||
|
||||
@@ -482,15 +499,44 @@ pub fn load_mods() -> Result<(Registries, Vec<String>), LoadError> {
|
||||
parse_entries(parsed.options, &ctx, &mut reg.options, &mut warnings);
|
||||
parse_entries(parsed.prefabs, &ctx, &mut reg.prefabs, &mut warnings);
|
||||
parse_entries(parsed.floors, &ctx, &mut reg.floors, &mut warnings);
|
||||
parse_entries(parsed.abilities, &ctx, &mut reg.abilities, &mut warnings);
|
||||
parse_entries(parsed.creatures, &ctx, &mut reg.creatures, &mut warnings);
|
||||
parse_entries(parsed.modifiers, &ctx, &mut reg.modifiers, &mut warnings);
|
||||
|
||||
// `[balance]` verschmilzt **feldweise** (Ticket 14): Ein Mod, der
|
||||
// einen Knopf dreht, schreibt eine Zeile — und ein neuer Knopf in
|
||||
// der naechsten Version bricht ihn nicht.
|
||||
if let Some(table) = parsed.balance {
|
||||
merge_balance(table, &mut balance_raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// `[balance]` erst am Ende deserialisieren: Fehlende Felder fallen dann auf
|
||||
// die Engine-Standards zurueck, nicht auf die des zuletzt geladenen Mods.
|
||||
match toml::Value::Table(balance_raw).try_into() {
|
||||
Ok(b) => reg.balance = b,
|
||||
Err(e) => warnings.push(format!("[balance]: {} — Standardwerte gelten", e.message())),
|
||||
}
|
||||
|
||||
// Phase 3 — Referenzen aufloesen
|
||||
resolve(&mut reg, &mut warnings);
|
||||
|
||||
Ok((reg, warnings))
|
||||
}
|
||||
|
||||
/// Feldweises Verschmelzen. Die Ausnahme bleibt eng, weil ihre Begruendung eng
|
||||
/// ist: `[balance]` hat ein **festes, der Engine bekanntes Schema** — genau das
|
||||
/// fehlte bei Inhalt mit offenen Feldern, und das war Ticket 03s Argument gegen
|
||||
/// feldweises Patchen.
|
||||
fn merge_balance(from: toml::Value, into: &mut toml::value::Table) {
|
||||
if let toml::Value::Table(t) = from {
|
||||
for (k, v) in t {
|
||||
into.insert(k, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn toml_files(dir: &Path) -> Vec<PathBuf> {
|
||||
let mut files: Vec<PathBuf> = fs::read_dir(dir)
|
||||
.into_iter()
|
||||
|
||||
Reference in New Issue
Block a user