168 lines
5.9 KiB
C++
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
|