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:
parent
8c468dd38c
commit
2ab91b89dc
5 changed files with 191 additions and 72 deletions
|
@ -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 );
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
}
|
|
@ -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 );
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue