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

autoattack damage stat calc funcs, bnpc stat calculation

This commit is contained in:
NotAdam 2019-04-24 23:25:07 +10:00
parent b6a9e41cbd
commit ec3e93eed9
11 changed files with 253 additions and 95 deletions

View file

@ -1114,6 +1114,7 @@ Sapphire::Data::ClassJob::ClassJob( uint32_t row_id, Sapphire::Data::ExdDataGene
classJobParent = exdData->getField< uint8_t >( row, 26 ); classJobParent = exdData->getField< uint8_t >( row, 26 );
nameEnglish = exdData->getField< std::string >( row, 27 ); nameEnglish = exdData->getField< std::string >( row, 27 );
itemStartingWeapon = exdData->getField< int32_t >( row, 28 ); itemStartingWeapon = exdData->getField< int32_t >( row, 28 );
primaryStat = exdData->getField< uint8_t >( row, 33 );
limitBreak1 = exdData->getField< uint16_t >( row, 34 ); limitBreak1 = exdData->getField< uint16_t >( row, 34 );
limitBreak2 = exdData->getField< uint16_t >( row, 35 ); limitBreak2 = exdData->getField< uint16_t >( row, 35 );
limitBreak3 = exdData->getField< uint16_t >( row, 36 ); limitBreak3 = exdData->getField< uint16_t >( row, 36 );

View file

@ -1485,6 +1485,7 @@ struct ClassJob
uint8_t classJobParent; uint8_t classJobParent;
std::string nameEnglish; std::string nameEnglish;
int32_t itemStartingWeapon; int32_t itemStartingWeapon;
uint8_t primaryStat;
uint16_t limitBreak1; uint16_t limitBreak1;
uint16_t limitBreak2; uint16_t limitBreak2;
uint16_t limitBreak3; uint16_t limitBreak3;

View file

@ -22,18 +22,22 @@
#include "Network/PacketWrappers/MoveActorPacket.h" #include "Network/PacketWrappers/MoveActorPacket.h"
#include "Navi/NaviProvider.h" #include "Navi/NaviProvider.h"
#include "Math/CalcBattle.h"
#include "Math/CalcStats.h"
#include "StatusEffect/StatusEffect.h" #include "StatusEffect/StatusEffect.h"
#include "ServerMgr.h" #include "ServerMgr.h"
#include "Session.h" #include "Session.h"
#include "Math/CalcBattle.h"
#include "Chara.h" #include "Chara.h"
#include "Player.h" #include "Player.h"
#include "BNpc.h" #include "BNpc.h"
#include "BNpcTemplate.h" #include "BNpcTemplate.h"
#include "Manager/TerritoryMgr.h"
#include "Common.h" #include "Common.h"
#include "Framework.h" #include "Framework.h"
#include <Logging/Logger.h>
#include <Manager/TerritoryMgr.h>
#include <Manager/NaviMgr.h> #include <Manager/NaviMgr.h>
#include <Manager/TerritoryMgr.h> #include <Manager/TerritoryMgr.h>
#include <Manager/RNGMgr.h> #include <Manager/RNGMgr.h>
@ -72,7 +76,9 @@ Sapphire::Entity::BNpc::BNpc( uint32_t id, BNpcTemplatePtr pTemplate, float posX
m_levelId = 0; m_levelId = 0;
m_flags = 0; m_flags = 0;
m_pCurrentZone = pZone; m_class = ClassJob::Adventurer;
m_pCurrentZone = std::move( pZone );
m_spawnPos = m_pos; m_spawnPos = m_pos;
@ -112,6 +118,8 @@ Sapphire::Entity::BNpc::BNpc( uint32_t id, BNpcTemplatePtr pTemplate, float posX
// todo: is this actually good? // todo: is this actually good?
//m_naviTargetReachedDistance = m_scale * 2.f; //m_naviTargetReachedDistance = m_scale * 2.f;
m_naviTargetReachedDistance = 4.f; m_naviTargetReachedDistance = 4.f;
calculateStats();
} }
Sapphire::Entity::BNpc::~BNpc() = default; Sapphire::Entity::BNpc::~BNpc() = default;
@ -262,7 +270,7 @@ void Sapphire::Entity::BNpc::sendPositionUpdate()
void Sapphire::Entity::BNpc::hateListClear() void Sapphire::Entity::BNpc::hateListClear()
{ {
auto it = m_hateList.begin(); auto it = m_hateList.begin();
for( auto listEntry : m_hateList ) for( auto& listEntry : m_hateList )
{ {
if( isInRangeSet( listEntry->m_pChara ) ) if( isInRangeSet( listEntry->m_pChara ) )
deaggro( listEntry->m_pChara ); deaggro( listEntry->m_pChara );
@ -681,7 +689,7 @@ void Sapphire::Entity::BNpc::autoAttack( CharaPtr pTarget )
srand( static_cast< uint32_t >( tick ) ); srand( static_cast< uint32_t >( tick ) );
auto pRNGMgr = m_pFw->get< World::Manager::RNGMgr >(); auto pRNGMgr = m_pFw->get< World::Manager::RNGMgr >();
auto damage = static_cast< uint16_t >( pRNGMgr->getRandGenerator< float >( m_level, m_level + m_level * 1.5f ).next() ); auto damage = Math::CalcStats::calculateAutoAttackDamage( *this );
auto effectPacket = std::make_shared< Server::EffectPacket >( getId(), pTarget->getId(), 7 ); auto effectPacket = std::make_shared< Server::EffectPacket >( getId(), pTarget->getId(), 7 );
effectPacket->setRotation( Util::floatToUInt16Rot( getRot() ) ); effectPacket->setRotation( Util::floatToUInt16Rot( getRot() ) );
@ -696,4 +704,38 @@ void Sapphire::Entity::BNpc::autoAttack( CharaPtr pTarget )
pTarget->takeDamage( damage ); pTarget->takeDamage( damage );
} }
}
void Sapphire::Entity::BNpc::calculateStats()
{
uint8_t level = getLevel();
uint8_t job = static_cast< uint8_t >( getClass() );
auto pExdData = m_pFw->get< Data::ExdDataGenerated >();
auto classInfo = pExdData->get< Sapphire::Data::ClassJob >( job );
auto paramGrowthInfo = pExdData->get< Sapphire::Data::ParamGrow >( level );
float base = Math::CalcStats::calculateBaseStat( *this );
m_baseStats.str = static_cast< uint32_t >( base * ( static_cast< float >( classInfo->modifierStrength ) / 100 ) );
m_baseStats.dex = static_cast< uint32_t >( base * ( static_cast< float >( classInfo->modifierDexterity ) / 100 ) );
m_baseStats.vit = static_cast< uint32_t >( base * ( static_cast< float >( classInfo->modifierVitality ) / 100 ) );
m_baseStats.inte = static_cast< uint32_t >( base * ( static_cast< float >( classInfo->modifierIntelligence ) / 100 ) );
m_baseStats.mnd = static_cast< uint32_t >( base * ( static_cast< float >( classInfo->modifierMind ) / 100 ) );
m_baseStats.pie = static_cast< uint32_t >( base * ( static_cast< float >( classInfo->modifierPiety ) / 100 ) );
m_baseStats.determination = static_cast< uint32_t >( base );
m_baseStats.pie = static_cast< uint32_t >( base );
m_baseStats.skillSpeed = paramGrowthInfo->baseSpeed;
m_baseStats.spellSpeed = paramGrowthInfo->baseSpeed;
m_baseStats.accuracy = paramGrowthInfo->baseSpeed;
m_baseStats.critHitRate = paramGrowthInfo->baseSpeed;
m_baseStats.attackPotMagic = paramGrowthInfo->baseSpeed;
m_baseStats.healingPotMagic = paramGrowthInfo->baseSpeed;
m_baseStats.tenacity = paramGrowthInfo->baseSpeed;
m_baseStats.attack = m_baseStats.str;
m_baseStats.attackPotMagic = m_baseStats.inte;
m_baseStats.healingPotMagic = m_baseStats.mnd;
} }

View file

@ -118,6 +118,8 @@ namespace Sapphire::Entity
bool hasFlag( uint32_t flag ) const; bool hasFlag( uint32_t flag ) const;
void setFlag( uint32_t flags ); void setFlag( uint32_t flags );
void calculateStats() override;
private: private:
uint32_t m_bNpcBaseId; uint32_t m_bNpcBaseId;
uint32_t m_bNpcNameId; uint32_t m_bNpcNameId;

View file

@ -718,4 +718,15 @@ void Sapphire::Entity::Chara::setAgentId( uint32_t agentId )
float Sapphire::Entity::Chara::getRadius() const float Sapphire::Entity::Chara::getRadius() const
{ {
return m_radius; return m_radius;
}
Sapphire::Common::BaseParam Sapphire::Entity::Chara::getPrimaryStat() const
{
auto exdData = m_pFw->get< Data::ExdDataGenerated >();
assert( exdData );
auto classJob = exdData->get< Data::ClassJob >( static_cast< uint16_t >( getClass() ) );
assert( classJob );
return static_cast< Sapphire::Common::BaseParam >( classJob->primaryStat );
} }

View file

@ -280,6 +280,8 @@ namespace Sapphire::Entity
float getRadius() const; float getRadius() const;
Common::BaseParam getPrimaryStat() const;
}; };
} }

View file

@ -256,7 +256,7 @@ void Sapphire::Entity::Player::calculateStats()
auto tribeInfo = pExdData->get< Sapphire::Data::Tribe >( tribe ); auto tribeInfo = pExdData->get< Sapphire::Data::Tribe >( tribe );
auto paramGrowthInfo = pExdData->get< Sapphire::Data::ParamGrow >( level ); auto paramGrowthInfo = pExdData->get< Sapphire::Data::ParamGrow >( level );
float base = Math::CalcStats::calculateBaseStat( getAsPlayer() ); float base = Math::CalcStats::calculateBaseStat( *this );
m_baseStats.str = static_cast< uint32_t >( base * ( static_cast< float >( classInfo->modifierStrength ) / 100 ) + m_baseStats.str = static_cast< uint32_t >( base * ( static_cast< float >( classInfo->modifierStrength ) / 100 ) +
tribeInfo->sTR ); tribeInfo->sTR );
@ -1559,8 +1559,7 @@ void Sapphire::Entity::Player::autoAttack( CharaPtr pTarget )
auto pRNGMgr = m_pFw->get< World::Manager::RNGMgr >(); auto pRNGMgr = m_pFw->get< World::Manager::RNGMgr >();
auto variation = static_cast< uint32_t >( pRNGMgr->getRandGenerator< float >( 0, 3 ).next() ); auto variation = static_cast< uint32_t >( pRNGMgr->getRandGenerator< float >( 0, 3 ).next() );
auto damage = static_cast< uint32_t >( pRNGMgr->getRandGenerator< float >( static_cast< uint32_t > ( getLevel() * 1.5f ), auto damage = Math::CalcStats::calculateAutoAttackDamage( *this );
getLevel() + static_cast< uint32_t >( mainWeap->getAutoAttackDmg() * 2 ) ).next() );
if( getClass() == ClassJob::Machinist || getClass() == ClassJob::Bard || getClass() == ClassJob::Archer ) if( getClass() == ClassJob::Machinist || getClass() == ClassJob::Bard || getClass() == ClassJob::Archer )
{ {
@ -2116,3 +2115,13 @@ Sapphire::World::SessionPtr Sapphire::Entity::Player::getSession()
return m_pSession; return m_pSession;
} }
void Sapphire::Entity::Player::setActiveLand( uint8_t land, uint8_t ward )
{
m_activeLand.plot = land;
m_activeLand.ward = ward;
}
Sapphire::Common::ActiveLand Sapphire::Entity::Player::getActiveLand() const
{
return m_activeLand;
}

