use std::fmt::Debug; use crate::dynamic_data::Pokemon; use crate::static_data::Statistic; use crate::static_data::StatisticSet; /// A battle stat calculator is used to calculate stats for a Pokemon. pub trait BattleStatCalculator: Debug { /// Calculate all the flat stats of a Pokemon, disregarding stat boosts. fn calculate_flat_stats(&self, pokemon: &Pokemon, stats: &StatisticSet); /// Calculate a single flat stat of a Pokemon, disregarding stat boost fn calculate_flat_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32; /// Calculate all the boosted stats of a Pokemon, including stat boosts. fn calculate_boosted_stats(&self, pokemon: &Pokemon, stats: &StatisticSet); /// Calculate a single boosted stat of a Pokemon, including stat boosts. fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32; } /// A basic implementation of the Gen 7 stat calculator. #[derive(Debug)] pub struct Gen7BattleStatCalculator {} impl Gen7BattleStatCalculator { /// The calculation used for health points. fn calculate_health_stat(&self, pokemon: &Pokemon) -> u32 { let base = pokemon.form().get_base_stat(Statistic::HP) as u32; let iv = pokemon.individual_values().hp() as u32; let ev = pokemon.effort_values().hp() as u32; let level = pokemon.level() as u32; (((2 * base + iv + (ev / 4)) * level) / 100) + level + 10 } /// The calculation used for all other stats fn calculate_other_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32 { let base = pokemon.form().get_base_stat(stat) as u32; let iv = pokemon.individual_values().get_stat(stat) as u32; let ev = pokemon.effort_values().get_stat(stat) as u32; let level = pokemon.level() as u32; let unmodified = (((2 * base + iv + (ev / 4)) * level) / 100) + 5; return (unmodified as f32 * pokemon.nature().get_stat_modifier(stat)) as u32; } /// This functions returns the modifier we need to do to a stat for a given stat boost. fn get_stat_boost_modifier(&self, pokemon: &Pokemon, stat: Statistic) -> f32 { let boost = pokemon.stat_boost(stat); match boost { -6 => 2.0 / 8.0, -5 => 2.0 / 7.0, -4 => 2.0 / 6.0, -3 => 2.0 / 5.0, -2 => 2.0 / 4.0, -1 => 2.0 / 3.0, 0 => 1.0, 1 => 3.0 / 2.0, 2 => 4.0 / 2.0, 3 => 5.0 / 2.0, 4 => 6.0 / 2.0, 5 => 7.0 / 2.0, 6 => 8.0 / 2.0, _ => panic!("Stat boost was out of expected range of -6 to 6"), } } } impl BattleStatCalculator for Gen7BattleStatCalculator { fn calculate_flat_stats(&self, pokemon: &Pokemon, stats: &StatisticSet) { stats.set_stat(Statistic::HP, self.calculate_health_stat(pokemon)); stats.set_stat(Statistic::Attack, self.calculate_other_stat(pokemon, Statistic::Attack)); stats.set_stat( Statistic::Defense, self.calculate_other_stat(pokemon, Statistic::Defense), ); stats.set_stat( Statistic::SpecialAttack, self.calculate_other_stat(pokemon, Statistic::SpecialAttack), ); stats.set_stat( Statistic::SpecialDefense, self.calculate_other_stat(pokemon, Statistic::SpecialDefense), ); stats.set_stat(Statistic::Speed, self.calculate_other_stat(pokemon, Statistic::Speed)); } fn calculate_flat_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32 { if stat == Statistic::HP { self.calculate_health_stat(pokemon) } else { self.calculate_other_stat(pokemon, stat) } } fn calculate_boosted_stats(&self, pokemon: &Pokemon, stats: &StatisticSet) { stats.set_stat(Statistic::HP, self.calculate_boosted_stat(pokemon, Statistic::HP)); stats.set_stat( Statistic::Attack, self.calculate_boosted_stat(pokemon, Statistic::Attack), ); stats.set_stat( Statistic::Defense, self.calculate_boosted_stat(pokemon, Statistic::Defense), ); stats.set_stat( Statistic::SpecialAttack, self.calculate_boosted_stat(pokemon, Statistic::SpecialAttack), ); stats.set_stat( Statistic::SpecialDefense, self.calculate_boosted_stat(pokemon, Statistic::SpecialDefense), ); stats.set_stat(Statistic::Speed, self.calculate_boosted_stat(pokemon, Statistic::Speed)); } fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32 { (self.calculate_flat_stat(pokemon, stat) as f32 * self.get_stat_boost_modifier(pokemon, stat)) as u32 } }