PkmnLib_rs/src/dynamic_data/libraries/damage_library.rs

274 lines
7.6 KiB
Rust
Raw Normal View History

use std::sync::Arc;
use crate::dynamic_data::script_handling::ScriptSource;
use crate::dynamic_data::Pokemon;
use crate::dynamic_data::{ExecutingMove, HitData};
use crate::script_hook;
use crate::static_data::{MoveCategory, Statistic};
pub trait DamageLibrary: std::fmt::Debug {
fn has_randomness(&self) -> bool;
fn get_damage(
&self,
executing_move: &ExecutingMove,
target: &Arc<Pokemon>,
hit_number: u8,
hit_data: &HitData,
) -> u32;
fn get_base_power(
&self,
executing_move: &ExecutingMove,
target: &Arc<Pokemon>,
hit_number: u8,
hit_data: &HitData,
) -> u8;
fn get_stat_modifier(
&self,
executing_move: &ExecutingMove,
target: &Arc<Pokemon>,
hit_number: u8,
hit_data: &HitData,
) -> f32;
fn get_damage_modifier(
&self,
executing_move: &ExecutingMove,
target: &Arc<Pokemon>,
hit_number: u8,
hit_data: &HitData,
) -> f32;
}
#[derive(Debug)]
pub struct Gen7DamageLibrary {
has_randomness: bool,
}
impl Gen7DamageLibrary {
pub fn new(has_randomness: bool) -> Self {
Self { has_randomness }
}
}
impl DamageLibrary for Gen7DamageLibrary {
fn has_randomness(&self) -> bool {
self.has_randomness
}
fn get_damage(
&self,
executing_move: &ExecutingMove,
target: &Arc<Pokemon>,
hit_number: u8,
hit_data: &HitData,
) -> u32 {
if executing_move.use_move().category() == MoveCategory::Status {
return 0;
}
let level_modifier = ((2.0 * executing_move.user().level() as f32) / 5.0).floor() + 2.0;
let base_power = hit_data.base_power();
let stat_modifier = self.get_stat_modifier(executing_move, target, hit_number, hit_data);
let damage_modifier = self.get_damage_modifier(executing_move, target, hit_number, hit_data);
let mut float_damage = (level_modifier * base_power as f32).floor();
float_damage = (float_damage * stat_modifier).floor();
float_damage = (float_damage / 50.0).floor() + 2.0;
float_damage = (float_damage * damage_modifier).floor();
if executing_move.target_count() > 1 {
float_damage = (float_damage * 0.75).floor();
}
if hit_data.is_critical() {
let mut crit_modifier = 1.5;
script_hook!(
change_critical_modifier,
executing_move,
executing_move,
target,
hit_number,
&mut crit_modifier
);
float_damage = (float_damage * crit_modifier).floor();
}
if self.has_randomness {
let random_percentage = 85 + executing_move.user().get_battle().unwrap().random().get_between(0, 16);
float_damage = (float_damage * (random_percentage as f32 / 100.0)).floor();
}
if executing_move.user().types().contains(&hit_data.move_type()) {
let mut stab_modifier = 1.5;
script_hook!(
change_stab_modifier,
executing_move,
executing_move,
target,
hit_number,
&mut stab_modifier
);
float_damage = (float_damage * stab_modifier).floor();
}
float_damage = (float_damage * hit_data.effectiveness()).floor();
let mut damage = if float_damage <= 0.0 {
if hit_data.effectiveness() == 0.0 {
0
} else {
1
}
} else if float_damage >= u32::MAX as f32 {
u32::MAX
} else {
float_damage as u32
};
script_hook!(
change_damage,
executing_move,
executing_move,
target,
hit_number,
&mut damage
);
script_hook!(
change_incoming_damage,
target,
executing_move,
target,
hit_number,
&mut damage
);
damage
}
fn get_base_power(
&self,
executing_move: &ExecutingMove,
target: &Arc<Pokemon>,
hit_number: u8,
_hit_data: &HitData,
) -> u8 {
if executing_move.use_move().category() == MoveCategory::Status {
return 0;
}
let mut base_power = executing_move.use_move().base_power();
script_hook!(
change_base_power,
executing_move,
executing_move,
target,
hit_number,
&mut base_power
);
base_power
}
fn get_stat_modifier(
&self,
executing_move: &ExecutingMove,
target: &Arc<Pokemon>,
hit_number: u8,
hit_data: &HitData,
) -> f32 {
let mut user = executing_move.user().clone();
script_hook!(
change_damage_stats_user,
executing_move,
executing_move,
target,
hit_number,
&mut user
);
let offensive_stat;
let defensive_stat;
if executing_move.use_move().category() == MoveCategory::Physical {
offensive_stat = Statistic::Attack;
defensive_stat = Statistic::Defense;
} else {
offensive_stat = Statistic::SpecialAttack;
defensive_stat = Statistic::SpecialDefense;
}
let mut bypass_defensive_stat_boost = hit_data.is_critical() && target.stat_boost(defensive_stat) > 0;
script_hook!(
bypass_defensive_stat_boost,
executing_move,
executing_move,
target,
hit_number,
&mut bypass_defensive_stat_boost
);
let mut bypass_offensive_stat_boost = hit_data.is_critical() && user.stat_boost(offensive_stat) > 0;
script_hook!(
bypass_offensive_stat_boost,
executing_move,
executing_move,
target,
hit_number,
&mut bypass_offensive_stat_boost
);
let mut defensive_stat = if bypass_defensive_stat_boost {
target.flat_stats().get_stat(offensive_stat)
} else {
target.boosted_stats().get_stat(offensive_stat)
};
let mut offensive_stat = if bypass_offensive_stat_boost {
user.flat_stats().get_stat(offensive_stat)
} else {
user.boosted_stats().get_stat(offensive_stat)
};
script_hook!(
change_defensive_stat_value,
executing_move,
executing_move,
target,
hit_number,
&mut defensive_stat
);
script_hook!(
change_offensive_stat_value,
executing_move,
executing_move,
target,
hit_number,
&mut offensive_stat
);
let mut stat_modifier = offensive_stat as f32 / defensive_stat as f32;
script_hook!(
change_damage_stat_modifier,
executing_move,
executing_move,
target,
hit_number,
&mut stat_modifier
);
stat_modifier
}
fn get_damage_modifier(
&self,
executing_move: &ExecutingMove,
target: &Arc<Pokemon>,
hit_number: u8,
_hit_data: &HitData,
) -> f32 {
let mut modifier = 1.0;
script_hook!(
change_damage_modifier,
executing_move,
executing_move,
target,
hit_number,
&mut modifier
);
modifier
}
}