Files
pokemon-battle-engine/include/core/pokemon_stats.h
2025-08-15 14:30:00 +00:00

168 lines
5.9 KiB
C++

#ifndef POKEMON_STATS_H
#define POKEMON_STATS_H
#include "config.h"
#include <cstdint>
#include <array>
namespace PokEng {
// Forward declaration
class PokemonInfo;
// Base stats structure for a Pokemon species
struct BaseStats {
uint16_t hp;
uint16_t attack;
uint16_t defense;
uint16_t sp_attack;
uint16_t sp_defense;
uint16_t speed;
BaseStats() : hp(0), attack(0), defense(0), sp_attack(0), sp_defense(0), speed(0) {}
BaseStats(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) {}
};
// 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
struct IndividualValues {
uint8_t hp;
uint8_t attack;
uint8_t defense;
uint8_t sp_attack;
uint8_t sp_defense;
uint8_t speed;
IndividualValues() : hp(0), attack(0), defense(0), sp_attack(0), sp_defense(0), speed(0) {}
IndividualValues(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) {}
// Validate IVs (each <= 31)
bool isValid() const {
return hp <= 31 && attack <= 31 && defense <= 31 &&
sp_attack <= 31 && sp_defense <= 31 && speed <= 31;
}
};
// Computed battle stats
struct BattleStats {
uint16_t hp; // Max 20,000
uint16_t attack; // Max 20,000
uint16_t defense; // Max 20,000
uint16_t sp_attack; // Max 20,000
uint16_t sp_defense; // Max 20,000
uint16_t speed; // Max 20,000
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_level(level), m_nature(nature), m_ivs(ivs), m_evs(evs) {}
// 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;
uint8_t m_level = 1;
Nature m_nature = Nature::HARDY;
IndividualValues m_ivs;
EffortValues m_evs;
};
// Nature utility functions
class NatureUtils {
public:
// Get the stat that is increased by this nature (returns StatIndex, or HP if none)
static StatIndex getIncreasedStat(Nature nature);
// Get the stat that is decreased by this nature (returns StatIndex, or HP if none)
static StatIndex getDecreasedStat(Nature nature);
// Get the multiplier for a specific stat given a nature (1.1f for increased, 0.9f for decreased, 1.0f for neutral)
static float getStatMultiplier(Nature nature, StatIndex stat);
// Check if a nature is neutral (increases and decreases the same stat)
static bool isNeutralNature(Nature nature);
};
// Stat calculation functions
class StatCalculator {
public:
// Generation I & II stat calculation
template<Generation Gen>
static typename std::enable_if<Gen == Generation::I || Gen == Generation::II, uint16_t>::type
calculateHP(uint16_t base, uint8_t dv, uint16_t statExp, uint8_t level);
template<Generation Gen>
static typename std::enable_if<Gen == Generation::I || Gen == Generation::II, uint16_t>::type
calculateStat(uint16_t base, uint8_t dv, uint16_t statExp, uint8_t level);
// Generation III+ stat calculation
template<Generation Gen>
static typename std::enable_if<Gen >= Generation::III, uint16_t>::type
calculateHP(uint16_t base, uint8_t iv, uint8_t ev, uint8_t level);
template<Generation Gen>
static typename std::enable_if<Gen >= Generation::III, uint16_t>::type
calculateStat(uint16_t base, uint8_t iv, uint8_t ev, uint8_t level, Nature nature, StatIndex statIndex);
private:
// Helper functions
static uint16_t clampStat(uint32_t value) {
return (value > 20000) ? 20000 : static_cast<uint16_t>(value);
}
};
} // namespace PokEng
#endif // POKEMON_STATS_H