#ifndef STATS_H #define STATS_H #include "config.h" #include #include #include namespace PokEng { // Forward declaration class PokemonInfo; // Base stats structure for a Pokemon species struct BaseStats { uint8_t hp; uint8_t attack; uint8_t defense; uint8_t sp_attack; uint8_t sp_defense; uint8_t speed; BaseStats() : hp(0), attack(0), defense(0), sp_attack(0), sp_defense(0), speed(0) {} BaseStats(uint8_t hp_, uint8_t atk, uint8_t def, uint8_t spa, uint8_t spd, uint8_t spe) : hp(hp_), attack(atk), defense(def), sp_attack(spa), sp_defense(spd), speed(spe) {} }; // Effort Values (EVs) - max 510 total, max 255 per stat struct EffortValues { uint8_t hp; uint8_t attack; uint8_t defense; uint8_t sp_attack; uint8_t sp_defense; uint8_t speed; EffortValues() : hp(0), attack(0), defense(0), sp_attack(0), sp_defense(0), speed(0) {} EffortValues(uint8_t hp_, uint8_t atk, uint8_t def, uint8_t spa, uint8_t spd, uint8_t spe) : hp(hp_), attack(atk), defense(def), sp_attack(spa), sp_defense(spd), speed(spe) {} // Get total EVs (should not exceed 510) uint16_t getTotal() const { return static_cast(static_cast(hp) + attack + defense + sp_attack + sp_defense + speed); } // Validate EVs (total <= 510, each <= 255) bool isValid() const { return getTotal() <= 510; } }; // Individual Values (IVs) - 0-31 per stat // Packed into 32 bits: 5 bits per stat + 2 bits unused struct IndividualValues { private: uint32_t m_packed; // 30 bits used: HP(0-4), ATK(5-9), DEF(10-14), SPA(15-19), SPD(20-24), SPE(25-29) public: IndividualValues() : m_packed(0) {} IndividualValues(uint8_t hp_, uint8_t atk, uint8_t def, uint8_t spa, uint8_t spd, uint8_t spe) { setHP(hp_); setAttack(atk); setDefense(def); setSpAttack(spa); setSpDefense(spd); setSpeed(spe); } // Getters uint8_t getHP() const { return (m_packed & 0x1F); } uint8_t getAttack() const { return (m_packed >> 5) & 0x1F; } uint8_t getDefense() const { return (m_packed >> 10) & 0x1F; } uint8_t getSpAttack() const { return (m_packed >> 15) & 0x1F; } uint8_t getSpDefense() const { return (m_packed >> 20) & 0x1F; } uint8_t getSpeed() const { return (m_packed >> 25) & 0x1F; } // Legacy getters for compatibility uint8_t hp() const { return getHP(); } uint8_t attack() const { return getAttack(); } uint8_t defense() const { return getDefense(); } uint8_t sp_attack() const { return getSpAttack(); } uint8_t sp_defense() const { return getSpDefense(); } uint8_t speed() const { return getSpeed(); } // Setters void setHP(uint8_t value) { if (value > 31) value = 31; m_packed = (m_packed & ~0x1FU) | (value & 0x1FU); } void setAttack(uint8_t value) { if (value > 31) value = 31; m_packed = (m_packed & ~(0x1FU << 5)) | ((value & 0x1FU) << 5); } void setDefense(uint8_t value) { if (value > 31) value = 31; m_packed = (m_packed & ~(0x1FU << 10)) | ((value & 0x1FU) << 10); } void setSpAttack(uint8_t value) { if (value > 31) value = 31; m_packed = (m_packed & ~(0x1FU << 15)) | ((value & 0x1FU) << 15); } void setSpDefense(uint8_t value) { if (value > 31) value = 31; m_packed = (m_packed & ~(0x1FU << 20)) | ((value & 0x1FU) << 20); } void setSpeed(uint8_t value) { if (value > 31) value = 31; m_packed = (m_packed & ~(0x1FU << 25)) | ((value & 0x1FU) << 25); } // Validate IVs (each <= 31) - always true with our implementation bool isValid() const { return true; // Always valid since we enforce limits in setters } }; // Computed battle stat struct BattleStats { uint16_t hp; uint16_t attack; uint16_t defense; uint16_t sp_attack; uint16_t sp_defense; uint16_t speed; BattleStats() : hp(0), attack(0), defense(0), sp_attack(0), sp_defense(0), speed(0) {} BattleStats(uint16_t hp_, uint16_t atk, uint16_t def, uint16_t spa, uint16_t spd, uint16_t spe) : hp(hp_), attack(atk), defense(def), sp_attack(spa), sp_defense(spd), speed(spe) {} }; // Pokemon information class - holds data not directly relevant to battle class PokemonInfo { public: PokemonInfo() = default; PokemonInfo(const BaseStats& baseStats, uint8_t level = 1, Nature nature = Nature::HARDY(), const IndividualValues& ivs = IndividualValues(), const EffortValues& evs = EffortValues()) : m_baseStats(baseStats), m_ivs(ivs), m_evs(evs), m_level(level), m_nature(nature) {} // Getters const BaseStats& getBaseStats() const { return m_baseStats; } uint8_t getLevel() const { return m_level; } Nature getNature() const { return m_nature; } const IndividualValues& getIVs() const { return m_ivs; } const EffortValues& getEVs() const { return m_evs; } // Setters void setBaseStats(const BaseStats& baseStats) { m_baseStats = baseStats; } void setLevel(uint8_t level) { m_level = (level > 100) ? 100 : level; } void setNature(Nature nature) { m_nature = nature; } void setIVs(const IndividualValues& ivs) { if (ivs.isValid()) m_ivs = ivs; } void setEVs(const EffortValues& evs) { if (evs.isValid()) m_evs = evs; } // Calculate battle stats for different generations template BattleStats calculateBattleStats() const; private: BaseStats m_baseStats; // size 6, align 1 IndividualValues m_ivs; // size 6, align 1 EffortValues m_evs; // size 6, align 1 uint8_t m_level = 1; // size 1, align 1 Nature m_nature; // size 1, align 1 }; struct StatCalculatorParams { StatCalculatorParams() = default; StatCalculatorParams(uint8_t base, uint8_t iv, uint8_t ev, uint8_t level, Nature nature, StatIndex statIndex, uint16_t statExp) : m_base(base), m_iv(iv), m_ev(ev), m_level(level), m_nature(nature), m_statIndex(statIndex), m_statExp(statExp) {} uint8_t m_base; uint8_t m_iv; uint8_t m_ev; uint8_t m_level; Nature m_nature; StatIndex m_statIndex; uint16_t m_statExp; }; inline uint16_t CalculateHP_GenI_II(StatCalculatorParams params) { // HP=⌊((Base+DV)×2+⌊⌈sqrt(STATEXP)⌉4⌋)×Level100⌋+Level+10 return (((params.m_base + (params.m_iv >> 1u)) << 1u) + (static_cast(std::ceil(std::sqrt(params.m_statExp))) >> 2u)) * params.m_level / 100u + params.m_level + 10u; } inline uint16_t CalculateStat_GenI_II(StatCalculatorParams params) { // OtherStat=⌊((Base+DV)×2+⌊⌈sqrt(STATEXP)⌉4⌋)×Level100⌋+5 return (((params.m_base + (params.m_iv >> 1u)) << 1u) + (static_cast(std::ceil(std::sqrt(params.m_statExp))) >> 2u)) * params.m_level / 100u + 5u; } template uint16_t CalculateHP(StatCalculatorParams params); template uint16_t CalculateStat(StatCalculatorParams params); template <> inline uint16_t CalculateHP(StatCalculatorParams params) { return CalculateHP_GenI_II(params); } template <> inline uint16_t CalculateHP(StatCalculatorParams params) { return CalculateHP_GenI_II(params); } template <> inline uint16_t CalculateStat(StatCalculatorParams params) { return CalculateStat_GenI_II(params); } template <> inline uint16_t CalculateStat(StatCalculatorParams params) { return CalculateStat_GenI_II(params); } template inline uint16_t CalculateHP(StatCalculatorParams params) { // HP=⌊(2×Base+IV+⌊EV4⌋)×Level100⌋+Level+10 return ((2 * params.m_base + params.m_iv + (params.m_ev >> 2)) * params.m_level / 100) + params.m_level + 10; } template inline uint16_t CalculateStat(StatCalculatorParams params) { // OtherStat=⌊(⌊(2×Base+IV+⌊EV4⌋)×Level100⌋+5)×Nature⌋ return (((2 * params.m_base + params.m_iv + (params.m_ev >> 2)) * params.m_level / 100) + 5) * params.m_nature.getMultiplier10(params.m_statIndex) / 10; } } // namespace PokEng #endif // STATS_H