1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-27 22:57:45 +00:00

CalcBattle stuff;

This commit is contained in:
Maru 2017-08-20 19:20:37 -03:00
parent dcb0578d03
commit 1b6b7abfd2
7 changed files with 142 additions and 85 deletions

View file

@ -236,7 +236,7 @@ bool Core::Data::ExdData::loadParamGrowInfo()
uint32_t id = row.first; uint32_t id = row.first;
info.level = id; info.level = id;
info.needed_exp = getField< int32_t >( fields, 0 ); info.needed_exp = getField< int32_t >( fields, 0 );
info.piety_scalar = getField< uint16_t >( fields, 3 ); // 3 info.mp_mod = getField< uint16_t >( fields, 3 ); // 3
info.mp_const = getField< int32_t >( fields, 4 ); // 4 info.mp_const = getField< int32_t >( fields, 4 ); // 4
info.base_secondary = getField< int32_t >( fields, 5 );// 5 info.base_secondary = getField< int32_t >( fields, 5 );// 5
info.quest_exp_mod = getField< uint8_t >( fields, 7 ); // 7 info.quest_exp_mod = getField< uint8_t >( fields, 7 ); // 7

View file

@ -116,7 +116,7 @@ namespace Core {
uint32_t needed_exp; uint32_t needed_exp;
int16_t hp_mod; int16_t hp_mod;
int32_t mp_const; int32_t mp_const;
int16_t piety_scalar; int16_t mp_mod;
int32_t base_secondary; int32_t base_secondary;
uint16_t quest_exp_mod; uint16_t quest_exp_mod;
}; };

View file

@ -79,6 +79,12 @@ Core::Entity::Actor::Stance Core::Entity::Actor::getStance() const
return m_currentStance; return m_currentStance;
} }
/*! \return actor stats */
Core::Entity::Actor::ActorStats Core::Entity::Actor::getStats() const
{
return m_baseStats;
}
/*! \return current HP */ /*! \return current HP */
uint32_t Core::Entity::Actor::getHp() const uint32_t Core::Entity::Actor::getHp() const
{ {
@ -207,11 +213,8 @@ void Core::Entity::Actor::die()
// fire onDeath event // fire onDeath event
onDeath(); onDeath();
bool selfNeedsUpdate = false;
// if the actor is a player, the update needs to be send to himself too // if the actor is a player, the update needs to be send to himself too
if( isPlayer() ) bool selfNeedsUpdate = isPlayer();
selfNeedsUpdate = true;
sendToInRangeSet( ActorControlPacket142( m_id, SetStatus, static_cast< uint8_t>( ActorStatus::Dead ) ), selfNeedsUpdate ); sendToInRangeSet( ActorControlPacket142( m_id, SetStatus, static_cast< uint8_t>( ActorStatus::Dead ) ), selfNeedsUpdate );

View file

@ -55,6 +55,51 @@ public:
SMachine = 0x08 SMachine = 0x08
}; };
struct ActorStats
{
uint32_t max_mp = 0;
uint32_t max_hp = 0;
uint32_t str = 0;
uint32_t dex = 0;
uint32_t vit = 0;
uint32_t inte = 0;
uint32_t mnd = 0;
uint32_t pie = 0;
uint32_t parry = 0;
uint32_t attack = 0;
uint32_t defense = 0;
uint32_t accuracy = 0;
uint32_t spellSpeed = 0;
uint32_t magicDefense = 0;
uint32_t critHitRate = 0;
uint32_t resistSlash = 0;
uint32_t resistPierce = 0;
uint32_t resistBlunt = 0;
uint32_t attackPotMagic = 0;
uint32_t healingPotMagic = 0;
uint32_t determination = 0;
uint32_t skillSpeed = 0;
uint32_t resistSlow = 0;
uint32_t resistSilence = 0;
uint32_t resistBlind = 0;
uint32_t resistPoison = 0;
uint32_t resistStun = 0;
uint32_t resistSleep = 0;
uint32_t resistBind = 0;
uint32_t resistHeavy = 0;
uint32_t resistFire = 0;
uint32_t resistIce = 0;
uint32_t resistWind = 0;
uint32_t resistEarth = 0;
uint32_t resistLightning = 0;
uint32_t resistWater = 0;
} m_baseStats;
protected: protected:
// TODO: The position class should probably be abolished and // TODO: The position class should probably be abolished and
// the FFXIV_POS struct used instead ( the functions in there // the FFXIV_POS struct used instead ( the functions in there
@ -106,51 +151,6 @@ protected:
/*! Container for status effects */ /*! Container for status effects */
StatusEffect::StatusEffectContainerPtr m_pStatusEffectContainer; StatusEffect::StatusEffectContainerPtr m_pStatusEffectContainer;
struct
{
uint32_t max_mp = 0;
uint32_t max_hp = 0;
uint32_t str = 0;
uint32_t dex = 0;
uint32_t vit = 0;
uint32_t inte = 0;
uint32_t mnd = 0;
uint32_t pie = 0;
uint32_t parry = 0;
uint32_t attack = 0;
uint32_t defense = 0;
uint32_t accuracy = 0;
uint32_t spellSpeed = 0;
uint32_t magicDefense = 0;
uint32_t critHitRate = 0;
uint32_t resistSlash = 0;
uint32_t resistPierce = 0;
uint32_t resistBlunt = 0;
uint32_t attackPotMagic = 0;
uint32_t healingPotMagic = 0;
uint32_t determination = 0;
uint32_t skillSpeed = 0;
uint32_t resistSlow = 0;
uint32_t resistSilence = 0;
uint32_t resistBlind = 0;
uint32_t resistPoison = 0;
uint32_t resistStun = 0;
uint32_t resistSleep = 0;
uint32_t resistBind = 0;
uint32_t resistHeavy = 0;
uint32_t resistFire = 0;
uint32_t resistIce = 0;
uint32_t resistWind = 0;
uint32_t resistEarth = 0;
uint32_t resistLightning = 0;
uint32_t resistWater = 0;
} m_baseStats;
public: public:
Actor(); Actor();
@ -189,6 +189,8 @@ public:
void setStance( Stance stance ); void setStance( Stance stance );
ActorStats getStats() const;
uint32_t getHp() const; uint32_t getHp() const;
uint32_t getMp() const; uint32_t getMp() const;

