2019-07-25 22:46:10 +10:00
|
|
|
#include "EffectBuilder.h"
|
|
|
|
#include "EffectResult.h"
|
|
|
|
|
2019-07-26 20:28:01 +10:00
|
|
|
#include <Actor/Player.h>
|
2019-07-25 22:46:10 +10:00
|
|
|
|
|
|
|
#include <Network/PacketWrappers/EffectPacket.h>
|
2022-01-06 20:25:50 +01:00
|
|
|
#include <Network/PacketWrappers/EffectPacket1.h>
|
2019-07-25 22:46:10 +10:00
|
|
|
|
|
|
|
#include <Territory/Territory.h>
|
|
|
|
|
|
|
|
#include <Util/Util.h>
|
|
|
|
#include <Util/UtilMath.h>
|
|
|
|
|
|
|
|
#include <Logging/Logger.h>
|
|
|
|
|
|
|
|
using namespace Sapphire;
|
|
|
|
using namespace Sapphire::World::Action;
|
|
|
|
using namespace Sapphire::Network::Packets;
|
2021-11-27 00:53:57 +01:00
|
|
|
using namespace Sapphire::Network::Packets::WorldPackets::Server;
|
2019-07-25 22:46:10 +10:00
|
|
|
|
2019-07-26 20:28:01 +10:00
|
|
|
EffectBuilder::EffectBuilder( Entity::CharaPtr source, uint32_t actionId, uint16_t sequence ) :
|
2019-07-25 22:46:10 +10:00
|
|
|
m_sourceChara( std::move( source ) ),
|
2019-07-26 20:28:01 +10:00
|
|
|
m_actionId( actionId ),
|
|
|
|
m_sequence( sequence )
|
2019-07-25 22:46:10 +10:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-07-27 13:59:35 +10:00
|
|
|
uint64_t EffectBuilder::getResultDelayMs()
|
2019-07-25 22:46:10 +10:00
|
|
|
{
|
|
|
|
// todo: actually figure this retarded shit out
|
|
|
|
|
2019-07-27 13:59:35 +10:00
|
|
|
return Common::Util::getTimeMs() + 850;
|
2019-07-25 22:46:10 +10:00
|
|
|
}
|
|
|
|
|
2020-01-06 17:52:45 +09:00
|
|
|
void EffectBuilder::moveToResultList( Entity::CharaPtr& chara, EffectResultPtr result )
|
2019-07-25 22:46:10 +10:00
|
|
|
{
|
|
|
|
auto it = m_resolvedEffects.find( chara->getId() );
|
|
|
|
if( it == m_resolvedEffects.end() )
|
|
|
|
{
|
2020-01-06 17:52:45 +09:00
|
|
|
// create a new one
|
2020-01-05 17:09:27 +09:00
|
|
|
auto resultList = std::make_shared< std::vector< EffectResultPtr > >();
|
2019-07-25 22:46:10 +10:00
|
|
|
|
2020-01-05 17:09:27 +09:00
|
|
|
m_resolvedEffects[ chara->getId() ] = resultList;
|
2019-07-25 22:46:10 +10:00
|
|
|
|
2020-01-06 17:52:45 +09:00
|
|
|
resultList->push_back( std::move( result ) );
|
|
|
|
|
|
|
|
return;
|
2019-07-25 22:46:10 +10:00
|
|
|
}
|
|
|
|
|
2020-01-06 17:52:45 +09:00
|
|
|
it->second->push_back( std::move( result ) );
|
2019-07-25 22:46:10 +10:00
|
|
|
}
|
|
|
|
|
2020-01-05 20:49:50 +09:00
|
|
|
void EffectBuilder::heal( Entity::CharaPtr& effectTarget, Entity::CharaPtr& healingTarget, uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionEffectResultFlag flag )
|
2019-07-25 22:46:10 +10:00
|
|
|
{
|
2020-01-05 20:49:50 +09:00
|
|
|
EffectResultPtr nextResult = make_EffectResult( healingTarget, getResultDelayMs() );
|
|
|
|
nextResult->heal( amount, severity, flag );
|
2020-01-06 17:52:45 +09:00
|
|
|
moveToResultList( effectTarget, nextResult );
|
2020-01-05 17:09:27 +09:00
|
|
|
}
|
|
|
|
|
2020-01-05 20:49:50 +09:00
|
|
|
void EffectBuilder::restoreMP( Entity::CharaPtr& target, Entity::CharaPtr& restoringTarget, uint32_t amount, Common::ActionEffectResultFlag flag )
|
2020-01-05 17:09:27 +09:00
|
|
|
{
|
2020-01-05 20:49:50 +09:00
|
|
|
EffectResultPtr nextResult = make_EffectResult( restoringTarget, getResultDelayMs() ); // restore mp source actor
|
|
|
|
nextResult->restoreMP( amount, flag );
|
2020-01-06 17:52:45 +09:00
|
|
|
moveToResultList( target, nextResult );
|
2020-01-05 17:09:27 +09:00
|
|
|
}
|
|
|
|
|
2020-01-05 20:49:50 +09:00
|
|
|
void EffectBuilder::damage( Entity::CharaPtr& effectTarget, Entity::CharaPtr& damagingTarget, uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionEffectResultFlag flag )
|
2020-01-05 17:09:27 +09:00
|
|
|
{
|
2020-01-05 20:49:50 +09:00
|
|
|
EffectResultPtr nextResult = make_EffectResult( damagingTarget, getResultDelayMs() );
|
|
|
|
nextResult->damage( amount, severity, flag );
|
2020-01-06 17:52:45 +09:00
|
|
|
moveToResultList( effectTarget, nextResult );
|
2020-01-05 17:09:27 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
void EffectBuilder::startCombo( Entity::CharaPtr& target, uint16_t actionId )
|
|
|
|
{
|
|
|
|
EffectResultPtr nextResult = make_EffectResult( target, 0 );
|
|
|
|
nextResult->startCombo( actionId );
|
2020-01-06 17:52:45 +09:00
|
|
|
moveToResultList( target, nextResult );
|
2020-01-05 17:09:27 +09:00
|
|
|
}
|
|
|
|
|
2020-01-05 20:49:50 +09:00
|
|
|
void EffectBuilder::comboSucceed( Entity::CharaPtr& target )
|
2020-01-05 17:09:27 +09:00
|
|
|
{
|
|
|
|
EffectResultPtr nextResult = make_EffectResult( target, 0 );
|
2020-01-05 20:49:50 +09:00
|
|
|
nextResult->comboSucceed();
|
2020-01-06 17:52:45 +09:00
|
|
|
moveToResultList( target, nextResult );
|
2019-07-25 22:46:10 +10:00
|
|
|
}
|
|
|
|
|
2020-01-06 19:25:01 +09:00
|
|
|
void EffectBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint8_t param )
|
|
|
|
{
|
|
|
|
EffectResultPtr nextResult = make_EffectResult( target, 0 );
|
|
|
|
nextResult->applyStatusEffect( statusId, param );
|
|
|
|
moveToResultList( target, nextResult );
|
|
|
|
}
|
|
|
|
|
2020-01-23 22:36:01 +09:00
|
|
|
void EffectBuilder::mount( Entity::CharaPtr& target, uint16_t mountId )
|
|
|
|
{
|
|
|
|
EffectResultPtr nextResult = make_EffectResult( target, getResultDelayMs() );
|
|
|
|
nextResult->mount( mountId );
|
|
|
|
moveToResultList( target, nextResult );
|
|
|
|
}
|
|
|
|
|
2019-07-25 22:46:10 +10:00
|
|
|
void EffectBuilder::buildAndSendPackets()
|
|
|
|
{
|
2020-01-05 17:09:27 +09:00
|
|
|
auto targetCount = m_resolvedEffects.size();
|
2019-07-25 23:21:42 +10:00
|
|
|
Logger::debug( "EffectBuilder result: " );
|
2020-01-05 17:09:27 +09:00
|
|
|
Logger::debug( "Targets afflicted: {}", targetCount );
|
|
|
|
|
|
|
|
auto globalSequence = m_sourceChara->getCurrentTerritory()->getNextEffectSequence();
|
|
|
|
|
2020-01-06 04:29:45 +09:00
|
|
|
do // we want to send at least one packet even nothing is hit so other players can see
|
2020-01-05 17:09:27 +09:00
|
|
|
{
|
|
|
|
auto packet = buildNextEffectPacket( globalSequence );
|
|
|
|
m_sourceChara->sendToInRangeSet( packet, true );
|
|
|
|
}
|
2020-01-06 04:29:45 +09:00
|
|
|
while( !m_resolvedEffects.empty() );
|
2020-01-05 17:09:27 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr< FFXIVPacketBase > EffectBuilder::buildNextEffectPacket( uint32_t globalSequence )
|
|
|
|
{
|
|
|
|
auto remainingTargetCount = m_resolvedEffects.size();
|
2019-07-25 22:46:10 +10:00
|
|
|
|
2020-01-05 17:09:27 +09:00
|
|
|
if( remainingTargetCount > 1 ) // use AoeEffect packets
|
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto effectResult = makeZonePacket< FFXIVIpcActionResult >( m_sourceChara->getId() );
|
|
|
|
Common::CalcResultParam* pEntry;
|
2020-01-05 17:09:27 +09:00
|
|
|
uint64_t* pEffectTargetId;
|
2021-11-27 00:53:57 +01:00
|
|
|
|
|
|
|
effectResult->data().ActionKey = m_actionId;
|
2022-01-02 22:32:17 +01:00
|
|
|
effectResult->data().ActionKind = 1;
|
2021-11-27 00:53:57 +01:00
|
|
|
effectResult->data().Action = static_cast< uint16_t >( m_actionId );
|
|
|
|
effectResult->data().MainTarget = m_sourceChara->getId();
|
|
|
|
effectResult->data().DirTarget = Common::Util::floatToUInt16Rot( m_sourceChara->getRot() );
|
|
|
|
effectResult->data().Flag = Common::ActionEffectDisplayType::ShowActionName;
|
|
|
|
effectResult->data().TargetCount = static_cast< uint8_t >( remainingTargetCount );
|
|
|
|
effectResult->data().RequestId = m_sequence;
|
|
|
|
effectResult->data().ResultId = globalSequence;
|
2020-01-05 17:09:27 +09:00
|
|
|
|
|
|
|
uint8_t targetIndex = 0;
|
|
|
|
for( auto it = m_resolvedEffects.begin(); it != m_resolvedEffects.end(); )
|
|
|
|
{
|
|
|
|
auto resultList = it->second;
|
2020-01-05 20:54:49 +09:00
|
|
|
assert( !resultList->empty() );
|
2020-01-05 17:09:27 +09:00
|
|
|
auto firstResult = resultList->data()[ 0 ];
|
|
|
|
pEffectTargetId[ targetIndex ] = firstResult->getTarget()->getId();
|
|
|
|
Logger::debug( " - id: {}", pEffectTargetId[ targetIndex ] );
|
|
|
|
|
|
|
|
for( auto i = 0; i < resultList->size(); i++ )
|
|
|
|
{
|
|
|
|
auto result = resultList->data()[ i ];
|
|
|
|
pEntry[ targetIndex * 8 + i ] = result->buildEffectEntry();
|
|
|
|
m_sourceChara->getCurrentTerritory()->addEffectResult( std::move( result ) );
|
|
|
|
}
|
|
|
|
resultList->clear();
|
|
|
|
|
|
|
|
it = m_resolvedEffects.erase( it );
|
|
|
|
|
|
|
|
targetIndex++;
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
if( targetIndex == 15 )
|
2020-01-05 17:09:27 +09:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
return effectResult;
|
2020-01-05 17:09:27 +09:00
|
|
|
}
|
2020-01-06 04:29:45 +09:00
|
|
|
else if ( remainingTargetCount == 1 ) // use Effect for single target
|
2019-07-25 22:46:10 +10:00
|
|
|
{
|
2020-01-05 17:09:27 +09:00
|
|
|
auto resultList = m_resolvedEffects.begin()->second;
|
2020-01-05 20:49:50 +09:00
|
|
|
assert( !resultList->empty() );
|
2020-01-05 17:09:27 +09:00
|
|
|
auto firstResult = resultList->data()[ 0 ];
|
|
|
|
Logger::debug( " - id: {}", firstResult->getTarget()->getId() );
|
2019-07-25 23:21:42 +10:00
|
|
|
|
2019-07-26 21:58:13 +10:00
|
|
|
auto seq = m_sourceChara->getCurrentTerritory()->getNextEffectSequence();
|
|
|
|
|
2022-01-06 20:25:50 +01:00
|
|
|
auto effectPacket = std::make_shared< EffectPacket1 >( m_sourceChara->getId(), firstResult->getTarget()->getId(), m_actionId );
|
2019-07-25 22:46:10 +10:00
|
|
|
effectPacket->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) );
|
2019-07-26 21:58:13 +10:00
|
|
|
effectPacket->setSequence( seq, m_sequence );
|
2019-07-25 22:46:10 +10:00
|
|
|
|
2020-01-05 17:09:27 +09:00
|
|
|
for( int i = 0; i < resultList->size(); i++ )
|
|
|
|
{
|
|
|
|
auto result = resultList->data()[ i ];
|
2021-11-27 00:53:57 +01:00
|
|
|
effectPacket->addEffect( result->buildEffectEntry(), static_cast< uint64_t >( firstResult->getTarget()->getId() ) );
|
2020-01-05 17:09:27 +09:00
|
|
|
m_sourceChara->getCurrentTerritory()->addEffectResult( std::move( result ) );
|
|
|
|
}
|
2019-07-25 22:46:10 +10:00
|
|
|
|
2020-01-05 17:09:27 +09:00
|
|
|
resultList->clear();
|
2019-07-25 22:46:10 +10:00
|
|
|
|
2020-01-05 17:09:27 +09:00
|
|
|
m_resolvedEffects.clear();
|
2019-07-27 13:59:35 +10:00
|
|
|
|
2020-01-06 04:29:45 +09:00
|
|
|
return effectPacket;
|
|
|
|
}
|
|
|
|
else // nothing is hit, this only happens when using aoe and AoeEffect8 is used on retail
|
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto effectPacket = makeZonePacket< FFXIVIpcActionResult1 >( m_sourceChara->getId() );
|
|
|
|
|
|
|
|
effectPacket->data().ActionKey = m_actionId;
|
|
|
|
effectPacket->data().Action = static_cast< uint16_t >( m_actionId );
|
|
|
|
effectPacket->data().Target = m_sourceChara->getId();
|
|
|
|
effectPacket->data().MainTarget = static_cast< uint64_t >( m_sourceChara->getId() );
|
|
|
|
effectPacket->data().DirTarget = Common::Util::floatToUInt16Rot( m_sourceChara->getRot() );
|
|
|
|
effectPacket->data().Flag = Common::ActionEffectDisplayType::HideActionName;
|
|
|
|
effectPacket->data().RequestId = m_sequence;
|
|
|
|
effectPacket->data().ResultId = globalSequence;
|
2020-01-06 04:29:45 +09:00
|
|
|
|
2020-01-05 17:09:27 +09:00
|
|
|
return effectPacket;
|
2019-07-27 13:59:35 +10:00
|
|
|
}
|
2019-07-25 22:46:10 +10:00
|
|
|
}
|