222 lines
8.0 KiB
C++
222 lines
8.0 KiB
C++
#ifndef STATS_H
|
||
#define STATS_H
|
||
|
||
#include "config.h"
|
||
#include <cstdint>
|
||
#include <array>
|
||
#include <cmath>
|
||
|
||
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<uint16_t>(static_cast<uint16_t>(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<Generation Gen>
|
||
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;
|
||
};
|
||
|
||
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<uint16_t>(std::ceil(std::sqrt(params.m_statExp))) >> 2u)) * params.m_level / 100u + params.m_level + 10u;
|
||
}
|
||
|
||
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<uint16_t>(std::ceil(std::sqrt(params.m_statExp))) >> 2u)) * params.m_level / 100u + 5u;
|
||
}
|
||
|
||
template <Generation Gen>
|
||
uint16_t CalculateHP(StatCalculatorParams params);
|
||
template <Generation Gen>
|
||
uint16_t CalculateStat(StatCalculatorParams params);
|
||
|
||
template <> uint16_t CalculateHP<Generation::I>(StatCalculatorParams params) { return CalculateHP_GenI_II(params); }
|
||
template <> uint16_t CalculateHP<Generation::II>(StatCalculatorParams params) { return CalculateHP_GenI_II(params); }
|
||
|
||
template <> uint16_t CalculateStat<Generation::I>(StatCalculatorParams params) { return CalculateStat_GenI_II(params); }
|
||
template <> uint16_t CalculateStat<Generation::II>(StatCalculatorParams params) { return CalculateStat_GenI_II(params); }
|
||
|
||
template <Generation Gen>
|
||
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 <Generation Gen>
|
||
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
|