225 lines
11 KiB
C++
225 lines
11 KiB
C++
#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
|