1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-29 07:37:45 +00:00

cleanup stat calculation code, slightly better working aa dmg calc

This commit is contained in:
NotAdam 2019-04-25 21:57:41 +10:00
parent 8c468dd38c
commit 2ab91b89dc
5 changed files with 191 additions and 72 deletions

View file

@ -21,7 +21,7 @@
#include "Action/Action.h"
#include "ServerMgr.h"
#include "Session.h"
#include "Math/CalcBattle.h"
#include "Math/CalcStats.h"
#include "Chara.h"
#include "Player.h"
#include "Manager/TerritoryMgr.h"
@ -730,3 +730,131 @@ Sapphire::Common::BaseParam Sapphire::Entity::Chara::getPrimaryStat() const
return static_cast< Sapphire::Common::BaseParam >( classJob->primaryStat );
}
uint32_t Sapphire::Entity::Chara::getStatValue( Sapphire::Common::BaseParam baseParam ) const
{
uint32_t value = 0;
switch( baseParam )
{
case Common::BaseParam::Strength:
{
value = m_baseStats.str;
break;
}
case Common::BaseParam::Dexterity:
{
value = m_baseStats.dex;
break;
}
case Common::BaseParam::Vitality:
{
value = m_baseStats.vit;
break;
}
case Common::BaseParam::Intelligence:
{
value = m_baseStats.inte;
break;
}
case Common::BaseParam::Mind:
{
value = m_baseStats.mnd;
break;
}
case Common::BaseParam::Piety:
{
value = m_baseStats.pie;
break;
}
case Common::BaseParam::Determination:
{
value = m_baseStats.determination;
break;
}
case Common::BaseParam::HP:
{
value = m_baseStats.max_hp;
break;
}
case Common::BaseParam::MP:
{
value = m_baseStats.max_mp;
break;
}
case Common::BaseParam::AttackPower:
{
value = m_baseStats.attack;
break;
}
case Common::BaseParam::AttackMagicPotency:
{
value = m_baseStats.attackPotMagic;
break;
}
case Common::BaseParam::HealingMagicPotency:
{
value = m_baseStats.healingPotMagic;
break;
}
case Common::BaseParam::SkillSpeed:
{
value = m_baseStats.skillSpeed;
break;
}
case Common::BaseParam::SpellSpeed:
{
value = m_baseStats.spellSpeed;
break;
}
case Common::BaseParam::CriticalHit:
{
value = m_baseStats.critHitRate;
break;
}
case Common::BaseParam::Defense:
{
value = m_baseStats.defense;
break;
}
case Common::BaseParam::MagicDefense:
{
value = m_baseStats.magicDefense;
break;
}
case Common::BaseParam::Tenacity:
{
value = m_baseStats.tenacity;
break;
}
// todo: not sure if this is right?
case Common::BaseParam::DirectHitRate:
{
value = m_baseStats.accuracy;
break;
}
default:
break;
}
return value + getBonusStat( baseParam );
}

View file

@ -191,6 +191,8 @@ namespace Sapphire::Entity
ActorStats getStats() const;
uint32_t getStatValue( Common::BaseParam baseParam ) const;
uint32_t getHp() const;
uint32_t getHpPercent() const;

View file

