2017-08-28 16:13:23 -03:00
|
|
|
#include <cmath>
|
2017-08-20 02:46:06 -03:00
|
|
|
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <Exd/ExdDataGenerated.h>
|
|
|
|
#include <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
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
using namespace Sapphire::Math;
|
|
|
|
using namespace Sapphire::Entity;
|
2017-08-20 02:46:06 -03:00
|
|
|
|
2019-03-20 15:22:40 +01:00
|
|
|
const int levelTable[70][8] =
|
|
|
|
{
|
|
|
|
// PIE, MP, MAIN,SUB,DIV,HP,ELMT,THREAT
|
|
|
|
{ 50, 104, 20, 56, 56, 0, 52, 2 },
|
|
|
|
{ 55, 114, 21, 57, 57, 0, 54, 2 },
|
|
|
|
{ 60, 123, 22, 60, 60, 0, 56, 3 },
|
|
|
|
{ 65,133,24,62,62,0,58 },
|
|
|
|
{ 70,142,26,65,65,0,60 },
|
|
|
|
{ 75,152,27,68,68,0,62 },
|
|
|
|
{ 80,161,29,70,70,0,64},
|
|
|
|
{ 85,171,31,73,73,0,66},
|
|
|
|
{ 90,180,33,76,76,0,68},
|
|
|
|
{ 95,190,35,78,78,0,70},
|
|
|
|
{ 100,209,36,82,82,0,73},
|
|
|
|
{ 105,228,38,85,85,0,75},
|
|
|
|
{ 110,247,41,89,89,0,78},
|
|
|
|
{ 115,266,44,93,93,0,81},
|
|
|
|
{ 120,285,46,96,96,0,84},
|
|
|
|
{ 125,304,49,100,100,0,86},
|
|
|
|
{ 130,323,52,104,104,0,89},
|
|
|
|
{ 135,342,54,109,109,0,93},
|
|
|
|
{ 140,361,57,113,113,0,95},
|
|
|
|
{ 145,380,60,116,116,0,98},
|
|
|
|
{ 150,418,63,122,122,0,102},
|
|
|
|
{ 155,456,67,127,127,0,105},
|
|
|
|
{ 160,494,71,133,133,0,109},
|
|
|
|
{ 165,532,74,138,138,0,113},
|
|
|
|
{ 170,570,78,144,144,0,117},
|
|
|
|
{ 175,608,81,150,150,0,121},
|
|
|
|
{ 180,646,85,155,155,0,125},
|
|
|
|
{ 185,684,89,162,162,0,129},
|
|
|
|
{ 190,722,92,168,168,0,133},
|
|
|
|
{ 195,760,97,173,173,0,137},
|
|
|
|
{ 200,826,101,181,181,0,143},
|
|
|
|
{ 205,893,106,188,188,0,148},
|
|
|
|
{ 210,959,110,194,194,0,153},
|
|
|
|
{ 215,1026,115,202,202,0,159},
|
|
|
|
{ 220,1092,119,209,209,0,165},
|
|
|
|
{ 225,1159,124,215,215,0,170},
|
|
|
|
{ 230,1225,128,223,223,0,176},
|
|
|
|
{ 235,1292,134,229,229,0,181},
|
|
|
|
{ 240,1358,139,236,236,0,186},
|
|
|
|
{ 245,1425,144,244,244,0,192},
|
|
|
|
{ 250,1548,150,253,253,0,200},
|
|
|
|
{ 255,1672,155,263,263,0,207},
|
|
|
|
{ 260,1795,161,272,272,0,215},
|
|
|
|
{ 265,1919,166,283,283,0,223},
|
|
|
|
{ 270,2042,171,292,292,0,231},
|
|
|
|
{ 275,2166,177,302,302,0,238},
|
|
|
|
{ 280,2289,183,311,311,0,246},
|
|
|
|
{ 285,2413,189,322,322,0,254},
|
|
|
|
{ 290,2536,196,331,331,0,261},
|
|
|
|
{ 300,2660,202,341,341,1700,269},
|
|
|
|
{ 315,3000,204,342,393,1774,270},
|
|
|
|
{ 330,3380,205,344,444,1851,271},
|
|
|
|
{ 360,3810,207,345,496,1931,273},
|
|
|
|
{ 390,4300,209,346,548,2015,274},
|
|
|
|
{ 420,4850,210,347,600,2102,275},
|
|
|
|
{ 450,5470,212,349,651,2194,276},
|
|
|
|
{ 480,6170,214,350,703,2289,278},
|
|
|
|
{ 510,6950,215,351,755,2388,279},
|
|
|
|
{ 540,7840,217,352,806,2492,280},
|
|
|
|
{ 620,8840,218,354,858,2600,282},
|
|
|
|
{ 650,8980,224,355,941,2700,283},
|
|
|
|
{ 680,9150,228,356,1032,2800,284},
|
|
|
|
{ 710,9350,236,357,1133,2900,286},
|
|
|
|
{ 740,9590,244,358,1243,3000,287},
|
|
|
|
{ 770,9870,252,359,1364,3100,288},
|
|
|
|
{ 800,10190,260,360,1497,3200,290},
|
|
|
|
{ 830,10560,268,361,1643,3300,292},
|
|
|
|
{ 860,10980,276,362,1802,3400,293},
|
|
|
|
{ 890,11450,284,363,1978,3500,294},
|
|
|
|
{ 890,12000,292,364,2170,3600,295}
|
|
|
|
};
|
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
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
float base = 0.0f;
|
|
|
|
uint8_t level = pPlayer->getLevel();
|
|
|
|
|
|
|
|
// SB Base Stat Formula (Aligned)
|
|
|
|
if( level > 60 )
|
|
|
|
{
|
|
|
|
base = static_cast< float >( ( ( ( level == 61 ) ? 224 : 220 ) + ( level - 61 ) * 8 ) );
|
|
|
|
}
|
|
|
|
// 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)
|
|
|
|
else
|
|
|
|
base = 0.052602f * ( level * level ) + ( 1.0179f * level ) + 19.6f;
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
2018-12-29 00:53:52 +01:00
|
|
|
uint32_t CalcStats::calculateMaxHp( PlayerPtr pPlayer, Sapphire::FrameworkPtr pFw )
|
2017-08-20 02:46:06 -03:00
|
|
|
{
|
2018-12-29 00:53:52 +01:00
|
|
|
auto pExdData = pFw->get< Data::ExdDataGenerated >();
|
2018-08-29 21:40:59 +02:00
|
|
|
// 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
|
2017-08-20 19:20:37 -03:00
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
auto classInfo = pExdData->get< Sapphire::Data::ClassJob >( static_cast< uint8_t >( pPlayer->getClass() ) );
|
|
|
|
auto paramGrowthInfo = pExdData->get< Sapphire::Data::ParamGrow >( pPlayer->getLevel() );
|
2017-08-23 00:38:54 -03:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !classInfo || !paramGrowthInfo )
|
|
|
|
return 0;
|
2017-08-23 00:38:54 -03:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint8_t level = pPlayer->getLevel();
|
2017-08-20 19:20:37 -03:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
float baseStat = calculateBaseStat( pPlayer );
|
|
|
|
uint16_t vitStat = pPlayer->getStats().vit;
|
|
|
|
uint16_t hpMod = paramGrowthInfo->hpModifier;
|
|
|
|
uint16_t jobModHp = classInfo->modifierHitPoints;
|
|
|
|
float approxBaseHp = 0.0f; // Read above
|
2017-08-20 19:20:37 -03:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// These values are not precise.
|
2017-08-20 19:20:37 -03:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( level >= 60 )
|
|
|
|
approxBaseHp = static_cast< float >( 2600 + ( level - 60 ) * 100 );
|
|
|
|
else if( level >= 50 )
|
|
|
|
approxBaseHp = 1700 + ( ( level - 50 ) * ( 1700 * 1.04325f ) );
|
|
|
|
else
|
|
|
|
approxBaseHp = paramGrowthInfo->mpModifier * 0.7667f;
|
2017-08-20 19:20:37 -03:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint16_t result = static_cast< uint16_t >( floor( jobModHp * ( approxBaseHp / 100.0f ) ) +
|
|
|
|
floor( hpMod / 100.0f * ( vitStat - baseStat ) ) );
|
|
|
|
|
|
|
|
return result;
|
2017-08-20 19:20:37 -03:00
|
|
|
}
|
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
|
|
|
|
2018-12-29 00:53:52 +01:00
|
|
|
uint32_t CalcStats::calculateMaxMp( PlayerPtr pPlayer, Sapphire::FrameworkPtr pFw )
|
2017-08-20 19:20:37 -03:00
|
|
|
{
|
2018-12-29 00:53:52 +01:00
|
|
|
auto pExdData = pFw->get< Data::ExdDataGenerated >();
|
2018-11-29 16:55:48 +01:00
|
|
|
auto classInfo = pExdData->get< Sapphire::Data::ClassJob >( static_cast< uint8_t >( pPlayer->getClass() ) );
|
|
|
|
auto paramGrowthInfo = pExdData->get< Sapphire::Data::ParamGrow >( pPlayer->getLevel() );
|
2017-08-20 19:20:37 -03:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !classInfo || !paramGrowthInfo )
|
|
|
|
return 0;
|
2017-08-23 00:38:54 -03:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
float baseStat = calculateBaseStat( pPlayer );
|
|
|
|
uint16_t piety = pPlayer->getStats().pie;
|
|
|
|
uint16_t pietyScalar = paramGrowthInfo->mpModifier;
|
|
|
|
uint16_t jobModMp = classInfo->modifierManaPoints;
|
|
|
|
uint16_t baseMp = paramGrowthInfo->mpModifier;
|
2017-08-20 19:20:37 -03:00
|
|
|
|
2018-08-29 21:40:59 +02: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
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return result;
|
2017-12-08 15:38:25 +01:00
|
|
|
}
|