View file

@ -1,6 +1,7 @@
#include "CalcBattle.h" #include "CalcBattle.h"
#include <src/servers/Server_Common/Exd/ExdData.h> #include <src/servers/Server_Common/Exd/ExdData.h>
#include <src/servers/Server_Common/Logging/Logger.h>
#include "Actor.h" #include "Actor.h"
#include "Player.h" #include "Player.h"
@ -8,9 +9,10 @@
using namespace Core::Entity; using namespace Core::Entity;
extern Core::Data::ExdData g_exdData; extern Core::Data::ExdData g_exdData;
extern Core::Logger g_log;
/* /*
Class used for battle-related formulas and calculatio ns. Class used for battle-related formulas and calculations.
Big thanks to the Theoryjerks group! Big thanks to the Theoryjerks group!
NOTE: NOTE:
@ -20,31 +22,94 @@ extern Core::Data::ExdData g_exdData;
TODO: TODO:
Vitality HP modifier. I can only find values for levels 50~70. Base HP val modifier. I can only find values for levels 50~70.
HP calculation. Not a lot limiting us here. It should be next. Attack power (and healing power). Need more researchg on this.
Damage outgoing calculations. This includes auto-attacks, etc. Damage outgoing calculations. This includes auto-attacks, etc.
Stats. Will need to align stats from retail with what we have.
*/ */
uint32_t Core::Entity::CalcBattle::measureHp( ActorPtr pActor ) uint32_t Core::Entity::CalcBattle::calculateBaseStat(PlayerPtr pPlayer)
{ {
// todo: reduce autos here // Don't know too much about this formula, but seems to work for some of the levels tested.
// Originally from Player.cpp, calculateStats().
PlayerPtr pPlayer = pActor->getAsPlayer(); float base = 0.0f;
uint8_t level = pPlayer->getLevel();
auto classInfoIt = g_exdData.m_classJobInfoMap.find( pPlayer->getClass() ); if (level < 51)
auto paramGrowthInfoIt = g_exdData.m_paramGrowthInfoMap.find( pPlayer->getLevel() ); base = static_cast<uint32_t>(0.053f * (level * level) + (1.022f * level) - 0.907f + 20);
else
base = static_cast<uint32_t>(1.627f * level + 120.773f);
return 10; return base;
} }
uint32_t Core::Entity::CalcBattle::measureHeal( ActorPtr pActor, uint32_t potency ) // ROUNDDOWN(JobModHP * (BaseHP / 100)) + ROUNDDOWN(VitHPMod / 100 * (VIT - BaseDET))
uint32_t Core::Entity::CalcBattle::calculateMaxHp( PlayerPtr pPlayer )
{ {
// todo: reduce autos here // TODO: Replace ApproxBaseHP with something that can get us a BaseHP reliably.
// Is there any way to pull BaseHP without having to manually use a pet for every level, and using the values from a table?
PlayerPtr pPlayer = pActor->getAsPlayer(); auto classInfoIt = g_exdData.m_classJobInfoMap.find(pPlayer->getClass());
auto paramGrowthInfoIt = g_exdData.m_paramGrowthInfoMap.find(pPlayer->getLevel());
float baseStat = calculateBaseStat(pPlayer);
uint16_t vit = pPlayer->getStats().vit;
uint16_t hp_mod = paramGrowthInfoIt->second.hp_mod;
uint16_t jobModHp = classInfoIt->second.mod_hp;
uint16_t approxBaseHp = 0; // Read above
// These values are not precise.
if (pPlayer->getLevel() > 50)
approxBaseHp = 0.1452f * paramGrowthInfoIt->second.mp_const + 1356.6f;
else
approxBaseHp = paramGrowthInfoIt->second.mp_const * 0.525f;
uint16_t result = floor( jobModHp * ( approxBaseHp / 100.0f ) ) + floor( hp_mod / 100.0f * ( vit - baseStat ) );
g_log.error("MaxHP: " + std::to_string(result)
+ " vit is " + std::to_string(vit)
+ " basestat is " + std::to_string(baseStat)
+ " hp_mod is " + std::to_string(hp_mod)
+ " approxBaseHp is " + std::to_string(approxBaseHp)
+ " jobmodhp is " + std::to_string(jobModHp)
);
return result;
}
// Floor[(Floor[(283 - 218) * (540/100)] + 8840) * (115/100)]
// Floor[(Floor[(Piety - BaseDet) (PieMPMod / 100)] + BaseMP) * (JobModMP / 100)]
// ROUNDDOWN(((ROUNDDOWN(((PIE - BaseDET) * PieMPMod/100),0) + BaseMP) * JobModMP / 100),0)
uint32_t Core::Entity::CalcBattle::calculateMaxMp( PlayerPtr pPlayer )
{
auto classInfoIt = g_exdData.m_classJobInfoMap.find(pPlayer->getClass());
auto paramGrowthInfoIt = g_exdData.m_paramGrowthInfoMap.find(pPlayer->getLevel());
float baseStat = calculateBaseStat( pPlayer );
uint16_t piety = pPlayer->getStats().pie;
uint16_t piety_scalar = paramGrowthInfoIt->second.mp_mod;
uint16_t jobModMp = classInfoIt->second.mod_mpcpgp;
uint16_t baseMp = paramGrowthInfoIt->second.mp_const;
uint16_t result = floor( floor( piety - baseStat ) * ( piety_scalar / 100 ) + baseMp ) * jobModMp / 100;
g_log.error("MaxMP: " + std::to_string(result)
+ " piety is " + std::to_string(piety)
+ " basestat is " + std::to_string(baseStat)
+ " mp_mod is " + std::to_string(piety_scalar)
+ " baseMp is " + std::to_string(baseMp)
+ " jobmodmp is " + std::to_string(jobModMp)
);
return result;
}
uint32_t Core::Entity::CalcBattle::calculateHealValue( PlayerPtr pPlayer, uint32_t potency )
{
auto classInfoIt = g_exdData.m_classJobInfoMap.find( pPlayer->getClass() ); auto classInfoIt = g_exdData.m_classJobInfoMap.find( pPlayer->getClass() );
auto paramGrowthInfoIt = g_exdData.m_paramGrowthInfoMap.find( pPlayer->getLevel() ); auto paramGrowthInfoIt = g_exdData.m_paramGrowthInfoMap.find( pPlayer->getLevel() );

View file

@ -11,8 +11,10 @@ namespace Entity {
{ {
public: public:
static uint32_t measureHp( ActorPtr Player ); static uint32_t calculateBaseStat( PlayerPtr pPlayer );
static uint32_t measureHeal( ActorPtr Player, uint32_t potency ); static uint32_t calculateMaxMp( PlayerPtr pPlayer );
static uint32_t calculateMaxHp( PlayerPtr pPlayer );
static uint32_t calculateHealValue( PlayerPtr pPlayer, uint32_t potency );
private: private:

View file

@ -204,12 +204,7 @@ void Core::Entity::Player::calculateStats()
auto paramGrowthInfo = paramGrowthInfoIt->second; auto paramGrowthInfo = paramGrowthInfoIt->second;
// TODO: put formula somewhere else... // TODO: put formula somewhere else...
float base = 0.0f; float base = CalcBattle::calculateBaseStat( getAsPlayer() );
if( level < 51 )
base = 0.053f * ( level * level ) + ( 1.022f * level ) - 0.907f + 20;
else
base = 1.627f * level + 120.773f;
m_baseStats.str = base * ( static_cast< float >( classInfo.mod_str ) / 100 ) + tribeInfo.mod_str; m_baseStats.str = base * ( static_cast< float >( classInfo.mod_str ) / 100 ) + tribeInfo.mod_str;
m_baseStats.dex = base * ( static_cast< float >( classInfo.mod_dex ) / 100 ) + tribeInfo.mod_dex; m_baseStats.dex = base * ( static_cast< float >( classInfo.mod_dex ) / 100 ) + tribeInfo.mod_dex;
@ -225,15 +220,9 @@ void Core::Entity::Player::calculateStats()
m_baseStats.attackPotMagic = paramGrowthInfo.base_secondary; m_baseStats.attackPotMagic = paramGrowthInfo.base_secondary;
m_baseStats.healingPotMagic = paramGrowthInfo.base_secondary; m_baseStats.healingPotMagic = paramGrowthInfo.base_secondary;
m_baseStats.max_mp = floor( m_baseStats.max_mp = CalcBattle::calculateMaxMp( getAsPlayer() );
floor(
( ( m_baseStats.pie - base ) * ( static_cast< float >( paramGrowthInfo.piety_scalar ) / 100 ) ) + paramGrowthInfo.mp_const ) * ( static_cast< float >( classInfo.mod_mpcpgp ) / 100 )
);
m_baseStats.max_hp = floor( m_baseStats.max_hp = CalcBattle::calculateMaxHp( getAsPlayer() );
floor(
( ( m_baseStats.vit - base ) * ( ( static_cast< float >( paramGrowthInfo.piety_scalar ) ) / 100 ) ) + paramGrowthInfo.hp_mod ) * ( static_cast< float >( classInfo.mod_hp * 0.9f ) / 100 ) * 15
);
if( m_mp > m_baseStats.max_mp ) if( m_mp > m_baseStats.max_mp )
m_mp = m_baseStats.max_mp; m_mp = m_baseStats.max_mp;
@ -1536,15 +1525,11 @@ void Core::Entity::Player::handleScriptSkill( uint32_t type, uint32_t actionId,
case Core::Common::HandleSkillType::StdHeal: case Core::Common::HandleSkillType::StdHeal:
{ {
uint32_t calculatedHeal = CalcBattle::measureHeal( shared_from_this(), param1 ); uint32_t calculatedHeal = CalcBattle::calculateHealValue( getAsPlayer(), param1 );
sendDebug( "STD_HEAL" ); sendDebug( "STD_HEAL" );
<<<<<<< HEAD
GamePacketNew< FFXIVIpcEffect > effectPacket( getId() );
=======
GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket( getId() ); GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket( getId() );
>>>>>>> 0e8a5c38209f993e65acfdd0e5e0cf1920089fb5
effectPacket.data().targetId = pTarget.getId(); effectPacket.data().targetId = pTarget.getId();
effectPacket.data().actionAnimationId = actionId; effectPacket.data().actionAnimationId = actionId;
effectPacket.data().unknown_2 = 0; effectPacket.data().unknown_2 = 0;