@ -313,28 +313,28 @@ void Sapphire::Entity::Player::sendStats()
{
auto statPacket = makeZonePacket< FFXIVIpcPlayerStats >( getId() );
statPacket->data().strength = m_baseStats.str + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Strength ) ];
statPacket->data().dexterity = m_baseStats.dex + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Dexterity ) ];
statPacket->data().vitality = m_baseStats.vit + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Vitality ) ];
statPacket->data().intelligence = m_baseStats.inte + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Intelligence ) ];
statPacket->data().mind = m_baseStats.mnd + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Mind ) ];
statPacket->data().piety = m_baseStats.pie + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Piety ) ];
statPacket->data().determination = m_baseStats.determination + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Determination ) ];
statPacket->data().hp = m_baseStats.max_hp + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::HP ) ];
statPacket->data().mp = m_baseStats.max_mp + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::MP ) ];
statPacket->data().strength = getStatValue( Common::BaseParam::Strength );
statPacket->data().dexterity = getStatValue( Common::BaseParam::Dexterity );
statPacket->data().vitality = getStatValue( Common::BaseParam::Vitality );
statPacket->data().intelligence = getStatValue( Common::BaseParam::Intelligence );
statPacket->data().mind = getStatValue( Common::BaseParam::Mind );
statPacket->data().piety = getStatValue( Common::BaseParam::Piety );
statPacket->data().determination = getStatValue( Common::BaseParam::Determination );
statPacket->data().hp = getStatValue( Common::BaseParam::HP );
statPacket->data().mp = getStatValue( Common::BaseParam::MP );
statPacket->data().accuracy = m_baseStats.accuracy;
statPacket->data().attack = m_baseStats.attack + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::AttackPower ) ];
statPacket->data().attackMagicPotency = m_baseStats.attackPotMagic + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::AttackMagicPotency ) ];
statPacket->data().healingMagicPotency = m_baseStats.healingPotMagic + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::HealingMagicPotency ) ];
statPacket->data().skillSpeed = m_baseStats.skillSpeed + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::SkillSpeed ) ];
statPacket->data().spellSpeed = m_baseStats.spellSpeed + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::SpellSpeed ) ];
statPacket->data().spellSpeed1 = m_baseStats.spellSpeed + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::SpellSpeed ) ];
statPacket->data().attack = getStatValue( Common::BaseParam::AttackPower );
statPacket->data().attackMagicPotency = getStatValue( Common::BaseParam::AttackMagicPotency );
statPacket->data().healingMagicPotency = getStatValue( Common::BaseParam::HealingMagicPotency );
statPacket->data().skillSpeed = getStatValue( Common::BaseParam::SkillSpeed );
statPacket->data().spellSpeed = getStatValue( Common::BaseParam::SpellSpeed );
statPacket->data().spellSpeed1 = getStatValue( Common::BaseParam::SpellSpeed );
statPacket->data().spellSpeedMod = 100;
statPacket->data().criticalHitRate = m_baseStats.critHitRate + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::CriticalHit ) ];
statPacket->data().defense = m_baseStats.defense + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Defense ) ];
statPacket->data().magicDefense = m_baseStats.magicDefense + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::MagicDefense ) ];
statPacket->data().tenacity = m_baseStats.tenacity + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Tenacity ) ];
statPacket->data().criticalHitRate = getStatValue( Common::BaseParam::CriticalHit );
statPacket->data().defense = getStatValue( Common::BaseParam::Defense );
statPacket->data().magicDefense = getStatValue( Common::BaseParam::MagicDefense );
statPacket->data().tenacity = getStatValue( Common::BaseParam::Tenacity );
queuePacket( statPacket );
}

View file

