1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//! # 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 [`Effect`](dotzuki_engine::battle::stack::Effect)s
//! 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`](dotzuki_engine::battle::stack::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`](dotzuki_engine::battle::stack::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`](dotzuki_engine::battle::rng::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`](dotzuki_engine::battle::stack::EffectId) and live state lives in
//! the engine's `EffectState` arena, not the data — the reload swaps the
//! *vocabulary*, never the *in-flight state*.
pub use rules_ron;
pub use RuleBindings;
pub use ;
pub use ;
pub use ;
pub use RuleSource;
pub use ;