Merge commit '269ad43957cf5f7cbbd6c8fa2b6038d81e4d483a'

This commit is contained in:
cdemeyer-teachx
2025-08-16 10:59:23 +09:00
7 changed files with 612 additions and 9 deletions

33
Prompts/4-StatSystem Normal file
View File

@@ -0,0 +1,33 @@
This repo is the start of a high performant pokemon battle simulator. It only uses integers.
I want you to implement the stat system of pokemon.
In the pokemon class, only save the values that are relevant to battle.
Make a PokemonInfo class that holds values not relevant to combat, but that can be used to calculate stats relevant to combat.
Combat:
Create fields for the HP, Attack, Defense, Sp. Atk, Sp. Def, Speed (max 20'000).
Create a value for friendship (max 255).
Info:
Each pokemon has its base stats that mirror the combat stats (HP, Attack, Defense, Sp. Atk, Sp. Def, Speed).
Create Effort Values (EV) that are like alternate values between 0-255 that mirror the combat stats .
There can only be 510 EV values max assigned in total.
Create Individual Values (IV) that are values between 0-31.
Implement pokemon natures, which increases the stat by either positive or negative 10%.
Create a stat formula for each generation.
Natures:
- Attack - Defense - Sp. Atk - Sp. Def - Speed
+ Attack Hardy Lonely Adamant Naughty Brave
+ Defense Bold Docile Impish Lax Relaxed
+ Sp. Atk Modest Mild Bashful Rash Quiet
+ Sp. Def Calm Gentle Careful Quirky Sassy
+ Speed Timid Hasty Jolly Naive Serious
formula for stats:
Generations I and II:
HP=⌊((Base+DV)×2+⌊⌈STATEXP⌉4⌋)×Level100⌋+Level+10
OtherStat=⌊((Base+DV)×2+⌊⌈STATEXP⌉4⌋)×Level100⌋+5
Generation III onward:
HP=⌊(2×Base+IV+⌊EV4⌋)×Level100⌋+Level+10
OtherStat=⌊(⌊(2×Base+IV+⌊EV4⌋)×Level100⌋+5)×Nature⌋

View File

@@ -0,0 +1,93 @@
#include "pokemon_battle_sim.h"
#include <iostream>
#include <iomanip>
using namespace PokEng;
void printPokemonStats(const Pokemon& pokemon, const std::string& name) {
std::cout << "\n=== " << name << " ===\n";
std::cout << "ID: " << pokemon.getId() << "\n";
std::cout << "Current HP: " << pokemon.getCurrentHP() << "/" << pokemon.getMaxHP() << "\n";
std::cout << "Attack: " << pokemon.getAttack() << "\n";
std::cout << "Defense: " << pokemon.getDefense() << "\n";
std::cout << "Sp. Attack: " << pokemon.getSpAttack() << "\n";
std::cout << "Sp. Defense: " << pokemon.getSpDefense() << "\n";
std::cout << "Speed: " << pokemon.getSpeed() << "\n";
std::cout << "Friendship: " << static_cast<int>(pokemon.getFriendship()) << "\n";
std::cout << "Primary Type: " << static_cast<int>(pokemon.getPrimaryType()) << "\n";
if (pokemon.getSecondaryType() != Type::NONE) {
std::cout << "Secondary Type: " << static_cast<int>(pokemon.getSecondaryType()) << "\n";
}
}
void printNatureEffect(Nature nature) {
std::cout << "\nNature: " << static_cast<int>(nature);
StatIndex increased = NatureUtils::getIncreasedStat(nature);
StatIndex decreased = NatureUtils::getDecreasedStat(nature);
if (increased != StatIndex::HP) {
std::cout << " (+10% to stat " << static_cast<int>(increased) << ")";
}
if (decreased != StatIndex::HP) {
std::cout << " (-10% to stat " << static_cast<int>(decreased) << ")";
}
if (NatureUtils::isNeutralNature(nature)) {
std::cout << " (Neutral nature)";
}
std::cout << "\n";
}
int main() {
std::cout << "Pokemon Battle Simulator - Stat System Example\n";
std::cout << "===============================================\n";
// Create base stats for a Charizard-like Pokemon
BaseStats charizardBase(78, 84, 78, 109, 85, 100);
// Create different Pokemon with different configurations
// 1. Level 50 Charizard with neutral nature and no EVs/IVs
PokemonInfo basicInfo(charizardBase, 50, Nature::HARDY);
Pokemon basicCharizard(6, basicInfo, PokemonTypes(Type::FIRE, Type::FLYING), 128);
// 2. Level 100 Charizard with Modest nature (+Sp.Atk, -Atk) and perfect IVs
IndividualValues perfectIVs(31, 31, 31, 31, 31, 31);
PokemonInfo competitiveInfo(charizardBase, 100, Nature::MODEST, perfectIVs);
Pokemon competitiveCharizard(6, competitiveInfo, PokemonTypes(Type::FIRE, Type::FLYING), 255);
// 3. Level 100 Charizard with Adamant nature (+Atk, -Sp.Atk) and Attack EVs
EffortValues attackEVs(0, 252, 0, 0, 4, 252); // Max Attack and Speed, some HP
PokemonInfo physicalInfo(charizardBase, 100, Nature::ADAMANT, perfectIVs, attackEVs);
Pokemon physicalCharizard(6, physicalInfo, PokemonTypes(Type::FIRE, Type::FLYING), 255);
// Print all Pokemon
printPokemonStats(basicCharizard, "Basic Charizard (Lv50, Neutral)");
printNatureEffect(Nature::MODEST);
printPokemonStats(competitiveCharizard, "Competitive Charizard (Lv100, Modest, Perfect IVs)");
printNatureEffect(Nature::ADAMANT);
printPokemonStats(physicalCharizard, "Physical Charizard (Lv100, Adamant, Attack EVs)");
// Demonstrate Generation I/II calculation
std::cout << "\n=== Generation I/II Calculation Example ===\n";
Pokemon gen1Charizard(6, basicInfo.calculateBattleStats<Generation::I>(), PokemonTypes(Type::FIRE, Type::FLYING), 128);
printPokemonStats(gen1Charizard, "Gen I Charizard (Same base stats)");
// Show EV validation
std::cout << "\n=== EV Validation ===\n";
EffortValues validEVs(85, 85, 85, 85, 85, 85); // 510 total
EffortValues invalidEVs(100, 100, 100, 100, 100, 100); // 600 total
std::cout << "Valid EVs (510 total): " << (validEVs.isValid() ? "VALID" : "INVALID") << "\n";
std::cout << "Invalid EVs (600 total): " << (invalidEVs.isValid() ? "VALID" : "INVALID") << "\n";
// Show IV validation
IndividualValues validIVs(31, 31, 31, 31, 31, 31);
IndividualValues invalidIVs(32, 32, 32, 32, 32, 32);
std::cout << "Valid IVs (all 31): " << (validIVs.isValid() ? "VALID" : "INVALID") << "\n";
std::cout << "Invalid IVs (all 32): " << (invalidIVs.isValid() ? "VALID" : "INVALID") << "\n";
return 0;
}

View File

@@ -18,6 +18,56 @@ VIII = 8,
IX = 9
};
// Pokemon Nature enumeration
enum class Nature : uint8_t {
// Neutral natures (no stat changes)
HARDY = 0, // +Attack, -Attack
DOCILE, // +Defense, -Defense
BASHFUL, // +Sp. Atk, -Sp. Atk
QUIRKY, // +Sp. Def, -Sp. Def
SERIOUS, // +Speed, -Speed
// Attack boosting natures
LONELY, // +Attack, -Defense
ADAMANT, // +Attack, -Sp. Atk
NAUGHTY, // +Attack, -Sp. Def
BRAVE, // +Attack, -Speed
// Defense boosting natures
BOLD, // +Defense, -Attack
IMPISH, // +Defense, -Sp. Atk
LAX, // +Defense, -Sp. Def
RELAXED, // +Defense, -Speed
// Sp. Atk boosting natures
MODEST, // +Sp. Atk, -Attack
MILD, // +Sp. Atk, -Defense
RASH, // +Sp. Atk, -Sp. Def
QUIET, // +Sp. Atk, -Speed
// Sp. Def boosting natures
CALM, // +Sp. Def, -Attack
GENTLE, // +Sp. Def, -Defense
CAREFUL, // +Sp. Def, -Sp. Atk
SASSY, // +Sp. Def, -Speed
// Speed boosting natures
TIMID, // +Speed, -Attack
HASTY, // +Speed, -Defense
JOLLY, // +Speed, -Sp. Atk
NAIVE // +Speed, -Sp. Def
};
// Stat indices for nature calculations
enum class StatIndex : uint8_t {
HP = 0,
ATTACK = 1,
DEFENSE = 2,
SP_ATTACK = 3,
SP_DEFENSE = 4,
SPEED = 5
};
} // namespace PokEng