View file

@ -933,6 +933,8 @@ namespace Sapphire::Entity
/*! calculate and return player ilvl based off equipped gear */ /*! calculate and return player ilvl based off equipped gear */
uint16_t calculateEquippedGearItemLevel(); uint16_t calculateEquippedGearItemLevel();
ItemPtr getEquippedWeapon();
/*! return the current amount of currency of type */ /*! return the current amount of currency of type */
uint32_t getCurrency( Common::CurrencyType type ); uint32_t getCurrency( Common::CurrencyType type );
@ -964,6 +966,8 @@ namespace Sapphire::Entity
Sapphire::ItemPtr dropInventoryItem( Common::InventoryType type, uint16_t slotId ); Sapphire::ItemPtr dropInventoryItem( Common::InventoryType type, uint16_t slotId );
//////////////////////////////////////////////////////////////////////////////////////////////////////
Common::HuntingLogEntry& getHuntingLogEntry( uint8_t index ); Common::HuntingLogEntry& getHuntingLogEntry( uint8_t index );
void sendHuntingLog(); void sendHuntingLog();
@ -974,8 +978,6 @@ namespace Sapphire::Entity
World::SessionPtr getSession(); World::SessionPtr getSession();
//////////////////////////////////////////////////////////////////////////////////////////////////////
uint64_t m_lastMoveTime; uint64_t m_lastMoveTime;
uint8_t m_lastMoveflag; uint8_t m_lastMoveflag;
bool m_falling; bool m_falling;

