pub trait EffectProvider: BattleProvider + 'static {
type EffectStateKind: Clone;
// Required methods
fn effect_for_move(&self, m: &Self::Move) -> Option<&'static Effect<Self>>
where Self: Sized;
fn effect_for_status(
&self,
s: &Self::Status,
) -> Option<&'static Effect<Self>>
where Self: Sized;
fn turn_order_rank(
&self,
state: &BattleState<Self>,
who: BattlerRef,
action: &<Self as BattleProvider>::Move,
) -> (i32, i32)
where Self: Sized;
// Provided methods
fn effect_for_volatile(
&self,
kind: &Self::EffectStateKind,
) -> Option<&'static Effect<Self>>
where Self: Sized { ... }
fn forced_action(
&self,
effects: &[EffectState<Self>],
actor: BattlerRef,
chosen: &BattleAction<Self>,
) -> Option<BattleAction<Self>>
where Self: Sized { ... }
fn effect_for_ability(
&self,
b: &BattlerState<Self>,
) -> Option<&'static Effect<Self>>
where Self: Sized { ... }
fn effect_for_item(
&self,
b: &BattlerState<Self>,
) -> Option<&'static Effect<Self>>
where Self: Sized { ... }
fn side_effects(
&self,
ctx: &BattleCtx<'_, Self>,
side: u8,
) -> &[&'static Effect<Self>]
where Self: Sized { ... }
fn field_effects(
&self,
ctx: &BattleCtx<'_, Self>,
) -> &[&'static Effect<Self>]
where Self: Sized { ... }
}Expand description
The game’s effect registry, extending BattleProvider (design §1.5).
The engine ships the dispatch machinery with zero game-specific types; all
specifics (which move maps to which Effect, the volatile state enum) live
in the game via this trait. For the POC, EffectStateKind is a concrete
game-supplied associated type (design §3.1 — promote to richer generics when
a second game lands).
Required Associated Types§
Sourcetype EffectStateKind: Clone
type EffectStateKind: Clone
The game-supplied typed per-effect-kind state enum (design §3.1). The
engine treats it opaquely (it only stamps effect_order and routes it to
the host). pokered supplies the Gen-1 enum (Toxic counter, Substitute hp,
…).
Required Methods§
Sourcefn effect_for_move(&self, m: &Self::Move) -> Option<&'static Effect<Self>>where
Self: Sized,
fn effect_for_move(&self, m: &Self::Move) -> Option<&'static Effect<Self>>where
Self: Sized,
Resolve the Effect registered for a given move. Returns None if the
move registers no stack hooks.
Sourcefn effect_for_status(&self, s: &Self::Status) -> Option<&'static Effect<Self>>where
Self: Sized,
fn effect_for_status(&self, s: &Self::Status) -> Option<&'static Effect<Self>>where
Self: Sized,
Resolve the Effect registered for a non-volatile status (e.g. the
poison residual). Returns None if the status registers no hooks.
Sourcefn turn_order_rank(
&self,
state: &BattleState<Self>,
who: BattlerRef,
action: &<Self as BattleProvider>::Move,
) -> (i32, i32)where
Self: Sized,
fn turn_order_rank(
&self,
state: &BattleState<Self>,
who: BattlerRef,
action: &<Self as BattleProvider>::Move,
) -> (i32, i32)where
Self: Sized,
Turn-order rank for who — drawing NO randomness (design §1.3/§2).
The driver compares the two ranks; on an exact tie it draws one byte
to break it (mirroring pokered’s single order_random coin flip,
turn_order.rs:41, bug #22) — the only turn-order RNG site. This is why
the stack does NOT reuse BattleProvider::turn_order_key (which draws
per actor): a per-actor draw would consume the wrong number of bytes and
break draw-order parity with the legacy oracle (design §4.1).
Lower rank acts first; encode “acts earlier” as a smaller key
(e.g. (-priority, -effective_speed)).
Provided Methods§
Sourcefn effect_for_volatile(
&self,
kind: &Self::EffectStateKind,
) -> Option<&'static Effect<Self>>where
Self: Sized,
fn effect_for_volatile(
&self,
kind: &Self::EffectStateKind,
) -> Option<&'static Effect<Self>>where
Self: Sized,
Resolve the Effect registered for a live volatile in the effect
arena (design §3.4: every live effect on a battler contributes its
handlers, not only the non-volatile status). Returns None (the default)
when the volatile registers no hooks — so a provider that has no
volatile-borne residuals (every game built on the engine so far) is
completely unaffected and the driver’s arena-residual pass is inert.
This is the generic seam that lets a game host a residual on a volatile
(Gen-1 Leech Seed / badly-poisoned both live in status2/status3 bit
flags, NOT the non-volatile status byte) without the engine knowing any
game-specific semantics. The /16, the toxic counter, and the ASM “status then
leech” order all live in the game’s handlers; the engine only fires
the hooks the game registers, in the order the game’s order values dictate.
Sourcefn forced_action(
&self,
effects: &[EffectState<Self>],
actor: BattlerRef,
chosen: &BattleAction<Self>,
) -> Option<BattleAction<Self>>where
Self: Sized,
fn forced_action(
&self,
effects: &[EffectState<Self>],
actor: BattlerRef,
chosen: &BattleAction<Self>,
) -> Option<BattleAction<Self>>where
Self: Sized,
Cross-turn action override (design §3 / §9, the multi-turn lock-in
seam). Before the driver executes actor’s chosen action, it asks the
game whether a live volatile forces a different action this turn — Gen-1
Thrash/Petal Dance and Wrap/Bind re-issue the locked move ignoring the
player’s choice, Fly/Dig/Solar Beam strike on the second turn, and Hyper
Beam recharge forces inaction (BattleAction::Nothing). The game reads
its own effects arena (the cross-turn home of the lock counter / charge
flag / recharge flag) and returns Some(forced) to override chosen, or
None to let the chosen action stand.
This is the canonical proof (design §9) that a per-turn [Action; 2]
input is insufficient: the locked volatile, recorded on a PRIOR turn,
hijacks this turn’s action. The seam is generic (the engine names no
game-specific volatile — it only swaps one BattleAction for another) and
defaulted to None, so it is completely INERT for every other game
and for slices 1–5 (which never register a forcing volatile). All Gen-1
lock-in semantics (which volatile forces which move, the lock counter, the
recharge skip) live in the game’s forced_action impl, never in the engine.
Sourcefn effect_for_ability(
&self,
b: &BattlerState<Self>,
) -> Option<&'static Effect<Self>>where
Self: Sized,
fn effect_for_ability(
&self,
b: &BattlerState<Self>,
) -> Option<&'static Effect<Self>>where
Self: Sized,
Resolve the Effect registered for a battler’s ability, hosted on
that battler (design §2.4). Returns None (the default) when the game
has no abilities or this one registers no stack hooks.
Sourcefn effect_for_item(
&self,
b: &BattlerState<Self>,
) -> Option<&'static Effect<Self>>where
Self: Sized,
fn effect_for_item(
&self,
b: &BattlerState<Self>,
) -> Option<&'static Effect<Self>>where
Self: Sized,
Resolve the Effect registered for a battler’s held item, hosted
on that battler (design §2.4). Returns None (the default) when the game
has no items or this one registers no stack hooks.
Sourcefn side_effects(
&self,
ctx: &BattleCtx<'_, Self>,
side: u8,
) -> &[&'static Effect<Self>]where
Self: Sized,
fn side_effects(
&self,
ctx: &BattleCtx<'_, Self>,
side: u8,
) -> &[&'static Effect<Self>]where
Self: Sized,
Resolve the side-hosted effects for side (screens, hazards, Wish;
design §2.4). Returns &[] (the default) when the game has no side
conditions.
The returned slice borrows from self (the provider owns the
registry of &'static Effect tables); ctx is passed read-only so a
game can decide which side conditions are currently live by consulting
its arena/field state. The engine only fetches hook tables — it never
reads a side condition’s meaning.
Sourcefn field_effects(&self, ctx: &BattleCtx<'_, Self>) -> &[&'static Effect<Self>]where
Self: Sized,
fn field_effects(&self, ctx: &BattleCtx<'_, Self>) -> &[&'static Effect<Self>]where
Self: Sized,
Resolve the field-hosted effects (weather, terrain, Trick Room;
design §2.4). Returns &[] (the default) when the game has no field
conditions. The returned slice borrows from self (see
side_effects).
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".