View File

@@ -3,6 +3,7 @@
#include "config.h"
#include "types.h"
#include "pokemon_stats.h"
#include <string>
namespace PokEng {
@@ -13,24 +14,56 @@ public:
Pokemon() = default;
~Pokemon() = default;
// Basic constructors
Pokemon(uint16_t id) : m_id(id) {}
Pokemon(uint16_t id, uint16_t health) : m_id(id), m_health(health) {}
Pokemon(uint16_t id, uint16_t health, Type primaryType) : m_id(id), m_health(health), m_types(primaryType) {}
Pokemon(uint16_t id, uint16_t health, Type primaryType, Type secondaryType) : m_id(id), m_health(health), m_types(primaryType, secondaryType) {}
Pokemon(uint16_t id, uint16_t currentHP) : m_id(id), m_currentHP(currentHP) {}
Pokemon(uint16_t id, uint16_t currentHP, Type primaryType) : m_id(id), m_currentHP(currentHP), m_types(primaryType) {}
Pokemon(uint16_t id, uint16_t currentHP, Type primaryType, Type secondaryType) : m_id(id), m_currentHP(currentHP), m_types(primaryType, secondaryType) {}
// Constructor that calculates stats from PokemonInfo
template<Generation Gen = Generation::III>
Pokemon(uint16_t id, const PokemonInfo& info, const PokemonTypes& types, uint8_t friendship = 0)
: m_id(id), m_types(types), m_friendship(friendship) {
m_battleStats = info.calculateBattleStats<Gen>();
m_currentHP = m_battleStats.hp; // Start at full health
}
// Constructor that takes pre-calculated battle stats
Pokemon(uint16_t id, const BattleStats& stats, const PokemonTypes& types, uint8_t friendship = 0)
: m_id(id), m_battleStats(stats), m_types(types), m_friendship(friendship) {
m_currentHP = m_battleStats.hp; // Start at full health
}
public:
// Getters
// Basic getters
uint16_t getId() const { return m_id; }
uint16_t getHealth() const { return m_health; }
uint16_t getCurrentHP() const { return m_currentHP; }
uint16_t getMaxHP() const { return m_battleStats.hp; }
PokemonTypes getTypes() const { return m_types; }
Type getPrimaryType() const { return m_types.getPrimary(); }
Type getSecondaryType() const { return m_types.getSecondary(); }
uint8_t getFriendship() const { return m_friendship; }
// Battle stat getters
const BattleStats& getBattleStats() const { return m_battleStats; }
uint16_t getAttack() const { return m_battleStats.attack; }
uint16_t getDefense() const { return m_battleStats.defense; }
uint16_t getSpAttack() const { return m_battleStats.sp_attack; }
uint16_t getSpDefense() const { return m_battleStats.sp_defense; }
uint16_t getSpeed() const { return m_battleStats.speed; }
// Setters
void setHealth(uint16_t health) { m_health = health; }
// Basic setters
void setCurrentHP(uint16_t hp) { m_currentHP = (hp > m_battleStats.hp) ? m_battleStats.hp : hp; }
void setTypes(Type primary) { m_types.setPrimary(primary); m_types.setSecondary(Type::NONE); }
void setTypes(Type primary, Type secondary) { m_types.setPrimary(primary); m_types.setSecondary(secondary); }
void SetPokemonTypes(PokemonTypes types) { m_types = types; }
void setFriendship(uint8_t friendship) { m_friendship = friendship; }
// Battle stat setters (for direct stat assignment if needed)
void setBattleStats(const BattleStats& stats) {
m_battleStats = stats;
if (m_currentHP > m_battleStats.hp) m_currentHP = m_battleStats.hp;
}
public:
// Type-based operations
@@ -40,9 +73,11 @@ public:
}
private:
uint16_t m_id;
uint16_t m_health;
uint16_t m_id = 0;
uint16_t m_currentHP = 0;
BattleStats m_battleStats;
PokemonTypes m_types;
uint8_t m_friendship = 0;
};
} // namespace PokEng