View file

@ -831,17 +831,6 @@ void Sapphire::Entity::Player::discardItem( uint16_t fromInventoryId, uint8_t fr
queuePacket( invTransFinPacket ); queuePacket( invTransFinPacket );
} }
void Sapphire::Entity::Player::setActiveLand( uint8_t land, uint8_t ward )
{
m_activeLand.plot = land;
m_activeLand.ward = ward;
}
Sapphire::Common::ActiveLand Sapphire::Entity::Player::getActiveLand() const
{
return m_activeLand;
}
uint16_t Sapphire::Entity::Player::calculateEquippedGearItemLevel() uint16_t Sapphire::Entity::Player::calculateEquippedGearItemLevel()
{ {
uint32_t iLvlResult = 0; uint32_t iLvlResult = 0;
@ -871,6 +860,10 @@ uint16_t Sapphire::Entity::Player::calculateEquippedGearItemLevel()
return static_cast< uint16_t >( std::min( static_cast< int32_t >( iLvlResult / 13 ), 9999 ) ); return static_cast< uint16_t >( std::min( static_cast< int32_t >( iLvlResult / 13 ), 9999 ) );
} }
Sapphire::ItemPtr Sapphire::Entity::Player::getEquippedWeapon()
{
return m_storageMap[ GearSet0 ]->getItem( GearSetSlot::MainHand );
}
uint8_t Sapphire::Entity::Player::getFreeSlotsInBags() uint8_t Sapphire::Entity::Player::getFreeSlotsInBags()
{ {

View file

@ -2,11 +2,13 @@
#include <Exd/ExdDataGenerated.h> #include <Exd/ExdDataGenerated.h>
#include <Common.h> #include <Common.h>
#include <Logging/Logger.h>
#include "Actor/Chara.h" #include "Actor/Chara.h"
#include "Actor/Player.h" #include "Actor/Player.h"
#include "Inventory/Item.h"
#include "CalcStats.h" #include "CalcStats.h"
#include "Framework.h" #include "Framework.h"
@ -108,10 +110,10 @@ const int levelTable[71][7] =
// 3 Versions. SB and HW are linear, ARR is polynomial. // 3 Versions. SB and HW are linear, ARR is polynomial.
// Originally from Player.cpp, calculateStats(). // Originally from Player.cpp, calculateStats().
float CalcStats::calculateBaseStat( PlayerPtr pPlayer ) float CalcStats::calculateBaseStat( const Chara& chara )
{ {
float base = 0.0f; float base = 0.0f;
uint8_t level = pPlayer->getLevel(); uint8_t level = chara.getLevel();
if( level > 70 ) if( level > 70 )
level = 70; level = 70;
@ -138,7 +140,7 @@ uint32_t CalcStats::calculateMaxHp( PlayerPtr pPlayer, Sapphire::FrameworkPtr pF
uint8_t level = pPlayer->getLevel(); uint8_t level = pPlayer->getLevel();
auto vitMod = pPlayer->getBonusStat( Common::BaseParam::Vitality ); auto vitMod = pPlayer->getBonusStat( Common::BaseParam::Vitality );
float baseStat = calculateBaseStat( pPlayer ); float baseStat = calculateBaseStat( *pPlayer );
uint16_t vitStat = pPlayer->getStats().vit + static_cast< uint16_t >( vitMod ); uint16_t vitStat = pPlayer->getStats().vit + static_cast< uint16_t >( vitMod );
uint16_t hpMod = paramGrowthInfo->hpModifier; uint16_t hpMod = paramGrowthInfo->hpModifier;
uint16_t jobModHp = classInfo->modifierHitPoints; uint16_t jobModHp = classInfo->modifierHitPoints;
@ -173,7 +175,7 @@ uint32_t CalcStats::calculateMaxMp( PlayerPtr pPlayer, Sapphire::FrameworkPtr pF
auto pieMod = pPlayer->getBonusStat( Common::BaseParam::Piety ); auto pieMod = pPlayer->getBonusStat( Common::BaseParam::Piety );
float baseStat = calculateBaseStat( pPlayer ); float baseStat = calculateBaseStat( *pPlayer );
uint16_t piety = pPlayer->getStats().pie + pieMod; uint16_t piety = pPlayer->getStats().pie + pieMod;
uint16_t pietyScalar = paramGrowthInfo->mpModifier; uint16_t pietyScalar = paramGrowthInfo->mpModifier;
uint16_t jobModMp = classInfo->modifierManaPoints; uint16_t jobModMp = classInfo->modifierManaPoints;
@ -308,49 +310,67 @@ float CalcStats::potency( uint16_t potency )
return potency / 100.f; return potency / 100.f;
} }
//float CalcStats::weaponDamage( const Sapphire::Entity::Chara& chara, float weaponDamage, bool isMagicDamage ) float CalcStats::weaponDamage( const Sapphire::Entity::Chara& chara, float weaponDamage )
//{ {
// const auto& baseStats = chara.getStats(); const auto& baseStats = chara.getStats();
// auto level = chara.getLevel(); auto level = chara.getLevel();
//
// auto mainVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::MAIN ] );
//
// float jobAttribute = 1.f;
//
// // todo: fix this
// return 1.f
//}
// todo: this is all retarded, needs to be per weapon and etcetc auto mainVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::MAIN ] );
//uint32_t CalcStats::getPrimaryClassJobAttribute( const Sapphire::Entity::Chara& chara )
//{ uint32_t jobAttribute = 1;
//
//} switch( chara.getPrimaryStat() )
{
case Common::BaseParam::Intelligence:
{
jobAttribute = baseStats.healingPotMagic;
break;
}
case Common::BaseParam::Mind:
{
jobAttribute = baseStats.attackPotMagic;
break;
}
default:
{
jobAttribute = baseStats.attack;
break;
}
}
return std::floor( ( ( mainVal * jobAttribute ) / 1000.f ) + weaponDamage );
}
float CalcStats::calcAttackPower( uint32_t attackPower ) float CalcStats::calcAttackPower( uint32_t attackPower )
{ {
return std::floor( ( 125.f * ( attackPower - 292.f ) / 292.f ) + 100.f ) / 100.f; return std::floor( ( 125.f * ( attackPower - 292.f ) / 292.f ) + 100.f ) / 100.f;
} }
float CalcStats::magicAttackPower( const Sapphire::Entity::Chara& chara )
{
const auto& baseStats = chara.getStats();
return calcAttackPower( baseStats.attackPotMagic );
}
float CalcStats::healingMagicPower( const Sapphire::Entity::Chara& chara )
{
const auto& baseStats = chara.getStats();
return calcAttackPower( baseStats.healingPotMagic );
}
float CalcStats::attackPower( const Sapphire::Entity::Chara& chara ) float CalcStats::attackPower( const Sapphire::Entity::Chara& chara )
{ {
const auto& baseStats = chara.getStats(); const auto& baseStats = chara.getStats();
return calcAttackPower( baseStats.attack ); // todo: this is wrong
if( chara.isBattleNpc() )
return calcAttackPower( baseStats.attack );
switch( chara.getPrimaryStat() )
{
case Common::BaseParam::Mind:
{
return calcAttackPower( baseStats.healingPotMagic );
}
case Common::BaseParam::Intelligence:
{
return calcAttackPower( baseStats.attackPotMagic );
}
default:
{
return calcAttackPower( baseStats.attack );
}
}
} }
float CalcStats::determination( const Sapphire::Entity::Chara& chara ) float CalcStats::determination( const Sapphire::Entity::Chara& chara )
@ -386,18 +406,10 @@ float CalcStats::speed( const Sapphire::Entity::Chara& chara )
uint32_t speedVal = 0; uint32_t speedVal = 0;
// check whether we use spellspeed or skillspeed // check whether we use spellspeed or skillspeed
// todo: this is kinda shitty though switch( chara.getPrimaryStat() )
switch( chara.getClass() )
{ {
case Common::ClassJob::Arcanist: case Common::BaseParam::Intelligence:
case Common::ClassJob::Astrologian: case Common::BaseParam::Mind:
case Common::ClassJob::Whitemage:
case Common::ClassJob::Redmage:
case Common::ClassJob::Bluemage:
case Common::ClassJob::Blackmage:
case Common::ClassJob::Summoner:
case Common::ClassJob::Scholar:
case Common::ClassJob::Thaumaturge:
speedVal = baseStats.spellSpeed; speedVal = baseStats.spellSpeed;
break; break;
@ -439,14 +451,105 @@ float CalcStats::magicDefence( const Sapphire::Entity::Chara& chara )
return std::floor( 15.f * baseStats.magicDefense ) / 100.f; return std::floor( 15.f * baseStats.magicDefense ) / 100.f;
} }
//float CalcStats::blockStrength( const Sapphire::Entity::Chara& chara ) float CalcStats::blockStrength( const Sapphire::Entity::Chara& chara )
//{ {
// auto level = chara.getLevel();
//} auto blockStrength = static_cast< float >( chara.getBonusStat( Common::BaseParam::BlockStrength ) );
auto levelVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
return std::floor( ( 30 * blockStrength ) / levelVal + 10 ) / 100.f;
}
float CalcStats::autoAttack( const Sapphire::Entity::Chara& chara )
{
// todo: default values for NPCs, not sure what we should have here
float autoAttackDelay = 2.f;
float weaponDamage = 10.f;
// fetch actual auto attack delay if its a player
if( chara.isPlayer() )
{
// todo: ew
auto pPlayer = const_cast< Entity::Chara& >( chara ).getAsPlayer();
assert( pPlayer );
auto pItem = pPlayer->getEquippedWeapon();
assert( pItem );
autoAttackDelay = pItem->getDelay() / 1000.f;
weaponDamage = pItem->getWeaponDmg();
}
auto level = chara.getLevel();
auto mainVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::MAIN ] );
auto innerCalc = std::floor( ( ( mainVal * primaryStatValue( chara ) ) / 1000.f ) + weaponDamage );
return std::floor( innerCalc * ( autoAttackDelay / 3.f ) );
}
float CalcStats::healingMagicPotency( const Sapphire::Entity::Chara& chara ) float CalcStats::healingMagicPotency( const Sapphire::Entity::Chara& chara )
{ {
const auto& baseStats = chara.getStats(); 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 * ( baseStats.healingPotMagic - 292.f ) / 264.f + 100.f ) / 100.f;
}
////////
float CalcStats::calculateAutoAttackDamage( const Sapphire::Entity::Chara& chara )
{
// D = ⌊ f(ptc) × f(aa) × f(ap) × f(det) × f(tnc) × traits ⌋ × f(ss) ⌋ ×
// f(chr) ⌋ × f(dhr) ⌋ × rand[ 0.95, 1.05 ] ⌋ × buff_1 ⌋ × buff... ⌋
auto pot = potency( AUTO_ATTACK_POTENCY );
auto aa = autoAttack( chara );
//auto ap = attackPower( chara );
auto ap = 1.f;
auto det = determination( chara );
auto ten = tenacity( chara );
Logger::info( "auto attack: pot: {} aa: {} ap: {} det: {} ten: {}", pot, aa, ap, det, ten );
auto factor = std::floor( pot * aa * ap * det * ten );
// todo: traits
factor = std::floor( factor * speed( chara ) );
// todo: surely this aint right?
//factor = std::floor( factor * criticalHitProbability( chara ) );
//factor = std::floor( factor * directHitProbability( chara ) );
// todo: random 0.95 - 1.05 factor
// todo: buffs
return factor;
}
uint32_t CalcStats::primaryStatValue( const Sapphire::Entity::Chara& chara )
{
const auto& baseStats = chara.getStats();
switch( chara.getPrimaryStat() )
{
default:
return 1;
case Common::BaseParam::Intelligence:
return baseStats.inte;
case Common::BaseParam::Mind:
return baseStats.mnd;
case Common::BaseParam::Strength:
return baseStats.str;
case Common::BaseParam::Vitality:
return baseStats.vit;
case Common::BaseParam::Dexterity:
return baseStats.dex;
}
} }

