1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-25 22:17:45 +00:00
sapphire/src/servers/sapphire_zone/Math/CalcStats.cpp

115 lines
4 KiB
C++
Raw Normal View History

2017-08-28 16:13:23 -03:00
#include <cmath>
2018-01-31 11:43:22 +01:00
#include <common/Exd/ExdDataGenerated.h>
#include <common/Common.h>
#include "Actor/Chara.h"
#include "Actor/Player.h"
#include "CalcStats.h"
#include "Framework.h"
using namespace Core::Math;
using namespace Core::Entity;
extern Core::Framework g_framework;
/*
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.
Dereferencing the actor (Player right now) for stats seem meh, perhaps consider a structure purely for stats?
Reduce repeated code (more specifically the data we pull from exd)
*/
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 CalcStats::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)
2018-03-02 08:25:48 -03:00
if( level > 60 )
2017-09-07 22:09:30 -03:00
{
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))
uint32_t CalcStats::calculateMaxHp( PlayerPtr pPlayer )
{
// TODO: Replace ApproxBaseHP with something that can get us an accurate BaseHP.
// Is there any way to pull reliable 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
auto classInfo = g_framework.getExdDataGen().get< Core::Data::ClassJob >( static_cast< uint8_t >( pPlayer->getClass() ) );
auto paramGrowthInfo = g_framework.getExdDataGen().get< Core::Data::ParamGrow >( pPlayer->getLevel() );
2017-08-20 19:20:37 -03:00
2018-03-02 08:25:48 -03:00
if( !classInfo || !paramGrowthInfo )
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;
2018-01-31 11:43:22 +01:00
uint16_t hpMod = paramGrowthInfo->hpModifier;
uint16_t jobModHp = classInfo->modifierHitPoints;
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
2018-01-31 11:43:22 +01:00
approxBaseHp = paramGrowthInfo->mpModifier * 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)
uint32_t CalcStats::calculateMaxMp( PlayerPtr pPlayer )
2017-08-20 19:20:37 -03:00
{
auto classInfo = g_framework.getExdDataGen().get< Core::Data::ClassJob >( static_cast< uint8_t >( pPlayer->getClass() ) );
auto paramGrowthInfo = g_framework.getExdDataGen().get< Core::Data::ParamGrow >( pPlayer->getLevel() );
2017-08-20 19:20:37 -03:00
2018-03-02 08:25:48 -03:00
if( !classInfo || !paramGrowthInfo )
return 0;
2017-08-20 19:20:37 -03:00
float baseStat = calculateBaseStat( pPlayer );
uint16_t piety = pPlayer->getStats().pie;
2018-01-31 11:43:22 +01:00
uint16_t pietyScalar = paramGrowthInfo->mpModifier;
uint16_t jobModMp = classInfo->modifierManaPoints;
uint16_t baseMp = paramGrowthInfo->mpModifier;
2017-08-20 19:20:37 -03:00
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;
}