#include "DamageLibrary.hpp" #include "../PkmnScriptHook.hpp" using HitData = const CreatureLib::Battling::ExecutingAttack::HitData; inline constexpr float fl(float a) { return std::floor(a); } uint32_t PkmnLib::Battling::DamageLibrary::GetDamage(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitIndex, const HitData& hitData) const { auto levelMod = fl((2 * attack->GetUser()->GetLevel()) / 5.0f) + 2; auto bp = hitData.GetBasePower(); auto statMod = GetStatModifier(attack, target, hitIndex, hitData); PKMN_HOOK(ModifyStatModifier, attack, attack, target, hitIndex, &statMod); auto damageMod = GetDamageModifier(attack, target, hitIndex, hitData); auto floatDamage = fl(levelMod * bp); floatDamage = fl(floatDamage * statMod); floatDamage = fl(floatDamage / 50) + 2; floatDamage = fl(floatDamage * damageMod); if (attack->GetTargetCount() > 1) { floatDamage = fl(floatDamage * 0.75f); } if (hitData.IsCritical()) { float critModifier = 1.5; PKMN_HOOK(OverrideCriticalModifier, attack, attack, target, hitIndex, &critModifier); floatDamage = fl(floatDamage * critModifier); } if (_hasRandomness) { Ensure(attack->GetUser()->GetBattle().GetValue()); float randPercentage = 85 + attack->GetUser()->GetBattle().GetValue()->GetRandom()->Get(0, 16); floatDamage = fl(floatDamage * (randPercentage / 100.0f)); } if (attack->GetUser()->HasType(hitData.GetType())) { float stabModifier = 1.5; PKMN_HOOK(OverrideSTABModifier, attack, attack, target, hitIndex, &stabModifier); floatDamage = fl(floatDamage * stabModifier); } floatDamage = fl(floatDamage * hitData.GetEffectiveness()); uint32_t damage = 0; if (floatDamage <= 0) { if (hitData.GetEffectiveness() == 0) { damage = 0; } else { damage = 1; } } else if (floatDamage >= (float)UINT32_MAX) { damage = UINT32_MAX; } else { damage = static_cast(floatDamage); } PKMN_HOOK(OverrideDamage, attack, attack, target, hitIndex, &damage); PKMN_HOOK(OverrideIncomingDamage, target, attack, target, hitIndex, &damage); return damage; } uint8_t PkmnLib::Battling::DamageLibrary::GetBasePower(CreatureLib::Battling::ExecutingAttack* attack, [[maybe_unused]] CreatureLib::Battling::Creature* target, [[maybe_unused]] uint8_t hitIndex, [[maybe_unused]] const HitData& hitData) const { auto bp = attack->GetUseAttack()->GetBasePower(); PKMN_HOOK(OverrideBasePower, attack, attack, target, hitIndex, &bp); return bp; } float PkmnLib::Battling::DamageLibrary::GetStatModifier(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hit, const HitData& hitData) const { auto* user = attack->GetUser().GetRaw(); PKMN_HOOK(ChangeDamageStatsUser, attack, attack, target, hit, &user); CreatureLib::Library::Statistic offensiveStat; CreatureLib::Library::Statistic defensiveStat; auto moveData = attack->GetUseAttack().ForceAs(); if (moveData->GetCategory() == Library::MoveCategory::Physical) { offensiveStat = Library::Statistic::PhysicalAttack; defensiveStat = Library::Statistic::PhysicalDefense; } else { offensiveStat = Library::Statistic::SpecialAttack; defensiveStat = Library::Statistic::SpecialDefense; } auto bypassDefensive = hitData.IsCritical() && target->GetStatBoost(defensiveStat) > 0; PKMN_HOOK(BypassDefensiveStat, attack, attack, target, hit, &bypassDefensive); auto bypassOffensive = hitData.IsCritical() && user->GetStatBoost(offensiveStat) < 0; PKMN_HOOK(BypassOffensiveStat, attack, attack, target, hit, &bypassOffensive); float offensiveValue = bypassOffensive ? (float)user->GetFlatStat(offensiveStat) : (float)user->GetBoostedStat(offensiveStat); float defensiveValue = bypassDefensive ? (float)target->GetFlatStat(defensiveStat) : (float)target->GetBoostedStat(defensiveStat); PKMN_HOOK(ModifyOffensiveStatValue, attack, attack, target, hit, &offensiveValue); PKMN_HOOK(ModifyDefensiveStatValue, attack, attack, target, hit, &defensiveValue); return offensiveValue / defensiveValue; } float PkmnLib::Battling::DamageLibrary::GetDamageModifier(CreatureLib::Battling::ExecutingAttack*, CreatureLib::Battling::Creature*, uint8_t, const HitData&) const { float mod = 1; // HOOK: Modify damage modifier. return mod; }