use engine::prelude::*; use crate::{ config::{ attributes::{AgilitySettings, AttributeSettings, IntelligenceSettings, StrengthSettings}, items::ItemSettings, }, damage_type::DamageType, }; use super::{ attributes::{Agility, Attributes, Intelligence, Strength}, item_slots::ItemSlotContainer, macros::AttributeAssociation, statistic_types::StatisticType, }; // --------------- elements --------------- // Air generate_stat!(AirResistance, u32, "Air Resistance"); associate_strength!(AirResistance); generate_stat!(AirDamage, u32, "Air Damage"); associate_intelligence!(AirDamage); // fire generate_stat!(FireResistance, u32, "Fire Resistance"); associate_strength!(FireResistance); generate_stat!(FireDamage, u32, "Fire Damage"); associate_intelligence!(FireDamage); // water generate_stat!(WaterResistance, u32, "Water Resistance"); associate_strength!(WaterResistance); generate_stat!(WaterDamage, u32, "Water Damage"); associate_intelligence!(WaterDamage); // physical generate_stat!(Armor, u32, "Armor"); associate_agility!(Armor); generate_stat!(PhysicalDamage, u32, "Physical Damage"); associate_strength!(PhysicalDamage); // ---------------- special --------------- // crit generate_stat!(CriticalHitChance, f32, "Crit Chance"); associate_agility!(CriticalHitChance); generate_stat!(CriticalHitDamage, f32, "Crit Damage"); associate_agility!(CriticalHitDamage); // ----------------- base ----------------- // health generate_stat!(Health, f32, "Health"); associate_strength!(Health); impl std::ops::Add for Health { type Output = Self; fn add(self, other: HealthRegeneration) -> Self { Health(self.0 + other.0) } } impl std::ops::AddAssign for Health { fn add_assign(&mut self, other: HealthRegeneration) { self.0 += other.0 } } generate_stat!(HealthRegeneration, f32, "Health Regeneration"); associate_strength!(HealthRegeneration); // mana generate_stat!(Mana, f32, "Mana"); associate_intelligence!(Mana); impl std::ops::Add for Mana { type Output = Self; fn add(self, other: ManaRegeneration) -> Self { Mana(self.0 + other.0) } } impl std::ops::AddAssign for Mana { fn add_assign(&mut self, other: ManaRegeneration) { self.0 += other.0 } } generate_stat!(ManaRegeneration, f32, "Mana Regeneration"); associate_intelligence!(ManaRegeneration); #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct Statistics { // air pub air_resistance: AirResistance, pub air_damage: AirDamage, // fire pub fire_resistance: FireResistance, pub fire_damage: FireDamage, // water pub water_resistance: WaterResistance, pub water_damage: WaterDamage, // physical pub armor: Armor, pub physical_damage: PhysicalDamage, // crit pub critical_hit_chance: CriticalHitChance, pub critical_hit_damage: CriticalHitDamage, // health pub health: Health, pub health_regeneration: HealthRegeneration, // mana pub mana: Mana, pub mana_regeneration: ManaRegeneration, } impl Statistics { pub fn update<'a, 'b>( &mut self, attributes: &mut Attributes, attribute_settings: &AttributeSettings, items: impl Into>, ) { *self = Self::default(); let items = items.into(); if let Some((items, item_settings)) = items { let (agility, strength, intelligence) = items.collect_attribute_bonuses(item_settings); attributes.bonus_agility = strength; attributes.bonus_strength = agility; attributes.bonus_intelligence = intelligence; } // agility self.apply_agility(&attributes.agility(), &attribute_settings.agility_settings); // strength self.apply_strength( &attributes.strength(), &attribute_settings.strength_settings, ); // intelligence self.apply_intelligence( &attributes.intelligence(), &attribute_settings.intelligence_settings, ); // apply items if let Some((items, _)) = items { let item_bonuses = items.collect_stat_bonuses(); for item_bonus in item_bonuses.into_iter() { self.apply_bonus(item_bonus); } } } pub fn calculate_resistance(&self, damage_type: DamageType) -> u32 { match damage_type { DamageType::Air => self.air_resistance.raw(), DamageType::Fire => self.fire_resistance.raw(), DamageType::Water => self.water_resistance.raw(), DamageType::Physical => self.armor.raw(), } } fn apply_agility(&mut self, agility: &Agility, agility_settings: &AgilitySettings) { self.armor += Armor(agility.raw() * agility_settings.armor); self.critical_hit_chance += CriticalHitChance(agility.raw() as f32 * agility_settings.crit_chance); self.critical_hit_damage += CriticalHitDamage(agility.raw() as f32 * agility_settings.crit_damage); } fn apply_strength(&mut self, strength: &Strength, strength_settings: &StrengthSettings) { self.health += Health(strength.raw() as f32 * strength_settings.health); self.health_regeneration += HealthRegeneration(strength.raw() as f32 * strength_settings.health_regen); self.physical_damage += PhysicalDamage(strength.raw() * strength_settings.physical_damage); self.air_resistance += AirResistance(strength.raw() * strength_settings.air_resistance); self.fire_resistance += FireResistance(strength.raw() * strength_settings.fire_resistance); self.water_resistance += WaterResistance(strength.raw() * strength_settings.water_resistance); } fn apply_intelligence( &mut self, intelligence: &Intelligence, intelligence_settings: &IntelligenceSettings, ) { self.mana += Mana(intelligence.raw() as f32 * intelligence_settings.mana); self.mana_regeneration += ManaRegeneration(intelligence.raw() as f32 * intelligence_settings.mana_regen); self.air_damage += AirDamage(intelligence.raw() * intelligence_settings.air_damage); self.fire_damage += FireDamage(intelligence.raw() * intelligence_settings.fire_damage); self.water_damage += WaterDamage(intelligence.raw() * intelligence_settings.water_damage); } fn apply_bonus(&mut self, stat_type: StatisticType) { match stat_type { StatisticType::AirResistance(air_resistance) => self.air_resistance += air_resistance, StatisticType::AirDamage(air_damage) => self.air_damage += air_damage, StatisticType::FireResistance(fire_resistance) => { self.fire_resistance += fire_resistance } StatisticType::FireDamage(fire_damage) => self.fire_damage += fire_damage, StatisticType::WaterResistance(water_resistance) => { self.water_resistance += water_resistance } StatisticType::WaterDamage(water_damage) => self.water_damage += water_damage, StatisticType::Armor(armor) => self.armor += armor, StatisticType::PhysicalDamage(physical_damage) => { self.physical_damage += physical_damage } StatisticType::CriticalHitChance(crit_chance) => { self.critical_hit_chance += crit_chance } StatisticType::CriticalHitDamage(crit_damage) => { self.critical_hit_damage += crit_damage } StatisticType::Health(health) => self.health += health, StatisticType::HealthRegeneration(health_regen) => { self.health_regeneration += health_regen } StatisticType::Mana(mana) => self.mana += mana, StatisticType::ManaRegeneration(mana_regen) => self.mana_regeneration += mana_regen, } } } impl EntityComponent for Statistics { fn name(&self) -> &str { Self::debug_name() } } impl ComponentDebug for Statistics { fn debug_name() -> &'static str { "Statistics" } }