mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-25 14:07:46 +00:00
Merge branch 'stat_calc' into develop
This commit is contained in:
commit
ed3e44afcc
11 changed files with 455 additions and 134 deletions
|
@ -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 );
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 );
|
||||||
|
@ -684,7 +692,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() ) );
|
||||||
|
@ -700,4 +708,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;
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "Action/Action.h"
|
#include "Action/Action.h"
|
||||||
#include "ServerMgr.h"
|
#include "ServerMgr.h"
|
||||||
#include "Session.h"
|
#include "Session.h"
|
||||||
#include "Math/CalcBattle.h"
|
#include "Math/CalcStats.h"
|
||||||
#include "Chara.h"
|
#include "Chara.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "Manager/TerritoryMgr.h"
|
#include "Manager/TerritoryMgr.h"
|
||||||
|
@ -719,4 +719,150 @@ 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
{
|
||||||
|
auto primaryStat = getPrimaryStat();
|
||||||
|
|
||||||
|
// everything else uses str for atk power except for brd/rogue/etc who use dex
|
||||||
|
if( primaryStat == Common::BaseParam::Dexterity )
|
||||||
|
{
|
||||||
|
return getStatValue( primaryStat );
|
||||||
|
}
|
||||||
|
|
||||||
|
return getStatValue( Common::BaseParam::Strength );
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
ActorStats getStats() const;
|
||||||
|
|
||||||
|
uint32_t getStatValue( Common::BaseParam baseParam ) const;
|
||||||
|
|
||||||
uint32_t getHp() const;
|
uint32_t getHp() const;
|
||||||
|
|
||||||
uint32_t getHpPercent() const;
|
uint32_t getHpPercent() const;
|
||||||
|
@ -280,6 +282,8 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
float getRadius() const;
|
float getRadius() const;
|
||||||
|
|
||||||
|
Common::BaseParam getPrimaryStat() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 );
|
||||||
|
@ -313,28 +313,28 @@ void Sapphire::Entity::Player::sendStats()
|
||||||
{
|
{
|
||||||
|
|
||||||
auto statPacket = makeZonePacket< FFXIVIpcPlayerStats >( getId() );
|
auto statPacket = makeZonePacket< FFXIVIpcPlayerStats >( getId() );
|
||||||
statPacket->data().strength = m_baseStats.str + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Strength ) ];
|
statPacket->data().strength = getStatValue( Common::BaseParam::Strength );
|
||||||
statPacket->data().dexterity = m_baseStats.dex + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Dexterity ) ];
|
statPacket->data().dexterity = getStatValue( Common::BaseParam::Dexterity );
|
||||||
statPacket->data().vitality = m_baseStats.vit + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Vitality ) ];
|
statPacket->data().vitality = getStatValue( Common::BaseParam::Vitality );
|
||||||
statPacket->data().intelligence = m_baseStats.inte + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Intelligence ) ];
|
statPacket->data().intelligence = getStatValue( Common::BaseParam::Intelligence );
|
||||||
statPacket->data().mind = m_baseStats.mnd + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Mind ) ];
|
statPacket->data().mind = getStatValue( Common::BaseParam::Mind );
|
||||||
statPacket->data().piety = m_baseStats.pie + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Piety ) ];
|
statPacket->data().piety = getStatValue( Common::BaseParam::Piety );
|
||||||
statPacket->data().determination = m_baseStats.determination + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Determination ) ];
|
statPacket->data().determination = getStatValue( Common::BaseParam::Determination );
|
||||||
statPacket->data().hp = m_baseStats.max_hp + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::HP ) ];
|
statPacket->data().hp = getStatValue( Common::BaseParam::HP );
|
||||||
statPacket->data().mp = m_baseStats.max_mp + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::MP ) ];
|
statPacket->data().mp = getStatValue( Common::BaseParam::MP );
|
||||||
statPacket->data().accuracy = m_baseStats.accuracy;
|
statPacket->data().accuracy = m_baseStats.accuracy;
|
||||||
statPacket->data().attack = m_baseStats.attack + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::AttackPower ) ];
|
statPacket->data().attack = getStatValue( Common::BaseParam::AttackPower );
|
||||||
statPacket->data().attackMagicPotency = m_baseStats.attackPotMagic + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::AttackMagicPotency ) ];
|
statPacket->data().attackMagicPotency = getStatValue( Common::BaseParam::AttackMagicPotency );
|
||||||
statPacket->data().healingMagicPotency = m_baseStats.healingPotMagic + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::HealingMagicPotency ) ];
|
statPacket->data().healingMagicPotency = getStatValue( Common::BaseParam::HealingMagicPotency );
|
||||||
statPacket->data().skillSpeed = m_baseStats.skillSpeed + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::SkillSpeed ) ];
|
statPacket->data().skillSpeed = getStatValue( Common::BaseParam::SkillSpeed );
|
||||||
statPacket->data().spellSpeed = m_baseStats.spellSpeed + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::SpellSpeed ) ];
|
statPacket->data().spellSpeed = getStatValue( Common::BaseParam::SpellSpeed );
|
||||||
statPacket->data().spellSpeed1 = m_baseStats.spellSpeed + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::SpellSpeed ) ];
|
statPacket->data().spellSpeed1 = getStatValue( Common::BaseParam::SpellSpeed );
|
||||||
statPacket->data().spellSpeedMod = 100;
|
statPacket->data().spellSpeedMod = 100;
|
||||||
|
|
||||||
statPacket->data().criticalHitRate = m_baseStats.critHitRate + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::CriticalHit ) ];
|
statPacket->data().criticalHitRate = getStatValue( Common::BaseParam::CriticalHit );
|
||||||
statPacket->data().defense = m_baseStats.defense + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Defense ) ];
|
statPacket->data().defense = getStatValue( Common::BaseParam::Defense );
|
||||||
statPacket->data().magicDefense = m_baseStats.magicDefense + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::MagicDefense ) ];
|
statPacket->data().magicDefense = getStatValue( Common::BaseParam::MagicDefense );
|
||||||
statPacket->data().tenacity = m_baseStats.tenacity + m_bonusStats[ static_cast< uint8_t >( Common::BaseParam::Tenacity ) ];
|
statPacket->data().tenacity = getStatValue( Common::BaseParam::Tenacity );
|
||||||
|
|
||||||
queuePacket( statPacket );
|
queuePacket( statPacket );
|
||||||
}
|
}
|
||||||
|
@ -1105,9 +1105,10 @@ void Sapphire::Entity::Player::update( uint64_t tickCount )
|
||||||
{
|
{
|
||||||
if( actor->getId() == m_targetId && actor->getAsChara()->isAlive() && mainWeap )
|
if( actor->getId() == m_targetId && actor->getAsChara()->isAlive() && mainWeap )
|
||||||
{
|
{
|
||||||
|
auto chara = actor->getAsChara();
|
||||||
|
|
||||||
// default autoattack range
|
// default autoattack range
|
||||||
// TODO make this dependant on bnpc size
|
float range = 3.f + chara->getRadius();
|
||||||
uint32_t range = 7;
|
|
||||||
|
|
||||||
// default autoattack range for ranged classes
|
// default autoattack range for ranged classes
|
||||||
if( getClass() == ClassJob::Machinist ||
|
if( getClass() == ClassJob::Machinist ||
|
||||||
|
@ -1566,8 +1567,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 )
|
||||||
{
|
{
|
||||||
|
@ -2124,3 +2124,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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -854,7 +843,7 @@ uint16_t Sapphire::Entity::Player::calculateEquippedGearItemLevel()
|
||||||
{
|
{
|
||||||
auto currItem = it->second;
|
auto currItem = it->second;
|
||||||
|
|
||||||
if( currItem )
|
if( currItem && currItem->getCategory() != Common::ItemUICategory::SoulCrystal )
|
||||||
{
|
{
|
||||||
iLvlResult += currItem->getItemLevel();
|
iLvlResult += currItem->getItemLevel();
|
||||||
|
|
||||||
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -268,7 +270,7 @@ uint16_t CalcStats::calculateMpCost( const Sapphire::Entity::Chara& chara, uint1
|
||||||
float CalcStats::blockProbability( const Chara& chara )
|
float CalcStats::blockProbability( const Chara& chara )
|
||||||
{
|
{
|
||||||
auto level = chara.getLevel();
|
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 ] );
|
auto levelVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
||||||
|
|
||||||
return std::floor( ( 30 * blockRate ) / levelVal + 10 );
|
return std::floor( ( 30 * blockRate ) / levelVal + 10 );
|
||||||
|
@ -279,8 +281,7 @@ float CalcStats::directHitProbability( const Chara& chara )
|
||||||
const auto& baseStats = chara.getStats();
|
const auto& baseStats = chara.getStats();
|
||||||
auto level = chara.getLevel();
|
auto level = chara.getLevel();
|
||||||
|
|
||||||
float dhRate = static_cast< float >( chara.getBonusStat( Common::BaseParam::DirectHitRate ) ) +
|
float dhRate = chara.getStatValue( Common::BaseParam::DirectHitRate );
|
||||||
baseStats.accuracy;
|
|
||||||
|
|
||||||
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
||||||
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
||||||
|
@ -293,8 +294,7 @@ float CalcStats::criticalHitProbability( const Chara& chara )
|
||||||
const auto& baseStats = chara.getStats();
|
const auto& baseStats = chara.getStats();
|
||||||
auto level = chara.getLevel();
|
auto level = chara.getLevel();
|
||||||
|
|
||||||
float chRate = static_cast< float >( chara.getBonusStat( Common::BaseParam::CriticalHit ) ) +
|
float chRate = chara.getStatValue( Common::BaseParam::CriticalHit );
|
||||||
baseStats.critHitRate;
|
|
||||||
|
|
||||||
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
||||||
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
||||||
|
@ -308,77 +308,142 @@ 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::autoAttackPotency( const Sapphire::Entity::Chara& chara )
|
||||||
//{
|
|
||||||
// const auto& baseStats = chara.getStats();
|
|
||||||
// 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
|
|
||||||
//uint32_t CalcStats::getPrimaryClassJobAttribute( const Sapphire::Entity::Chara& chara )
|
|
||||||
//{
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
|
|
||||||
float CalcStats::calcAttackPower( uint32_t attackPower )
|
|
||||||
{
|
{
|
||||||
return std::floor( ( 125.f * ( attackPower - 292.f ) / 292.f ) + 100.f ) / 100.f;
|
uint32_t aaPotency = AUTO_ATTACK_POTENCY;
|
||||||
|
|
||||||
|
// check if ranged class
|
||||||
|
switch( chara.getClass() )
|
||||||
|
{
|
||||||
|
case Common::ClassJob::Machinist:
|
||||||
|
case Common::ClassJob::Bard:
|
||||||
|
case Common::ClassJob::Archer:
|
||||||
|
aaPotency = RANGED_AUTO_ATTACK_POTENCY;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
float autoAttackDelay = 2.5f;
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// factors in f(PTC) in order to not lose precision
|
||||||
|
return std::floor( aaPotency / 3.f * autoAttackDelay ) / 100.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float CalcStats::magicAttackPower( const Sapphire::Entity::Chara& chara )
|
float CalcStats::weaponDamage( const Sapphire::Entity::Chara& chara, float weaponDamage )
|
||||||
|
{
|
||||||
|
const auto& baseStats = chara.getStats();
|
||||||
|
auto level = chara.getLevel();
|
||||||
|
|
||||||
|
auto mainVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::MAIN ] );
|
||||||
|
|
||||||
|
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( const Sapphire::Entity::Chara& chara, uint32_t attackPower )
|
||||||
|
{
|
||||||
|
auto level = chara.getLevel();
|
||||||
|
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::getPrimaryAttackPower( const Sapphire::Entity::Chara& chara )
|
||||||
{
|
{
|
||||||
const auto& baseStats = chara.getStats();
|
const auto& baseStats = chara.getStats();
|
||||||
|
|
||||||
return calcAttackPower( baseStats.attackPotMagic );
|
switch( chara.getPrimaryStat() )
|
||||||
}
|
{
|
||||||
|
case Common::BaseParam::Mind:
|
||||||
|
{
|
||||||
|
return healingMagicPower( chara );
|
||||||
|
}
|
||||||
|
case Common::BaseParam::Intelligence:
|
||||||
|
{
|
||||||
|
return magicAttackPower( chara );
|
||||||
|
}
|
||||||
|
|
||||||
float CalcStats::healingMagicPower( const Sapphire::Entity::Chara& chara )
|
default:
|
||||||
{
|
{
|
||||||
const auto& baseStats = chara.getStats();
|
return attackPower( chara );
|
||||||
|
}
|
||||||
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();
|
return calcAttackPower( chara, chara.getStatValue( Common::BaseParam::AttackPower ) );
|
||||||
|
}
|
||||||
|
|
||||||
return calcAttackPower( baseStats.attack );
|
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 )
|
float CalcStats::determination( const Sapphire::Entity::Chara& chara )
|
||||||
{
|
{
|
||||||
auto level = chara.getLevel();
|
auto level = chara.getLevel();
|
||||||
const auto& baseStats = chara.getStats();
|
|
||||||
|
|
||||||
auto mainVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::MAIN ] );
|
auto mainVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::MAIN ] );
|
||||||
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
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 )
|
float CalcStats::tenacity( const Sapphire::Entity::Chara& chara )
|
||||||
{
|
{
|
||||||
auto level = chara.getLevel();
|
auto level = chara.getLevel();
|
||||||
const auto& baseStats = chara.getStats();
|
|
||||||
|
|
||||||
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
||||||
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
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 )
|
float CalcStats::speed( const Sapphire::Entity::Chara& chara )
|
||||||
{
|
{
|
||||||
auto level = chara.getLevel();
|
auto level = chara.getLevel();
|
||||||
const auto& baseStats = chara.getStats();
|
|
||||||
|
|
||||||
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
||||||
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
||||||
|
@ -386,23 +451,15 @@ 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:
|
speedVal = chara.getStatValue( Common::BaseParam::SpellSpeed );
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
speedVal = baseStats.skillSpeed;
|
speedVal = chara.getStatValue( Common::BaseParam::SkillSpeed );
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::floor( 130.f * ( speedVal - subVal ) / divVal + 1000.f ) / 1000.f;
|
return std::floor( 130.f * ( speedVal - subVal ) / divVal + 1000.f ) / 1000.f;
|
||||||
|
@ -411,42 +468,104 @@ float CalcStats::speed( const Sapphire::Entity::Chara& chara )
|
||||||
float CalcStats::criticalHitBonus( const Sapphire::Entity::Chara& chara )
|
float CalcStats::criticalHitBonus( const Sapphire::Entity::Chara& chara )
|
||||||
{
|
{
|
||||||
auto level = chara.getLevel();
|
auto level = chara.getLevel();
|
||||||
const auto& baseStats = chara.getStats();
|
|
||||||
|
|
||||||
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
||||||
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
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 )
|
float CalcStats::physicalDefence( const Sapphire::Entity::Chara& chara )
|
||||||
{
|
{
|
||||||
auto level = chara.getLevel();
|
auto level = chara.getLevel();
|
||||||
const auto& baseStats = chara.getStats();
|
|
||||||
|
|
||||||
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
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 )
|
float CalcStats::magicDefence( const Sapphire::Entity::Chara& chara )
|
||||||
{
|
{
|
||||||
auto level = chara.getLevel();
|
auto level = chara.getLevel();
|
||||||
const auto& baseStats = chara.getStats();
|
|
||||||
|
|
||||||
auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
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 )
|
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();
|
return std::floor( 100.f * ( chara.getStatValue( Common::BaseParam::HealingMagicPotency ) - 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 = autoAttackPotency( chara );
|
||||||
|
auto aa = autoAttack( chara );
|
||||||
|
auto ap = getPrimaryAttackPower( chara );
|
||||||
|
auto det = determination( chara );
|
||||||
|
auto ten = tenacity( chara );
|
||||||
|
|
||||||
|
Logger::debug( "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 )
|
||||||
|
{
|
||||||
|
return chara.getStatValue( chara.getPrimaryStat() );
|
||||||
}
|
}
|
|
@ -10,7 +10,10 @@ namespace Sapphire::Math
|
||||||
class CalcStats
|
class CalcStats
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static float calculateBaseStat( Sapphire::Entity::PlayerPtr pPlayer );
|
static const uint32_t AUTO_ATTACK_POTENCY = 110;
|
||||||
|
static const uint32_t RANGED_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 );
|
||||||
|
|
||||||
|
@ -47,36 +50,28 @@ namespace Sapphire::Math
|
||||||
*/
|
*/
|
||||||
static float potency( uint16_t potency );
|
static float potency( uint16_t potency );
|
||||||
|
|
||||||
|
static float autoAttackPotency( const Sapphire::Entity::Chara& chara );
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Weapon damage is the contribution the weapon's damage rating
|
* @brief Weapon damage is the contribution the weapon's damage rating
|
||||||
*
|
*
|
||||||
* @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 getPrimaryAttackPower( const Sapphire::Entity::Chara& chara );
|
||||||
|
|
||||||
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 );
|
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 );
|
static float healingMagicPower( const Sapphire::Entity::Chara& chara );
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -131,6 +126,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,16 +137,20 @@ 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 );
|
||||||
|
|
||||||
|
static uint32_t primaryStatValue( 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.
|
||||||
*
|
*
|
||||||
* @param attackPower The magic/physical attack power value.
|
* @param attackPower The magic/physical attack power value.
|
||||||
*/
|
*/
|
||||||
static float calcAttackPower( uint32_t attackPower );
|
static float calcAttackPower( const Sapphire::Entity::Chara& chara, uint32_t attackPower );
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue