use crate::battle::rng::ScriptedRng;
use crate::battle::stack::ctx::{BattleCtx, EffectProvider, EffectState, MoveContext};
use crate::battle::stack::event::Effect;
use crate::battle::{
BattleProvider, BattleState, BattlerRef, BattlerState, DamageResult, EnumMap, EffectResult,
MoveEffect,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TStat {
Hp,
Atk,
Def,
Spe,
SpA,
SpD,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum TStatus {
Poisoned,
Burned,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum TType {
Normal,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TSpecies {
Plain,
HasAbility,
HasItem,
HasBoth,
}
#[derive(Debug, Clone, PartialEq)]
pub struct TMove {
pub power: u8,
}
#[derive(Clone)]
#[allow(dead_code)]
pub enum TKind {
None,
Vol,
Counter { n: u8 },
}
pub struct TProvider {
pub field_on: bool,
}
impl Default for TProvider {
fn default() -> Self {
Self { field_on: false }
}
}
impl BattleProvider for TProvider {
type Monster = ();
type Move = TMove;
type Ability = ();
type Status = TStatus;
type Stat = TStat;
type Species = TSpecies;
type Type = TType;
type Item = ();
fn calculate_damage(
&self,
move_: &Self::Move,
_a: &BattlerState<Self>,
_d: &BattlerState<Self>,
_r: u8,
_c: bool,
) -> DamageResult {
DamageResult {
damage: move_.power as u16,
effectiveness: 1.0,
is_miss: false,
}
}
fn select_move(&self, b: &BattlerState<Self>, _s: &BattleState<Self>) -> Self::Move {
b.moves.first().cloned().unwrap()
}
fn apply_move_effect(
&self,
_e: MoveEffect,
_u: &mut BattlerState<Self>,
_t: &mut BattlerState<Self>,
) -> EffectResult {
EffectResult::NoEffect
}
fn create_monster(&self, s: Self::Species, _l: u8) -> BattlerState<Self> {
BattlerState::new(s, 100, 100, EnumMap::new(), vec![])
}
}
impl EffectProvider for TProvider {
type EffectStateKind = TKind;
fn effect_for_move(&self, _m: &Self::Move) -> Option<&'static Effect<Self>> {
None
}
fn effect_for_status(&self, _s: &Self::Status) -> Option<&'static Effect<Self>> {
None
}
fn effect_for_volatile(&self, kind: &Self::EffectStateKind) -> Option<&'static Effect<Self>> {
match kind {
TKind::Vol => Some(&MOCK_VOLATILE),
_ => None,
}
}
fn effect_for_ability(&self, b: &BattlerState<Self>) -> Option<&'static Effect<Self>> {
matches!(b.species, TSpecies::HasAbility | TSpecies::HasBoth).then_some(&MOCK_ABILITY)
}
fn effect_for_item(&self, b: &BattlerState<Self>) -> Option<&'static Effect<Self>> {
matches!(b.species, TSpecies::HasItem | TSpecies::HasBoth).then_some(&MOCK_ITEM)
}
fn field_effects(&self, _ctx: &BattleCtx<'_, Self>) -> &[&'static Effect<Self>] {
if self.field_on {
&MOCK_FIELD_LIST
} else {
&[]
}
}
fn turn_order_rank(
&self,
_state: &BattleState<Self>,
_who: BattlerRef,
_action: &Self::Move,
) -> (i32, i32) {
(0, 0)
}
}
use crate::battle::stack::event::{
EffectId, EffectType, Event, EventHook, HandlerResult, RelayVar,
};
pub fn mark<P: EffectProvider<Stat = TStat> + ?Sized>(
ctx: &mut BattleCtx<'_, P>,
who: BattlerRef,
tag: i8,
) {
let b = ctx.battler_mut(who);
let cur = b.stat_stages.get(TStat::Atk).copied().unwrap_or(0);
b.stat_stages.set(TStat::Atk, cur + tag);
}
fn ability_hit<P: EffectProvider<Stat = TStat> + ?Sized>(
ctx: &mut BattleCtx<'_, P>,
_r: RelayVar,
target: BattlerRef,
_s: BattlerRef,
_e: EffectId,
) -> HandlerResult {
mark(ctx, target, 1);
HandlerResult::Unchanged
}
fn item_hit<P: EffectProvider<Stat = TStat> + ?Sized>(
ctx: &mut BattleCtx<'_, P>,
_r: RelayVar,
target: BattlerRef,
_s: BattlerRef,
_e: EffectId,
) -> HandlerResult {
mark(ctx, target, 10);
HandlerResult::Unchanged
}
fn field_hit<P: EffectProvider<Stat = TStat> + ?Sized>(
ctx: &mut BattleCtx<'_, P>,
_r: RelayVar,
target: BattlerRef,
_s: BattlerRef,
_e: EffectId,
) -> HandlerResult {
mark(ctx, target, 100);
HandlerResult::Unchanged
}
pub fn mock_src_hit<P: EffectProvider<Stat = TStat> + ?Sized>(
ctx: &mut BattleCtx<'_, P>,
_r: RelayVar,
target: BattlerRef,
_s: BattlerRef,
_e: EffectId,
) -> HandlerResult {
mark(ctx, target, 5);
HandlerResult::Unchanged
}
fn volatile_hit<P: EffectProvider<Stat = TStat> + ?Sized>(
ctx: &mut BattleCtx<'_, P>,
_r: RelayVar,
target: BattlerRef,
_s: BattlerRef,
_e: EffectId,
) -> HandlerResult {
mark(ctx, target, 50);
HandlerResult::Unchanged
}
pub static MOCK_ABILITY: Effect<TProvider> = Effect {
id: EffectId(0xA1),
kind: EffectType::Condition,
hooks: &[EventHook {
event: Event::DamagingHit,
call: ability_hit::<TProvider>,
order: 10,
priority: 0,
sub_order: None,
}],
};
pub static MOCK_ITEM: Effect<TProvider> = Effect {
id: EffectId(0xB1),
kind: EffectType::Condition,
hooks: &[EventHook {
event: Event::DamagingHit,
call: item_hit::<TProvider>,
order: 20,
priority: 0,
sub_order: None,
}],
};
pub static MOCK_FIELD: Effect<TProvider> = Effect {
id: EffectId(0xF1),
kind: EffectType::Condition,
hooks: &[EventHook {
event: Event::DamagingHit,
call: field_hit::<TProvider>,
order: 30,
priority: 0,
sub_order: None,
}],
};
pub static MOCK_VOLATILE: Effect<TProvider> = Effect {
id: EffectId(0xC1),
kind: EffectType::Condition,
hooks: &[EventHook {
event: Event::DamagingHit,
call: volatile_hit::<TProvider>,
order: 15,
priority: 0,
sub_order: None,
}],
};
pub static MOCK_FIELD_LIST: [&Effect<TProvider>; 1] = [&MOCK_FIELD];
pub fn mon(hp: u16, species: TSpecies) -> BattlerState<TProvider> {
let mut stats = EnumMap::new();
stats.set(TStat::Hp, hp);
BattlerState::new(species, hp, hp, stats, vec![TMove { power: 10 }])
}
pub fn parts(
player: BattlerState<TProvider>,
opp: BattlerState<TProvider>,
) -> (
BattleState<TProvider>,
Vec<EffectState<TProvider>>,
MoveContext,
ScriptedRng,
) {
(
BattleState::new(vec![player], vec![opp]),
Vec::new(),
MoveContext::default(),
ScriptedRng::new(vec![]),
)
}
pub fn marker(state: &BattleState<TProvider>, who: BattlerRef) -> i8 {
let b = if who.side == 0 {
&state.player_battlers[who.slot as usize]
} else {
&state.opponent_battlers[who.slot as usize]
};
b.stat_stages.get(TStat::Atk).copied().unwrap_or(0)
}