diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index 739cfd7c..d2edf3bf 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -50,7 +50,8 @@ Action::Action::Action( Entity::CharaPtr caster, uint32_t actionId, uint16_t seq m_targetId( 0 ), m_startTime( 0 ), m_interruptType( Common::ActionInterruptType::None ), - m_sequence( sequence ) + m_sequence( sequence ), + m_isAutoAttack( false ) { } @@ -288,7 +289,8 @@ void Action::Action::start() // todo: m_recastTimeMs needs to be adjusted for player sks/sps auto actionStartPkt = makeActorControlSelf( m_pSource->getId(), ActorControlType::ActionStart, 1, getId(), m_recastTimeMs / 10 ); - player->queuePacket( actionStartPkt ); + if( player ) + player->queuePacket( actionStartPkt ); auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >(); @@ -406,7 +408,10 @@ void Action::Action::execute() std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcDamage( uint32_t potency ) { - return Math::CalcStats::calcActionDamage( *m_pSource, static_cast< Common::AttackType >( m_actionData->attackType ), potency, Math::CalcStats::getWeaponDamage( m_pSource ) ); + if( m_isAutoAttack ) + return Math::CalcStats::calcAutoAttackDamage( *m_pSource, potency ); + else + return Math::CalcStats::calcActionDamage( *m_pSource, static_cast< Common::AttackType >( m_actionData->attackType ), potency, Math::CalcStats::getWeaponDamage( m_pSource ) ); } std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcHealing( uint32_t potency ) @@ -472,7 +477,7 @@ void Action::Action::buildEffects() if( reflectDmg.first > 0 ) { - m_effectBuilder->damage( actor, m_pSource, dmg.first, dmg.second, Common::ActionEffectResultFlag::Reflected ); + m_effectBuilder->damage( actor, m_pSource, reflectDmg.first, reflectDmg.second, Common::ActionEffectResultFlag::Reflected ); } if( isCorrectCombo() && shouldApplyComboSucceedEffect ) @@ -813,6 +818,11 @@ Data::ActionPtr Action::Action::getActionData() const return m_actionData; } +void Action::Action::setAutoAttack() +{ + m_isAutoAttack = true; +} + bool Action::Action::isPhysical() const { return isAttackTypePhysical( static_cast< Common::AttackType >( m_actionData->attackType ) ); diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index 5786f93b..e73890cb 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -52,6 +52,8 @@ namespace Sapphire::World::Action bool isComboAction() const; + void setAutoAttack(); + /*! * @brief Checks if a chara has enough resources available to cast the action (tp/mp/etc) * @return true if they have the required resources @@ -188,6 +190,7 @@ namespace Sapphire::World::Action bool m_canTargetFriendly; bool m_canTargetHostile; bool m_canTargetDead; + bool m_isAutoAttack; Common::ActionInterruptType m_interruptType; diff --git a/src/world/Action/ActionLutData.cpp b/src/world/Action/ActionLutData.cpp index a9ef671e..af9b9984 100644 --- a/src/world/Action/ActionLutData.cpp +++ b/src/world/Action/ActionLutData.cpp @@ -2816,6 +2816,14 @@ ActionLut::Lut ActionLut::m_actionLut = //Hagakure, 葉隠 { 7495, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, + //attack, 攻撃 + //has damage: potency 110, combo potency 0, directional potency 0 + { 7, { 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, + + //Shot, ショット + //has damage: potency 110, combo potency 0, directional potency 0 + { 8, { 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, + }; ActionLut::StatusEffectTable ActionLut::m_statusEffectTable = diff --git a/src/world/Action/EffectBuilder.cpp b/src/world/Action/EffectBuilder.cpp index 0a1335dd..d84ab85d 100644 --- a/src/world/Action/EffectBuilder.cpp +++ b/src/world/Action/EffectBuilder.cpp @@ -94,8 +94,8 @@ void EffectBuilder::applyStatusEffect( Entity::CharaPtr& target, Entity::CharaPt void EffectBuilder::buildAndSendPackets() { auto targetCount = m_resolvedEffects.size(); - Logger::debug( "EffectBuilder result: " ); - Logger::debug( "Targets afflicted: {}", targetCount ); + //Logger::debug( "EffectBuilder result: " ); + //Logger::debug( "Targets afflicted: {}", targetCount ); auto globalSequence = m_sourceChara->getCurrentTerritory()->getNextEffectSequence(); @@ -184,7 +184,7 @@ std::shared_ptr< FFXIVPacketBase > EffectBuilder::buildNextEffectPacket( uint32_ assert( !resultList->empty() ); auto firstResult = resultList->data()[ 0 ]; pEffectTargetId[ targetIndex ] = firstResult->getTarget()->getId(); - Logger::debug( " - id: {}", pEffectTargetId[ targetIndex ] ); + //Logger::debug( " - id: {}", pEffectTargetId[ targetIndex ] ); for( auto i = 0; i < resultList->size(); i++ ) { @@ -213,7 +213,7 @@ std::shared_ptr< FFXIVPacketBase > EffectBuilder::buildNextEffectPacket( uint32_ auto resultList = m_resolvedEffects.begin()->second; assert( !resultList->empty() ); auto firstResult = resultList->data()[ 0 ]; - Logger::debug( " - id: {}", firstResult->getTarget()->getId() ); + //Logger::debug( " - id: {}", firstResult->getTarget()->getId() ); auto seq = m_sourceChara->getCurrentTerritory()->getNextEffectSequence(); diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index e850179e..1d5309ec 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -680,10 +680,7 @@ void Sapphire::Entity::BNpc::setFlag( uint32_t flag ) } /*! -Autoattack prototype implementation -TODO: move the check if the autoAttack can be performed to the callee -also rename autoAttack to autoAttack as that is more elaborate -On top of that, this only solves attacks from melee classes. +TODO: this only solves attacks from melee classes. Will have to be extended for ranged attacks. \param ActorPtr the autoAttack is performed on @@ -698,18 +695,20 @@ void Sapphire::Entity::BNpc::autoAttack( CharaPtr pTarget ) pTarget->onActionHostile( getAsChara() ); m_lastAttack = tick; - auto pSource = getAsChara(); - auto damage = Math::CalcStats::calcAutoAttackDamage( *this ); - damage.first = Math::CalcStats::applyDamageReceiveMultiplier( *pTarget, damage.first, Common::AttackType::Physical ); - auto reflectDmg = Math::CalcStats::calcDamageReflect( pSource, pTarget, damage.first, Common::ActionTypeFilter::Physical ); + auto exdData = m_pFw->get< Data::ExdDataGenerated >(); + assert( exdData ); + auto actionData = exdData->get< Data::Action >( 7 ); + assert( actionData ); + auto action = World::Action::make_Action( getAsChara(), 7, 0, actionData, m_pFw ); - World::Action::EffectBuilder effectBuilder( pSource, 7, 0 ); - effectBuilder.damage( pTarget, pTarget, damage.first, damage.second ); - if( reflectDmg.first > 0 ) + action->setTargetId( pTarget->getId() ); + action->setPos( getPos() ); + action->setAutoAttack(); + + if( action->init() ) { - effectBuilder.damage( pTarget, pSource, reflectDmg.first, reflectDmg.second, Common::ActionEffectResultFlag::Reflected ); + action->start(); } - effectBuilder.buildAndSendPackets(); } } diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index b5bb3de4..1dddff29 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -1565,32 +1565,31 @@ uint32_t Sapphire::Entity::Player::getPersistentEmote() const void Sapphire::Entity::Player::autoAttack( CharaPtr pTarget ) { - - auto mainWeap = getItemAt( Common::GearSet0, Common::GearSetSlot::MainHand ); - pTarget->onActionHostile( getAsChara() ); - - auto pSource = getAsChara(); - auto damage = Math::CalcStats::calcAutoAttackDamage( *this ); - damage.first = Math::CalcStats::applyDamageReceiveMultiplier( *pTarget, damage.first, Common::AttackType::Physical ); - auto reflectDmg = Math::CalcStats::calcDamageReflect( pSource, pTarget, damage.first, Common::ActionTypeFilter::Physical ); - - World::Action::EffectBuilderPtr effectBuilder = nullptr; + auto exdData = m_pFw->get< Data::ExdDataGenerated >(); + assert( exdData ); + World::Action::ActionPtr action; if( getClass() == ClassJob::Machinist || getClass() == ClassJob::Bard || getClass() == ClassJob::Archer ) { - effectBuilder = World::Action::make_EffectBuilder( pSource, 8, 0 ); + auto actionData = exdData->get< Data::Action >( 8 ); + assert( actionData ); + action = World::Action::make_Action( getAsChara(), 8, 0, actionData, m_pFw ); } else { - effectBuilder = World::Action::make_EffectBuilder( pSource, 7, 0 ); + auto actionData = exdData->get< Data::Action >( 7 ); + assert( actionData ); + action = World::Action::make_Action( getAsChara(), 7, 0, actionData, m_pFw ); } - effectBuilder->damage( pTarget, pTarget, damage.first, damage.second ); - if( reflectDmg.first > 0 ) + action->setTargetId( pTarget->getId() ); + action->setPos( getPos() ); + action->setAutoAttack(); + + if( action->init() ) { - effectBuilder->damage( pTarget, pSource, reflectDmg.first, reflectDmg.second, Common::ActionEffectResultFlag::Reflected ); + action->start(); } - effectBuilder->buildAndSendPackets(); } diff --git a/src/world/Math/CalcStats.cpp b/src/world/Math/CalcStats.cpp index 0c862049..d54728d4 100644 --- a/src/world/Math/CalcStats.cpp +++ b/src/world/Math/CalcStats.cpp @@ -252,15 +252,8 @@ float CalcStats::potency( uint16_t potency ) return potency / 100.f; } -float CalcStats::autoAttackPotency( const Sapphire::Entity::Chara& chara ) +float CalcStats::autoAttackPotency( const Sapphire::Entity::Chara& chara, uint32_t aaPotency ) { - uint32_t aaPotency = AUTO_ATTACK_POTENCY; - - if( chara.getRole() == Common::Role::RangedPhysical ) - { - aaPotency = RANGED_AUTO_ATTACK_POTENCY; - } - float autoAttackDelay = 2.5f; // fetch actual auto attack delay if its a player if( chara.isPlayer() ) @@ -495,12 +488,12 @@ 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; } -std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ) +std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoAttackDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc ) { // 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 pot = autoAttackPotency( chara, ptc ); auto aa = autoAttack( chara ); auto ap = getPrimaryAttackPower( chara ); auto det = determination( chara ); diff --git a/src/world/Math/CalcStats.h b/src/world/Math/CalcStats.h index 69ae5d8a..428ee731 100644 --- a/src/world/Math/CalcStats.h +++ b/src/world/Math/CalcStats.h @@ -11,9 +11,6 @@ namespace Sapphire::Math class CalcStats { public: - 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 calculateMaxHp( Sapphire::Entity::PlayerPtr pPlayer, FrameworkPtr pFw ); @@ -40,7 +37,7 @@ namespace Sapphire::Math */ static float potency( uint16_t potency ); - static float autoAttackPotency( const Sapphire::Entity::Chara& chara ); + static float autoAttackPotency( const Sapphire::Entity::Chara& chara, uint32_t aaPotency ); /*! * @brief Weapon damage is the contribution the weapon's damage rating @@ -135,7 +132,7 @@ namespace Sapphire::Math static float calcHealBaseOnPotency( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); - static std::pair< float, Common::ActionHitSeverityType > calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ); + static std::pair< float, Common::ActionHitSeverityType > calcAutoAttackDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc ); static std::pair< float, Common::ActionHitSeverityType > calcActionDamage( const Sapphire::Entity::Chara& chara, Common::AttackType attackType, uint32_t ptc, float wepDmg );