mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-06 00:32:25 +00:00
initial tie in of makebuffpacket to logic (still need to do buff definition work)
This commit is contained in:
parent
301eed2168
commit
05cb1921e8
@ -24,14 +24,16 @@ public:
|
||||
IBuff() = default;
|
||||
virtual ~IBuff() = default;
|
||||
|
||||
virtual std::unique_ptr<EQApplicationPacket> MakeLegacyBuffsPacket(Mob* mob, int32_t timer, bool for_target,
|
||||
// TODO: I think all of the legacy stuff can just be rolled into regular buff functions and the call sites modified
|
||||
virtual std::unique_ptr<EQApplicationPacket> MakeLegacyBuffsPacket(Mob* mob, bool for_target,
|
||||
bool clear_buffs) const = 0;
|
||||
virtual std::unique_ptr<EQApplicationPacket> LegacyBuffDefinition(Mob* mob, Buffs_Struct& buff, int slot) const = 0; // TODO: add the buffs definition packet
|
||||
|
||||
virtual std::unique_ptr<EQApplicationPacket> BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot,
|
||||
bool fade) const = 0;
|
||||
virtual std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, int32_t timer, bool remove,
|
||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const = 0;
|
||||
virtual void SetRefreshType(const 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;
|
||||
};
|
||||
|
||||
} // namespace Buff
|
||||
|
||||
@ -35,6 +35,8 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "zone/mob.h"
|
||||
|
||||
|
||||
namespace SoD
|
||||
{
|
||||
@ -4285,3 +4287,66 @@ namespace SoD
|
||||
return index; // as long as we guard against bad slots server side, we should be fine
|
||||
}
|
||||
} /*SoD*/
|
||||
|
||||
namespace Buff {
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> SoD::MakeLegacyBuffsPacket(Mob* mob, bool for_target, bool clear_buffs) const
|
||||
{
|
||||
// SoD only supports target refresh, not self refresh packets
|
||||
if (for_target) {
|
||||
uint32 count = 0;
|
||||
uint32 buff_count;
|
||||
|
||||
// for self we want all buffs, for target, we want to skip song window buffs
|
||||
// since NPCs and pets don't have a song window, we still see it for them :P
|
||||
if (for_target) {
|
||||
buff_count = (clear_buffs) ? 0 : mob->GetMaxBuffSlots();
|
||||
}
|
||||
else {
|
||||
buff_count = mob->GetMaxTotalSlots();
|
||||
}
|
||||
|
||||
Buffs_Struct* buffs = mob->GetBuffs();
|
||||
|
||||
for(int i = 0; i < buff_count; ++i) {
|
||||
if (buffs[i].spellid > 1) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_RefreshTargetBuffs,
|
||||
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();
|
||||
// there are more types, the client doesn't seem to really care though. The others are also currently hard to fill in here ...
|
||||
// (see comment in common/eq_packet_structs.h)
|
||||
if (for_target)
|
||||
buff->type = mob->IsClient() ? 5 : 7;
|
||||
else
|
||||
buff->type = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace Buff
|
||||
|
||||
@ -68,6 +68,9 @@ class SoD : public SoF
|
||||
public:
|
||||
SoD() = default;
|
||||
~SoD() override = default;
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> MakeLegacyBuffsPacket(Mob* mob, bool for_target,
|
||||
bool clear_buffs) const override;
|
||||
};
|
||||
|
||||
} // namespace Buff
|
||||
|
||||
@ -4019,58 +4019,40 @@ void Titanium::ResolveArguments(uint32_t id, std::array<const char*, 9>& args) c
|
||||
} // namespace Message
|
||||
|
||||
namespace Buff {
|
||||
std::unique_ptr<EQApplicationPacket> Titanium::MakeLegacyBuffsPacket(Mob* mob, int32_t timer, bool for_target,
|
||||
bool clear_buffs) const
|
||||
std::unique_ptr<EQApplicationPacket> Titanium::MakeLegacyBuffsPacket(Mob* mob, bool for_target, bool clear_buffs) const
|
||||
{
|
||||
uint32 count = 0;
|
||||
uint32 buff_count;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// for self we want all buffs, for target, we want to skip song window buffs
|
||||
// since NPCs and pets don't have a song window, we still see it for them :P
|
||||
if (for_target) {
|
||||
buff_count = (clear_buffs) ? 0 : mob->GetMaxBuffSlots();
|
||||
}
|
||||
else {
|
||||
buff_count = mob->GetMaxTotalSlots();
|
||||
}
|
||||
std::unique_ptr<EQApplicationPacket> Titanium::LegacyBuffDefinition(Mob* mob, Buffs_Struct& buff, int slot) const
|
||||
{
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_BuffDefinition, sizeof(SpellBuffPacket_Struct));
|
||||
SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer;
|
||||
|
||||
Buffs_Struct* buffs = mob->GetBuffs();
|
||||
sbf->entityid = mob->GetID();
|
||||
|
||||
for(int i = 0; i < buff_count; ++i) {
|
||||
if (buffs[i].spellid > 1) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
sbf->buff.effect_type = 2;
|
||||
|
||||
//Create it for a targeting window, else create it for a create buff packet.
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(for_target ? OP_RefreshTargetBuffs : OP_RefreshBuffs,
|
||||
sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count);
|
||||
sbf->buff.level = buff.casterlevel > 0 ? buff.casterlevel : mob->GetLevel();
|
||||
sbf->buff.bard_modifier = buff.instrument_mod;
|
||||
sbf->buff.spellid = buff.spellid;
|
||||
sbf->buff.duration = buff.ticsremaining;
|
||||
if (buff.dot_rune)
|
||||
sbf->buff.counters = buff.dot_rune;
|
||||
else if (buff.magic_rune)
|
||||
sbf->buff.counters = buff.magic_rune;
|
||||
else if (buff.melee_rune)
|
||||
sbf->buff.counters = buff.melee_rune;
|
||||
else if (buff.counters)
|
||||
sbf->buff.counters = buff.counters;
|
||||
sbf->buff.player_id = buff.casterid;
|
||||
sbf->buff.num_hits = buff.hit_number;
|
||||
sbf->buff.y = buff.caston_y;
|
||||
sbf->buff.x = buff.caston_x;
|
||||
sbf->buff.z = buff.caston_z;
|
||||
|
||||
BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer;
|
||||
buff->entity_id = mob->GetID();
|
||||
buff->count = count;
|
||||
buff->all_buffs = 1;
|
||||
buff->tic_timer = timer;
|
||||
// there are more types, the client doesn't seem to really care though. The others are also currently hard to fill in here ...
|
||||
// (see comment in common/eq_packet_structs.h)
|
||||
if (for_target)
|
||||
buff->type = mob->IsClient() ? 5 : 7;
|
||||
else
|
||||
buff->type = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
sbf->slotid = slot;
|
||||
sbf->bufffade = 0;
|
||||
|
||||
return outapp;
|
||||
}
|
||||
@ -4087,6 +4069,6 @@ std::unique_ptr<EQApplicationPacket> Titanium::RefreshBuffs(EmuOpcode opcode, Mo
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Titanium::SetRefreshType(const std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const {}
|
||||
void Titanium::SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const {}
|
||||
|
||||
} // namespace Buff
|
||||
|
||||
@ -85,14 +85,15 @@ public:
|
||||
Titanium() = default;
|
||||
~Titanium() override = default;
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> MakeLegacyBuffsPacket(Mob* mob, int32_t timer, bool for_target,
|
||||
std::unique_ptr<EQApplicationPacket> MakeLegacyBuffsPacket(Mob* mob, bool for_target,
|
||||
bool clear_buffs) const override;
|
||||
std::unique_ptr<EQApplicationPacket> LegacyBuffDefinition(Mob* mob, Buffs_Struct& buff, int slot) const override;
|
||||
|
||||
std::unique_ptr<EQApplicationPacket>
|
||||
BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, bool fade) const override;
|
||||
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, int32_t timer, bool remove,
|
||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const override;
|
||||
void SetRefreshType(const std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const override;
|
||||
void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const override;
|
||||
};
|
||||
|
||||
} // namespace Buff
|
||||
|
||||
@ -5613,8 +5613,7 @@ std::unique_ptr<EQApplicationPacket> TOB::InterruptSpellOther(Mob* sender, uint3
|
||||
} // namespace Message
|
||||
|
||||
namespace Buff {
|
||||
std::unique_ptr<EQApplicationPacket> TOB::MakeLegacyBuffsPacket(Mob* mob, int32_t timer, bool for_target,
|
||||
bool clear_buffs) const { return nullptr; }
|
||||
// std::unique_ptr<EQApplicationPacket> TOB::MakeLegacyBuffsPacket(Mob* mob, bool for_target, bool clear_buffs) const { return nullptr; }
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> TOB::BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, bool fade) const
|
||||
{
|
||||
@ -5712,7 +5711,7 @@ std::unique_ptr<EQApplicationPacket> TOB::RefreshBuffs(EmuOpcode opcode, Mob* mo
|
||||
}
|
||||
|
||||
// 0 = self buff window, 1 = self target window, 2 = pet buff or target window, 4 = group, 5 = PC, 7 = NPC
|
||||
void TOB::SetRefreshType(const std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const
|
||||
void TOB::SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const
|
||||
{
|
||||
unsigned char* type = &packet->pBuffer[packet->size - 2];
|
||||
|
||||
|
||||
@ -65,14 +65,14 @@ public:
|
||||
TOB() = default;
|
||||
~TOB() override = default;
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> MakeLegacyBuffsPacket(Mob* mob, int32_t timer, bool for_target,
|
||||
bool clear_buffs) const override;
|
||||
// std::unique_ptr<EQApplicationPacket> MakeLegacyBuffsPacket(Mob* mob, bool for_target,
|
||||
// bool clear_buffs) const override;
|
||||
|
||||
std::unique_ptr<EQApplicationPacket>
|
||||
BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, bool fade) const override;
|
||||
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, int32_t timer, bool remove,
|
||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const override;
|
||||
void SetRefreshType(const std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const override;
|
||||
void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const override;
|
||||
};
|
||||
|
||||
} // namespace Buff
|
||||
|
||||
@ -38,6 +38,8 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "zone/mob.h"
|
||||
|
||||
|
||||
namespace UF
|
||||
{
|
||||
@ -5234,3 +5236,64 @@ namespace UF
|
||||
return index; // as long as we guard against bad slots server side, we should be fine
|
||||
}
|
||||
} /*UF*/
|
||||
|
||||
namespace Buff {
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> UF::MakeLegacyBuffsPacket(Mob* mob, bool for_target, bool clear_buffs) const
|
||||
{
|
||||
// UF introduced the self update buff packet
|
||||
|
||||
uint32 count = 0;
|
||||
uint32 buff_count;
|
||||
|
||||
// for self we want all buffs, for target, we want to skip song window buffs
|
||||
// since NPCs and pets don't have a song window, we still see it for them :P
|
||||
if (for_target) {
|
||||
buff_count = (clear_buffs) ? 0 : mob->GetMaxBuffSlots();
|
||||
}
|
||||
else {
|
||||
buff_count = mob->GetMaxTotalSlots();
|
||||
}
|
||||
|
||||
Buffs_Struct* buffs = mob->GetBuffs();
|
||||
|
||||
for(int i = 0; i < buff_count; ++i) {
|
||||
if (buffs[i].spellid > 1) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
//Create it for a targeting window, else create it for a create buff packet.
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(for_target ? OP_RefreshTargetBuffs : OP_RefreshBuffs,
|
||||
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();
|
||||
// there are more types, the client doesn't seem to really care though. The others are also currently hard to fill in here ...
|
||||
// (see comment in common/eq_packet_structs.h)
|
||||
if (for_target)
|
||||
buff->type = mob->IsClient() ? 5 : 7;
|
||||
else
|
||||
buff->type = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace Buff
|
||||
|
||||
@ -68,6 +68,9 @@ class UF : public SoD
|
||||
public:
|
||||
UF() = default;
|
||||
~UF() override = default;
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> MakeLegacyBuffsPacket(Mob* mob, bool for_target,
|
||||
bool clear_buffs) const override;
|
||||
};
|
||||
|
||||
} // namespace Buff
|
||||
|
||||
@ -61,6 +61,8 @@
|
||||
#include <numbers>
|
||||
#include <set>
|
||||
|
||||
#include "client_version.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
extern Zone* zone;
|
||||
extern volatile bool is_zone_loaded;
|
||||
@ -933,10 +935,8 @@ void Client::CompleteConnect()
|
||||
delete pack;
|
||||
}
|
||||
|
||||
if (IsClient() && CastToClient()->ClientVersionBit() & EQ::versions::maskUFAndLater) {
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket(false);
|
||||
CastToClient()->FastQueuePacket(&outapp);
|
||||
}
|
||||
if (IsClient())
|
||||
Buff::SendLegacyBuffsPacket(CastToClient(), this, false);
|
||||
|
||||
// TODO: load these states
|
||||
// We at least will set them to the correct state for now
|
||||
@ -15108,30 +15108,7 @@ void Client::Handle_OP_TargetMouse(const EQApplicationPacket *app)
|
||||
if (nt)
|
||||
{
|
||||
SetTarget(nt);
|
||||
bool inspect_buffs = false;
|
||||
// rank 1 gives you ability to see NPC buffs in target window (SoD+)
|
||||
if (nt->IsNPC()) {
|
||||
if (IsRaidGrouped()) {
|
||||
Raid *raid = GetRaid();
|
||||
if (raid) {
|
||||
uint32 gid = raid->GetGroup(this);
|
||||
if (gid < 12 && raid->GroupCount(gid) > 2)
|
||||
inspect_buffs = raid->GetLeadershipAA(groupAAInspectBuffs, gid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Group *group = GetGroup();
|
||||
if (group && group->GroupCount() > 2)
|
||||
inspect_buffs = group->GetLeadershipAA(groupAAInspectBuffs);
|
||||
}
|
||||
}
|
||||
if (GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs) || nt == this || inspect_buffs || (nt->IsClient() && !nt->CastToClient()->GetPVP()) ||
|
||||
(nt->IsPet() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()) ||
|
||||
(nt->IsBot() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()) || // TODO: bot pets
|
||||
(nt->IsMerc() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()))
|
||||
{
|
||||
nt->SendBuffsToClient(this);
|
||||
}
|
||||
Buff::SendLegacyBuffsPacket(this, nt);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -45,6 +45,8 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "client_version.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
extern Zone* zone;
|
||||
extern volatile bool is_zone_loaded;
|
||||
@ -2307,11 +2309,8 @@ void Client::ClearHover()
|
||||
entity_list.QueueClients(this, outapp, false);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (IsClient() && CastToClient()->ClientVersionBit() & EQ::versions::maskUFAndLater)
|
||||
{
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket(false);
|
||||
CastToClient()->FastQueuePacket(&outapp);
|
||||
}
|
||||
if (IsClient())
|
||||
Buff::SendLegacyBuffsPacket(CastToClient(), this, false);
|
||||
|
||||
dead = false;
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ namespace ClientPatch {
|
||||
|
||||
using ClientList = std::unordered_map<uint16, Client*>;
|
||||
template<typename Obj> using ComponentGetter = std::function<Obj*(const Client*)>;
|
||||
using SendPredicate = std::function<bool(Client*)>;
|
||||
|
||||
template <typename Fun, typename Obj, typename... Args>
|
||||
requires std::is_member_function_pointer_v<Fun>
|
||||
@ -37,9 +38,8 @@ static auto QueueClients(Mob* sender, bool ignore_sender = false, bool ackreq =
|
||||
requires std::is_member_function_pointer_v<Fun>
|
||||
{
|
||||
std::array<std::unique_ptr<EQApplicationPacket>, EQ::versions::ClientVersionCount> build_packets;
|
||||
std::unordered_map<uint16, Client*> client_list = entity_list.GetClientList();
|
||||
|
||||
for (auto [_, ent] : client_list) {
|
||||
for (auto [_, ent] : entity_list.GetClientList()) {
|
||||
if (!ignore_sender || ent != sender) {
|
||||
auto& packet = build_packets.at(static_cast<uint32_t>(ent->ClientVersion()));
|
||||
if (!packet)
|
||||
@ -106,66 +106,25 @@ static void FastQueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args)
|
||||
}
|
||||
}
|
||||
|
||||
static auto QueueClientsByTarget(Mob* sender, bool iSendToSender, Mob* SkipThisMob, bool ackreq, bool HoTT,
|
||||
uint32 ClientVersionBits, bool inspect_buffs, bool clear_target_window)
|
||||
static auto QueueClientsByTarget(Mob* sender, bool ackreq, bool HoTT, const SendPredicate& ShouldSend)
|
||||
{
|
||||
return [=]<typename Fun, typename Obj, typename... Args>(Fun fun, const ComponentGetter<Obj> component, Args&&... args)
|
||||
requires std::is_member_function_pointer_v<Fun>
|
||||
{
|
||||
std::unordered_map<EQ::versions::ClientVersion, EQApplicationPacket*> build_packets;
|
||||
std::unordered_map<uint16, Client*> client_list = entity_list.GetClientList();
|
||||
if (sender != nullptr) {
|
||||
std::array<std::unique_ptr<EQApplicationPacket>, EQ::versions::ClientVersionCount> build_packets;
|
||||
|
||||
for (auto [_, c] : client_list) {
|
||||
if (c != SkipThisMob && (iSendToSender || c != sender)) {
|
||||
Mob* Target = c->GetTarget();
|
||||
if (Target != nullptr) {
|
||||
// if (Target == sender || (iSendToSender && c == sender) || (HoTT && Target->GetTarget() == sender)) {
|
||||
// // the client has the sender targeted, so check if we send the packet
|
||||
// EQApplicationPacket* app = std::invoke(fun, component_getter(c), std::forward<Args>(args)...);
|
||||
// }
|
||||
Mob* TargetsTarget = Target->GetTarget();
|
||||
bool Send = iSendToSender && c == sender;
|
||||
if (c != sender) {
|
||||
if (Target == sender) {
|
||||
if (inspect_buffs) { // if inspect_buffs is true we're sending a mob's buffs to those with the LAA
|
||||
Send = clear_target_window;
|
||||
if (c->GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs)) {
|
||||
if (c->GetGM()) {
|
||||
if (!c->EntityVariableExists(SEE_BUFFS_FLAG)) {
|
||||
c->Message(Chat::White,
|
||||
"Your GM flag allows you to always see your targets' buffs.");
|
||||
c->SetEntityVariable(SEE_BUFFS_FLAG, "1");
|
||||
}
|
||||
}
|
||||
for (auto [_, c] : entity_list.GetClientList()) {
|
||||
if (c != sender) {
|
||||
Mob* Target = c->GetTarget();
|
||||
if ((Target == sender || (HoTT && Target != nullptr && Target->GetTarget() == sender)) && ShouldSend(c)) {
|
||||
auto& packet = build_packets.at(static_cast<uint32_t>(c->ClientVersion()));
|
||||
if (!packet)
|
||||
if (auto comp = component(c); comp != nullptr)
|
||||
packet = std::invoke(fun, comp, std::forward<Args>(args)...);
|
||||
|
||||
Send = !clear_target_window;
|
||||
} else 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))
|
||||
Send = !clear_target_window;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Group* group = c->GetGroup();
|
||||
if (group && group->GroupCount() >= 3) {
|
||||
if (group->GetLeadershipAA(groupAAInspectBuffs)) {
|
||||
Send = !clear_target_window;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Send = true;
|
||||
}
|
||||
} else if (HoTT && TargetsTarget == sender) {
|
||||
Send = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Send && (c->ClientVersionBit() & ClientVersionBits)) {
|
||||
EQApplicationPacket* app = std::invoke(fun, component(c), std::forward<Args>(args)...);
|
||||
if (packet)
|
||||
c->QueuePacket(packet.get(), ackreq, Client::CLIENT_CONNECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -238,14 +197,58 @@ static std::function GetComponent = [](const Client* c) -> IBuff* {
|
||||
return GetBuffComponent(c->GetClientVersion()).get();
|
||||
};
|
||||
|
||||
inline void SendLegacyBuffsPacket(Client* c, Mob* sender, int32 timer, bool for_target = true, bool clear_buffs = false)
|
||||
static bool ShouldSendTargetBuffs(Client* c)
|
||||
{
|
||||
ClientPatch::FastQueuePacket(c, &IBuff::MakeLegacyBuffsPacket, GetComponent(c), sender, timer, for_target, clear_buffs);
|
||||
// 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)) {
|
||||
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 SendLegacyBuffsPacketToClients(Client* c, bool for_target = true, bool clear_buffs = false)
|
||||
inline void SendLegacyBuffsPacket(Client* c, Mob* sender, bool for_target = true, bool clear_buffs = false)
|
||||
{
|
||||
ClientPatch::FastQueuePacket(c, &IBuff::MakeLegacyBuffsPacket, GetComponent(c), sender, for_target, clear_buffs);
|
||||
}
|
||||
|
||||
inline void SendLegacyBuffsPacketToClients(Mob* sender, bool ackreq = true, bool HoTT = false, bool clear_buffs = false)
|
||||
{
|
||||
ClientPatch::QueueClientsByTarget(sender, ackreq, HoTT, ShouldSendTargetBuffs)(
|
||||
&IBuff::MakeLegacyBuffsPacket, GetComponent, sender, true, clear_buffs);
|
||||
}
|
||||
|
||||
inline void SendCharmDroppedBuffsPacket(Mob* sender, bool ackreq = true)
|
||||
{
|
||||
// dropping charm means that we want to remove the buff list from clients that shouldn't see non-pet buffs
|
||||
ClientPatch::QueueClientsByTarget(sender, ackreq, false, [](Client* c) { return !ShouldSendTargetBuffs(c); })(
|
||||
&IBuff::MakeLegacyBuffsPacket, GetComponent, sender, true, true);
|
||||
}
|
||||
|
||||
} // namespace Buff
|
||||
|
||||
@ -472,8 +472,6 @@ public:
|
||||
virtual uint32 GetLastBuffSlot(bool disc, bool song);
|
||||
virtual void InitializeBuffSlots() { buffs = nullptr; }
|
||||
virtual void UninitializeBuffSlots() { }
|
||||
EQApplicationPacket *MakeBuffsPacket(bool for_target = true, bool clear_buffs = false);
|
||||
void SendBuffsToClient(Client *c);
|
||||
inline Buffs_Struct* GetBuffs() { return buffs; }
|
||||
void DoGravityEffect();
|
||||
void DamageShield(Mob* other, bool spell_ds = false);
|
||||
@ -1303,7 +1301,6 @@ public:
|
||||
virtual int32 CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc = false);
|
||||
virtual int32 CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possible = 0);
|
||||
|
||||
//uint32 GetInstrumentMod(uint16 spell_id) const;
|
||||
uint32 GetInstrumentMod(uint16 spell_id);
|
||||
int64 CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0,uint16 casterid=0);
|
||||
int64 CalcSpellEffectValue_formula(uint32 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining = 0);
|
||||
@ -1368,6 +1365,7 @@ public:
|
||||
Timer* GetAIMovementTimer() { return AI_movement_timer.get(); }
|
||||
Timer GetAttackTimer() { return attack_timer; }
|
||||
Timer GetAttackDWTimer() { return attack_dw_timer; }
|
||||
uint32 GetRemainingTicTime() const { return tic_timer.GetRemainingTime(); }
|
||||
inline bool IsFindable() { return findable; }
|
||||
inline uint8 GetManaPercent() { return (uint8)((float)current_mana / (float)max_mana * 100.0f); }
|
||||
virtual uint8 GetEndurancePercent() { return 0; }
|
||||
|
||||
@ -33,6 +33,8 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "client_version.h"
|
||||
|
||||
|
||||
extern Zone* zone;
|
||||
extern volatile bool is_zone_loaded;
|
||||
@ -150,11 +152,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
if (spells[spell_id].endurance_upkeep > 0)
|
||||
SetEndurUpkeep(true);
|
||||
|
||||
if (IsClient() && CastToClient()->ClientVersionBit() & EQ::versions::maskUFAndLater)
|
||||
{
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket(false);
|
||||
CastToClient()->FastQueuePacket(&outapp);
|
||||
}
|
||||
if (IsClient())
|
||||
Buff::SendLegacyBuffsPacket(CastToClient(), this, false);
|
||||
}
|
||||
|
||||
if (IsClient()) {
|
||||
@ -813,9 +812,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
|
||||
// This was done in AddBuff, but we were not a pet yet, so
|
||||
// the target windows didn't get updated.
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket();
|
||||
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQ::versions::maskSoDAndLater);
|
||||
safe_delete(outapp);
|
||||
Buff::SendLegacyBuffsPacketToClients(this);
|
||||
|
||||
if(caster->IsClient()){
|
||||
auto app = new EQApplicationPacket(OP_Charm, sizeof(Charm_Struct));
|
||||
@ -4435,9 +4432,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
||||
// no longer see the buffs on the old pet.
|
||||
// QueueClientsByTarget preserves GM and leadership cases.
|
||||
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket(true, true);
|
||||
|
||||
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQ::versions::maskSoDAndLater, true, true);
|
||||
Buff::SendCharmDroppedBuffsPacket(this);
|
||||
|
||||
if (IsAIControlled())
|
||||
{
|
||||
@ -4664,32 +4659,14 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
||||
if(IsPet() && GetOwner() && GetOwner()->IsClient()) {
|
||||
SendPetBuffsToClient();
|
||||
}
|
||||
if((IsClient() && !CastToClient()->GetPVP()) ||
|
||||
(IsPet() && GetOwner() && GetOwner()->IsClient() && !GetOwner()->CastToClient()->GetPVP()) ||
|
||||
(IsBot() && GetOwner() && GetOwner()->IsClient() && !GetOwner()->CastToClient()->GetPVP()) ||
|
||||
(IsMerc() && GetOwner() && GetOwner()->IsClient() && !GetOwner()->CastToClient()->GetPVP()))
|
||||
{
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket();
|
||||
|
||||
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQ::versions::maskSoDAndLater);
|
||||
if(IsClient() && GetTarget() == this) {
|
||||
CastToClient()->QueuePacket(outapp);
|
||||
}
|
||||
Buff::SendLegacyBuffsPacketToClients(this);
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
if (IsClient() && GetTarget() == this)
|
||||
Buff::SendLegacyBuffsPacket(CastToClient(), this);
|
||||
|
||||
if (IsNPC()) {
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket();
|
||||
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQ::versions::maskSoDAndLater, true);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
if (IsClient() && CastToClient()->ClientVersionBit() & EQ::versions::maskUFAndLater)
|
||||
{
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket(false);
|
||||
CastToClient()->FastQueuePacket(&outapp);
|
||||
}
|
||||
if (IsClient())
|
||||
Buff::SendLegacyBuffsPacket(CastToClient(), this, false);
|
||||
|
||||
// we will eventually call CalcBonuses() even if we skip it right here, so should correct itself if we still have them
|
||||
degenerating_effects = false;
|
||||
|
||||
@ -3744,26 +3744,10 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
||||
if (IsPet() && GetOwner() && GetOwner()->IsClient())
|
||||
SendPetBuffsToClient();
|
||||
|
||||
if((IsClient() && !CastToClient()->GetPVP()) ||
|
||||
(IsPet() && GetOwner() && GetOwner()->IsClient() && !GetOwner()->CastToClient()->GetPVP()) ||
|
||||
(IsBot() && GetOwner() && GetOwner()->IsClient() && !GetOwner()->CastToClient()->GetPVP()) ||
|
||||
(IsMerc() && GetOwner() && GetOwner()->IsClient() && !GetOwner()->CastToClient()->GetPVP()))
|
||||
{
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket();
|
||||
Buff::SendLegacyBuffsPacketToClients(this);
|
||||
|
||||
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQ::versions::maskSoDAndLater);
|
||||
|
||||
if(IsClient() && GetTarget() == this)
|
||||
CastToClient()->QueuePacket(outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
if (IsNPC()) {
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket();
|
||||
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQ::versions::maskSoDAndLater, true);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
if (IsClient() && GetTarget() == this)
|
||||
Buff::SendLegacyBuffsPacket(CastToClient(), this);
|
||||
|
||||
// recalculate bonuses since we stripped/added buffs
|
||||
CalcBonuses();
|
||||
@ -6615,76 +6599,6 @@ void Mob::SendPetBuffsToClient()
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Mob::SendBuffsToClient(Client *c)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
|
||||
if (c->ClientVersionBit() & EQ::versions::maskSoDAndLater)
|
||||
{
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket();
|
||||
c->FastQueuePacket(&outapp);
|
||||
}
|
||||
}
|
||||
|
||||
EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target, bool clear_buffs)
|
||||
{
|
||||
uint32 count = 0;
|
||||
uint32 buff_count;
|
||||
|
||||
// for self we want all buffs, for target, we want to skip song window buffs
|
||||
// since NPCs and pets don't have a song window, we still see it for them :P
|
||||
if (for_target) {
|
||||
buff_count = (clear_buffs) ? 0 : GetMaxBuffSlots();
|
||||
}
|
||||
else {
|
||||
buff_count = GetMaxTotalSlots();
|
||||
}
|
||||
|
||||
for(int i = 0; i < buff_count; ++i) {
|
||||
if (IsValidSpell(buffs[i].spellid)) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
EQApplicationPacket* outapp = nullptr;
|
||||
|
||||
//Create it for a targeting window, else create it for a create buff packet.
|
||||
if(for_target) {
|
||||
outapp = new EQApplicationPacket(OP_RefreshTargetBuffs, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count);
|
||||
}
|
||||
else {
|
||||
outapp = new EQApplicationPacket(OP_RefreshBuffs, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count);
|
||||
}
|
||||
BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer;
|
||||
buff->entity_id = GetID();
|
||||
buff->count = count;
|
||||
buff->all_buffs = 1;
|
||||
buff->tic_timer = tic_timer.GetRemainingTime();
|
||||
// there are more types, the client doesn't seem to really care though. The others are also currently hard to fill in here ...
|
||||
// (see comment in common/eq_packet_structs.h)
|
||||
if (for_target)
|
||||
buff->type = IsClient() ? 5 : 7;
|
||||
else
|
||||
buff->type = 0;
|
||||
|
||||
buff->name_lengths = 0; // hacky shit
|
||||
uint32 index = 0;
|
||||
for(int i = 0; i < buff_count; ++i) {
|
||||
if (IsValidSpell(buffs[i].spellid)) {
|
||||
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;
|
||||
}
|
||||
|
||||
void Mob::BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration)
|
||||
{
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user