diff --git a/src/world/Actor/Chara.cpp b/src/world/Actor/Chara.cpp index 06216194..fac42d99 100644 --- a/src/world/Actor/Chara.cpp +++ b/src/world/Actor/Chara.cpp @@ -15,6 +15,7 @@ #include "Network/PacketWrappers/ActorControlTargetPacket.h" #include "Network/PacketWrappers/UpdateHpMpTpPacket.h" #include "Network/PacketWrappers/EffectPacket1.h" +#include "Network/PacketWrappers/HudParamPacket.h" #include "StatusEffect/StatusEffect.h" #include "Action/Action.h" @@ -601,11 +602,11 @@ void Sapphire::Entity::Chara::removeSingleStatusEffectById( uint32_t id ) } } -void Sapphire::Entity::Chara::removeStatusEffect( uint8_t effectSlotId ) +std::map< uint8_t, Sapphire::StatusEffect::StatusEffectPtr >::iterator Sapphire::Entity::Chara::removeStatusEffect( uint8_t effectSlotId ) { auto pEffectIt = m_statusEffectMap.find( effectSlotId ); if( pEffectIt == m_statusEffectMap.end() ) - return; + return pEffectIt; statusEffectFreeSlot( effectSlotId ); @@ -614,9 +615,14 @@ void Sapphire::Entity::Chara::removeStatusEffect( uint8_t effectSlotId ) server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeActorControl( getId(), StatusEffectLose, pEffect->getId() ) ); - m_statusEffectMap.erase( effectSlotId ); + auto it = m_statusEffectMap.erase( pEffectIt ); - sendStatusEffectUpdate(); + if( isPlayer() ) + server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeHudParam( *getAsPlayer() ) ); + else if( isBattleNpc() ) + server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeHudParam( *getAsBNpc() ) ); + + return it; } std::map< uint8_t, Sapphire::StatusEffect::StatusEffectPtr > Sapphire::Entity::Chara::getStatusEffectMap() const @@ -668,10 +674,10 @@ void Sapphire::Entity::Chara::updateStatusEffects() { uint64_t currentTimeMs = Util::getTimeMs(); - for( const auto& effectIt : m_statusEffectMap ) + for( auto effectIt = m_statusEffectMap.begin(); effectIt != m_statusEffectMap.end(); ) { - uint8_t effectIndex = effectIt.first; - auto effect = effectIt.second; + uint8_t effectIndex = effectIt->first; + auto effect = effectIt->second; uint64_t lastTick = effect->getLastTickMs(); uint64_t startTime = effect->getStartTimeMs(); @@ -679,12 +685,9 @@ void Sapphire::Entity::Chara::updateStatusEffects() uint32_t tickRate = effect->getTickRate(); if( duration > 0 && ( currentTimeMs - startTime ) > duration ) - { - // remove status effect - removeStatusEffect( effectIndex ); - // break because removing invalidates iterators - break; - } + effectIt = removeStatusEffect( effectIndex ); + else + ++effectIt; if( ( currentTimeMs - lastTick ) > tickRate ) { diff --git a/src/world/Actor/Chara.h b/src/world/Actor/Chara.h index 064197fd..35e4235f 100644 --- a/src/world/Actor/Chara.h +++ b/src/world/Actor/Chara.h @@ -106,7 +106,7 @@ namespace Sapphire::Entity /// Status effect functions void addStatusEffect( StatusEffect::StatusEffectPtr pEffect ); - void removeStatusEffect( uint8_t effectSlotId ); + std::map< uint8_t, StatusEffect::StatusEffectPtr >::iterator removeStatusEffect( uint8_t effectSlotId ); void removeSingleStatusEffectById( uint32_t id ); diff --git a/src/world/Network/PacketWrappers/HudParamPacket.h b/src/world/Network/PacketWrappers/HudParamPacket.h index 98e7d523..664023dd 100644 --- a/src/world/Network/PacketWrappers/HudParamPacket.h +++ b/src/world/Network/PacketWrappers/HudParamPacket.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "Forwards.h" namespace Sapphire::Network::Packets::WorldPackets::Server @@ -19,6 +21,11 @@ namespace Sapphire::Network::Packets::WorldPackets::Server initialize( player ); }; + HudParamPacket( Entity::BNpc& bnpc ) : ZoneChannelPacket< FFXIVIpcHudParam >( bnpc.getId(), bnpc.getId() ) + { + initialize( bnpc ); + }; + private: void initialize( Entity::Player& player ) { @@ -32,19 +39,58 @@ namespace Sapphire::Network::Packets::WorldPackets::Server m_data.HpMax = player.getMaxHp(); m_data.MpMax = player.getMaxMp(); + for( int i = 0; i < 30; ++i ) + m_data.effect[ i ] = { 0, 0, 0.0f, 0 }; + auto statusMap = player.getStatusEffectMap(); int i = 0; for( const auto& [ key, val ] : statusMap ) { + auto timeLeft = static_cast< int32_t >( val->getDuration() - ( Common::Util::getTimeMs() - val->getStartTimeMs() ) ); m_data.effect[ i ].Id = val->getId(); m_data.effect[ i ].Source = val->getSrcActorId(); m_data.effect[ i ].SystemParam = val->getParam(); - m_data.effect[ i ].Time = ( val->getDuration() - ( Common::Util::getTimeMs() - val->getStartTimeMs() ) ) / 1000.f; + if( timeLeft <= 0 ) + m_data.effect[ i ].Time = 0.f; + else + m_data.effect[ i ].Time = timeLeft / 1000.f; i++; } - }; + } + void initialize( Entity::BNpc& bnpc ) + { + m_data.ClassJob = static_cast< uint8_t >( bnpc.getClass() ); + m_data.Lv = bnpc.getLevel(); + m_data.OrgLv = bnpc.getLevel(); + m_data.LvSync = 0; + m_data.Hp = bnpc.getHp(); + m_data.Mp = bnpc.getMp(); + m_data.Tp = bnpc.getTp(); + m_data.HpMax = bnpc.getMaxHp(); + m_data.MpMax = bnpc.getMaxMp(); + + for( int i = 0; i < 30; ++i ) + m_data.effect[ i ] = { 0, 0, 0.0f, 0 }; + + auto statusMap = bnpc.getStatusEffectMap(); + + int i = 0; + for( const auto& [ key, val ] : statusMap ) + { + auto timeLeft = static_cast< int32_t >( val->getDuration() - ( Common::Util::getTimeMs() - val->getStartTimeMs() ) ); + m_data.effect[ i ].Id = val->getId(); + m_data.effect[ i ].Source = val->getSrcActorId(); + m_data.effect[ i ].SystemParam = val->getParam(); + if( timeLeft <= 0 ) + m_data.effect[ i ].Time = 0.f; + else + m_data.effect[ i ].Time = timeLeft / 1000.f; + + i++; + } + } }; template< typename... Args > std::shared_ptr< HudParamPacket > makeHudParam( Args... args )