2022-06-19 19:34:08 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2022-06-16 15:59:33 +00:00
|
|
|
use crate::dynamic_data::script_handling::ScriptSource;
|
2022-06-19 19:34:08 +00:00
|
|
|
use crate::dynamic_data::Pokemon;
|
|
|
|
use crate::dynamic_data::{ExecutingMove, HitData};
|
2022-06-18 13:52:39 +00:00
|
|
|
use crate::script_hook;
|
2022-06-16 15:59:33 +00:00
|
|
|
use crate::static_data::{MoveCategory, Statistic};
|
|
|
|
|
|
|
|
pub trait DamageLibrary: std::fmt::Debug {
|
|
|
|
fn has_randomness(&self) -> bool;
|
|
|
|
fn get_damage(
|
|
|
|
&self,
|
|
|
|
executing_move: &ExecutingMove,
|
2022-06-18 13:52:39 +00:00
|
|
|
target: &Arc<Pokemon>,
|
2022-06-16 15:59:33 +00:00
|
|
|
hit_number: u8,
|
|
|
|
hit_data: &HitData,
|
|
|
|
) -> u32;
|
|
|
|
|
|
|
|
fn get_base_power(
|
|
|
|
&self,
|
|
|
|
executing_move: &ExecutingMove,
|
2022-06-18 13:52:39 +00:00
|
|
|
target: &Arc<Pokemon>,
|
2022-06-16 15:59:33 +00:00
|
|
|
hit_number: u8,
|
|
|
|
hit_data: &HitData,
|
|
|
|
) -> u8;
|
|
|
|
|
|
|
|
fn get_stat_modifier(
|
|
|
|
&self,
|
|
|
|
executing_move: &ExecutingMove,
|
2022-06-18 13:52:39 +00:00
|
|
|
target: &Arc<Pokemon>,
|
2022-06-16 15:59:33 +00:00
|
|
|
hit_number: u8,
|
|
|
|
hit_data: &HitData,
|
|
|
|
) -> f32;
|
|
|
|
|
|
|
|
fn get_damage_modifier(
|
|
|
|
&self,
|
|
|
|
executing_move: &ExecutingMove,
|
2022-06-18 13:52:39 +00:00
|
|
|
target: &Arc<Pokemon>,
|
2022-06-16 15:59:33 +00:00
|
|
|
hit_number: u8,
|
|
|
|
hit_data: &HitData,
|
|
|
|
) -> f32;
|
|
|
|
}
|
2022-06-17 17:53:33 +00:00
|
|
|
|
2022-06-16 15:59:33 +00:00
|
|
|
#[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,
|
2022-06-18 13:52:39 +00:00
|
|
|
target: &Arc<Pokemon>,
|
2022-06-16 15:59:33 +00:00
|
|
|
hit_number: u8,
|
|
|
|
hit_data: &HitData,
|
|
|
|
) -> u32 {
|
|
|
|
if executing_move.use_move().category() == MoveCategory::Status {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-06-18 13:52:39 +00:00
|
|
|
let level_modifier = ((2.0 * executing_move.user().level() as f32) / 5.0).floor() + 2.0;
|
2022-06-16 15:59:33 +00:00
|
|
|
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 {
|
2022-06-18 13:52:39 +00:00
|
|
|
let random_percentage = 85 + executing_move.user().get_battle().unwrap().random().get_between(0, 16);
|
2022-06-16 15:59:33 +00:00
|
|
|
float_damage = (float_damage * (random_percentage as f32 / 100.0)).floor();
|
|
|
|
}
|
|
|
|
|
2022-06-18 13:52:39 +00:00
|
|
|
if executing_move.user().types().contains(&hit_data.move_type()) {
|
2022-06-16 15:59:33 +00:00
|
|
|
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
|
|
|
|
);
|
2022-06-18 13:52:39 +00:00
|
|
|
script_hook!(
|
2022-06-16 15:59:33 +00:00
|
|
|
change_incoming_damage,
|
|
|
|
target,
|
|
|
|
executing_move,
|
|
|
|
target,
|
|
|
|
hit_number,
|
|
|
|
&mut damage
|
|
|
|
);
|
|
|
|
damage
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_base_power(
|
|
|
|
&self,
|
|
|
|
executing_move: &ExecutingMove,
|
2022-06-18 13:52:39 +00:00
|
|
|
target: &Arc<Pokemon>,
|
2022-06-16 15:59:33 +00:00
|
|
|
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,
|
2022-06-18 13:52:39 +00:00
|
|
|
target: &Arc<Pokemon>,
|
2022-06-16 15:59:33 +00:00
|
|
|
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 =
|
2022-06-18 13:52:39 +00:00
|
|
|
hit_data.is_critical() && target.stat_boost().get_stat(defensive_stat) > 0;
|
2022-06-16 15:59:33 +00:00
|
|
|
script_hook!(
|
|
|
|
bypass_defensive_stat_boost,
|
|
|
|
executing_move,
|
|
|
|
executing_move,
|
|
|
|
target,
|
|
|
|
hit_number,
|
|
|
|
&mut bypass_defensive_stat_boost
|
|
|
|
);
|
2022-06-18 13:52:39 +00:00
|
|
|
let mut bypass_offensive_stat_boost = hit_data.is_critical() && user.stat_boost().get_stat(offensive_stat) > 0;
|
2022-06-16 15:59:33 +00:00
|
|
|
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 {
|
2022-06-18 13:52:39 +00:00
|
|
|
target.flat_stats().get_stat(offensive_stat)
|
2022-06-16 15:59:33 +00:00
|
|
|
} else {
|
2022-06-18 13:52:39 +00:00
|
|
|
target.boosted_stats().get_stat(offensive_stat)
|
2022-06-16 15:59:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let mut offensive_stat = if bypass_offensive_stat_boost {
|
2022-06-18 13:52:39 +00:00
|
|
|
user.flat_stats().get_stat(offensive_stat)
|
2022-06-16 15:59:33 +00:00
|
|
|
} else {
|
2022-06-18 13:52:39 +00:00
|
|
|
user.boosted_stats().get_stat(offensive_stat)
|
2022-06-16 15:59:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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,
|
2022-06-18 13:52:39 +00:00
|
|
|
target: &Arc<Pokemon>,
|
2022-06-16 15:59:33 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|