@ -270,7 +270,7 @@ uint16_t CalcStats::calculateMpCost( const Sapphire::Entity::Chara& chara, uint1
float CalcStats::blockProbability( const Chara& chara )
{
auto level = chara.getLevel();
auto blockRate = static_cast< float >( chara.getBonusStat( Common::BaseParam::BlockRate ) );
auto blockRate = static_cast< float >( chara.getStatValue( Common::BaseParam::BlockRate ) );
auto levelVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
return std::floor( ( 30 * blockRate ) / levelVal + 10 );
@ -281,8 +281,7 @@ float CalcStats::directHitProbability( const Chara& chara )
const auto& baseStats = chara.getStats();
auto level = chara.getLevel();
float dhRate = static_cast< float >( chara.getBonusStat( Common::BaseParam::DirectHitRate ) ) +
baseStats.accuracy;
float dhRate = chara.getStatValue( Common::BaseParam::DirectHitRate );
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
@ -295,8 +294,7 @@ float CalcStats::criticalHitProbability( const Chara& chara )
const auto& baseStats = chara.getStats();
auto level = chara.getLevel();
float chRate = static_cast< float >( chara.getBonusStat( Common::BaseParam::CriticalHit ) ) +
baseStats.critHitRate;
float chRate = chara.getStatValue( Common::BaseParam::CriticalHit );
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
@ -348,61 +346,70 @@ float CalcStats::calcAttackPower( const Sapphire::Entity::Chara& chara, uint32_t
auto mainVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::MAIN ] );
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
// todo: not sure if its ( ap - mv ) / mv or ( ap - mv ) / dv
return std::floor( ( 125.f * ( attackPower - mainVal ) / divVal ) + 100.f ) / 100.f;
}
float CalcStats::attackPower( const Sapphire::Entity::Chara& chara )
float CalcStats::getPrimaryAttackPower( const Sapphire::Entity::Chara& chara )
{
const auto& baseStats = chara.getStats();
// todo: this is wrong
if( chara.isBattleNpc() )
return calcAttackPower( chara, baseStats.attack );
switch( chara.getPrimaryStat() )
{
case Common::BaseParam::Mind:
{
return calcAttackPower( chara, baseStats.healingPotMagic );
return healingMagicPower( chara );
}
case Common::BaseParam::Intelligence:
{
return calcAttackPower( chara, baseStats.attackPotMagic );
return magicAttackPower( chara );
}
default:
{
return calcAttackPower( chara, baseStats.attack );
return attackPower( chara );
}
}
}
float CalcStats::attackPower( const Sapphire::Entity::Chara& chara )
{
return calcAttackPower( chara, chara.getStatValue( Common::BaseParam::AttackPower ) );
}
float CalcStats::magicAttackPower( const Sapphire::Entity::Chara& chara )
{
return calcAttackPower( chara, chara.getStatValue( Common::BaseParam::AttackMagicPotency ) );
}
float CalcStats::healingMagicPower( const Sapphire::Entity::Chara& chara )
{
return calcAttackPower( chara, chara.getStatValue( Common::BaseParam::HealingMagicPotency ) );
}
float CalcStats::determination( const Sapphire::Entity::Chara& chara )
{
auto level = chara.getLevel();
const auto& baseStats = chara.getStats();
auto mainVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::MAIN ] );
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
return std::floor( 130.f * ( baseStats.determination - mainVal ) / divVal + 1000.f ) / 1000.f;
return std::floor( 130.f * ( chara.getStatValue( Common::BaseParam::Determination ) - mainVal ) / divVal + 1000.f ) / 1000.f;
}
float CalcStats::tenacity( const Sapphire::Entity::Chara& chara )
{
auto level = chara.getLevel();
const auto& baseStats = chara.getStats();
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
return std::floor( 100.f * ( baseStats.tenacity - subVal ) / divVal + 1000.f ) / 1000.f;
return std::floor( 100.f * ( chara.getStatValue( Common::BaseParam::Tenacity ) - subVal ) / divVal + 1000.f ) / 1000.f;
}
float CalcStats::speed( const Sapphire::Entity::Chara& chara )
{
auto level = chara.getLevel();
const auto& baseStats = chara.getStats();
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
@ -414,11 +421,11 @@ float CalcStats::speed( const Sapphire::Entity::Chara& chara )
{
case Common::BaseParam::Intelligence:
case Common::BaseParam::Mind:
speedVal = baseStats.spellSpeed;
speedVal = chara.getStatValue( Common::BaseParam::SpellSpeed );
break;
default:
speedVal = baseStats.skillSpeed;
speedVal = chara.getStatValue( Common::BaseParam::SkillSpeed );
}
return std::floor( 130.f * ( speedVal - subVal ) / divVal + 1000.f ) / 1000.f;
@ -427,32 +434,29 @@ float CalcStats::speed( const Sapphire::Entity::Chara& chara )
float CalcStats::criticalHitBonus( const Sapphire::Entity::Chara& chara )
{
auto level = chara.getLevel();
const auto& baseStats = chara.getStats();
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
return std::floor( 200.f * ( baseStats.critHitRate - subVal ) / divVal + 1400.f ) / 1000.f;
return std::floor( 200.f * ( chara.getStatValue( Common::BaseParam::CriticalHit ) - subVal ) / divVal + 1400.f ) / 1000.f;
}
float CalcStats::physicalDefence( const Sapphire::Entity::Chara& chara )
{
auto level = chara.getLevel();
const auto& baseStats = chara.getStats();
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
return std::floor( 15.f * baseStats.defense ) / 100.f;
return std::floor( 15.f * chara.getStatValue( Common::BaseParam::Defense ) ) / 100.f;
}
float CalcStats::magicDefence( const Sapphire::Entity::Chara& chara )
{
auto level = chara.getLevel();
const auto& baseStats = chara.getStats();
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
return std::floor( 15.f * baseStats.magicDefense ) / 100.f;
return std::floor( 15.f * chara.getStatValue( Common::BaseParam::MagicDefense ) ) / 100.f;
}
float CalcStats::blockStrength( const Sapphire::Entity::Chara& chara )
@ -494,9 +498,7 @@ float CalcStats::autoAttack( const Sapphire::Entity::Chara& chara )
float CalcStats::healingMagicPotency( const Sapphire::Entity::Chara& chara )
{
const auto& baseStats = chara.getStats();
return std::floor( 100.f * ( baseStats.healingPotMagic - 292.f ) / 264.f + 100.f ) / 100.f;
return std::floor( 100.f * ( chara.getStatValue( Common::BaseParam::HealingMagicPotency ) - 292.f ) / 264.f + 100.f ) / 100.f;
}
float CalcStats::calculateAutoAttackDamage( const Sapphire::Entity::Chara& chara )
@ -506,11 +508,11 @@ float CalcStats::calculateAutoAttackDamage( const Sapphire::Entity::Chara& chara
auto pot = potency( AUTO_ATTACK_POTENCY );
auto aa = autoAttack( chara );
auto ap = attackPower( chara );
auto ap = getPrimaryAttackPower( chara );
auto det = determination( chara );
auto ten = tenacity( chara );
Logger::info( "auto attack: pot: {} aa: {} ap: {} det: {} ten: {}", pot, aa, ap, det, ten );
Logger::debug( "auto attack: pot: {} aa: {} ap: {} det: {} ten: {}", pot, aa, ap, det, ten );
auto factor = std::floor( pot * aa * ap * det * ten );
@ -531,24 +533,5 @@ float CalcStats::calculateAutoAttackDamage( const Sapphire::Entity::Chara& chara
uint32_t CalcStats::primaryStatValue( const Sapphire::Entity::Chara& chara )
{
const auto& baseStats = chara.getStats();
switch( chara.getPrimaryStat() )
{
case Common::BaseParam::Strength:
default:
return baseStats.str;
case Common::BaseParam::Intelligence:
return baseStats.inte;
case Common::BaseParam::Mind:
return baseStats.mnd;
case Common::BaseParam::Vitality:
return baseStats.vit;
case Common::BaseParam::Dexterity:
return baseStats.dex;
}
return chara.getStatValue( chara.getPrimaryStat() );
}

View file

@ -63,8 +63,14 @@ namespace Sapphire::Math
*
* @param chara The source/casting character.
*/
static float getPrimaryAttackPower( const Sapphire::Entity::Chara& chara );
static float attackPower( const Sapphire::Entity::Chara& chara );
static float magicAttackPower( const Sapphire::Entity::Chara& chara );
static float healingMagicPower( const Sapphire::Entity::Chara& chara );
/*!
* @brief Calculates determinations contribution to damage and healing output.
*
@ -132,6 +138,7 @@ namespace Sapphire::Math
static float calculateAutoAttackDamage( const Sapphire::Entity::Chara& chara );
static uint32_t primaryStatValue( const Sapphire::Entity::Chara& chara );
private:
/*!
@ -141,7 +148,6 @@ namespace Sapphire::Math
*/
static float calcAttackPower( const Sapphire::Entity::Chara& chara, uint32_t attackPower );
static uint32_t primaryStatValue( const Sapphire::Entity::Chara& chara );
};