rpg_base/rpg_components/src/components/statistics.rs

266 lines
8.2 KiB
Rust
Raw Normal View History

2025-02-28 07:43:35 +00:00
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<HealthRegeneration> for Health {
type Output = Self;
fn add(self, other: HealthRegeneration) -> Self {
Health(self.0 + other.0)
}
}
impl std::ops::AddAssign<HealthRegeneration> 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<ManaRegeneration> for Mana {
type Output = Self;
fn add(self, other: ManaRegeneration) -> Self {
Mana(self.0 + other.0)
}
}
impl std::ops::AddAssign<ManaRegeneration> 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<Option<(&'a ItemSlotContainer, &'a ItemSettings)>>,
) {
*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"
}
}