diff --git a/src/common/Common.h b/src/common/Common.h index a41095ca..14e279c8 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -990,6 +990,18 @@ namespace Sapphire::Common CircularAoEPlaced = 7 }; + enum class Role : uint8_t + { + None, + Tank, + Healer, + RangedPhysical, + RangedMagical, + Melee, + Crafter, + Gatherer + }; + using PlayerStateFlagList = std::vector< PlayerStateFlag >; } diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index 61d4c991..6d1b2662 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -2,6 +2,8 @@ #include "ActionLut.h" #include "EffectBuilder.h" +#include + #include #include #include "Framework.h" @@ -357,6 +359,32 @@ void Action::Action::execute() } } +std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcDamage( uint32_t potency ) +{ + // todo: what do for npcs? + auto wepDmg = 1.f; + + if( auto player = m_pSource->getAsPlayer() ) + { + auto item = player->getEquippedWeapon(); + assert( item ); + + auto role = player->getRole(); + if( role == Common::Role::RangedMagical || role == Common::Role::Healer ) + { + wepDmg = item->getMagicalDmg(); + } + else + { + wepDmg = item->getPhysicalDmg(); + } + } + + auto dmg = Math::CalcStats::calcActionDamage( *m_pSource, potency, wepDmg ); + + return std::make_pair( dmg, Common::ActionHitSeverityType::NormalDamage ); +} + void Action::Action::buildEffects() { snapshotAffectedActors( m_hitActors ); @@ -390,10 +418,16 @@ void Action::Action::buildEffects() { // todo: this is shit if( lutEntry.curePotency > 0 ) + { + m_effectBuilder->healTarget( actor, lutEntry.curePotency ); + } else if( lutEntry.potency > 0 ) - m_effectBuilder->damageTarget( actor, lutEntry.potency ); + { + auto dmg = calcDamage( lutEntry.potency ); + m_effectBuilder->damageTarget( actor, dmg.first, dmg.second ); + } } m_effectBuilder->buildAndSendPackets(); diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index d4308882..8288b90e 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -98,6 +98,10 @@ namespace Sapphire::World::Action */ void addDefaultActorFilters(); + std::pair< uint32_t, Common::ActionHitSeverityType > calcDamage( uint32_t potency ); + + std::pair< uint32_t, Common::ActionHitSeverityType > calcHealing( uint32_t potency ); + std::vector< Entity::CharaPtr >& getHitCharas(); diff --git a/src/world/Action/EffectResult.cpp b/src/world/Action/EffectResult.cpp index fd7cc0e1..710c046d 100644 --- a/src/world/Action/EffectResult.cpp +++ b/src/world/Action/EffectResult.cpp @@ -25,6 +25,11 @@ uint32_t EffectResult::getValue() const return m_value; } +void EffectResult::setParam( uint8_t param ) +{ + m_param = param; +} + void EffectResult::damage( uint32_t amount, Common::ActionHitSeverityType severity ) { m_severity = severity; @@ -49,7 +54,7 @@ Common::EffectEntry EffectResult::buildEffectEntry() const entry.value = getValue(); entry.hitSeverity = m_severity; entry.effectType = m_type; - + entry.param = m_param; return entry; } \ No newline at end of file diff --git a/src/world/Action/EffectResult.h b/src/world/Action/EffectResult.h index 65026802..083ab273 100644 --- a/src/world/Action/EffectResult.h +++ b/src/world/Action/EffectResult.h @@ -22,6 +22,8 @@ namespace Sapphire::World::Action uint32_t getValue() const; + void setParam( uint8_t param ); + Common::EffectEntry buildEffectEntry() const; private: @@ -33,6 +35,7 @@ namespace Sapphire::World::Action Common::ActionEffectType m_type; uint32_t m_value; + uint8_t m_param; }; } diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index e297c2fd..b2b7f439 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -692,7 +692,7 @@ void Sapphire::Entity::BNpc::autoAttack( CharaPtr pTarget ) srand( static_cast< uint32_t >( tick ) ); auto pRNGMgr = m_pFw->get< World::Manager::RNGMgr >(); - auto damage = Math::CalcStats::calculateAutoAttackDamage( *this ); + auto damage = Math::CalcStats::calcAutoAttackDamage( *this ); auto effectPacket = std::make_shared< Server::EffectPacket >( getId(), pTarget->getId(), 7 ); effectPacket->setRotation( Util::floatToUInt16Rot( getRot() ) ); diff --git a/src/world/Actor/Chara.cpp b/src/world/Actor/Chara.cpp index 7a2b94cd..26ba4918 100644 --- a/src/world/Actor/Chara.cpp +++ b/src/world/Actor/Chara.cpp @@ -123,6 +123,67 @@ void Sapphire::Entity::Chara::setClass( Common::ClassJob classJob ) m_class = classJob; } +Sapphire::Common::Role Sapphire::Entity::Chara::getRole() const +{ + switch( getClass() ) + { + case ClassJob::Gladiator: + case ClassJob::Marauder: + case ClassJob::Paladin: + case ClassJob::Warrior: + case ClassJob::Darkknight: + case ClassJob::Gunbreaker: + return Role::Tank; + + case ClassJob::Pugilist: + case ClassJob::Lancer: + case ClassJob::Monk: + case ClassJob::Dragoon: + case ClassJob::Rogue: + case ClassJob::Ninja: + case ClassJob::Samurai: + return Role::Melee; + + case ClassJob::Archer: + case ClassJob::Bard: + case ClassJob::Machinist: + case ClassJob::Dancer: + return Role::RangedPhysical; + + case ClassJob::Conjurer: + case ClassJob::Whitemage: + case ClassJob::Scholar: + case ClassJob::Astrologian: + return Role::Healer; + + case ClassJob::Thaumaturge: + case ClassJob::Blackmage: + case ClassJob::Arcanist: + case ClassJob::Summoner: + case ClassJob::Redmage: + case ClassJob::Bluemage: + return Role::RangedMagical; + + case ClassJob::Carpenter: + case ClassJob::Blacksmith: + case ClassJob::Armorer: + case ClassJob::Goldsmith: + case ClassJob::Leatherworker: + case ClassJob::Weaver: + case ClassJob::Alchemist: + case ClassJob::Culinarian: + return Role::Crafter; + + case ClassJob::Miner: + case ClassJob::Botanist: + case ClassJob::Fisher: + return Role::Gatherer; + + default: + return Role::None; + } +} + /*! \param Id of the target to set */ void Sapphire::Entity::Chara::setTargetId( uint64_t targetId ) { diff --git a/src/world/Actor/Chara.h b/src/world/Actor/Chara.h index 83d14fb6..d9fea85b 100644 --- a/src/world/Actor/Chara.h +++ b/src/world/Actor/Chara.h @@ -209,6 +209,8 @@ namespace Sapphire::Entity void setClass( Common::ClassJob classJob ); + Common::Role getRole() const; + void setTargetId( uint64_t targetId ); uint64_t getTargetId() const; diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index 0ab82688..9243a68c 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -1565,7 +1565,7 @@ void Sapphire::Entity::Player::autoAttack( CharaPtr pTarget ) auto pRNGMgr = m_pFw->get< World::Manager::RNGMgr >(); auto variation = static_cast< uint32_t >( pRNGMgr->getRandGenerator< float >( 0, 3 ).next() ); - auto damage = Math::CalcStats::calculateAutoAttackDamage( *this ); + auto damage = Math::CalcStats::calcAutoAttackDamage( *this ); if( getClass() == ClassJob::Machinist || getClass() == ClassJob::Bard || getClass() == ClassJob::Archer ) { diff --git a/src/world/Math/CalcStats.cpp b/src/world/Math/CalcStats.cpp index a2cee7e8..d6513a14 100644 --- a/src/world/Math/CalcStats.cpp +++ b/src/world/Math/CalcStats.cpp @@ -219,16 +219,9 @@ float CalcStats::autoAttackPotency( const Sapphire::Entity::Chara& chara ) { uint32_t aaPotency = AUTO_ATTACK_POTENCY; - // check if ranged class - switch( chara.getClass() ) + if( chara.getRole() == Common::Role::RangedPhysical ) { - case Common::ClassJob::Machinist: - case Common::ClassJob::Bard: - case Common::ClassJob::Archer: - aaPotency = RANGED_AUTO_ATTACK_POTENCY; - - default: - break; + aaPotency = RANGED_AUTO_ATTACK_POTENCY; } float autoAttackDelay = 2.5f; @@ -442,7 +435,7 @@ float CalcStats::healingMagicPotency( const Sapphire::Entity::Chara& chara ) 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 ) +float CalcStats::calcAutoAttackDamage( 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... ⌋ @@ -451,12 +444,25 @@ float CalcStats::calculateAutoAttackDamage( const Sapphire::Entity::Chara& 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 ten = 1.f; + if( chara.getRole() == Common::Role::Tank ) + ten = tenacity( chara ); + // todo: everything after tenacity auto factor = std::floor( pot * aa * ap * det * ten ); + constexpr auto format = "auto attack: pot: {} aa: {} ap: {} det: {} ten: {} = {}"; + + if( auto player = const_cast< Entity::Chara& >( chara ).getAsPlayer() ) + { + player->sendDebug( format, pot, aa, ap, det, ten, factor ); + } + else + { + Logger::debug( format, pot, aa, ap, det, ten, factor ); + } + // todo: traits factor = std::floor( factor * speed( chara ) ); @@ -472,6 +478,38 @@ float CalcStats::calculateAutoAttackDamage( const Sapphire::Entity::Chara& chara return factor; } +float CalcStats::calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) +{ + // D = ⌊ f(pot) × f(wd) × f(ap) × f(det) × f(tnc) × traits ⌋ + // × f(chr) ⌋ × f(dhr) ⌋ × rand[ 0.95, 1.05 ] ⌋ buff_1 ⌋ × buff_1 ⌋ × buff... ⌋ + + auto pot = potency( ptc ); + auto wd = weaponDamage( chara, wepDmg ); + auto ap = getPrimaryAttackPower( chara ); + auto det = determination( chara ); + + auto ten = 1.f; + if( chara.getRole() == Common::Role::Tank ) + ten = tenacity( chara ); + + auto factor = std::floor( pot * wd * ap * det * ten ); + + constexpr auto format = "dmg: pot: {} wd: {} ap: {} det: {} ten: {} = {}"; + + if( auto player = const_cast< Entity::Chara& >( chara ).getAsPlayer() ) + { + player->sendDebug( format, pot, wd, ap, det, ten, factor ); + } + else + { + Logger::debug( format, pot, wd, ap, det, ten, factor ); + } + + // todo: the rest + + return factor; +} + uint32_t CalcStats::primaryStatValue( const Sapphire::Entity::Chara& chara ) { return chara.getStatValue( chara.getPrimaryStat() ); diff --git a/src/world/Math/CalcStats.h b/src/world/Math/CalcStats.h index 8b8f7d36..1b22238a 100644 --- a/src/world/Math/CalcStats.h +++ b/src/world/Math/CalcStats.h @@ -128,7 +128,9 @@ namespace Sapphire::Math //////////////////////////////////////////// - static float calculateAutoAttackDamage( const Sapphire::Entity::Chara& chara ); + static float calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ); + + static float calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); static uint32_t primaryStatValue( const Sapphire::Entity::Chara& chara ); private: