dotzuki-rules 0.1.1

No-code RON authoring loader + closed primitive interpreter for dotzuki-engine's battle effect-stack. Parses a rules.ron into runtime Effects dispatched through ONE zero-capture interpreter-bridge fn keyed by source_effect (doc 11 Option A — zero engine change).
Documentation

dotzuki-rules — no-code RON authoring for the battle effect-stack (Phase 1)

A game-side loader that turns a declarative rules.ron into runtime Effects dispatched through ONE zero-capture interpreter-bridge fn ([interpret]) plus a closed primitive-op interpreter ([run_ops]).

What this crate is (and is NOT)

  • It depends on the game-agnostic [dotzuki_engine] only — zero pokered / pokered-core / pokered-data / minimon, zero concrete game type in non-test code, no rand.
  • It is a consumer of the engine's closed primitive vocabulary (doc 11 §1.1 + doc 12 §3). It amortizes content (one InflictStatus covers every secondary-status move) — it does not extend mechanics. A genuinely new mechanic still needs a Rust primitive + test (doc 11 §5).

The bridge (doc 11 §2 — Option A, ZERO engine change)

The fold's only handler call site is a zero-capture fn pointer (HandlerFn); data cannot be a fn pointer. So every data hook points its call field at the single generic [interpret] fn, which on each call looks up its op-list by the [EffectId] the engine already threads as source_effect (dispatch.rs:128). The loader mints one distinct EffectId per (effect, event) hook and registers each as its own tiny runtime Effect through the existing defaulted resolvers — exactly the Option-A shape doc 11 §2.2 recommends, and the shape minimon already proves with effectiveness_chart_hook. No engine edit, no new trait method on an engine trait.

Determinism (doc 11 §4)

The interpreter has NO entropy except ctx.rng (a &mut dyn BattleRng). The chance gate compiles to ctx.rng.chance(num, den); there is no clock, no pointer hashing, no HashMap iteration affecting draw order. A ScriptedRng replays a data ruleset identically (same draw count and order) as the native path — a structural guarantee, proved by [tests::scripted_rng_replays_identically].

Dual-mode sourcing (Phase 2, doc 11 §4.2)

[RuleSource] yields the same runtime [Ruleset] from either a baked include_str!'d text (RELEASE; the default build, zero file IO) or a disk path (DEV; behind the hot-reload feature it also watches the file and [RuleSource::poll_changed] signals an edit so the game rebuilds the registry between turns). A mid-battle reload is safe because effects are addressed by EffectId and live state lives in the engine's EffectState arena, not the data — the reload swaps the vocabulary, never the in-flight state.