From 2ab91b89dc214ee93c9d3b649f6dd7f8f432cd75 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 25 Apr 2019 21:57:41 +1000 Subject: [PATCH] cleanup stat calculation code, slightly better working aa dmg calc --- src/world/Actor/Chara.cpp | 130 ++++++++++++++++++++++++++++++++++- src/world/Actor/Chara.h | 2 + src/world/Actor/Player.cpp | 38 +++++----- src/world/Math/CalcStats.cpp | 85 +++++++++-------------- src/world/Math/CalcStats.h | 8 ++- 5 files changed, 191 insertions(+), 72 deletions(-) diff --git a/src/world/Actor/Chara.cpp b/src/world/Actor/Chara.cpp index 968698b0..779c3afd 100644 --- a/src/world/Actor/Chara.cpp +++ b/src/world/Actor/Chara.cpp @@ -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" @@ -729,4 +729,132 @@ Sapphire::Common::BaseParam Sapphire::Entity::Chara::getPrimaryStat() const assert( classJob ); 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 ); } \ No newline at end of file diff --git a/src/world/Actor/Chara.h b/src/world/Actor/Chara.h index 4e2d8e9b..5679b2cb 100644 --- a/src/world/Actor/Chara.h +++ b/src/world/Actor/Chara.h @@ -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; diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index 1547a860..32852714 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -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 ); } diff --git a/src/world/Math/CalcStats.cpp b/src/world/Math/CalcStats.cpp index 1134ffa0..1542e2fd 100644 --- a/src/world/Math/CalcStats.cpp +++ b/src/world/Math/CalcStats.cpp @@ -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() ); } \ No newline at end of file diff --git a/src/world/Math/CalcStats.h b/src/world/Math/CalcStats.h index 70859de6..5f2b4060 100644 --- a/src/world/Math/CalcStats.h +++ b/src/world/Math/CalcStats.h @@ -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 ); };