mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-31 09:06:46 +00:00
Reorganization and PR comments
This commit is contained in:
+33
-8
@@ -1,15 +1,27 @@
|
|||||||
//
|
/* EQEmu: EQEmulator
|
||||||
// Created by dannu on 4/24/2026.
|
|
||||||
//
|
Copyright (C) 2001-2026 EQEmu Development Team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "client_version.h"
|
|
||||||
#include "common/emu_opcodes.h"
|
#include "common/emu_opcodes.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
#include "common/types.h"
|
|
||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
class Mob;
|
class Mob;
|
||||||
@@ -21,14 +33,27 @@ namespace ClientPatch {
|
|||||||
class IBuff
|
class IBuff
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IBuff() = default;
|
using BuffSequenceFunc = std::function<std::unique_ptr<EQApplicationPacket>(const Client*)>;
|
||||||
|
|
||||||
|
IBuff(uint32_t maxLongBuffs, uint32_t maxShortBuffs)
|
||||||
|
: m_maxLongBuffs(maxLongBuffs)
|
||||||
|
, m_maxShortBuffs(maxShortBuffs)
|
||||||
|
{}
|
||||||
|
|
||||||
|
IBuff() = delete;
|
||||||
virtual ~IBuff() = default;
|
virtual ~IBuff() = default;
|
||||||
|
|
||||||
virtual std::unique_ptr<EQApplicationPacket> BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot,
|
virtual std::unique_ptr<EQApplicationPacket> BuffDefinition(Mob* mob, const Buffs_Struct& buff, uint32_t slot,
|
||||||
bool fade) const = 0;
|
bool fade) const = 0;
|
||||||
virtual std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
virtual std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
||||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const = 0;
|
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const = 0;
|
||||||
virtual void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const = 0;
|
virtual void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const = 0;
|
||||||
|
|
||||||
|
uint32_t ServerToPatchBuffSlot(uint32_t slot) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32_t m_maxLongBuffs;
|
||||||
|
uint32_t m_maxShortBuffs;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Buff
|
} // namespace Buff
|
||||||
|
|||||||
@@ -15,9 +15,8 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "client_version.h"
|
#pragma once
|
||||||
|
|
||||||
// Migration path: replace string_ids.h usage with ID enum values one call site at a time.
|
// Migration path: replace string_ids.h usage with ID enum values one call site at a time.
|
||||||
|
|
||||||
|
|||||||
@@ -18,13 +18,22 @@
|
|||||||
|
|
||||||
#include "client_version.h"
|
#include "client_version.h"
|
||||||
|
|
||||||
|
#include "common/emu_constants.h"
|
||||||
|
|
||||||
#include "common/patches/titanium.h"
|
#include "common/patches/titanium.h"
|
||||||
|
#include "common/patches/titanium_limits.h"
|
||||||
#include "common/patches/sof.h"
|
#include "common/patches/sof.h"
|
||||||
|
#include "common/patches/sof_limits.h"
|
||||||
#include "common/patches/sod.h"
|
#include "common/patches/sod.h"
|
||||||
|
#include "common/patches/sod_limits.h"
|
||||||
#include "common/patches/uf.h"
|
#include "common/patches/uf.h"
|
||||||
|
#include "common/patches/uf_limits.h"
|
||||||
#include "common/patches/rof.h"
|
#include "common/patches/rof.h"
|
||||||
|
#include "common/patches/rof_limits.h"
|
||||||
#include "common/patches/rof2.h"
|
#include "common/patches/rof2.h"
|
||||||
|
#include "common/patches/rof2_limits.h"
|
||||||
#include "common/patches/tob.h"
|
#include "common/patches/tob.h"
|
||||||
|
#include "common/patches/tob_limits.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
@@ -36,31 +45,31 @@ struct ClientComponents
|
|||||||
{
|
{
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case Version::TOB:
|
case Version::TOB:
|
||||||
buffComponent = std::make_unique<TOB::BuffComponent>();
|
buffComponent = std::make_unique<TOB::BuffComponent>(TOB::spells::LONG_BUFFS, TOB::spells::SHORT_BUFFS);
|
||||||
messageComponent = std::make_unique<TOB::MessageComponent>();
|
messageComponent = std::make_unique<TOB::MessageComponent>();
|
||||||
break;
|
break;
|
||||||
case Version::RoF2:
|
case Version::RoF2:
|
||||||
buffComponent = std::make_unique<UF::BuffComponent>();
|
buffComponent = std::make_unique<UF::BuffComponent>(RoF2::spells::LONG_BUFFS, RoF2::spells::SHORT_BUFFS);
|
||||||
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
||||||
break;
|
break;
|
||||||
case Version::RoF:
|
case Version::RoF:
|
||||||
buffComponent = std::make_unique<UF::BuffComponent>();
|
buffComponent = std::make_unique<UF::BuffComponent>(RoF::spells::LONG_BUFFS, RoF::spells::SHORT_BUFFS);
|
||||||
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
||||||
break;
|
break;
|
||||||
case Version::UF:
|
case Version::UF:
|
||||||
buffComponent = std::make_unique<UF::BuffComponent>();
|
buffComponent = std::make_unique<UF::BuffComponent>(UF::spells::LONG_BUFFS, UF::spells::SHORT_BUFFS);
|
||||||
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
||||||
break;
|
break;
|
||||||
case Version::SoD:
|
case Version::SoD:
|
||||||
buffComponent = std::make_unique<SoD::BuffComponent>();
|
buffComponent = std::make_unique<SoD::BuffComponent>(SoD::spells::LONG_BUFFS, SoD::spells::SHORT_BUFFS);
|
||||||
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
||||||
break;
|
break;
|
||||||
case Version::SoF:
|
case Version::SoF:
|
||||||
buffComponent = std::make_unique<Titanium::BuffComponent>();
|
buffComponent = std::make_unique<Titanium::BuffComponent>(SoF::spells::LONG_BUFFS, SoF::spells::SHORT_BUFFS);
|
||||||
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
||||||
break;
|
break;
|
||||||
case Version::Titanium:
|
case Version::Titanium:
|
||||||
buffComponent = std::make_unique<Titanium::BuffComponent>();
|
buffComponent = std::make_unique<Titanium::BuffComponent>(Titanium::spells::LONG_BUFFS, Titanium::spells::SHORT_BUFFS);
|
||||||
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
messageComponent = std::make_unique<Titanium::MessageComponent>();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -69,7 +78,7 @@ struct ClientComponents
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Version version;
|
const Version version;
|
||||||
std::unique_ptr<ClientPatch::IBuff> buffComponent;
|
std::unique_ptr<ClientPatch::IBuff> buffComponent;
|
||||||
std::unique_ptr<ClientPatch::IMessage> messageComponent;
|
std::unique_ptr<ClientPatch::IMessage> messageComponent;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,3 +108,16 @@ const std::unique_ptr<ClientPatch::IMessage>& GetComponent(Version version)
|
|||||||
{
|
{
|
||||||
return s_patches.at(static_cast<uint32_t>(version)).messageComponent;
|
return s_patches.at(static_cast<uint32_t>(version)).messageComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t ClientPatch::IBuff::ServerToPatchBuffSlot(uint32_t slot) const
|
||||||
|
{
|
||||||
|
// we're a disc
|
||||||
|
if (slot >= EQ::spells::LONG_BUFFS + EQ::spells::SHORT_BUFFS)
|
||||||
|
return slot - EQ::spells::LONG_BUFFS - EQ::spells::SHORT_BUFFS +
|
||||||
|
m_maxLongBuffs + m_maxShortBuffs;
|
||||||
|
// we're a song
|
||||||
|
if (slot >= EQ::spells::LONG_BUFFS)
|
||||||
|
return slot - EQ::spells::LONG_BUFFS + m_maxLongBuffs;
|
||||||
|
// we're a normal buff
|
||||||
|
return slot; // as long as we guard against bad slots server side, we should be fine
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,26 @@
|
|||||||
//
|
/* EQEmu: EQEmulator
|
||||||
// Created by dannu on 4/21/2026.
|
|
||||||
//
|
Copyright (C) 2001-2026 EQEmu Development Team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/emu_versions.h"
|
#include "common/emu_versions.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "zone/client.h"
|
|
||||||
|
|
||||||
namespace ClientPatch {
|
namespace ClientPatch {
|
||||||
class IBuff;
|
class IBuff;
|
||||||
class IMessage;
|
class IMessage;
|
||||||
@@ -24,9 +36,3 @@ const std::unique_ptr<ClientPatch::IBuff>& GetComponent(EQ::versions::ClientVers
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
const std::unique_ptr<ClientPatch::IMessage>& GetComponent(EQ::versions::ClientVersion version);
|
const std::unique_ptr<ClientPatch::IMessage>& GetComponent(EQ::versions::ClientVersion version);
|
||||||
|
|
||||||
template <typename Component>
|
|
||||||
static Component* GetClientComponent(const Client* client)
|
|
||||||
{
|
|
||||||
return GetComponent<Component>(client->GetClientVersion()).get();
|
|
||||||
}
|
|
||||||
|
|||||||
+2
-99
@@ -67,7 +67,6 @@ namespace RoF
|
|||||||
static inline spells::CastingSlot ServerToRoFCastingSlot(EQ::spells::CastingSlot slot);
|
static inline spells::CastingSlot ServerToRoFCastingSlot(EQ::spells::CastingSlot slot);
|
||||||
static inline EQ::spells::CastingSlot RoFToServerCastingSlot(spells::CastingSlot slot);
|
static inline EQ::spells::CastingSlot RoFToServerCastingSlot(spells::CastingSlot slot);
|
||||||
|
|
||||||
static inline int ServerToRoFBuffSlot(int index);
|
|
||||||
static inline int RoFToServerBuffSlot(int index);
|
static inline int RoFToServerBuffSlot(int index);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
@@ -410,8 +409,7 @@ namespace RoF
|
|||||||
OUT(entityid);
|
OUT(entityid);
|
||||||
OUT(buff.effect_type);
|
OUT(buff.effect_type);
|
||||||
OUT(buff.level);
|
OUT(buff.level);
|
||||||
// just so we're 100% sure we get a 1.0f ...
|
OUT(buff.bard_modifier);
|
||||||
eq->buff.bard_modifier = emu->buff.bard_modifier == 10 ? 1.0f : emu->buff.bard_modifier / 10.0f;
|
|
||||||
OUT(buff.spellid);
|
OUT(buff.spellid);
|
||||||
OUT(buff.duration);
|
OUT(buff.duration);
|
||||||
OUT(buff.player_id);
|
OUT(buff.player_id);
|
||||||
@@ -420,59 +418,13 @@ namespace RoF
|
|||||||
OUT(buff.x);
|
OUT(buff.x);
|
||||||
OUT(buff.z);
|
OUT(buff.z);
|
||||||
// TODO: implement slot_data stuff
|
// TODO: implement slot_data stuff
|
||||||
eq->slotid = ServerToRoFBuffSlot(emu->slotid);
|
OUT(slotid);
|
||||||
|
|
||||||
if (emu->bufffade == 1)
|
if (emu->bufffade == 1)
|
||||||
eq->bufffade = 1;
|
eq->bufffade = 1;
|
||||||
else
|
else
|
||||||
eq->bufffade = 2;
|
eq->bufffade = 2;
|
||||||
|
|
||||||
// Bit of a hack. OP_BuffDefinition appears to add/remove the buff while OP_RefreshBuffs adds/removes the actual buff icon
|
|
||||||
EQApplicationPacket *outapp = nullptr;
|
|
||||||
if (eq->bufffade == 1)
|
|
||||||
{
|
|
||||||
outapp = new EQApplicationPacket(OP_RefreshBuffs, 29);
|
|
||||||
outapp->WriteUInt32(emu->entityid);
|
|
||||||
outapp->WriteUInt32(0); // tic timer
|
|
||||||
outapp->WriteUInt8(0); // Type of OP_RefreshBuffs packet ?
|
|
||||||
outapp->WriteUInt16(1); // 1 buff in this packet
|
|
||||||
outapp->WriteUInt32(eq->slotid);
|
|
||||||
outapp->WriteUInt32(0xffffffff); // SpellID (0xffff to remove)
|
|
||||||
outapp->WriteUInt32(0); // Duration
|
|
||||||
outapp->WriteUInt32(0); // numhits
|
|
||||||
outapp->WriteUInt8(0); // Caster name
|
|
||||||
outapp->WriteUInt8(0); // Type
|
|
||||||
}
|
|
||||||
FINISH_ENCODE();
|
|
||||||
|
|
||||||
if (outapp)
|
|
||||||
dest->FastQueuePacket(&outapp); // Send the OP_RefreshBuffs to remove the buff
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE(OP_RefreshBuffs)
|
|
||||||
{
|
|
||||||
SETUP_VAR_ENCODE(BuffIcon_Struct);
|
|
||||||
|
|
||||||
uint32 sz = 12 + (17 * emu->count) + emu->name_lengths; // 17 includes nullterm
|
|
||||||
__packet->size = sz;
|
|
||||||
__packet->pBuffer = new unsigned char[sz];
|
|
||||||
memset(__packet->pBuffer, 0, sz);
|
|
||||||
|
|
||||||
__packet->WriteUInt32(emu->entity_id);
|
|
||||||
__packet->WriteUInt32(emu->tic_timer);
|
|
||||||
__packet->WriteUInt8(emu->all_buffs); // 1 indicates all buffs on the player (0 to add or remove a single buff)
|
|
||||||
__packet->WriteUInt16(emu->count);
|
|
||||||
|
|
||||||
for (int i = 0; i < emu->count; ++i)
|
|
||||||
{
|
|
||||||
__packet->WriteUInt32(emu->type == 0 ? ServerToRoFBuffSlot(emu->entries[i].buff_slot) : emu->entries[i].buff_slot);
|
|
||||||
__packet->WriteSInt32 (emu->entries[i].spell_id);
|
|
||||||
__packet->WriteUInt32(emu->entries[i].tics_remaining);
|
|
||||||
__packet->WriteUInt32(emu->entries[i].num_hits); // Unknown
|
|
||||||
__packet->WriteString(emu->entries[i].caster);
|
|
||||||
}
|
|
||||||
__packet->WriteUInt8(emu->type); // Unknown
|
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1858,38 +1810,6 @@ namespace RoF
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_RefreshPetBuffs)
|
|
||||||
{
|
|
||||||
// The format of the RoF packet is identical to the OP_RefreshBuffs packet.
|
|
||||||
|
|
||||||
SETUP_VAR_ENCODE(PetBuff_Struct);
|
|
||||||
|
|
||||||
uint32 sz = 12 + (17 * emu->buffcount);
|
|
||||||
__packet->size = sz;
|
|
||||||
__packet->pBuffer = new unsigned char[sz];
|
|
||||||
memset(__packet->pBuffer, 0, sz);
|
|
||||||
|
|
||||||
__packet->WriteUInt32(emu->petid);
|
|
||||||
__packet->WriteUInt32(0); // PlayerID ?
|
|
||||||
__packet->WriteUInt8(1); // 1 indicates all buffs on the pet (0 to add or remove a single buff)
|
|
||||||
__packet->WriteUInt16(emu->buffcount);
|
|
||||||
|
|
||||||
for (uint16 i = 0; i < PET_BUFF_COUNT; ++i)
|
|
||||||
{
|
|
||||||
if (emu->spellid[i])
|
|
||||||
{
|
|
||||||
__packet->WriteUInt32(i);
|
|
||||||
__packet->WriteSInt32 (emu->spellid[i]);
|
|
||||||
__packet->WriteUInt32(emu->ticsremaining[i]);
|
|
||||||
__packet->WriteUInt32(0); // numhits
|
|
||||||
__packet->WriteString("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
__packet->WriteUInt8(0); // some sort of type
|
|
||||||
|
|
||||||
FINISH_ENCODE();
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE(OP_PlayerProfile)
|
ENCODE(OP_PlayerProfile)
|
||||||
{
|
{
|
||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
@@ -3239,8 +3159,6 @@ namespace RoF
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_RefreshTargetBuffs) { ENCODE_FORWARD(OP_RefreshBuffs); }
|
|
||||||
|
|
||||||
ENCODE(OP_TaskDescription)
|
ENCODE(OP_TaskDescription)
|
||||||
{
|
{
|
||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
@@ -6263,21 +6181,6 @@ namespace RoF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// these should be optimized out for RoF since they should all boil down to return index :P
|
|
||||||
// but lets leave it here for future proofing
|
|
||||||
static inline int ServerToRoFBuffSlot(int index)
|
|
||||||
{
|
|
||||||
// we're a disc
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS + EQ::spells::SHORT_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS - EQ::spells::SHORT_BUFFS +
|
|
||||||
spells::LONG_BUFFS + spells::SHORT_BUFFS;
|
|
||||||
// we're a song
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS + spells::LONG_BUFFS;
|
|
||||||
// we're a normal buff
|
|
||||||
return index; // as long as we guard against bad slots server side, we should be fine
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int RoFToServerBuffSlot(int index)
|
static inline int RoFToServerBuffSlot(int index)
|
||||||
{
|
{
|
||||||
// we're a disc
|
// we're a disc
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "uf.h"
|
|
||||||
#include "common/struct_strategy.h"
|
#include "common/struct_strategy.h"
|
||||||
|
#include "common/patches/uf.h"
|
||||||
|
|
||||||
class EQStreamIdentifier;
|
class EQStreamIdentifier;
|
||||||
|
|
||||||
|
|||||||
+1
-97
@@ -69,7 +69,6 @@ namespace RoF2
|
|||||||
static inline spells::CastingSlot ServerToRoF2CastingSlot(EQ::spells::CastingSlot slot);
|
static inline spells::CastingSlot ServerToRoF2CastingSlot(EQ::spells::CastingSlot slot);
|
||||||
static inline EQ::spells::CastingSlot RoF2ToServerCastingSlot(spells::CastingSlot slot);
|
static inline EQ::spells::CastingSlot RoF2ToServerCastingSlot(spells::CastingSlot slot);
|
||||||
|
|
||||||
static inline int ServerToRoF2BuffSlot(int index);
|
|
||||||
static inline int RoF2ToServerBuffSlot(int index);
|
static inline int RoF2ToServerBuffSlot(int index);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
@@ -678,59 +677,13 @@ namespace RoF2
|
|||||||
OUT(buff.y);
|
OUT(buff.y);
|
||||||
OUT(buff.x);
|
OUT(buff.x);
|
||||||
OUT(buff.z);
|
OUT(buff.z);
|
||||||
eq->slotid = ServerToRoF2BuffSlot(emu->slotid);
|
OUT(slotid);
|
||||||
// TODO: implement slot_data stuff
|
// TODO: implement slot_data stuff
|
||||||
if (emu->bufffade == 1)
|
if (emu->bufffade == 1)
|
||||||
eq->bufffade = 1;
|
eq->bufffade = 1;
|
||||||
else
|
else
|
||||||
eq->bufffade = 2;
|
eq->bufffade = 2;
|
||||||
|
|
||||||
// Bit of a hack. OP_BuffDefinition appears to add/remove the buff while OP_RefreshBuffs adds/removes the actual buff icon
|
|
||||||
EQApplicationPacket *outapp = nullptr;
|
|
||||||
if (eq->bufffade == 1)
|
|
||||||
{
|
|
||||||
outapp = new EQApplicationPacket(OP_RefreshBuffs, 29u);
|
|
||||||
outapp->WriteUInt32(emu->entityid);
|
|
||||||
outapp->WriteUInt32(0); // tic timer
|
|
||||||
outapp->WriteUInt8(0); // Type of OP_RefreshBuffs packet ?
|
|
||||||
outapp->WriteUInt16(1); // 1 buff in this packet
|
|
||||||
outapp->WriteUInt32(eq->slotid);
|
|
||||||
outapp->WriteUInt32(0xffffffff); // SpellID (0xffff to remove)
|
|
||||||
outapp->WriteUInt32(0); // Duration
|
|
||||||
outapp->WriteUInt32(0); // numhits
|
|
||||||
outapp->WriteUInt8(0); // Caster name
|
|
||||||
outapp->WriteUInt8(0); // Type
|
|
||||||
}
|
|
||||||
FINISH_ENCODE();
|
|
||||||
|
|
||||||
if (outapp)
|
|
||||||
dest->FastQueuePacket(&outapp); // Send the OP_RefreshBuffs to remove the buff
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE(OP_RefreshBuffs)
|
|
||||||
{
|
|
||||||
SETUP_VAR_ENCODE(BuffIcon_Struct);
|
|
||||||
|
|
||||||
uint32 sz = 12 + (17 * emu->count) + emu->name_lengths; // 17 includes nullterm
|
|
||||||
__packet->size = sz;
|
|
||||||
__packet->pBuffer = new unsigned char[sz];
|
|
||||||
memset(__packet->pBuffer, 0, sz);
|
|
||||||
|
|
||||||
__packet->WriteUInt32(emu->entity_id);
|
|
||||||
__packet->WriteUInt32(emu->tic_timer);
|
|
||||||
__packet->WriteUInt8(emu->all_buffs); // 1 indicates all buffs on the player (0 to add or remove a single buff)
|
|
||||||
__packet->WriteUInt16(emu->count);
|
|
||||||
|
|
||||||
for (int i = 0; i < emu->count; ++i)
|
|
||||||
{
|
|
||||||
__packet->WriteUInt32(emu->type == 0 ? ServerToRoF2BuffSlot(emu->entries[i].buff_slot) : emu->entries[i].buff_slot);
|
|
||||||
__packet->WriteSInt32 (emu->entries[i].spell_id);
|
|
||||||
__packet->WriteUInt32(emu->entries[i].tics_remaining);
|
|
||||||
__packet->WriteUInt32(emu->entries[i].num_hits); // Unknown
|
|
||||||
__packet->WriteString(emu->entries[i].caster);
|
|
||||||
}
|
|
||||||
__packet->WriteUInt8(emu->type); // Unknown
|
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2464,38 +2417,6 @@ namespace RoF2
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_RefreshPetBuffs)
|
|
||||||
{
|
|
||||||
// The format of the RoF2 packet is identical to the OP_RefreshBuffs packet.
|
|
||||||
|
|
||||||
SETUP_VAR_ENCODE(PetBuff_Struct);
|
|
||||||
|
|
||||||
uint32 sz = 12 + (17 * emu->buffcount);
|
|
||||||
__packet->size = sz;
|
|
||||||
__packet->pBuffer = new unsigned char[sz];
|
|
||||||
memset(__packet->pBuffer, 0, sz);
|
|
||||||
|
|
||||||
__packet->WriteUInt32(emu->petid);
|
|
||||||
__packet->WriteUInt32(0); // PlayerID ?
|
|
||||||
__packet->WriteUInt8(1); // 1 indicates all buffs on the pet (0 to add or remove a single buff)
|
|
||||||
__packet->WriteUInt16(emu->buffcount);
|
|
||||||
|
|
||||||
for (uint16 i = 0; i < PET_BUFF_COUNT; ++i)
|
|
||||||
{
|
|
||||||
if (emu->spellid[i])
|
|
||||||
{
|
|
||||||
__packet->WriteUInt32(i);
|
|
||||||
__packet->WriteSInt32 (emu->spellid[i]);
|
|
||||||
__packet->WriteUInt32(emu->ticsremaining[i]);
|
|
||||||
__packet->WriteUInt32(0); // num hits
|
|
||||||
__packet->WriteString("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
__packet->WriteUInt8(0); // some sort of type
|
|
||||||
|
|
||||||
FINISH_ENCODE();
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE(OP_PlayerProfile)
|
ENCODE(OP_PlayerProfile)
|
||||||
{
|
{
|
||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
@@ -3841,8 +3762,6 @@ namespace RoF2
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_RefreshTargetBuffs) { ENCODE_FORWARD(OP_RefreshBuffs); }
|
|
||||||
|
|
||||||
ENCODE(OP_TaskDescription)
|
ENCODE(OP_TaskDescription)
|
||||||
{
|
{
|
||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
@@ -7495,21 +7414,6 @@ namespace RoF2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// these should be optimized out for RoF2 since they should all boil down to return index :P
|
|
||||||
// but lets leave it here for future proofing
|
|
||||||
static inline int ServerToRoF2BuffSlot(int index)
|
|
||||||
{
|
|
||||||
// we're a disc
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS + EQ::spells::SHORT_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS - EQ::spells::SHORT_BUFFS +
|
|
||||||
spells::LONG_BUFFS + spells::SHORT_BUFFS;
|
|
||||||
// we're a song
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS + spells::LONG_BUFFS;
|
|
||||||
// we're a normal buff
|
|
||||||
return index; // as long as we guard against bad slots server side, we should be fine
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int RoF2ToServerBuffSlot(int index)
|
static inline int RoF2ToServerBuffSlot(int index)
|
||||||
{
|
{
|
||||||
// we're a disc
|
// we're a disc
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "rof.h"
|
|
||||||
#include "common/struct_strategy.h"
|
#include "common/struct_strategy.h"
|
||||||
|
#include "common/patches/rof.h"
|
||||||
|
|
||||||
class EQStreamIdentifier;
|
class EQStreamIdentifier;
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ E(OP_BecomeTrader)
|
|||||||
E(OP_BeginCast)
|
E(OP_BeginCast)
|
||||||
E(OP_BlockedBuffs)
|
E(OP_BlockedBuffs)
|
||||||
E(OP_BuffDefinition)
|
E(OP_BuffDefinition)
|
||||||
E(OP_RefreshBuffs)
|
|
||||||
E(OP_BuyerItems)
|
E(OP_BuyerItems)
|
||||||
E(OP_CancelTrade)
|
E(OP_CancelTrade)
|
||||||
E(OP_CastSpell)
|
E(OP_CastSpell)
|
||||||
@@ -100,7 +99,6 @@ E(OP_MoveItem)
|
|||||||
E(OP_NewSpawn)
|
E(OP_NewSpawn)
|
||||||
E(OP_NewZone)
|
E(OP_NewZone)
|
||||||
E(OP_OnLevelMessage)
|
E(OP_OnLevelMessage)
|
||||||
E(OP_RefreshPetBuffs)
|
|
||||||
E(OP_PlayerProfile)
|
E(OP_PlayerProfile)
|
||||||
E(OP_RaidJoin)
|
E(OP_RaidJoin)
|
||||||
E(OP_RaidUpdate)
|
E(OP_RaidUpdate)
|
||||||
@@ -123,7 +121,6 @@ E(OP_SpawnAppearance)
|
|||||||
E(OP_SpawnDoor)
|
E(OP_SpawnDoor)
|
||||||
E(OP_SpecialMesg)
|
E(OP_SpecialMesg)
|
||||||
E(OP_Stun)
|
E(OP_Stun)
|
||||||
E(OP_RefreshTargetBuffs)
|
|
||||||
E(OP_TaskDescription)
|
E(OP_TaskDescription)
|
||||||
E(OP_TaskHistoryReply)
|
E(OP_TaskHistoryReply)
|
||||||
E(OP_Track)
|
E(OP_Track)
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ E(OP_BazaarSearch)
|
|||||||
E(OP_BeginCast)
|
E(OP_BeginCast)
|
||||||
E(OP_BlockedBuffs)
|
E(OP_BlockedBuffs)
|
||||||
E(OP_BuffDefinition)
|
E(OP_BuffDefinition)
|
||||||
E(OP_RefreshBuffs)
|
|
||||||
E(OP_CancelTrade)
|
E(OP_CancelTrade)
|
||||||
E(OP_CastSpell)
|
E(OP_CastSpell)
|
||||||
E(OP_ChannelMessage)
|
E(OP_ChannelMessage)
|
||||||
@@ -81,7 +80,6 @@ E(OP_MoveItem)
|
|||||||
E(OP_NewSpawn)
|
E(OP_NewSpawn)
|
||||||
E(OP_NewZone)
|
E(OP_NewZone)
|
||||||
E(OP_OnLevelMessage)
|
E(OP_OnLevelMessage)
|
||||||
E(OP_RefreshPetBuffs)
|
|
||||||
E(OP_PlayerProfile)
|
E(OP_PlayerProfile)
|
||||||
E(OP_RaidJoin)
|
E(OP_RaidJoin)
|
||||||
E(OP_RaidUpdate)
|
E(OP_RaidUpdate)
|
||||||
@@ -104,7 +102,6 @@ E(OP_SpawnAppearance)
|
|||||||
E(OP_SpawnDoor)
|
E(OP_SpawnDoor)
|
||||||
E(OP_SpecialMesg)
|
E(OP_SpecialMesg)
|
||||||
E(OP_Stun)
|
E(OP_Stun)
|
||||||
E(OP_RefreshTargetBuffs)
|
|
||||||
E(OP_TaskDescription)
|
E(OP_TaskDescription)
|
||||||
E(OP_TaskHistoryReply)
|
E(OP_TaskHistoryReply)
|
||||||
E(OP_Track)
|
E(OP_Track)
|
||||||
|
|||||||
+44
-125
@@ -64,7 +64,6 @@ namespace SoD
|
|||||||
static inline spells::CastingSlot ServerToSoDCastingSlot(EQ::spells::CastingSlot slot);
|
static inline spells::CastingSlot ServerToSoDCastingSlot(EQ::spells::CastingSlot slot);
|
||||||
static inline EQ::spells::CastingSlot SoDToServerCastingSlot(spells::CastingSlot slot);
|
static inline EQ::spells::CastingSlot SoDToServerCastingSlot(spells::CastingSlot slot);
|
||||||
|
|
||||||
static inline int ServerToSoDBuffSlot(int index);
|
|
||||||
static inline int SoDToServerBuffSlot(int index);
|
static inline int SoDToServerBuffSlot(int index);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
@@ -309,7 +308,7 @@ namespace SoD
|
|||||||
OUT(buff.duration);
|
OUT(buff.duration);
|
||||||
OUT(buff.counters);
|
OUT(buff.counters);
|
||||||
OUT(buff.player_id);
|
OUT(buff.player_id);
|
||||||
eq->slotid = ServerToSoDBuffSlot(emu->slotid);
|
OUT(slotid);
|
||||||
OUT(bufffade);
|
OUT(bufffade);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@@ -1378,38 +1377,6 @@ namespace SoD
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_RefreshPetBuffs)
|
|
||||||
{
|
|
||||||
EQApplicationPacket *in = *p;
|
|
||||||
*p = nullptr;
|
|
||||||
|
|
||||||
unsigned char *__emu_buffer = in->pBuffer;
|
|
||||||
PetBuff_Struct *emu = (PetBuff_Struct *)__emu_buffer;
|
|
||||||
int PacketSize = 7 + (emu->buffcount * 13);
|
|
||||||
in->size = PacketSize;
|
|
||||||
in->pBuffer = new unsigned char[in->size];
|
|
||||||
char *Buffer = (char *)in->pBuffer;
|
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petid);
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, emu->buffcount);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < PET_BUFF_COUNT; ++i)
|
|
||||||
{
|
|
||||||
if (emu->spellid[i])
|
|
||||||
{
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, i);
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spellid[i]);
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->ticsremaining[i]);
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string. Name of the caster of the buff.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->buffcount); // I think this is actually some sort of type
|
|
||||||
|
|
||||||
delete[] __emu_buffer;
|
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE(OP_PlayerProfile)
|
ENCODE(OP_PlayerProfile)
|
||||||
{
|
{
|
||||||
SETUP_DIRECT_ENCODE(PlayerProfile_Struct, structs::PlayerProfile_Struct);
|
SETUP_DIRECT_ENCODE(PlayerProfile_Struct, structs::PlayerProfile_Struct);
|
||||||
@@ -2148,35 +2115,6 @@ namespace SoD
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_RefreshTargetBuffs)
|
|
||||||
{
|
|
||||||
SETUP_VAR_ENCODE(BuffIcon_Struct);
|
|
||||||
|
|
||||||
uint32 sz = 7 + (13 * emu->count);
|
|
||||||
__packet->size = sz;
|
|
||||||
__packet->pBuffer = new unsigned char[sz];
|
|
||||||
memset(__packet->pBuffer, 0, sz);
|
|
||||||
|
|
||||||
uchar *ptr = __packet->pBuffer;
|
|
||||||
*((uint32*)ptr) = emu->entity_id;
|
|
||||||
ptr += sizeof(uint32);
|
|
||||||
|
|
||||||
*((uint16*)ptr) = emu->count;
|
|
||||||
ptr += sizeof(uint16);
|
|
||||||
|
|
||||||
for (uint16 i = 0; i < emu->count; ++i)
|
|
||||||
{
|
|
||||||
*((uint32*)ptr) = emu->entries[i].buff_slot;
|
|
||||||
ptr += sizeof(uint32);
|
|
||||||
*((uint32*)ptr) = emu->entries[i].spell_id;
|
|
||||||
ptr += sizeof(uint32);
|
|
||||||
*((uint32*)ptr) = emu->entries[i].tics_remaining;
|
|
||||||
ptr += sizeof(uint32);
|
|
||||||
ptr += 1;
|
|
||||||
}
|
|
||||||
FINISH_ENCODE();
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE(OP_TaskDescription)
|
ENCODE(OP_TaskDescription)
|
||||||
{
|
{
|
||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
@@ -4262,19 +4200,6 @@ namespace SoD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ServerToSoDBuffSlot(int index)
|
|
||||||
{
|
|
||||||
// we're a disc
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS + EQ::spells::SHORT_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS - EQ::spells::SHORT_BUFFS +
|
|
||||||
spells::LONG_BUFFS + spells::SHORT_BUFFS;
|
|
||||||
// we're a song
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS + spells::LONG_BUFFS;
|
|
||||||
// we're a normal buff
|
|
||||||
return index; // as long as we guard against bad slots server side, we should be fine
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int SoDToServerBuffSlot(int index)
|
static inline int SoDToServerBuffSlot(int index)
|
||||||
{
|
{
|
||||||
// we're a disc
|
// we're a disc
|
||||||
@@ -4288,71 +4213,65 @@ namespace SoD
|
|||||||
return index; // as long as we guard against bad slots server side, we should be fine
|
return index; // as long as we guard against bad slots server side, we should be fine
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<EQApplicationPacket> BuffComponent::RefreshBuffs(EmuOpcode opcode, Mob* mob,
|
std::unique_ptr<EQApplicationPacket> BuffComponent::RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
||||||
bool remove,
|
|
||||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const
|
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const
|
||||||
{
|
{
|
||||||
// SoD only supports target refresh, not self refresh packets
|
if (opcode == OP_RefreshPetBuffs || opcode == OP_RefreshTargetBuffs) {
|
||||||
if (opcode == OP_RefreshTargetBuffs) {
|
Buffs_Struct* buffs = mob->GetBuffs();
|
||||||
uint32 count = 0;
|
|
||||||
uint32 buff_count;
|
|
||||||
|
|
||||||
buff_count = mob->GetMaxTotalSlots();
|
size_t buffer_size = 7; // 7 bytes outside the list
|
||||||
|
std::vector<uint32_t> send_slots;
|
||||||
Buffs_Struct* buffs = mob->GetBuffs();
|
if (slots.empty()) {
|
||||||
|
for (uint32_t slot = 0; slot < mob->GetMaxTotalSlots(); ++slot)
|
||||||
for(int i = 0; i < buff_count; ++i) {
|
if (buffs[slot].spellid > 1) {
|
||||||
if (buffs[i].spellid > 1) {
|
buffer_size += 13 + strlen(buffs[slot].caster_name); // 13 includes the null terminator
|
||||||
++count;
|
send_slots.push_back(slot);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (uint32_t slot : slots)
|
||||||
|
if (slot < mob->GetMaxTotalSlots() && buffs[slot].spellid > 1) {
|
||||||
|
buffer_size += 13 + strlen(buffs[slot].caster_name);
|
||||||
|
send_slots.push_back(slot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SoD only supports target and pet refresh, not self refresh packets
|
||||||
|
SerializeBuffer buffer(buffer_size);
|
||||||
|
|
||||||
|
buffer.WriteUInt32(mob->GetID());
|
||||||
|
buffer.WriteUInt16(send_slots.size());
|
||||||
|
|
||||||
|
for (uint32_t slot : send_slots) {
|
||||||
|
buffer.WriteUInt32(ServerToPatchBuffSlot(slot));
|
||||||
|
buffer.WriteInt32(remove ? -1 : buffs[slot].spellid);
|
||||||
|
buffer.WriteInt32(buffs[slot].ticsremaining);
|
||||||
|
buffer.WriteString(buffs[slot].caster_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.WriteUInt8(opcode == OP_RefreshPetBuffs ? 2 : 0);
|
||||||
|
|
||||||
|
return std::make_unique<EQApplicationPacket>(opcode, std::move(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto outapp = std::make_unique<EQApplicationPacket>(opcode,
|
return nullptr;
|
||||||
sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count);
|
|
||||||
|
|
||||||
BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer;
|
|
||||||
buff->entity_id = mob->GetID();
|
|
||||||
buff->count = count;
|
|
||||||
buff->all_buffs = 1;
|
|
||||||
buff->tic_timer = mob->GetRemainingTicTime();
|
|
||||||
// (see comment in common/eq_packet_structs.h), mutated in SetRefreshType
|
|
||||||
buff->type = mob->IsClient() ? 5 : 7;
|
|
||||||
|
|
||||||
buff->name_lengths = 0; // hacky shit
|
|
||||||
uint32 index = 0;
|
|
||||||
for(int i = 0; i < buff_count; ++i) {
|
|
||||||
if (buffs[i].spellid > 1) {
|
|
||||||
buff->entries[index].buff_slot = i;
|
|
||||||
buff->entries[index].spell_id = buffs[i].spellid;
|
|
||||||
buff->entries[index].tics_remaining = buffs[i].ticsremaining;
|
|
||||||
buff->entries[index].num_hits = buffs[i].hit_number;
|
|
||||||
strn0cpy(buff->entries[index].caster, buffs[i].caster_name, 64);
|
|
||||||
buff->name_lengths += strlen(buff->entries[index].caster);
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return outapp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0 = self buff window, 1 = self target window, 2 = pet buff or target window, 4 = group, 5 = PC, 7 = NPC
|
// 0 = self buff window, 1 = self target window, 2 = pet buff or target window, 4 = group, 5 = PC, 7 = NPC
|
||||||
void BuffComponent::SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const
|
void BuffComponent::SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const
|
||||||
{
|
{
|
||||||
if (packet) {
|
if (packet) {
|
||||||
BuffIcon_Struct *buff = (BuffIcon_Struct*)packet->pBuffer;
|
unsigned char* type = &packet->pBuffer[packet->size - 1];
|
||||||
|
|
||||||
if (target->GetID() == source->GetID())
|
if (target->GetID() == source->GetID())
|
||||||
buff->type = 1;
|
*type = 1;
|
||||||
else if (target->IsPet())
|
else if (target->IsPet())
|
||||||
buff->type = 2;
|
*type = 2;
|
||||||
else if (target->HasGroup() && source->GetGroup() == target->GetGroup())
|
else if (target->HasGroup() && source->GetGroup() == target->GetGroup())
|
||||||
buff->type = 4;
|
*type = 4;
|
||||||
else if (target->IsClient())
|
else if (target->IsClient())
|
||||||
buff->type = 5;
|
*type = 5;
|
||||||
else
|
else
|
||||||
buff->type = 7;
|
*type = 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sof.h"
|
|
||||||
#include "common/struct_strategy.h"
|
#include "common/struct_strategy.h"
|
||||||
|
#include "common/patches/sof.h"
|
||||||
|
|
||||||
class EQStreamIdentifier;
|
class EQStreamIdentifier;
|
||||||
|
|
||||||
@@ -44,7 +44,8 @@ protected:
|
|||||||
class BuffComponent : public Titanium::BuffComponent
|
class BuffComponent : public Titanium::BuffComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BuffComponent() = default;
|
BuffComponent(uint32_t maxLongBuffs, uint32_t maxShortBuffs) : Titanium::BuffComponent(maxLongBuffs, maxShortBuffs) {}
|
||||||
|
BuffComponent() = delete;
|
||||||
~BuffComponent() override = default;
|
~BuffComponent() override = default;
|
||||||
|
|
||||||
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ E(OP_MoveItem)
|
|||||||
E(OP_NewSpawn)
|
E(OP_NewSpawn)
|
||||||
E(OP_NewZone)
|
E(OP_NewZone)
|
||||||
E(OP_OnLevelMessage)
|
E(OP_OnLevelMessage)
|
||||||
E(OP_RefreshPetBuffs)
|
|
||||||
E(OP_PlayerProfile)
|
E(OP_PlayerProfile)
|
||||||
E(OP_RaidJoin)
|
E(OP_RaidJoin)
|
||||||
E(OP_RaidUpdate)
|
E(OP_RaidUpdate)
|
||||||
@@ -80,7 +79,6 @@ E(OP_SomeItemPacketMaybe)
|
|||||||
E(OP_SpawnDoor)
|
E(OP_SpawnDoor)
|
||||||
E(OP_SpecialMesg)
|
E(OP_SpecialMesg)
|
||||||
E(OP_Stun)
|
E(OP_Stun)
|
||||||
E(OP_RefreshTargetBuffs)
|
|
||||||
E(OP_TaskDescription)
|
E(OP_TaskDescription)
|
||||||
E(OP_Track)
|
E(OP_Track)
|
||||||
E(OP_Trader)
|
E(OP_Trader)
|
||||||
|
|||||||
+2
-37
@@ -60,7 +60,6 @@ namespace SoF
|
|||||||
static inline spells::CastingSlot ServerToSoFCastingSlot(EQ::spells::CastingSlot slot);
|
static inline spells::CastingSlot ServerToSoFCastingSlot(EQ::spells::CastingSlot slot);
|
||||||
static inline EQ::spells::CastingSlot SoFToServerCastingSlot(spells::CastingSlot slot, uint32 item_location);
|
static inline EQ::spells::CastingSlot SoFToServerCastingSlot(spells::CastingSlot slot, uint32 item_location);
|
||||||
|
|
||||||
static inline int ServerToSoFBuffSlot(int index);
|
|
||||||
static inline int SoFToServerBuffSlot(int index);
|
static inline int SoFToServerBuffSlot(int index);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
@@ -285,7 +284,7 @@ namespace SoF
|
|||||||
OUT(buff.duration);
|
OUT(buff.duration);
|
||||||
OUT(buff.counters);
|
OUT(buff.counters);
|
||||||
OUT(buff.player_id);
|
OUT(buff.player_id);
|
||||||
eq->slotid = ServerToSoFBuffSlot(emu->slotid);
|
eq->slotid = SoFToServerBuffSlot(emu->slotid);
|
||||||
OUT(bufffade);
|
OUT(bufffade);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@@ -1049,28 +1048,6 @@ namespace SoF
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_RefreshPetBuffs)
|
|
||||||
{
|
|
||||||
ENCODE_LENGTH_EXACT(PetBuff_Struct);
|
|
||||||
SETUP_DIRECT_ENCODE(PetBuff_Struct, PetBuff_Struct);
|
|
||||||
|
|
||||||
OUT(petid);
|
|
||||||
OUT(buffcount);
|
|
||||||
|
|
||||||
int EQBuffSlot = 0; // do we really want to shuffle them around like this?
|
|
||||||
|
|
||||||
for (uint32 EmuBuffSlot = 0; EmuBuffSlot < PET_BUFF_COUNT; ++EmuBuffSlot)
|
|
||||||
{
|
|
||||||
if (emu->spellid[EmuBuffSlot])
|
|
||||||
{
|
|
||||||
eq->spellid[EQBuffSlot] = emu->spellid[EmuBuffSlot];
|
|
||||||
eq->ticsremaining[EQBuffSlot++] = emu->ticsremaining[EmuBuffSlot];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FINISH_ENCODE();
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE(OP_PlayerProfile)
|
ENCODE(OP_PlayerProfile)
|
||||||
{
|
{
|
||||||
SETUP_DIRECT_ENCODE(PlayerProfile_Struct, structs::PlayerProfile_Struct);
|
SETUP_DIRECT_ENCODE(PlayerProfile_Struct, structs::PlayerProfile_Struct);
|
||||||
@@ -2334,7 +2311,7 @@ namespace SoF
|
|||||||
IN(buff.duration);
|
IN(buff.duration);
|
||||||
IN(buff.counters);
|
IN(buff.counters);
|
||||||
IN(buff.player_id);
|
IN(buff.player_id);
|
||||||
emu->slotid = SoFToServerBuffSlot(eq->slotid);
|
IN(slotid);
|
||||||
IN(bufffade);
|
IN(bufffade);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
@@ -3657,18 +3634,6 @@ namespace SoF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ServerToSoFBuffSlot(int index) {
|
|
||||||
// we're a disc
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS + EQ::spells::SHORT_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS - EQ::spells::SHORT_BUFFS +
|
|
||||||
spells::LONG_BUFFS + spells::SHORT_BUFFS;
|
|
||||||
// we're a song
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS + spells::LONG_BUFFS;
|
|
||||||
// we're a normal buff
|
|
||||||
return index; // as long as we guard against bad slots server side, we should be fine
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int SoFToServerBuffSlot(int index)
|
static inline int SoFToServerBuffSlot(int index)
|
||||||
{
|
{
|
||||||
// we're a disc
|
// we're a disc
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "titanium.h"
|
|
||||||
#include "common/struct_strategy.h"
|
#include "common/struct_strategy.h"
|
||||||
|
#include "common/patches/titanium.h"
|
||||||
|
|
||||||
class EQStreamIdentifier;
|
class EQStreamIdentifier;
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ E(OP_MoveItem)
|
|||||||
E(OP_NewSpawn)
|
E(OP_NewSpawn)
|
||||||
E(OP_NewZone)
|
E(OP_NewZone)
|
||||||
E(OP_OnLevelMessage)
|
E(OP_OnLevelMessage)
|
||||||
E(OP_RefreshPetBuffs)
|
|
||||||
E(OP_PlayerProfile)
|
E(OP_PlayerProfile)
|
||||||
E(OP_RaidJoin)
|
E(OP_RaidJoin)
|
||||||
E(OP_RaidUpdate)
|
E(OP_RaidUpdate)
|
||||||
|
|||||||
+42
-40
@@ -64,7 +64,6 @@ namespace Titanium
|
|||||||
static inline spells::CastingSlot ServerToTitaniumCastingSlot(EQ::spells::CastingSlot slot);
|
static inline spells::CastingSlot ServerToTitaniumCastingSlot(EQ::spells::CastingSlot slot);
|
||||||
static inline EQ::spells::CastingSlot TitaniumToServerCastingSlot(spells::CastingSlot slot, uint32 item_location);
|
static inline EQ::spells::CastingSlot TitaniumToServerCastingSlot(spells::CastingSlot slot, uint32 item_location);
|
||||||
|
|
||||||
static inline int ServerToTitaniumBuffSlot(int index);
|
|
||||||
static inline int TitaniumToServerBuffSlot(int index);
|
static inline int TitaniumToServerBuffSlot(int index);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
@@ -341,7 +340,7 @@ namespace Titanium
|
|||||||
OUT(buff.duration);
|
OUT(buff.duration);
|
||||||
OUT(buff.counters);
|
OUT(buff.counters);
|
||||||
OUT(buff.player_id);
|
OUT(buff.player_id);
|
||||||
eq->slotid = ServerToTitaniumBuffSlot(emu->slotid);
|
OUT(slotid);
|
||||||
OUT(bufffade);
|
OUT(bufffade);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@@ -1309,28 +1308,6 @@ namespace Titanium
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_RefreshPetBuffs)
|
|
||||||
{
|
|
||||||
ENCODE_LENGTH_EXACT(PetBuff_Struct);
|
|
||||||
SETUP_DIRECT_ENCODE(PetBuff_Struct, PetBuff_Struct);
|
|
||||||
|
|
||||||
OUT(petid);
|
|
||||||
OUT(buffcount);
|
|
||||||
|
|
||||||
int EQBuffSlot = 0; // do we really want to shuffle them around like this?
|
|
||||||
|
|
||||||
for (uint32 EmuBuffSlot = 0; EmuBuffSlot < PET_BUFF_COUNT; ++EmuBuffSlot)
|
|
||||||
{
|
|
||||||
if (emu->spellid[EmuBuffSlot])
|
|
||||||
{
|
|
||||||
eq->spellid[EQBuffSlot] = emu->spellid[EmuBuffSlot];
|
|
||||||
eq->ticsremaining[EQBuffSlot++] = emu->ticsremaining[EmuBuffSlot];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FINISH_ENCODE();
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE(OP_PlayerProfile)
|
ENCODE(OP_PlayerProfile)
|
||||||
{
|
{
|
||||||
SETUP_DIRECT_ENCODE(PlayerProfile_Struct, structs::PlayerProfile_Struct);
|
SETUP_DIRECT_ENCODE(PlayerProfile_Struct, structs::PlayerProfile_Struct);
|
||||||
@@ -3896,19 +3873,6 @@ namespace Titanium
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ServerToTitaniumBuffSlot(int index)
|
|
||||||
{
|
|
||||||
// we're a disc
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS + EQ::spells::SHORT_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS - EQ::spells::SHORT_BUFFS +
|
|
||||||
spells::LONG_BUFFS + spells::SHORT_BUFFS;
|
|
||||||
// we're a song
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS + spells::LONG_BUFFS;
|
|
||||||
// we're a normal buff
|
|
||||||
return index; // as long as we guard against bad slots server side, we should be fine
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int TitaniumToServerBuffSlot(int index)
|
static inline int TitaniumToServerBuffSlot(int index)
|
||||||
{
|
{
|
||||||
// we're a disc
|
// we're a disc
|
||||||
@@ -4014,11 +3978,11 @@ void MessageComponent::ResolveArguments(uint32_t id, std::array<const char*, 9>&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<EQApplicationPacket> BuffComponent::BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot,
|
std::unique_ptr<EQApplicationPacket> BuffComponent::BuffDefinition(Mob* mob, const Buffs_Struct& buff, uint32_t slot,
|
||||||
bool fade) const
|
bool fade) const
|
||||||
{
|
{
|
||||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_BuffDefinition, sizeof(SpellBuffPacket_Struct));
|
auto outapp = std::make_unique<EQApplicationPacket>(OP_BuffDefinition, sizeof(SpellBuffPacket_Struct));
|
||||||
SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer;
|
auto sbf = reinterpret_cast<SpellBuffPacket_Struct*>(outapp->pBuffer);
|
||||||
|
|
||||||
sbf->entityid = mob->GetID();
|
sbf->entityid = mob->GetID();
|
||||||
|
|
||||||
@@ -4042,7 +4006,7 @@ std::unique_ptr<EQApplicationPacket> BuffComponent::BuffDefinition(Mob* mob, con
|
|||||||
sbf->buff.x = buff.caston_x;
|
sbf->buff.x = buff.caston_x;
|
||||||
sbf->buff.z = buff.caston_z;
|
sbf->buff.z = buff.caston_z;
|
||||||
|
|
||||||
sbf->slotid = slot;
|
sbf->slotid = ServerToPatchBuffSlot(slot);
|
||||||
sbf->bufffade = fade;
|
sbf->bufffade = fade;
|
||||||
|
|
||||||
return outapp;
|
return outapp;
|
||||||
@@ -4051,6 +4015,44 @@ std::unique_ptr<EQApplicationPacket> BuffComponent::BuffDefinition(Mob* mob, con
|
|||||||
std::unique_ptr<EQApplicationPacket> BuffComponent::RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
std::unique_ptr<EQApplicationPacket> BuffComponent::RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
||||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const
|
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const
|
||||||
{
|
{
|
||||||
|
// titanium only sends refresh for pet buffs
|
||||||
|
if (opcode == OP_RefreshPetBuffs) {
|
||||||
|
Buffs_Struct* buffs = mob->GetBuffs();
|
||||||
|
|
||||||
|
std::vector<uint32_t> send_slots;
|
||||||
|
if (slots.empty()) {
|
||||||
|
for (uint32_t slot = 0; slot < mob->GetMaxTotalSlots(); ++slot)
|
||||||
|
if (buffs[slot].spellid > 1)
|
||||||
|
send_slots.push_back(slot);
|
||||||
|
} else {
|
||||||
|
for (uint32_t slot : slots)
|
||||||
|
if (slot < mob->GetMaxTotalSlots() && buffs[slot].spellid > 1)
|
||||||
|
send_slots.push_back(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto outapp = std::make_unique<EQApplicationPacket>(OP_RefreshPetBuffs, sizeof(PetBuff_Struct));
|
||||||
|
auto pbs = reinterpret_cast<PetBuff_Struct*>(outapp->pBuffer);
|
||||||
|
memset(outapp->pBuffer, 0, outapp->size);
|
||||||
|
|
||||||
|
pbs->petid = mob->GetID();
|
||||||
|
int MaxSlots = mob->GetMaxTotalSlots();
|
||||||
|
if (MaxSlots > PET_BUFF_COUNT)
|
||||||
|
MaxSlots = PET_BUFF_COUNT;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (uint32_t slot : send_slots) {
|
||||||
|
if (slot < MaxSlots) {
|
||||||
|
pbs->spellid[slot] = buffs[slot].spellid;
|
||||||
|
pbs->ticsremaining[slot] = buffs[slot].ticsremaining;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pbs->buffcount = count;
|
||||||
|
|
||||||
|
return outapp;
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "IBuff.h"
|
|
||||||
#include "IMessage.h"
|
|
||||||
#include "common/struct_strategy.h"
|
#include "common/struct_strategy.h"
|
||||||
|
#include "common/patches/IBuff.h"
|
||||||
|
#include "common/patches/IMessage.h"
|
||||||
|
|
||||||
class EQStreamIdentifier;
|
class EQStreamIdentifier;
|
||||||
|
|
||||||
@@ -66,10 +66,11 @@ protected:
|
|||||||
class BuffComponent : public ClientPatch::IBuff
|
class BuffComponent : public ClientPatch::IBuff
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BuffComponent() = default;
|
BuffComponent(uint32_t maxLongBuffs, uint32_t maxShortBuffs) : IBuff(maxLongBuffs, maxShortBuffs) {}
|
||||||
|
BuffComponent() = delete;
|
||||||
~BuffComponent() override = default;
|
~BuffComponent() override = default;
|
||||||
|
|
||||||
std::unique_ptr<EQApplicationPacket> BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot,
|
std::unique_ptr<EQApplicationPacket> BuffDefinition(Mob* mob, const Buffs_Struct& buff, uint32_t slot,
|
||||||
bool fade) const override;
|
bool fade) const override;
|
||||||
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
||||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const override;
|
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const override;
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ E(OP_ManaChange)
|
|||||||
E(OP_MemorizeSpell)
|
E(OP_MemorizeSpell)
|
||||||
E(OP_MoveItem)
|
E(OP_MoveItem)
|
||||||
E(OP_OnLevelMessage)
|
E(OP_OnLevelMessage)
|
||||||
E(OP_RefreshPetBuffs)
|
|
||||||
E(OP_PlayerProfile)
|
E(OP_PlayerProfile)
|
||||||
E(OP_NewSpawn)
|
E(OP_NewSpawn)
|
||||||
E(OP_MarkRaidNPC)
|
E(OP_MarkRaidNPC)
|
||||||
|
|||||||
+39
-35
@@ -1,22 +1,41 @@
|
|||||||
#include "../global_define.h"
|
/* EQEmu: EQEmulator
|
||||||
#include "../eqemu_config.h"
|
|
||||||
#include "../eqemu_logsys.h"
|
Copyright (C) 2001-2026 EQEmu Development Team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "tob.h"
|
#include "tob.h"
|
||||||
#include "../opcodemgr.h"
|
|
||||||
|
|
||||||
#include "../eq_stream_ident.h"
|
|
||||||
#include "../crc32.h"
|
|
||||||
|
|
||||||
#include "../eq_packet_structs.h"
|
|
||||||
#include "../misc_functions.h"
|
|
||||||
#include "../strings.h"
|
|
||||||
#include "../inventory_profile.h"
|
|
||||||
#include "tob_structs.h"
|
#include "tob_structs.h"
|
||||||
#include "../rulesys.h"
|
|
||||||
#include "../path_manager.h"
|
#include "common/global_define.h"
|
||||||
#include "../classes.h"
|
#include "common/eqemu_config.h"
|
||||||
#include "../races.h"
|
#include "common/eqemu_logsys.h"
|
||||||
#include "../raid.h"
|
#include "common/opcodemgr.h"
|
||||||
|
|
||||||
|
#include "common/eq_stream_ident.h"
|
||||||
|
#include "common/crc32.h"
|
||||||
|
|
||||||
|
#include "common/eq_packet_structs.h"
|
||||||
|
#include "common/misc_functions.h"
|
||||||
|
#include "common/strings.h"
|
||||||
|
#include "common/inventory_profile.h"
|
||||||
|
#include "common/rulesys.h"
|
||||||
|
#include "common/path_manager.h"
|
||||||
|
#include "common/classes.h"
|
||||||
|
#include "common/races.h"
|
||||||
|
#include "common/raid.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -69,7 +88,6 @@ namespace TOB
|
|||||||
static inline EQ::spells::CastingSlot TOBToServerCastingSlot(spells::CastingSlot slot);
|
static inline EQ::spells::CastingSlot TOBToServerCastingSlot(spells::CastingSlot slot);
|
||||||
|
|
||||||
// buff slots
|
// buff slots
|
||||||
static inline int ServerToTOBBuffSlot(int index);
|
|
||||||
static inline int TOBToServerBuffSlot(int index);
|
static inline int TOBToServerBuffSlot(int index);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier& into)
|
void Register(EQStreamIdentifier& into)
|
||||||
@@ -5452,20 +5470,6 @@ namespace TOB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TOB has the same # of long buffs as rof2, but 10 more short buffs
|
|
||||||
static inline int ServerToTOBBuffSlot(int index)
|
|
||||||
{
|
|
||||||
// we're a disc
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS + EQ::spells::SHORT_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS - EQ::spells::SHORT_BUFFS +
|
|
||||||
spells::LONG_BUFFS + spells::SHORT_BUFFS;
|
|
||||||
// we're a song
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS + spells::LONG_BUFFS;
|
|
||||||
// we're a normal buff
|
|
||||||
return index; // as long as we guard against bad slots server side, we should be fine
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int TOBToServerBuffSlot(int index)
|
static inline int TOBToServerBuffSlot(int index)
|
||||||
{
|
{
|
||||||
// we're a disc
|
// we're a disc
|
||||||
@@ -5607,7 +5611,7 @@ std::unique_ptr<EQApplicationPacket> MessageComponent::InterruptSpellOther(Mob*
|
|||||||
return outapp;
|
return outapp;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<EQApplicationPacket> BuffComponent::BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, bool fade) const
|
std::unique_ptr<EQApplicationPacket> BuffComponent::BuffDefinition(Mob* mob, const Buffs_Struct& buff, uint32_t slot, bool fade) const
|
||||||
{
|
{
|
||||||
auto packet = std::make_unique<EQApplicationPacket>(OP_BuffDefinition, sizeof(structs::EQAffectPacket_Struct));
|
auto packet = std::make_unique<EQApplicationPacket>(OP_BuffDefinition, sizeof(structs::EQAffectPacket_Struct));
|
||||||
auto affect = reinterpret_cast<structs::EQAffectPacket_Struct*>(packet->pBuffer);
|
auto affect = reinterpret_cast<structs::EQAffectPacket_Struct*>(packet->pBuffer);
|
||||||
@@ -5615,7 +5619,7 @@ std::unique_ptr<EQApplicationPacket> BuffComponent::BuffDefinition(Mob* mob, con
|
|||||||
// base packet
|
// base packet
|
||||||
affect->entity_id = mob->GetID();
|
affect->entity_id = mob->GetID();
|
||||||
affect->unknown004 = 0;
|
affect->unknown004 = 0;
|
||||||
affect->slot_id = ServerToTOBBuffSlot(slot);
|
affect->slot_id = ServerToPatchBuffSlot(slot);
|
||||||
affect->buff_fade = fade ? 1 : 2; // 1 is remove, 2 is modify, 3 is add (only seen 1 and 2 sent)
|
affect->buff_fade = fade ? 1 : 2; // 1 is remove, 2 is modify, 3 is add (only seen 1 and 2 sent)
|
||||||
|
|
||||||
memset(&affect->affect, 0, sizeof(affect->affect));
|
memset(&affect->affect, 0, sizeof(affect->affect));
|
||||||
@@ -5693,7 +5697,7 @@ std::unique_ptr<EQApplicationPacket> BuffComponent::RefreshBuffs(EmuOpcode opcod
|
|||||||
buffer.WriteUInt16(send_slots.size());
|
buffer.WriteUInt16(send_slots.size());
|
||||||
|
|
||||||
for (uint32_t slot : send_slots) {
|
for (uint32_t slot : send_slots) {
|
||||||
buffer.WriteUInt32(::TOB::ServerToTOBBuffSlot(slot)); // the server stores fewer buffs
|
buffer.WriteUInt32(ServerToPatchBuffSlot(slot)); // the server stores fewer buffs
|
||||||
buffer.WriteInt32(remove ? -1 : buffs[slot].spellid);
|
buffer.WriteInt32(remove ? -1 : buffs[slot].spellid);
|
||||||
buffer.WriteUInt32(buffs[slot].ticsremaining);
|
buffer.WriteUInt32(buffs[slot].ticsremaining);
|
||||||
buffer.WriteUInt32(buffs[slot].hit_number);
|
buffer.WriteUInt32(buffs[slot].hit_number);
|
||||||
|
|||||||
+23
-4
@@ -1,7 +1,25 @@
|
|||||||
|
/* EQEmu: EQEmulator
|
||||||
|
|
||||||
|
Copyright (C) 2001-2026 EQEmu Development Team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "rof2.h"
|
#include "common/struct_strategy.h"
|
||||||
#include "../struct_strategy.h"
|
#include "common/patches/rof2.h"
|
||||||
|
|
||||||
class EQStreamIdentifier;
|
class EQStreamIdentifier;
|
||||||
|
|
||||||
@@ -46,11 +64,12 @@ protected:
|
|||||||
class BuffComponent : public UF::BuffComponent
|
class BuffComponent : public UF::BuffComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BuffComponent() = default;
|
BuffComponent(uint32_t maxLongBuffs, uint32_t maxShortBuffs) : UF::BuffComponent(maxLongBuffs, maxShortBuffs) {}
|
||||||
|
BuffComponent() = delete;
|
||||||
~BuffComponent() override = default;
|
~BuffComponent() override = default;
|
||||||
|
|
||||||
std::unique_ptr<EQApplicationPacket>
|
std::unique_ptr<EQApplicationPacket>
|
||||||
BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, bool fade) const override;
|
BuffDefinition(Mob* mob, const Buffs_Struct& buff, uint32_t slot, bool fade) const override;
|
||||||
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
||||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const override;
|
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const override;
|
||||||
void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const override;
|
void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const override;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#ifndef COMMON_LAURION_LIMITS_H
|
#ifndef COMMON_LAURION_LIMITS_H
|
||||||
#define COMMON_LAURION_LIMITS_H
|
#define COMMON_LAURION_LIMITS_H
|
||||||
|
|
||||||
#include "../types.h"
|
#include "common/types.h"
|
||||||
#include "../emu_versions.h"
|
#include "common/emu_versions.h"
|
||||||
#include "../skills.h"
|
#include "common/skills.h"
|
||||||
|
|
||||||
namespace TOB
|
namespace TOB
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,25 @@
|
|||||||
#ifndef STEAM_LATEST_STRUCTS_H_
|
/* EQEmu: EQEmulator
|
||||||
#define STEAM_LATEST_STRUCTS_H_
|
|
||||||
|
Copyright (C) 2001-2026 EQEmu Development Team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/eq_packet_structs.h"
|
||||||
|
#include "common/skills.h"
|
||||||
|
|
||||||
namespace TOB {
|
namespace TOB {
|
||||||
namespace structs {
|
namespace structs {
|
||||||
@@ -1086,5 +1106,3 @@ namespace TOB {
|
|||||||
|
|
||||||
}; //end namespace structs
|
}; //end namespace structs
|
||||||
}; //end namespace tob
|
}; //end namespace tob
|
||||||
|
|
||||||
#endif /*LAURION_STRUCTS_H_*/
|
|
||||||
+31
-145
@@ -66,7 +66,6 @@ namespace UF
|
|||||||
static inline spells::CastingSlot ServerToUFCastingSlot(EQ::spells::CastingSlot slot);
|
static inline spells::CastingSlot ServerToUFCastingSlot(EQ::spells::CastingSlot slot);
|
||||||
static inline EQ::spells::CastingSlot UFToServerCastingSlot(spells::CastingSlot slot);
|
static inline EQ::spells::CastingSlot UFToServerCastingSlot(spells::CastingSlot slot);
|
||||||
|
|
||||||
static inline int ServerToUFBuffSlot(int index);
|
|
||||||
static inline int UFToServerBuffSlot(int index);
|
static inline int UFToServerBuffSlot(int index);
|
||||||
|
|
||||||
void Register(EQStreamIdentifier &into)
|
void Register(EQStreamIdentifier &into)
|
||||||
@@ -444,72 +443,17 @@ namespace UF
|
|||||||
OUT(entityid);
|
OUT(entityid);
|
||||||
OUT(buff.effect_type);
|
OUT(buff.effect_type);
|
||||||
OUT(buff.level);
|
OUT(buff.level);
|
||||||
// just so we're 100% sure we get a 1.0f ...
|
OUT(buff.bard_modifier);
|
||||||
eq->buff.bard_modifier = emu->buff.bard_modifier == 10 ? 1.0f : emu->buff.bard_modifier / 10.0f;
|
|
||||||
OUT(buff.spellid);
|
OUT(buff.spellid);
|
||||||
OUT(buff.duration);
|
OUT(buff.duration);
|
||||||
OUT(buff.num_hits);
|
OUT(buff.num_hits);
|
||||||
// TODO: implement slot_data stuff
|
// TODO: implement slot_data stuff
|
||||||
eq->slotid = ServerToUFBuffSlot(emu->slotid);
|
OUT(slotid);
|
||||||
OUT(bufffade); // Live (October 2011) sends a 2 rather than 0 when a buff is created, but it doesn't seem to matter.
|
OUT(bufffade); // Live (October 2011) sends a 2 rather than 0 when a buff is created, but it doesn't seem to matter.
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_RefreshBuffs)
|
|
||||||
{
|
|
||||||
SETUP_VAR_ENCODE(BuffIcon_Struct);
|
|
||||||
|
|
||||||
uint32 sz = 12 + (17 * emu->count) + emu->name_lengths; // 17 includes nullterm
|
|
||||||
__packet->size = sz;
|
|
||||||
__packet->pBuffer = new unsigned char[sz];
|
|
||||||
memset(__packet->pBuffer, 0, sz);
|
|
||||||
|
|
||||||
__packet->WriteUInt32(emu->entity_id);
|
|
||||||
__packet->WriteUInt32(emu->tic_timer);
|
|
||||||
__packet->WriteUInt8(emu->all_buffs); // 1 = all buffs, 0 = 1 buff
|
|
||||||
__packet->WriteUInt16(emu->count);
|
|
||||||
|
|
||||||
for (int i = 0; i < emu->count; ++i)
|
|
||||||
{
|
|
||||||
__packet->WriteUInt32(emu->type == 0 ? ServerToUFBuffSlot(emu->entries[i].buff_slot) : emu->entries[i].buff_slot);
|
|
||||||
__packet->WriteSInt32 (emu->entries[i].spell_id);
|
|
||||||
__packet->WriteUInt32(emu->entries[i].tics_remaining);
|
|
||||||
__packet->WriteUInt32(emu->entries[i].num_hits);
|
|
||||||
__packet->WriteString(emu->entries[i].caster);
|
|
||||||
}
|
|
||||||
__packet->WriteUInt8(emu->type);
|
|
||||||
|
|
||||||
FINISH_ENCODE();
|
|
||||||
/*
|
|
||||||
uint32 write_var32 = 60;
|
|
||||||
uint8 write_var8 = 1;
|
|
||||||
ss.write((const char*)&emu->entity_id, sizeof(uint32));
|
|
||||||
ss.write((const char*)&write_var32, sizeof(uint32));
|
|
||||||
ss.write((const char*)&write_var8, sizeof(uint8));
|
|
||||||
ss.write((const char*)&emu->count, sizeof(uint16));
|
|
||||||
write_var32 = 0;
|
|
||||||
write_var8 = 0;
|
|
||||||
for(uint16 i = 0; i < emu->count; ++i)
|
|
||||||
{
|
|
||||||
if(emu->entries[i].buff_slot >= 25 && emu->entries[i].buff_slot < 37)
|
|
||||||
{
|
|
||||||
emu->entries[i].buff_slot += 5;
|
|
||||||
}
|
|
||||||
else if(emu->entries[i].buff_slot >= 37)
|
|
||||||
{
|
|
||||||
emu->entries[i].buff_slot += 14;
|
|
||||||
}
|
|
||||||
ss.write((const char*)&emu->entries[i].buff_slot, sizeof(uint32));
|
|
||||||
ss.write((const char*)&emu->entries[i].spell_id, sizeof(uint32));
|
|
||||||
ss.write((const char*)&emu->entries[i].tics_remaining, sizeof(uint32));
|
|
||||||
ss.write((const char*)&write_var32, sizeof(uint32));
|
|
||||||
ss.write((const char*)&write_var8, sizeof(uint8));
|
|
||||||
}
|
|
||||||
ss.write((const char*)&write_var8, sizeof(uint8));
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE(OP_CancelTrade)
|
ENCODE(OP_CancelTrade)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CancelTrade_Struct);
|
ENCODE_LENGTH_EXACT(CancelTrade_Struct);
|
||||||
@@ -1802,44 +1746,6 @@ namespace UF
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_RefreshPetBuffs)
|
|
||||||
{
|
|
||||||
EQApplicationPacket *in = *p;
|
|
||||||
*p = nullptr;
|
|
||||||
|
|
||||||
unsigned char *__emu_buffer = in->pBuffer;
|
|
||||||
|
|
||||||
PetBuff_Struct *emu = (PetBuff_Struct *)__emu_buffer;
|
|
||||||
|
|
||||||
int PacketSize = 12 + (emu->buffcount * 17);
|
|
||||||
|
|
||||||
in->size = PacketSize;
|
|
||||||
in->pBuffer = new unsigned char[in->size];
|
|
||||||
|
|
||||||
char *Buffer = (char *)in->pBuffer;
|
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petid);
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 1);
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, emu->buffcount);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < PET_BUFF_COUNT; ++i)
|
|
||||||
{
|
|
||||||
if (emu->spellid[i])
|
|
||||||
{
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, i);
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spellid[i]);
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->ticsremaining[i]);
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // numhits
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string. Name of the caster of the buff.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->buffcount); /// I think this is actually some sort of type
|
|
||||||
|
|
||||||
delete[] __emu_buffer;
|
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE(OP_PlayerProfile)
|
ENCODE(OP_PlayerProfile)
|
||||||
{
|
{
|
||||||
SETUP_DIRECT_ENCODE(PlayerProfile_Struct, structs::PlayerProfile_Struct);
|
SETUP_DIRECT_ENCODE(PlayerProfile_Struct, structs::PlayerProfile_Struct);
|
||||||
@@ -2731,8 +2637,6 @@ namespace UF
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_RefreshTargetBuffs) { ENCODE_FORWARD(OP_RefreshBuffs); }
|
|
||||||
|
|
||||||
ENCODE(OP_TaskDescription)
|
ENCODE(OP_TaskDescription)
|
||||||
{
|
{
|
||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
@@ -5210,19 +5114,6 @@ namespace UF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ServerToUFBuffSlot(int index)
|
|
||||||
{
|
|
||||||
// we're a disc
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS + EQ::spells::SHORT_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS - EQ::spells::SHORT_BUFFS +
|
|
||||||
spells::LONG_BUFFS + spells::SHORT_BUFFS;
|
|
||||||
// we're a song
|
|
||||||
if (index >= EQ::spells::LONG_BUFFS)
|
|
||||||
return index - EQ::spells::LONG_BUFFS + spells::LONG_BUFFS;
|
|
||||||
// we're a normal buff
|
|
||||||
return index; // as long as we guard against bad slots server side, we should be fine
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int UFToServerBuffSlot(int index)
|
static inline int UFToServerBuffSlot(int index)
|
||||||
{
|
{
|
||||||
// we're a disc
|
// we're a disc
|
||||||
@@ -5240,48 +5131,43 @@ namespace UF
|
|||||||
bool remove,
|
bool remove,
|
||||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const
|
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const
|
||||||
{
|
{
|
||||||
// UF introduced the self update buff packet
|
// UF introduced the self refresh buff packet
|
||||||
|
|
||||||
uint32 count = 0;
|
|
||||||
uint32 buff_count;
|
|
||||||
|
|
||||||
buff_count = mob->GetMaxTotalSlots();
|
|
||||||
|
|
||||||
Buffs_Struct* buffs = mob->GetBuffs();
|
Buffs_Struct* buffs = mob->GetBuffs();
|
||||||
|
|
||||||
for(int i = 0; i < buff_count; ++i) {
|
size_t buffer_size = 12; // 12 bytes outside the list
|
||||||
if (buffs[i].spellid > 1) {
|
std::vector<uint32_t> send_slots;
|
||||||
++count;
|
if (slots.empty()) {
|
||||||
}
|
for (uint32_t slot = 0; slot < mob->GetMaxTotalSlots(); ++slot)
|
||||||
|
if (buffs[slot].spellid > 1) {
|
||||||
|
buffer_size += 17 + strlen(buffs[slot].caster_name); // 17 includes the null terminator
|
||||||
|
send_slots.push_back(slot);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (uint32_t slot : slots)
|
||||||
|
if (slot < mob->GetMaxTotalSlots() && buffs[slot].spellid > 1) {
|
||||||
|
buffer_size += 17 + strlen(buffs[slot].caster_name);
|
||||||
|
send_slots.push_back(slot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create it for a targeting window, else create it for a create buff packet.
|
SerializeBuffer buffer(buffer_size);
|
||||||
auto outapp = std::make_unique<EQApplicationPacket>(opcode,
|
|
||||||
sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count);
|
|
||||||
|
|
||||||
BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer;
|
buffer.WriteUInt32(mob->GetID());
|
||||||
buff->entity_id = mob->GetID();
|
buffer.WriteUInt32(mob->GetRemainingTicTime());
|
||||||
buff->count = count;
|
buffer.WriteUInt8(slots.empty() ? 1 : 0);
|
||||||
buff->all_buffs = 1;
|
buffer.WriteUInt16(send_slots.size());
|
||||||
buff->tic_timer = mob->GetRemainingTicTime();
|
|
||||||
// (see comment in common/eq_packet_structs.h)
|
|
||||||
buff->type = mob->IsClient() ? 5 : 7;
|
|
||||||
|
|
||||||
buff->name_lengths = 0; // hacky shit
|
for (uint32_t slot : send_slots) {
|
||||||
uint32 index = 0;
|
buffer.WriteUInt32(ServerToPatchBuffSlot(slot));
|
||||||
for(int i = 0; i < buff_count; ++i) {
|
buffer.WriteInt32(remove ? -1 : buffs[slot].spellid);
|
||||||
if (buffs[i].spellid > 1) {
|
buffer.WriteInt32(buffs[slot].ticsremaining);
|
||||||
buff->entries[index].buff_slot = i;
|
buffer.WriteUInt32(buffs[slot].hit_number);
|
||||||
buff->entries[index].spell_id = buffs[i].spellid;
|
buffer.WriteString(buffs[slot].caster_name);
|
||||||
buff->entries[index].tics_remaining = buffs[i].ticsremaining;
|
|
||||||
buff->entries[index].num_hits = buffs[i].hit_number;
|
|
||||||
strn0cpy(buff->entries[index].caster, buffs[i].caster_name, 64);
|
|
||||||
buff->name_lengths += strlen(buff->entries[index].caster);
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return outapp;
|
buffer.WriteUInt8(opcode == OP_RefreshPetBuffs ? 2 : 0);
|
||||||
|
|
||||||
|
return std::make_unique<EQApplicationPacket>(opcode, std::move(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
} /*UF*/
|
} /*UF*/
|
||||||
|
|||||||
+3
-2
@@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sod.h"
|
|
||||||
#include "common/struct_strategy.h"
|
#include "common/struct_strategy.h"
|
||||||
|
#include "common/patches/sod.h"
|
||||||
|
|
||||||
class EQStreamIdentifier;
|
class EQStreamIdentifier;
|
||||||
|
|
||||||
@@ -44,7 +44,8 @@ protected:
|
|||||||
class BuffComponent : public SoD::BuffComponent
|
class BuffComponent : public SoD::BuffComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BuffComponent() = default;
|
BuffComponent(uint32_t maxLongBuffs, uint32_t maxShortBuffs) : SoD::BuffComponent(maxLongBuffs, maxShortBuffs) {}
|
||||||
|
BuffComponent() = delete;
|
||||||
~BuffComponent() override = default;
|
~BuffComponent() override = default;
|
||||||
|
|
||||||
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ E(OP_Barter)
|
|||||||
E(OP_BazaarSearch)
|
E(OP_BazaarSearch)
|
||||||
E(OP_BecomeTrader)
|
E(OP_BecomeTrader)
|
||||||
E(OP_BuffDefinition)
|
E(OP_BuffDefinition)
|
||||||
E(OP_RefreshBuffs)
|
|
||||||
E(OP_CancelTrade)
|
E(OP_CancelTrade)
|
||||||
E(OP_ChannelMessage)
|
E(OP_ChannelMessage)
|
||||||
E(OP_CharInventory)
|
E(OP_CharInventory)
|
||||||
@@ -75,7 +74,6 @@ E(OP_MoveItem)
|
|||||||
E(OP_NewSpawn)
|
E(OP_NewSpawn)
|
||||||
E(OP_NewZone)
|
E(OP_NewZone)
|
||||||
E(OP_OnLevelMessage)
|
E(OP_OnLevelMessage)
|
||||||
E(OP_RefreshPetBuffs)
|
|
||||||
E(OP_PlayerProfile)
|
E(OP_PlayerProfile)
|
||||||
E(OP_RaidJoin)
|
E(OP_RaidJoin)
|
||||||
E(OP_RaidUpdate)
|
E(OP_RaidUpdate)
|
||||||
@@ -93,7 +91,6 @@ E(OP_SpawnAppearance)
|
|||||||
E(OP_SpawnDoor)
|
E(OP_SpawnDoor)
|
||||||
E(OP_SpecialMesg)
|
E(OP_SpecialMesg)
|
||||||
E(OP_Stun)
|
E(OP_Stun)
|
||||||
E(OP_RefreshTargetBuffs)
|
|
||||||
E(OP_TaskDescription)
|
E(OP_TaskDescription)
|
||||||
E(OP_Track)
|
E(OP_Track)
|
||||||
E(OP_Trader)
|
E(OP_Trader)
|
||||||
|
|||||||
@@ -27,3 +27,112 @@ void Client::SetClientVersion(Version client_version)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Version Client::GetClientVersion() const { return m_ClientVersion; }
|
Version Client::GetClientVersion() const { return m_ClientVersion; }
|
||||||
|
|
||||||
|
void ClientPatch::InterruptSpell(Client* c, uint32_t message, uint32_t spawn_id, const char* spell_link) {
|
||||||
|
QueuePacket(c, &IMessage::InterruptSpell, GetClientComponent<IMessage>(c), message, spawn_id, spell_link);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientPatch::InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, const char* name,
|
||||||
|
const char* spell_link) {
|
||||||
|
QueueCloseClients(sender, true, RuleI(Range, SongMessages), nullptr, true,
|
||||||
|
sender->IsClient() ? FilterPCSpells : FilterNPCSpells)(
|
||||||
|
&IMessage::InterruptSpellOther, GetClientComponent<IMessage>, sender, message, spawn_id, name, spell_link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ShouldSendTargetBuffs(Client* c) {
|
||||||
|
// this function checks for server rules against LAA and GM status to determine if a buffs packet should be sent
|
||||||
|
// to a client (c) for targeted mobs
|
||||||
|
if (c->GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs)) { // this rule bypasses LAA abilities, always return true
|
||||||
|
if (c->GetGM()) {
|
||||||
|
if (!c->EntityVariableExists(SEE_BUFFS_FLAG)) { // This flag just ensures that the following message is only sent once
|
||||||
|
c->Message(Chat::White,
|
||||||
|
"Your GM flag allows you to always see your targets' buffs.");
|
||||||
|
c->SetEntityVariable(SEE_BUFFS_FLAG, "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->IsRaidGrouped()) {
|
||||||
|
Raid* raid = c->GetRaid();
|
||||||
|
if (raid) {
|
||||||
|
uint32 gid = raid->GetGroup(c);
|
||||||
|
if (gid < MAX_RAID_GROUPS && raid->GroupCount(gid) >= 3) {
|
||||||
|
if (raid->GetLeadershipAA(groupAAInspectBuffs, gid))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Group* group = c->GetGroup();
|
||||||
|
if (group && group->GroupCount() >= 3) {
|
||||||
|
if (group->GetLeadershipAA(groupAAInspectBuffs)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientPatch::SendFullBuffRefresh(Mob* sender, bool remove, bool ackreq) {
|
||||||
|
bool suspended = zone->BuffTimersSuspended();
|
||||||
|
std::vector<uint32_t> slots;
|
||||||
|
|
||||||
|
// first, send to self if self is client
|
||||||
|
if (sender->IsClient()) {
|
||||||
|
Client* c = sender->CastToClient();
|
||||||
|
FastQueuePacket(c, &IBuff::RefreshBuffs, GetClientComponent<IBuff>(c), OP_RefreshBuffs, sender, false, suspended, slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
// next, send to owner if self is a pet to a client
|
||||||
|
if (sender->IsPet() && sender->GetOwner()->IsClient()) {
|
||||||
|
if (Mob* owner = sender->GetOwner(); owner != nullptr && owner->IsClient()) {
|
||||||
|
Client* c = owner->CastToClient();
|
||||||
|
FastQueuePacket(c, &IBuff::RefreshBuffs, GetClientComponent<IBuff>(c), OP_RefreshPetBuffs, sender, false, suspended, slots);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally send to all clients targeting the mob, will need to mutate the packet to set the type
|
||||||
|
auto mutate = [sender](std::unique_ptr<EQApplicationPacket>& packet, Client* c) {
|
||||||
|
GetClientComponent<IBuff>(c)->SetRefreshType(packet, sender, c);
|
||||||
|
};
|
||||||
|
|
||||||
|
QueueClientsByTarget(sender, ackreq, ShouldSendTargetBuffs, mutate)(
|
||||||
|
&IBuff::RefreshBuffs, GetClientComponent<IBuff>, OP_RefreshTargetBuffs, sender, false, suspended, slots);
|
||||||
|
|
||||||
|
// if we have remove set, this will clear any target windows that shouldn't see the buffs
|
||||||
|
if (remove)
|
||||||
|
QueueClientsByTarget(sender, ackreq, [](Client* c) { return !ShouldSendTargetBuffs(c); }, mutate)(
|
||||||
|
&IBuff::RefreshBuffs, GetClientComponent<IBuff>, OP_RefreshTargetBuffs, sender, true, suspended, slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientPatch::SendSingleBuffChange(Mob* sender, const Buffs_Struct& buff, int slot, bool remove, bool ackreq) {
|
||||||
|
bool suspended = zone->BuffTimersSuspended();
|
||||||
|
std::vector slots = { static_cast<uint32_t>(slot) };
|
||||||
|
|
||||||
|
// first, send to self if self is client, which takes the definition and the refresh
|
||||||
|
if (sender->IsClient()) {
|
||||||
|
Client* c = sender->CastToClient();
|
||||||
|
FastQueuePacket(c, &IBuff::BuffDefinition, GetClientComponent<IBuff>(c), sender, buff, slot, remove);
|
||||||
|
FastQueuePacket(c, &IBuff::RefreshBuffs, GetClientComponent<IBuff>(c), OP_RefreshBuffs, sender, remove, suspended, slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the rest of the buff packets do not take the definition, only the refresh
|
||||||
|
if (sender->IsPet() && sender->GetOwner()->IsClient()) {
|
||||||
|
if (Mob* owner = sender->GetOwner(); owner != nullptr && owner->IsClient()) {
|
||||||
|
Client* c = owner->CastToClient();
|
||||||
|
FastQueuePacket(c, &IBuff::RefreshBuffs, GetClientComponent<IBuff>(c), OP_RefreshPetBuffs, sender, remove, suspended, slots);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mutate = [sender](std::unique_ptr<EQApplicationPacket>& packet, Client* c) {
|
||||||
|
GetClientComponent<IBuff>(c)->SetRefreshType(packet, sender, c);
|
||||||
|
};
|
||||||
|
|
||||||
|
QueueClientsByTarget(sender, ackreq, ShouldSendTargetBuffs, mutate)(
|
||||||
|
&IBuff::RefreshBuffs, GetClientComponent<IBuff>, OP_RefreshTargetBuffs, sender, remove, suspended, slots);
|
||||||
|
|
||||||
|
// the client doesn't automatically do this for some reason, only send it to the sender (TOB doesn't actually need this, but it doesn't double show the message)
|
||||||
|
if (remove && sender->IsClient())
|
||||||
|
sender->CastToClient()->SendColoredText(Chat::Spells, spells[buff.spellid].spell_fades);
|
||||||
|
}
|
||||||
|
|||||||
+43
-134
@@ -1,9 +1,24 @@
|
|||||||
//
|
/* EQEmu: EQEmulator
|
||||||
// Created by dannu on 4/21/2026.
|
|
||||||
//
|
Copyright (C) 2001-2026 EQEmu Development Team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
#include "common/emu_versions.h"
|
#include "common/emu_versions.h"
|
||||||
#include "common/patches/client_version.h"
|
#include "common/patches/client_version.h"
|
||||||
@@ -17,13 +32,19 @@
|
|||||||
namespace ClientPatch {
|
namespace ClientPatch {
|
||||||
|
|
||||||
using ClientList = std::unordered_map<uint16, Client*>;
|
using ClientList = std::unordered_map<uint16, Client*>;
|
||||||
template<typename Obj> using ComponentGetter = Obj*(*)(const Client*); //std::function<Obj*(const Client*)>;
|
template<typename Obj> using ComponentGetter = Obj*(*)(const Client*);
|
||||||
using SendPredicate = std::function<bool(Client*)>;
|
using SendPredicate = std::function<bool(Client*)>;
|
||||||
using MutatePacket = std::function<void(std::unique_ptr<EQApplicationPacket>&, Client*)>;
|
using MutatePacket = std::function<void(std::unique_ptr<EQApplicationPacket>&, Client*)>;
|
||||||
|
|
||||||
|
template <typename Component>
|
||||||
|
static Component* GetClientComponent(const Client* client)
|
||||||
|
{
|
||||||
|
return GetComponent<Component>(client->GetClientVersion()).get();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Fun, typename Obj, typename... Args>
|
template <typename Fun, typename Obj, typename... Args>
|
||||||
requires std::is_member_function_pointer_v<Fun>
|
requires std::is_member_function_pointer_v<Fun>
|
||||||
static void QueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args)
|
void QueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args)
|
||||||
{
|
{
|
||||||
if (obj != nullptr) {
|
if (obj != nullptr) {
|
||||||
std::unique_ptr<EQApplicationPacket> app = std::invoke(fun, obj, std::forward<Args>(args)...);
|
std::unique_ptr<EQApplicationPacket> app = std::invoke(fun, obj, std::forward<Args>(args)...);
|
||||||
@@ -33,14 +54,14 @@ static void QueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// packet generator queue functions
|
// packet generator queue functions
|
||||||
static auto QueueClients(Mob* sender, bool ignore_sender = false, bool ackreq = true)
|
inline auto QueueClients(Mob* sender, bool ignore_sender = false, bool ackreq = true)
|
||||||
{
|
{
|
||||||
return [=]<typename Fun, typename Obj, typename... Args>(Fun fun, ComponentGetter<Obj> component, Args&&... args)
|
return [=]<typename Fun, typename Obj, typename... Args>(Fun fun, ComponentGetter<Obj> component, Args&&... args)
|
||||||
requires std::is_member_function_pointer_v<Fun>
|
requires std::is_member_function_pointer_v<Fun>
|
||||||
{
|
{
|
||||||
std::array<std::unique_ptr<EQApplicationPacket>, EQ::versions::ClientVersionCount> build_packets;
|
std::array<std::unique_ptr<EQApplicationPacket>, EQ::versions::ClientVersionCount> build_packets;
|
||||||
|
|
||||||
for (auto [_, ent] : entity_list.GetClientList()) {
|
for (auto ent : entity_list.GetClientList() | std::views::values) {
|
||||||
if (!ignore_sender || ent != sender) {
|
if (!ignore_sender || ent != sender) {
|
||||||
auto& packet = build_packets.at(static_cast<uint32_t>(ent->ClientVersion()));
|
auto& packet = build_packets.at(static_cast<uint32_t>(ent->ClientVersion()));
|
||||||
if (!packet)
|
if (!packet)
|
||||||
@@ -54,7 +75,7 @@ static auto QueueClients(Mob* sender, bool ignore_sender = false, bool ackreq =
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto QueueCloseClients(
|
inline auto QueueCloseClients(
|
||||||
Mob* sender, bool ignore_sender = false, float distance = 200,
|
Mob* sender, bool ignore_sender = false, float distance = 200,
|
||||||
Mob* skipped_mob = nullptr, bool is_ack_required = true,
|
Mob* skipped_mob = nullptr, bool is_ack_required = true,
|
||||||
eqFilterType filter = FilterNone)
|
eqFilterType filter = FilterNone)
|
||||||
@@ -70,14 +91,14 @@ static auto QueueCloseClients(
|
|||||||
float distance_squared = distance * distance;
|
float distance_squared = distance * distance;
|
||||||
std::array<std::unique_ptr<EQApplicationPacket>, EQ::versions::ClientVersionCount> build_packets;
|
std::array<std::unique_ptr<EQApplicationPacket>, EQ::versions::ClientVersionCount> build_packets;
|
||||||
|
|
||||||
for (auto& [_, mob] : sender->GetCloseMobList(distance)) {
|
for (auto mob : sender->GetCloseMobList(distance) | std::views::values) {
|
||||||
if (mob && mob->IsClient()) {
|
if (mob && mob->IsClient()) {
|
||||||
Client* client = mob->CastToClient();
|
Client* client = mob->CastToClient();
|
||||||
if ((!ignore_sender || client != sender)
|
if ((!ignore_sender || client != sender)
|
||||||
&& client != skipped_mob
|
&& client != skipped_mob
|
||||||
&& DistanceSquared(client->GetPosition(), sender->GetPosition()) < distance_squared
|
|
||||||
&& client->Connected()
|
&& client->Connected()
|
||||||
&& client->ShouldGetPacket(sender, filter))
|
&& client->ShouldGetPacket(sender, filter)
|
||||||
|
&& DistanceSquared(client->GetPosition(), sender->GetPosition()) < distance_squared)
|
||||||
{
|
{
|
||||||
auto& packet = build_packets.at(static_cast<uint32_t>(client->ClientVersion()));
|
auto& packet = build_packets.at(static_cast<uint32_t>(client->ClientVersion()));
|
||||||
if (!packet)
|
if (!packet)
|
||||||
@@ -94,7 +115,7 @@ static auto QueueCloseClients(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fun, typename Obj, typename... Args>
|
template <typename Fun, typename Obj, typename... Args>
|
||||||
static void FastQueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args)
|
void FastQueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args)
|
||||||
requires std::is_member_function_pointer_v<Fun>
|
requires std::is_member_function_pointer_v<Fun>
|
||||||
{
|
{
|
||||||
if (obj != nullptr) {
|
if (obj != nullptr) {
|
||||||
@@ -107,7 +128,7 @@ static void FastQueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto QueueClientsByTarget(Mob* sender, bool ackreq, bool HoTT, const SendPredicate& should_send, const MutatePacket& mutate)
|
inline auto QueueClientsByTarget(Mob* sender, bool ackreq, const SendPredicate& should_send, const MutatePacket& mutate)
|
||||||
{
|
{
|
||||||
return [=]<typename Fun, typename Obj, typename... Args>(Fun fun, ComponentGetter<Obj> component, Args&&... args)
|
return [=]<typename Fun, typename Obj, typename... Args>(Fun fun, ComponentGetter<Obj> component, Args&&... args)
|
||||||
requires std::is_member_function_pointer_v<Fun>
|
requires std::is_member_function_pointer_v<Fun>
|
||||||
@@ -115,10 +136,9 @@ static auto QueueClientsByTarget(Mob* sender, bool ackreq, bool HoTT, const Send
|
|||||||
if (sender != nullptr) {
|
if (sender != nullptr) {
|
||||||
std::array<std::unique_ptr<EQApplicationPacket>, EQ::versions::ClientVersionCount> build_packets;
|
std::array<std::unique_ptr<EQApplicationPacket>, EQ::versions::ClientVersionCount> build_packets;
|
||||||
|
|
||||||
for (auto [_, c] : entity_list.GetClientList()) {
|
for (auto c : entity_list.GetClientList() | std::views::values) {
|
||||||
Mob* Target = c->GetTarget();
|
Mob* Target = c->GetTarget();
|
||||||
if ((Target == sender || (HoTT && Target != nullptr && Target->GetTarget() == sender)) &&
|
if (Target == sender && should_send(c)) {
|
||||||
(Target == c || should_send(c))) {
|
|
||||||
auto& packet = build_packets.at(static_cast<uint32_t>(c->ClientVersion()));
|
auto& packet = build_packets.at(static_cast<uint32_t>(c->ClientVersion()));
|
||||||
if (!packet)
|
if (!packet)
|
||||||
if (auto comp = component(c); comp != nullptr)
|
if (auto comp = component(c); comp != nullptr)
|
||||||
@@ -128,7 +148,7 @@ static auto QueueClientsByTarget(Mob* sender, bool ackreq, bool HoTT, const Send
|
|||||||
|
|
||||||
if (packet)
|
if (packet)
|
||||||
c->QueuePacket(packet.get(), ackreq, Client::CLIENT_CONNECTED);
|
c->QueuePacket(packet.get(), ackreq, Client::CLIENT_CONNECTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -147,7 +167,7 @@ void MessageString(Client* c, uint32_t type, uint32_t id, Args&&... args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto CloseMessageString(
|
inline auto CloseMessageString(
|
||||||
Mob* sender, bool ignore_sender = false, float distance = 200.f,
|
Mob* sender, bool ignore_sender = false, float distance = 200.f,
|
||||||
Mob* skipped_mob = nullptr, bool is_ack_required = true,
|
Mob* skipped_mob = nullptr, bool is_ack_required = true,
|
||||||
eqFilterType filter = FilterNone)
|
eqFilterType filter = FilterNone)
|
||||||
@@ -167,122 +187,11 @@ static auto CloseMessageString(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void InterruptSpell(Client* c, uint32_t message, uint32_t spawn_id, const char* spell_link)
|
void InterruptSpell(Client* c, uint32_t message, uint32_t spawn_id, const char* spell_link);
|
||||||
{
|
void InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, const char* name,
|
||||||
QueuePacket(c, &IMessage::InterruptSpell, GetClientComponent<IMessage>(c), message, spawn_id, spell_link);
|
const char* spell_link);
|
||||||
}
|
|
||||||
|
|
||||||
inline void InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, const char* name,
|
void SendFullBuffRefresh(Mob* sender, bool remove = false, bool ackreq = true);
|
||||||
const char* spell_link)
|
void SendSingleBuffChange(Mob* sender, const Buffs_Struct& buff, int slot, bool remove = false, bool ackreq = true);
|
||||||
{
|
|
||||||
QueueCloseClients(sender, true, RuleI(Range, SongMessages), nullptr, true,
|
|
||||||
sender->IsClient() ? FilterPCSpells : FilterNPCSpells)(
|
|
||||||
&IMessage::InterruptSpellOther, GetClientComponent<IMessage>, sender, message, spawn_id, name, spell_link);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ShouldSendTargetBuffs(Client* c)
|
|
||||||
{
|
|
||||||
// this function checks for server rules against LAA and GM status to determine if a buffs packet should be sent
|
|
||||||
// to a client (c) for targeted mobs
|
|
||||||
if (c->GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs)) { // this rule bypasses LAA abilities, always return true
|
|
||||||
if (c->GetGM()) {
|
|
||||||
if (!c->EntityVariableExists(SEE_BUFFS_FLAG)) { // This flag just ensures that the following message is only sent once
|
|
||||||
c->Message(Chat::White,
|
|
||||||
"Your GM flag allows you to always see your targets' buffs.");
|
|
||||||
c->SetEntityVariable(SEE_BUFFS_FLAG, "1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c->IsRaidGrouped()) {
|
|
||||||
Raid* raid = c->GetRaid();
|
|
||||||
if (raid) {
|
|
||||||
uint32 gid = raid->GetGroup(c);
|
|
||||||
if (gid < MAX_RAID_GROUPS && raid->GroupCount(gid) >= 3) {
|
|
||||||
if (raid->GetLeadershipAA(groupAAInspectBuffs, gid))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Group* group = c->GetGroup();
|
|
||||||
if (group && group->GroupCount() >= 3) {
|
|
||||||
if (group->GetLeadershipAA(groupAAInspectBuffs)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SendFullBuffRefresh(Mob* sender, bool remove = false, bool ackreq = true)
|
|
||||||
{
|
|
||||||
bool suspended = zone->BuffTimersSuspended();
|
|
||||||
std::vector<uint32_t> slots;
|
|
||||||
|
|
||||||
// first, send to self if self is client
|
|
||||||
if (sender->IsClient()) {
|
|
||||||
Client* c = sender->CastToClient();
|
|
||||||
FastQueuePacket(c, &IBuff::RefreshBuffs, GetClientComponent<IBuff>(c), OP_RefreshBuffs, sender, false, suspended, slots);
|
|
||||||
}
|
|
||||||
|
|
||||||
// next, send to owner if self is a pet to a client
|
|
||||||
if (sender->IsPet() && sender->GetOwner()->IsClient()) {
|
|
||||||
if (Mob* owner = sender->GetOwner(); owner != nullptr && owner->IsClient()) {
|
|
||||||
Client* c = owner->CastToClient();
|
|
||||||
FastQueuePacket(c, &IBuff::RefreshBuffs, GetClientComponent<IBuff>(c), OP_RefreshPetBuffs, sender, false, suspended, slots);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally send to all clients targeting the mob, will need to mutate the packet to set the type
|
|
||||||
auto mutate = [sender](std::unique_ptr<EQApplicationPacket>& packet, Client* c) {
|
|
||||||
GetClientComponent<IBuff>(c)->SetRefreshType(packet, sender, c);
|
|
||||||
};
|
|
||||||
|
|
||||||
QueueClientsByTarget(sender, ackreq, false, ShouldSendTargetBuffs, mutate)(
|
|
||||||
&IBuff::RefreshBuffs, GetClientComponent<IBuff>, OP_RefreshTargetBuffs, sender, false, suspended, slots);
|
|
||||||
|
|
||||||
// if we have remove set, this will clear any target windows that shouldn't see the buffs
|
|
||||||
if (remove)
|
|
||||||
QueueClientsByTarget(sender, ackreq, true,
|
|
||||||
[](Client* c) { return !ShouldSendTargetBuffs(c); }, mutate)(
|
|
||||||
&IBuff::RefreshBuffs, GetClientComponent<IBuff>, OP_RefreshTargetBuffs, sender, true, suspended, slots);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SendSingleBuffChange(Mob* sender, const Buffs_Struct& buff, int slot, bool remove = false, bool ackreq = true)
|
|
||||||
{
|
|
||||||
bool suspended = zone->BuffTimersSuspended();
|
|
||||||
std::vector slots = { static_cast<uint32_t>(slot) };
|
|
||||||
|
|
||||||
// first, send to self if self is client, which takes the definition and the refresh
|
|
||||||
if (sender->IsClient()) {
|
|
||||||
Client* c = sender->CastToClient();
|
|
||||||
// FastQueuePacket(c, &IBuff::BuffDefinition, GetClientComponent<IBuff>(c), sender, buff, slot, false);
|
|
||||||
// FastQueuePacket(c, &IBuff::RefreshBuffs, GetClientComponent<IBuff>(c), OP_RefreshBuffs, sender, remove, suspended, slots);
|
|
||||||
// FastQueuePacket(c, &IBuff::BuffDefinition, GetClientComponent<IBuff>(c), sender, buff, slot, remove);
|
|
||||||
// FastQueuePacket(c, &IBuff::RefreshBuffs, GetClientComponent<IBuff>(c), OP_RefreshBuffs, sender, remove, suspended, slots);
|
|
||||||
FastQueuePacket(c, &IBuff::RefreshBuffs, GetClientComponent<IBuff>(c), OP_RefreshBuffs, sender, remove, suspended, slots);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the rest of the buff packets do not take the definition, only the refresh
|
|
||||||
if (sender->IsPet() && sender->GetOwner()->IsClient()) {
|
|
||||||
if (Mob* owner = sender->GetOwner(); owner != nullptr && owner->IsClient()) {
|
|
||||||
Client* c = owner->CastToClient();
|
|
||||||
FastQueuePacket(c, &IBuff::RefreshBuffs, GetClientComponent<IBuff>(c), OP_RefreshPetBuffs, sender, remove, suspended, slots);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mutate = [sender](std::unique_ptr<EQApplicationPacket>& packet, Client* c) {
|
|
||||||
GetClientComponent<IBuff>(c)->SetRefreshType(packet, sender, c);
|
|
||||||
};
|
|
||||||
|
|
||||||
QueueClientsByTarget(sender, ackreq, false, ShouldSendTargetBuffs, mutate)(
|
|
||||||
&IBuff::RefreshBuffs, GetClientComponent<IBuff>, OP_RefreshTargetBuffs, sender, remove, suspended, slots);
|
|
||||||
|
|
||||||
// the client doesn't automatically do this for some reason, only send it to the sender
|
|
||||||
// if (remove && sender->IsClient())
|
|
||||||
// sender->CastToClient()->SendColoredText(Chat::Spells, spells[buff.spellid].spell_fades);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ClientPatch
|
} // namespace ClientPatch
|
||||||
|
|||||||
Reference in New Issue
Block a user