2017-08-28 16:13:23 -03:00
|
|
|
#include <cmath>
|
2017-08-20 02:46:06 -03:00
|
|
|
|
2018-01-31 11:43:22 +01:00
|
|
|
#include <common/Exd/ExdDataGenerated.h>
|
2017-12-18 12:36:52 +01:00
|
|
|
#include <common/Common.h>
|
2018-03-02 07:22:25 -03:00
|
|
|
|
2018-02-20 22:46:44 +01:00
|
|
|
#include "Actor/Chara.h"
|
2018-03-06 00:10:36 +01:00
|
|
|
|
2017-12-08 15:38:25 +01:00
|
|
|
#include "Actor/Player.h"
|
2017-11-21 03:19:08 -02:00
|
|
|
|
|
|
|
#include "CalcStats.h"
|
2018-03-02 07:22:25 -03:00
|
|
|
#include "Framework.h"
|
2017-11-21 03:19:08 -02:00
|
|
|
|
|
|
|
using namespace Core::Math;
|
2017-08-20 02:46:06 -03:00
|
|
|
using namespace Core::Entity;
|
|
|
|
|
2018-03-02 07:22:25 -03:00
|
|
|
extern Core::Framework g_framework;
|
2017-08-20 02:46:06 -03:00
|
|
|
|
|
|
|
/*
|
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-11-21 03:19:08 -02:00
|
|
|
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-08-20 02:46:06 -03:00
|
|
|
*/
|
|
|
|
|
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().
|
2017-08-20 02:46:06 -03:00
|
|
|
|
2017-11-21 03:19:08 -02:00
|
|
|
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-08-20 02:46:06 -03:00
|
|
|
|
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 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-11-21 03:19:08 -02:00
|
|
|
uint32_t CalcStats::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-11-21 03:19:08 -02:00
|
|
|
// 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?
|
2017-08-23 00:38:54 -03:00
|
|
|
// More info here: https://docs.google.com/spreadsheets/d/1de06KGT0cNRUvyiXNmjNgcNvzBCCQku7jte5QxEQRbs/edit?usp=sharing
|
|
|
|
|
2018-03-02 07:22:25 -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 )
|
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;
|
2018-01-31 11:43:22 +01:00
|
|
|
uint16_t hpMod = paramGrowthInfo->hpModifier;
|
|
|
|
uint16_t jobModHp = classInfo->modifierHitPoints;
|
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 )
|
2017-10-20 14:12:24 -07:00
|
|
|
approxBaseHp = static_cast< float >( 2600 + ( level - 60 ) * 100 );
|
2017-08-23 00:38:54 -03:00
|
|
|
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
|
|
|
|
2017-09-15 00:56:29 -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 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-11-21 03:19:08 -02:00
|
|
|
uint32_t CalcStats::calculateMaxMp( PlayerPtr pPlayer )
|
2017-08-20 19:20:37 -03:00
|
|
|
{
|
2018-03-02 07:22:25 -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 )
|
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;
|
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
|
|
|
|
2017-09-15 00:56:29 -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;
|
2017-12-08 15:38:25 +01:00
|
|
|
}
|