View File

@@ -0,0 +1,167 @@
#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

View File

@@ -6,6 +6,7 @@
#include "core/types.h"
#include "core/pokemon.h"
#include "core/pokemon_stats.h"
#include "core/battle.h"
#include "core/config.h"

224
src/core/pokemon_stats.cpp Normal file
View File

@@ -0,0 +1,224 @@
#include "pokemon_battle_sim.h"
#include <cmath>
#include <algorithm>
namespace PokEng {
// Nature utility function implementations
StatIndex NatureUtils::getIncreasedStat(Nature nature) {
switch (nature) {
// Attack boosting
case Nature::LONELY:
case Nature::ADAMANT:
case Nature::NAUGHTY:
case Nature::BRAVE:
return StatIndex::ATTACK;
// Defense boosting
case Nature::BOLD:
case Nature::IMPISH:
case Nature::LAX:
case Nature::RELAXED:
return StatIndex::DEFENSE;
// Sp. Attack boosting
case Nature::MODEST:
case Nature::MILD:
case Nature::RASH:
case Nature::QUIET:
return StatIndex::SP_ATTACK;
// Sp. Defense boosting
case Nature::CALM:
case Nature::GENTLE:
case Nature::CAREFUL:
case Nature::SASSY:
return StatIndex::SP_DEFENSE;
// Speed boosting
case Nature::TIMID:
case Nature::HASTY:
case Nature::JOLLY:
case Nature::NAIVE:
return StatIndex::SPEED;
// Neutral natures
default:
return StatIndex::HP; // Use HP as "no stat" indicator
}
}
StatIndex NatureUtils::getDecreasedStat(Nature nature) {
switch (nature) {
// Attack decreasing
case Nature::BOLD:
case Nature::MODEST:
case Nature::CALM:
case Nature::TIMID:
return StatIndex::ATTACK;
// Defense decreasing
case Nature::LONELY:
case Nature::MILD:
case Nature::GENTLE:
case Nature::HASTY:
return StatIndex::DEFENSE;
// Sp. Attack decreasing
case Nature::ADAMANT:
case Nature::IMPISH:
case Nature::CAREFUL:
case Nature::JOLLY:
return StatIndex::SP_ATTACK;
// Sp. Defense decreasing
case Nature::NAUGHTY:
case Nature::LAX:
case Nature::RASH:
return StatIndex::SP_DEFENSE;
// Speed decreasing
case Nature::BRAVE:
case Nature::RELAXED:
case Nature::QUIET:
case Nature::SASSY:
return StatIndex::SPEED;
// Neutral natures
default:
return StatIndex::HP; // Use HP as "no stat" indicator
}
}
float NatureUtils::getStatMultiplier(Nature nature, StatIndex stat) {
StatIndex increased = getIncreasedStat(nature);
StatIndex decreased = getDecreasedStat(nature);
if (stat == increased && stat != StatIndex::HP) {
return 1.1f; // +10%
} else if (stat == decreased && stat != StatIndex::HP) {
return 0.9f; // -10%
} else {
return 1.0f; // Neutral
}
}
bool NatureUtils::isNeutralNature(Nature nature) {
return getIncreasedStat(nature) == getDecreasedStat(nature) ||
getIncreasedStat(nature) == StatIndex::HP;
}
// Generation I & II stat calculation implementations
template<Generation Gen>
typename std::enable_if<Gen == Generation::I || Gen == Generation::II, uint16_t>::type
StatCalculator::calculateHP(uint16_t base, uint8_t dv, uint16_t statExp, uint8_t level) {
// HP=⌊((Base+DV)×2+⌊⌈STATEXP⌉/4⌋)×Level/100⌋+Level+10
uint32_t result = ((static_cast<uint32_t>(base) + dv) * 2 +
static_cast<uint32_t>(std::ceil(statExp) / 4)) * level / 100 + level + 10;
return clampStat(result);
}
template<Generation Gen>
typename std::enable_if<Gen == Generation::I || Gen == Generation::II, uint16_t>::type
StatCalculator::calculateStat(uint16_t base, uint8_t dv, uint16_t statExp, uint8_t level) {
// OtherStat=⌊((Base+DV)×2+⌊⌈STATEXP⌉/4⌋)×Level/100⌋+5
uint32_t result = ((static_cast<uint32_t>(base) + dv) * 2 +
static_cast<uint32_t>(std::ceil(statExp) / 4)) * level / 100 + 5;
return clampStat(result);
}
// Generation III+ stat calculation implementations
template<Generation Gen>
typename std::enable_if<Gen >= Generation::III, uint16_t>::type
StatCalculator::calculateHP(uint16_t base, uint8_t iv, uint8_t ev, uint8_t level) {
// HP=⌊(2×Base+IV+⌊EV/4⌋)×Level/100⌋+Level+10
uint32_t result = (2 * static_cast<uint32_t>(base) + iv + ev / 4) * level / 100 + level + 10;
return clampStat(result);
}
template<Generation Gen>
typename std::enable_if<Gen >= Generation::III, uint16_t>::type
StatCalculator::calculateStat(uint16_t base, uint8_t iv, uint8_t ev, uint8_t level, Nature nature, StatIndex statIndex) {
// OtherStat=⌊(⌊(2×Base+IV+⌊EV/4⌋)×Level/100⌋+5)×Nature⌋
uint32_t baseStat = (2 * static_cast<uint32_t>(base) + iv + ev / 4) * level / 100 + 5;
float natureMultiplier = NatureUtils::getStatMultiplier(nature, statIndex);
uint32_t result = static_cast<uint32_t>(std::floor(static_cast<float>(baseStat) * natureMultiplier));
return clampStat(result);
}
// Explicit template instantiations for Generation I & II
template uint16_t StatCalculator::calculateHP<Generation::I>(uint16_t, uint8_t, uint16_t, uint8_t);
template uint16_t StatCalculator::calculateHP<Generation::II>(uint16_t, uint8_t, uint16_t, uint8_t);
template uint16_t StatCalculator::calculateStat<Generation::I>(uint16_t, uint8_t, uint16_t, uint8_t);
template uint16_t StatCalculator::calculateStat<Generation::II>(uint16_t, uint8_t, uint16_t, uint8_t);
// Explicit template instantiations for Generation III+
template uint16_t StatCalculator::calculateHP<Generation::III>(uint16_t, uint8_t, uint8_t, uint8_t);
template uint16_t StatCalculator::calculateHP<Generation::IV>(uint16_t, uint8_t, uint8_t, uint8_t);
template uint16_t StatCalculator::calculateHP<Generation::V>(uint16_t, uint8_t, uint8_t, uint8_t);
template uint16_t StatCalculator::calculateHP<Generation::VI>(uint16_t, uint8_t, uint8_t, uint8_t);
template uint16_t StatCalculator::calculateHP<Generation::VII>(uint16_t, uint8_t, uint8_t, uint8_t);
template uint16_t StatCalculator::calculateHP<Generation::VIII>(uint16_t, uint8_t, uint8_t, uint8_t);
template uint16_t StatCalculator::calculateHP<Generation::IX>(uint16_t, uint8_t, uint8_t, uint8_t);
template uint16_t StatCalculator::calculateStat<Generation::III>(uint16_t, uint8_t, uint8_t, uint8_t, Nature, StatIndex);
template uint16_t StatCalculator::calculateStat<Generation::IV>(uint16_t, uint8_t, uint8_t, uint8_t, Nature, StatIndex);
template uint16_t StatCalculator::calculateStat<Generation::V>(uint16_t, uint8_t, uint8_t, uint8_t, Nature, StatIndex);
template uint16_t StatCalculator::calculateStat<Generation::VI>(uint16_t, uint8_t, uint8_t, uint8_t, Nature, StatIndex);
template uint16_t StatCalculator::calculateStat<Generation::VII>(uint16_t, uint8_t, uint8_t, uint8_t, Nature, StatIndex);
template uint16_t StatCalculator::calculateStat<Generation::VIII>(uint16_t, uint8_t, uint8_t, uint8_t, Nature, StatIndex);
template uint16_t StatCalculator::calculateStat<Generation::IX>(uint16_t, uint8_t, uint8_t, uint8_t, Nature, StatIndex);
// PokemonInfo stat calculation implementations
template<Generation Gen>
BattleStats PokemonInfo::calculateBattleStats() const {
BattleStats stats;
if constexpr (Gen == Generation::I || Gen == Generation::II) {
// For Gen I/II, we need DV and STATEXP values
// For simplicity, we'll convert IVs to DVs (IV/2) and EVs to STATEXP (EV*EV/4)
uint8_t hp_dv = m_ivs.hp / 2;
uint8_t atk_dv = m_ivs.attack / 2;
uint8_t def_dv = m_ivs.defense / 2;
uint8_t spa_dv = m_ivs.sp_attack / 2;
uint8_t spd_dv = m_ivs.sp_defense / 2;
uint8_t spe_dv = m_ivs.speed / 2;
uint16_t hp_statexp = static_cast<uint16_t>((static_cast<uint32_t>(m_evs.hp) * m_evs.hp) / 4);
uint16_t atk_statexp = static_cast<uint16_t>((static_cast<uint32_t>(m_evs.attack) * m_evs.attack) / 4);
uint16_t def_statexp = static_cast<uint16_t>((static_cast<uint32_t>(m_evs.defense) * m_evs.defense) / 4);
uint16_t spa_statexp = static_cast<uint16_t>((static_cast<uint32_t>(m_evs.sp_attack) * m_evs.sp_attack) / 4);
uint16_t spd_statexp = static_cast<uint16_t>((static_cast<uint32_t>(m_evs.sp_defense) * m_evs.sp_defense) / 4);
uint16_t spe_statexp = static_cast<uint16_t>((static_cast<uint32_t>(m_evs.speed) * m_evs.speed) / 4);
stats.hp = StatCalculator::calculateHP<Gen>(m_baseStats.hp, hp_dv, hp_statexp, m_level);
stats.attack = StatCalculator::calculateStat<Gen>(m_baseStats.attack, atk_dv, atk_statexp, m_level);
stats.defense = StatCalculator::calculateStat<Gen>(m_baseStats.defense, def_dv, def_statexp, m_level);
stats.sp_attack = StatCalculator::calculateStat<Gen>(m_baseStats.sp_attack, spa_dv, spa_statexp, m_level);
stats.sp_defense = StatCalculator::calculateStat<Gen>(m_baseStats.sp_defense, spd_dv, spd_statexp, m_level);
stats.speed = StatCalculator::calculateStat<Gen>(m_baseStats.speed, spe_dv, spe_statexp, m_level);
} else {
// Generation III+
stats.hp = StatCalculator::calculateHP<Gen>(m_baseStats.hp, m_ivs.hp, m_evs.hp, m_level);
stats.attack = StatCalculator::calculateStat<Gen>(m_baseStats.attack, m_ivs.attack, m_evs.attack, m_level, m_nature, StatIndex::ATTACK);
stats.defense = StatCalculator::calculateStat<Gen>(m_baseStats.defense, m_ivs.defense, m_evs.defense, m_level, m_nature, StatIndex::DEFENSE);
stats.sp_attack = StatCalculator::calculateStat<Gen>(m_baseStats.sp_attack, m_ivs.sp_attack, m_evs.sp_attack, m_level, m_nature, StatIndex::SP_ATTACK);
stats.sp_defense = StatCalculator::calculateStat<Gen>(m_baseStats.sp_defense, m_ivs.sp_defense, m_evs.sp_defense, m_level, m_nature, StatIndex::SP_DEFENSE);
stats.speed = StatCalculator::calculateStat<Gen>(m_baseStats.speed, m_ivs.speed, m_evs.speed, m_level, m_nature, StatIndex::SPEED);
}
return stats;
}
// Explicit template instantiations for PokemonInfo::calculateBattleStats
template BattleStats PokemonInfo::calculateBattleStats<Generation::I>() const;
template BattleStats PokemonInfo::calculateBattleStats<Generation::II>() const;
template BattleStats PokemonInfo::calculateBattleStats<Generation::III>() const;
template BattleStats PokemonInfo::calculateBattleStats<Generation::IV>() const;
template BattleStats PokemonInfo::calculateBattleStats<Generation::V>() const;
template BattleStats PokemonInfo::calculateBattleStats<Generation::VI>() const;
template BattleStats PokemonInfo::calculateBattleStats<Generation::VII>() const;
template BattleStats PokemonInfo::calculateBattleStats<Generation::VIII>() const;
template BattleStats PokemonInfo::calculateBattleStats<Generation::IX>() const;
} // namespace PokEng