2017-08-20 02:46:06 -03:00
|
|
|
#include <src/servers/Server_Common/Exd/ExdData.h>
|
|
|
|
|
2017-08-20 19:27:06 -03:00
|
|
|
#include "CalcBattle.h"
|
2017-08-20 02:46:06 -03:00
|
|
|
#include "Actor.h"
|
|
|
|
#include "Player.h"
|
|
|
|
|
|
|
|
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.
|
2017-08-20 02:46:06 -03:00
|
|
|
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.
|
2017-08-23 00:38:54 -03:00
|
|
|
Attack power (and healing power). Needs more research on this.
|
2017-08-20 02:46:06 -03:00
|
|
|
Damage outgoing calculations. This includes auto-attacks, etc.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2017-08-20 19:27:06 -03:00
|
|
|
// Don't know too much about this formula, but seems to work for some of the levels tested.
|
|
|
|
// Originally from Player.cpp, calculateStats().
|
2017-08-20 02:46:06 -03:00
|
|
|
|
2017-08-20 19:27:06 -03:00
|
|
|
uint32_t CalcBattle::calculateBaseStat( PlayerPtr pPlayer )
|
|
|
|
{
|
2017-08-20 19:20:37 -03:00
|
|
|
float base = 0.0f;
|
|
|
|
uint8_t level = pPlayer->getLevel();
|
2017-08-20 02:46:06 -03:00
|
|
|
|
2017-08-20 19:20:37 -03:00
|
|
|
if (level < 51)
|
2017-08-23 00:38:54 -03:00
|
|
|
base = 0.053f * ( level * level ) + ( 1.022f * level ) - 0.907f + 20;
|
2017-08-20 19:20:37 -03:00
|
|
|
else
|
2017-08-23 00:38:54 -03:00
|
|
|
base = 1.627f * level + 120.773f;
|
2017-08-20 02:46:06 -03:00
|
|
|
|
2017-08-20 19:20:37 -03:00
|
|
|
return base;
|
2017-08-20 02:46:06 -03:00
|
|
|
}
|
|
|
|
|
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 )
|
2017-08-20 02:46:06 -03:00
|
|
|
{
|
2017-08-23 00:38:54 -03:00
|
|
|
// 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?
|
2017-08-23 00:38:54 -03:00
|
|
|
// 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() )
|
2017-08-23 00:38:54 -03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
uint8_t level = pPlayer->getLevel();
|
|
|
|
|
2017-08-20 19:27:06 -03:00
|
|
|
float baseStat = calculateBaseStat( pPlayer );
|
2017-08-23 00:38:54 -03:00
|
|
|
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;
|
2017-08-23 00:38:54 -03:00
|
|
|
float approxBaseHp = 0.0f; // Read above
|
2017-08-20 19:20:37 -03:00
|
|
|
|
|
|
|
// These values are not precise.
|
|
|
|
|
2017-08-23 00:38:54 -03:00
|
|
|
if ( level >= 60 )
|
|
|
|
approxBaseHp = 2600 + ( level - 60 ) * 100;
|
|
|
|
else if ( level >= 50 )
|
|
|
|
approxBaseHp = 1700 + ( ( level - 50 ) * ( 1700 * 1.04325f ) );
|
|
|
|
else
|
|
|
|
approxBaseHp = paramGrowthInfoIt->second.mp_const * 0.7596f;
|
2017-08-20 19:20:37 -03:00
|
|
|
|
2017-08-23 00:38:54 -03:00
|
|
|
uint16_t result = floor( jobModHp * ( approxBaseHp / 100.0f ) ) + floor( hpMod / 100.0f * ( vitStat - baseStat ) );
|
2017-08-20 19:20:37 -03:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2017-08-20 02:46:06 -03:00
|
|
|
|
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 02:46:06 -03:00
|
|
|
|
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() )
|
2017-08-23 00:38:54 -03:00
|
|
|
return 0;
|
|
|
|
|
2017-08-20 19:20:37 -03:00
|
|
|
float baseStat = calculateBaseStat( pPlayer );
|
|
|
|
uint16_t piety = pPlayer->getStats().pie;
|
2017-08-23 00:38:54 -03:00
|
|
|
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;
|
|
|
|
|
2017-08-23 00:38:54 -03:00
|
|
|
uint16_t result = 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
|
|
|
{
|
2017-08-20 02:46: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:27:06 -03:00
|
|
|
if ( classInfoIt == g_exdData.m_classJobInfoMap.end() ||
|
2017-08-20 02:46:06 -03:00
|
|
|
paramGrowthInfoIt == g_exdData.m_paramGrowthInfoMap.end())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
auto jobModVal = classInfoIt->second;
|
|
|
|
|
|
|
|
// consider 3% variation
|
|
|
|
return potency / 10;
|
|
|
|
}
|