View file

@ -10,7 +10,9 @@ namespace Sapphire::Math
class CalcStats class CalcStats
{ {
public: public:
static float calculateBaseStat( Sapphire::Entity::PlayerPtr pPlayer ); static const uint32_t AUTO_ATTACK_POTENCY = 100;
static float calculateBaseStat( const Entity::Chara& chara );
static uint32_t calculateMaxMp( Sapphire::Entity::PlayerPtr pPlayer, FrameworkPtr pFw ); static uint32_t calculateMaxMp( Sapphire::Entity::PlayerPtr pPlayer, FrameworkPtr pFw );
@ -52,33 +54,17 @@ namespace Sapphire::Math
* *
* @param chara The source/casting character. * @param chara The source/casting character.
* @param weaponDamage the weapons physical or magic damage * @param weaponDamage the weapons physical or magic damage
* @param isMagicDamage true if the damage is magical, otherwise it's treated as physical damage
*/ */
static float weaponDamage( const Sapphire::Entity::Chara& chara, float weaponDamage, bool isMagicDamage ); static float weaponDamage( const Sapphire::Entity::Chara& chara, float weaponDamage );
/*! /*!
* @brief Calculates the contribution of physical attack power to damage dealt * @brief Calculates the contribution of attack power to damage dealt with consideration for the primary stat
* @todo Only works at level 70 * @todo Only works at level 70
* *
* @param chara The source/casting character. * @param chara The source/casting character.
*/ */
static float attackPower( const Sapphire::Entity::Chara& chara ); static float attackPower( const Sapphire::Entity::Chara& chara );
/*!
* @brief Calculates the contribution of magical attack power to damage dealt
* @todo Only works at level 70
*
* @param chara The source/casting character.
*/
static float magicAttackPower( const Sapphire::Entity::Chara& chara );
/*!
* @brief Calculates the contribution of healing magic power to healing dealt
*
* @param chara The source/casting character.
*/
static float healingMagicPower( const Sapphire::Entity::Chara& chara );
/*! /*!
* @brief Calculates determinations contribution to damage and healing output. * @brief Calculates determinations contribution to damage and healing output.
* *
@ -131,6 +117,8 @@ namespace Sapphire::Math
*/ */
static float blockStrength( const Sapphire::Entity::Chara& chara ); static float blockStrength( const Sapphire::Entity::Chara& chara );
static float autoAttack( const Sapphire::Entity::Chara& chara );
/*! /*!
* @brief Calculates the multiplier that healing magic potency affects healing output * @brief Calculates the multiplier that healing magic potency affects healing output
* *
@ -140,9 +128,11 @@ namespace Sapphire::Math
*/ */
static float healingMagicPotency( const Sapphire::Entity::Chara& chara ); static float healingMagicPotency( const Sapphire::Entity::Chara& chara );
private: ////////////////////////////////////////////
static uint32_t getPrimaryClassJobAttribute( const Sapphire::Entity::Chara& chara ); static float calculateAutoAttackDamage( const Sapphire::Entity::Chara& chara );
private:
/*! /*!
* @brief Has the main attack power calculation allowing for de-duplication of functions. * @brief Has the main attack power calculation allowing for de-duplication of functions.
@ -151,6 +141,8 @@ namespace Sapphire::Math
*/ */
static float calcAttackPower( uint32_t attackPower ); static float calcAttackPower( uint32_t attackPower );
static uint32_t primaryStatValue( const Sapphire::Entity::Chara& chara );
}; };
} }