1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-26 06:27:45 +00:00
sapphire/src/servers/Server_Zone/Actor/CalcBattle.cpp

127 lines
4.4 KiB
C++
Raw Normal View History

#include <src/servers/Server_Common/Exd/ExdData.h>
2017-08-20 19:27:06 -03:00
#include "CalcBattle.h"
#include "Actor.h"
#include "Player.h"
2017-08-28 16:13:23 -03:00
#include <cmath>
using namespace Core::Data;
using namespace Core::Entity;
extern Core::Data::ExdData g_exdData;
/*
2017-08-20 19:20:37 -03:00
Class used for battle-related formulas and calculations.
Big thanks to the Theoryjerks group!
NOTE:
Formulas here shouldn't be considered final. It's possible that the formula it was based on is correct but
wasn't implemented correctly here, or approximated things due to limited knowledge of how things work in retail.
It's also possible that we're using formulas that were correct for previous patches, but not the current version.
TODO:
2017-08-20 19:20:37 -03:00
Base HP val modifier. I can only find values for levels 50~70.
Attack power (and healing power). Needs more research on this.
Damage outgoing calculations. This includes auto-attacks, etc.
*/
2017-09-07 22:09:30 -03:00
// 3 Versions. SB and HW are linear, ARR is polynomial.
2017-08-20 19:27:06 -03:00
// Originally from Player.cpp, calculateStats().
float CalcBattle::calculateBaseStat( PlayerPtr pPlayer )
2017-08-20 19:27:06 -03:00
{
2017-08-20 19:20:37 -03:00
float base = 0.0f;
uint8_t level = pPlayer->getLevel();
2017-09-07 22:09:30 -03:00
// SB Base Stat Formula (Aligned)
if ( level > 60 )
{
2017-10-20 14:12:24 -07:00
base = static_cast< float >( ( ( ( level == 61 ) ? 224 : 220 ) + ( level - 61 ) * 8) );
2017-09-07 22:09:30 -03:00
}
// HW Base Stat Formula (Aligned)
else if ( level > 50 )
base = 1.63f * level + 121.02f;
// ARR Base Stat Formula (Off by one in several cases)
2017-08-20 19:20:37 -03:00
else
2017-09-07 23:36:31 -03:00
base = 0.052602f * ( level * level ) + ( 1.0179f * level ) + 19.6f;
2017-08-20 19:20:37 -03:00
return base;
}
2017-08-20 19:27:06 -03:00
// Leggerless' HP Formula
2017-08-20 19:20:37 -03:00
// ROUNDDOWN(JobModHP * (BaseHP / 100)) + ROUNDDOWN(VitHPMod / 100 * (VIT - BaseDET))
2017-08-20 19:27:06 -03:00
uint32_t CalcBattle::calculateMaxHp( PlayerPtr pPlayer )
{
// TODO: Replace ApproxBaseHP with something that can get us an accurate BaseHP.
2017-08-20 19:20:37 -03:00
// Is there any way to pull BaseHP without having to manually use a pet for every level, and using the values from a table?
// More info here: https://docs.google.com/spreadsheets/d/1de06KGT0cNRUvyiXNmjNgcNvzBCCQku7jte5QxEQRbs/edit?usp=sharing
2017-08-20 19:27:06 -03:00
auto classInfoIt = g_exdData.m_classJobInfoMap.find( pPlayer->getClass() );
auto paramGrowthInfoIt = g_exdData.m_paramGrowthInfoMap.find( pPlayer->getLevel() );
2017-08-20 19:20:37 -03:00
2017-08-23 00:39:52 -03:00
if ( classInfoIt == g_exdData.m_classJobInfoMap.end() ||
paramGrowthInfoIt == g_exdData.m_paramGrowthInfoMap.end() )
return 0;
uint8_t level = pPlayer->getLevel();
2017-08-20 19:27:06 -03:00
float baseStat = calculateBaseStat( pPlayer );
uint16_t vitStat = pPlayer->getStats().vit;
uint16_t hpMod = paramGrowthInfoIt->second.hp_mod;
2017-08-20 19:20:37 -03:00
uint16_t jobModHp = classInfoIt->second.mod_hp;
float approxBaseHp = 0.0f; // Read above
2017-08-20 19:20:37 -03:00
// These values are not precise.
if ( level >= 60 )
2017-10-20 14:12:24 -07:00
approxBaseHp = static_cast< float >( 2600 + ( level - 60 ) * 100 );
else if ( level >= 50 )
approxBaseHp = 1700 + ( ( level - 50 ) * ( 1700 * 1.04325f ) );
else
2017-09-24 21:02:29 -03:00
approxBaseHp = paramGrowthInfoIt->second.mp_const * 0.7667f;
2017-08-20 19:20:37 -03:00
uint16_t result = static_cast< uint16_t >( floor( jobModHp * ( approxBaseHp / 100.0f ) ) + floor( hpMod / 100.0f * ( vitStat - baseStat ) ) );
2017-08-20 19:20:37 -03:00
return result;
}
2017-08-20 19:27:06 -03:00
// Leggerless' MP Formula
2017-08-20 19:20:37 -03:00
// ROUNDDOWN(((ROUNDDOWN(((PIE - BaseDET) * PieMPMod/100),0) + BaseMP) * JobModMP / 100),0)
2017-08-20 19:27:06 -03:00
uint32_t CalcBattle::calculateMaxMp( PlayerPtr pPlayer )
2017-08-20 19:20:37 -03:00
{
2017-08-20 19:27:06 -03:00
auto classInfoIt = g_exdData.m_classJobInfoMap.find( pPlayer->getClass() );
auto paramGrowthInfoIt = g_exdData.m_paramGrowthInfoMap.find( pPlayer->getLevel() );
2017-08-20 19:20:37 -03:00
2017-08-23 00:39:52 -03:00
if ( classInfoIt == g_exdData.m_classJobInfoMap.end() ||
paramGrowthInfoIt == g_exdData.m_paramGrowthInfoMap.end() )
return 0;
2017-08-20 19:20:37 -03:00
float baseStat = calculateBaseStat( pPlayer );
uint16_t piety = pPlayer->getStats().pie;
uint16_t pietyScalar = paramGrowthInfoIt->second.mp_mod;
2017-08-20 19:20:37 -03:00
uint16_t jobModMp = classInfoIt->second.mod_mpcpgp;
uint16_t baseMp = paramGrowthInfoIt->second.mp_const;
uint16_t result = static_cast< uint16_t >( floor( floor( piety - baseStat ) * ( pietyScalar / 100 ) + baseMp ) * jobModMp / 100 );
2017-08-20 19:20:37 -03:00
return result;
}
2017-08-20 19:27:06 -03:00
uint32_t CalcBattle::calculateHealValue( PlayerPtr pPlayer, uint32_t potency )
2017-08-20 19:20:37 -03:00
{
auto classInfoIt = g_exdData.m_classJobInfoMap.find( pPlayer->getClass() );
auto paramGrowthInfoIt = g_exdData.m_paramGrowthInfoMap.find( pPlayer->getLevel() );
2017-08-20 19:27:06 -03:00
if ( classInfoIt == g_exdData.m_classJobInfoMap.end() ||
paramGrowthInfoIt == g_exdData.m_paramGrowthInfoMap.end())
return 0;
auto jobModVal = classInfoIt->second;
// consider 3% variation
return potency / 10;
}