From 56296d295a13da51c9757a5fb74d313d0911a6a1 Mon Sep 17 00:00:00 2001 From: collett Date: Thu, 2 Jan 2020 08:07:33 +0900 Subject: [PATCH] Attempt to fix combo actions. --- src/common/Common.h | 1 + src/world/Action/Action.cpp | 50 +++++++++--- src/world/Action/Action.h | 2 + src/world/Action/EffectBuilder.cpp | 76 ++++++++++++++----- src/world/Action/EffectBuilder.h | 11 ++- src/world/Action/EffectResult.cpp | 20 ++++- src/world/Action/EffectResult.h | 5 +- .../Network/PacketWrappers/EffectPacket.h | 3 +- 8 files changed, 132 insertions(+), 36 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index a78728e4..46ce75e4 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -629,6 +629,7 @@ namespace Sapphire::Common * @param value The actionid that starts/continues the combo. eg, 3617 will start a spinning slash and/or syphon strike combo */ StartActionCombo = 28, + ComboVisualEffect = 29, Knockback = 33, Mount = 38, VFX = 59, // links to VFX sheet diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index c1aca445..888d0b28 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -336,7 +336,7 @@ void Action::Action::execute() } } - if( isComboAction() ) + if( isCorrectCombo() ) { auto player = m_pSource->getAsPlayer(); @@ -354,7 +354,7 @@ void Action::Action::execute() // set currently casted action as the combo action if it interrupts a combo // ignore it otherwise (ogcds, etc.) - if( !m_actionData->preservesCombo ) + if( !m_actionData->preservesCombo && ( !isComboAction() || isCorrectCombo() ) ) { m_pSource->setLastComboActionId( getId() ); } @@ -418,19 +418,40 @@ void Action::Action::buildEffects() for( auto& actor : m_hitActors ) { - // todo: this is shit - if( lutEntry.curePotency > 0 ) + if( lutEntry.potency > 0 ) { - - m_effectBuilder->healTarget( actor, lutEntry.curePotency ); - } - - else if( lutEntry.potency > 0 ) - { - auto dmg = calcDamage( lutEntry.potency ); + auto dmg = calcDamage( isCorrectCombo() ? lutEntry.comboPotency : lutEntry.potency ); m_effectBuilder->damageTarget( actor, dmg.first, dmg.second ); + if ( dmg.first > 0 ) actor->onActionHostile( m_pSource ); + + if ( isCorrectCombo() ) + { + m_effectBuilder->comboVisualEffect( actor ); + } + + if ( !isComboAction() || isCorrectCombo() ) + { + if( lutEntry.curePotency > 0 ) // actions with self heal + { + /* + Calling m_effectBuilder->healTarget( m_pSource, lutEntry.curePotency ) seems to work fine, + but it will end up sending two Effect packets to the client. However on retail everything is in one single packet. + */ + m_effectBuilder->selfHeal( actor, m_pSource, lutEntry.curePotency ); + } + + if ( !m_actionData->preservesCombo ) // we need something like m_actionData->hasNextComboAction + { + m_effectBuilder->startCombo( actor, getId() ); + } + } + } + else if( lutEntry.curePotency > 0 ) + { + // todo: calcHealing() + m_effectBuilder->healTarget( actor, lutEntry.curePotency ); } } @@ -513,7 +534,7 @@ void Action::Action::setAdditionalData( uint32_t data ) m_additionalData = data; } -bool Action::Action::isComboAction() const +bool Action::Action::isCorrectCombo() const { auto lastActionId = m_pSource->getLastComboActionId(); @@ -525,6 +546,11 @@ bool Action::Action::isComboAction() const return m_actionData->actionCombo == lastActionId; } +bool Action::Action::isComboAction() const +{ + return m_actionData->actionCombo != 0; +} + bool Action::Action::primaryCostCheck( bool subtractCosts ) { switch( m_primaryCostType ) diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index 8288b90e..ce10de5c 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -45,6 +45,8 @@ namespace Sapphire::World::Action uint32_t getAdditionalData() const; void setAdditionalData( uint32_t data ); + bool isCorrectCombo() const; + bool isComboAction() const; /*! diff --git a/src/world/Action/EffectBuilder.cpp b/src/world/Action/EffectBuilder.cpp index 7068c01e..85d05247 100644 --- a/src/world/Action/EffectBuilder.cpp +++ b/src/world/Action/EffectBuilder.cpp @@ -31,18 +31,17 @@ uint64_t EffectBuilder::getResultDelayMs() return Common::Util::getTimeMs() + 850; } -EffectResultPtr EffectBuilder::getResult( Entity::CharaPtr& chara ) +std::shared_ptr< std::vector< EffectResultPtr > > EffectBuilder::getResultList( Entity::CharaPtr& chara ) { auto it = m_resolvedEffects.find( chara->getId() ); if( it == m_resolvedEffects.end() ) { // create a new one and return it - // todo: this feels kinda dirty but makes for easy work - auto result = make_EffectResult( chara, getResultDelayMs() ); + auto resultList = std::make_shared< std::vector< EffectResultPtr > >(); - m_resolvedEffects[ chara->getId() ] = result; + m_resolvedEffects[ chara->getId() ] = resultList; - return result; + return resultList; } return it->second; @@ -50,18 +49,52 @@ EffectResultPtr EffectBuilder::getResult( Entity::CharaPtr& chara ) void EffectBuilder::healTarget( Entity::CharaPtr& target, uint32_t amount, Common::ActionHitSeverityType severity ) { - auto result = getResult( target ); - assert( result ); + auto resultList = getResultList( target ); + assert( resultList ); - result->heal( amount, severity ); + EffectResultPtr nextResult = make_EffectResult( target, getResultDelayMs() ); + nextResult->heal( amount, severity, false ); + resultList->push_back( std::move( nextResult ) ); +} + +void EffectBuilder::selfHeal( Entity::CharaPtr& target, Entity::CharaPtr& source, uint32_t amount, Common::ActionHitSeverityType severity ) +{ + auto resultList = getResultList( target ); + assert( resultList ); + + EffectResultPtr nextResult = make_EffectResult( source, getResultDelayMs() ); // heal the source actor + nextResult->heal( amount, severity, true ); + resultList->push_back( std::move( nextResult ) ); } void EffectBuilder::damageTarget( Entity::CharaPtr& target, uint32_t amount, Common::ActionHitSeverityType severity ) { - auto result = getResult( target ); - assert( result ); + auto resultList = getResultList( target ); + assert( resultList ); - result->damage( amount, severity ); + EffectResultPtr nextResult = make_EffectResult( target, getResultDelayMs() ); + nextResult->damage( amount, severity ); + resultList->push_back( std::move( nextResult ) ); +} + +void EffectBuilder::startCombo( Entity::CharaPtr& target, uint16_t actionId ) +{ + auto resultList = getResultList( target ); + assert( resultList ); + + EffectResultPtr nextResult = make_EffectResult( target, 0 ); + nextResult->startCombo( actionId ); + resultList->push_back( std::move( nextResult ) ); +} + +void EffectBuilder::comboVisualEffect( Entity::CharaPtr& target ) +{ + auto resultList = getResultList( target ); + assert( resultList ); + + EffectResultPtr nextResult = make_EffectResult( target, 0 ); + nextResult->comboVisualEffect(); + resultList->push_back( std::move( nextResult ) ); } void EffectBuilder::buildAndSendPackets() @@ -71,22 +104,29 @@ void EffectBuilder::buildAndSendPackets() for( auto it = m_resolvedEffects.begin(); it != m_resolvedEffects.end(); ) { - auto result = it->second; - Logger::debug( " - id: {}", result->getTarget()->getId() ); + auto resultList = it->second; + assert( resultList->size() > 0 ); + auto firstResult = resultList->data()[ 0 ]; + Logger::debug( " - id: {}", firstResult->getTarget()->getId() ); auto seq = m_sourceChara->getCurrentTerritory()->getNextEffectSequence(); - auto effectPacket = std::make_shared< Server::EffectPacket >( m_sourceChara->getId(), result->getTarget()->getId(), m_actionId ); + auto effectPacket = std::make_shared< Server::EffectPacket >( m_sourceChara->getId(), firstResult->getTarget()->getId(), m_actionId ); effectPacket->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) ); effectPacket->setSequence( seq, m_sequence ); - effectPacket->addEffect( result->buildEffectEntry() ); + for( int i = 0; i < resultList->size(); i++ ) + { + auto result = resultList->data()[ i ]; + effectPacket->addEffect( result->buildEffectEntry() ); + // add effect to territory + m_sourceChara->getCurrentTerritory()->addEffectResult( std::move( result ) ); + } + + resultList->clear(); m_sourceChara->sendToInRangeSet( effectPacket, true ); - // add effect to territory - m_sourceChara->getCurrentTerritory()->addEffectResult( std::move( result ) ); - it = m_resolvedEffects.erase( it ); } } \ No newline at end of file diff --git a/src/world/Action/EffectBuilder.h b/src/world/Action/EffectBuilder.h index d58bebfe..2662497e 100644 --- a/src/world/Action/EffectBuilder.h +++ b/src/world/Action/EffectBuilder.h @@ -15,14 +15,21 @@ namespace Sapphire::World::Action void healTarget( Entity::CharaPtr& target, uint32_t amount, Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalHeal ); + void selfHeal( Entity::CharaPtr& target, Entity::CharaPtr& source, uint32_t amount, + Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalHeal ); + void damageTarget( Entity::CharaPtr& target, uint32_t amount, Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalDamage ); + void startCombo( Entity::CharaPtr& target, uint16_t actionId ); + + void comboVisualEffect( Entity::CharaPtr& target ); + void buildAndSendPackets(); private: - EffectResultPtr getResult( Entity::CharaPtr& chara ); + std::shared_ptr< std::vector< EffectResultPtr > > getResultList( Entity::CharaPtr& chara ); uint64_t getResultDelayMs(); @@ -31,7 +38,7 @@ namespace Sapphire::World::Action uint16_t m_sequence; Entity::CharaPtr m_sourceChara; - std::unordered_map< uint32_t, EffectResultPtr > m_resolvedEffects; + std::unordered_map< uint32_t, std::shared_ptr< std::vector< EffectResultPtr > > > m_resolvedEffects; }; } diff --git a/src/world/Action/EffectResult.cpp b/src/world/Action/EffectResult.cpp index daf32155..15301357 100644 --- a/src/world/Action/EffectResult.cpp +++ b/src/world/Action/EffectResult.cpp @@ -14,7 +14,8 @@ EffectResult::EffectResult( Entity::CharaPtr target, uint64_t runAfter ) : m_value( 0 ), m_severity( Common::ActionHitSeverityType::NormalDamage ), m_type( Common::ActionEffectType::Nothing ), - m_param( 0 ) + m_param( 0 ), + m_flag( 0 ) { } @@ -47,14 +48,28 @@ void EffectResult::damage( uint32_t amount, Common::ActionHitSeverityType severi m_type = Common::ActionEffectType::Damage; } -void EffectResult::heal( uint32_t amount, Sapphire::Common::ActionHitSeverityType severity ) +void EffectResult::heal( uint32_t amount, Sapphire::Common::ActionHitSeverityType severity, bool isSelfHeal ) { m_severity = severity; m_value = amount; + m_flag = isSelfHeal ? 0x80 : 0; // flag == 0x80 displays healing text at source actor m_type = Common::ActionEffectType::Heal; } +void EffectResult::startCombo( uint16_t actionId ) +{ + m_value = actionId; + m_flag = 0x80; + + m_type = Common::ActionEffectType::StartActionCombo; +} + +void EffectResult::comboVisualEffect() +{ + m_type = Common::ActionEffectType::ComboVisualEffect; +} + Common::EffectEntry EffectResult::buildEffectEntry() const { Common::EffectEntry entry{}; @@ -64,6 +79,7 @@ Common::EffectEntry EffectResult::buildEffectEntry() const entry.hitSeverity = m_severity; entry.effectType = m_type; entry.param = m_param; + entry.flags = m_flag; return entry; } diff --git a/src/world/Action/EffectResult.h b/src/world/Action/EffectResult.h index f1dd8b9c..55ba0bfe 100644 --- a/src/world/Action/EffectResult.h +++ b/src/world/Action/EffectResult.h @@ -16,7 +16,9 @@ namespace Sapphire::World::Action explicit EffectResult( Entity::CharaPtr target, uint64_t delayMs ); void damage( uint32_t amount, Common::ActionHitSeverityType severity ); - void heal( uint32_t amount, Common::ActionHitSeverityType severity ); + void heal( uint32_t amount, Common::ActionHitSeverityType severity, bool isSelfHeal ); + void startCombo( uint16_t actionId ); + void comboVisualEffect(); Entity::CharaPtr getTarget() const; @@ -40,6 +42,7 @@ namespace Sapphire::World::Action uint32_t m_value; uint8_t m_param; + uint8_t m_flag; }; } diff --git a/src/world/Network/PacketWrappers/EffectPacket.h b/src/world/Network/PacketWrappers/EffectPacket.h index 46c8338b..5aa44c0a 100644 --- a/src/world/Network/PacketWrappers/EffectPacket.h +++ b/src/world/Network/PacketWrappers/EffectPacket.h @@ -25,13 +25,14 @@ namespace Sapphire::Network::Packets::Server m_data.effectTargetId = targetId; m_data.effectDisplayType = Common::ActionEffectDisplayType::ShowActionName; + + std::memset(m_data.effects, 0, sizeof(Common::EffectEntry) * 8); } void addEffect( const Common::EffectEntry& effect ) { assert( m_data.effectCount <= 8 ); - std::memset( m_data.effects, 0, sizeof( Common::EffectEntry ) * 8 ); std::memcpy( &m_data.effects[ m_data.effectCount * 8 ], &effect, sizeof( Common::EffectEntry ) ); m_data.effectCount++; }