From d16c1b2483aa320e642266f15e5b2a63e614f8f6 Mon Sep 17 00:00:00 2001 From: dannuic Date: Mon, 27 Apr 2026 17:52:45 -0600 Subject: [PATCH] Removed any 'legacy' functions from the new code --- common/patches/IBuff.h | 7 +-- common/patches/sod.cpp | 43 ++++++++++------- common/patches/sod.h | 5 +- common/patches/titanium.cpp | 17 ++----- common/patches/titanium.h | 10 ++-- common/patches/tob.cpp | 33 ++++++------- common/patches/tob.h | 5 +- common/patches/uf.cpp | 20 ++------ common/patches/uf.h | 4 +- zone/client_packet.cpp | 5 +- zone/client_process.cpp | 3 +- zone/client_version.h | 92 +++++++++++++++++++++++++++---------- zone/spell_effects.cpp | 20 ++------ zone/spells.cpp | 9 +--- 14 files changed, 141 insertions(+), 132 deletions(-) diff --git a/common/patches/IBuff.h b/common/patches/IBuff.h index adab437df..da2d9cdbc 100644 --- a/common/patches/IBuff.h +++ b/common/patches/IBuff.h @@ -24,14 +24,9 @@ public: IBuff() = default; virtual ~IBuff() = default; - // 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 MakeLegacyBuffsPacket(Mob* mob, bool for_target, - bool clear_buffs) const = 0; - virtual std::unique_ptr LegacyBuffDefinition(Mob* mob, Buffs_Struct& buff, int slot) const = 0; // TODO: add the buffs definition packet - virtual std::unique_ptr BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, bool fade) const = 0; - virtual std::unique_ptr RefreshBuffs(EmuOpcode opcode, Mob* mob, int32_t timer, bool remove, + virtual std::unique_ptr RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove, bool buff_timers_suspended, const std::vector& slots) const = 0; virtual void SetRefreshType(std::unique_ptr& packet, Mob* source, Client* target) const = 0; }; diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index e2cbf8f11..d18e664c4 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -35,6 +35,7 @@ #include #include +#include "zone/client.h" #include "zone/mob.h" @@ -4290,21 +4291,15 @@ namespace SoD namespace Buff { -std::unique_ptr SoD::MakeLegacyBuffsPacket(Mob* mob, bool for_target, bool clear_buffs) const +std::unique_ptr SoD::RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove, + bool buff_timers_suspended, const std::vector& slots) const { // SoD only supports target refresh, not self refresh packets - if (for_target) { + if (opcode == OP_RefreshTargetBuffs) { 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(); - } + buff_count = mob->GetMaxTotalSlots(); Buffs_Struct* buffs = mob->GetBuffs(); @@ -4314,7 +4309,7 @@ std::unique_ptr SoD::MakeLegacyBuffsPacket(Mob* mob, bool f } } - auto outapp = std::make_unique(OP_RefreshTargetBuffs, + auto outapp = std::make_unique(opcode, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count); BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer; @@ -4322,12 +4317,8 @@ std::unique_ptr SoD::MakeLegacyBuffsPacket(Mob* mob, bool f 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; + // (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; @@ -4349,4 +4340,22 @@ std::unique_ptr SoD::MakeLegacyBuffsPacket(Mob* mob, bool f return nullptr; } +// 0 = self buff window, 1 = self target window, 2 = pet buff or target window, 4 = group, 5 = PC, 7 = NPC +void SoD::SetRefreshType(std::unique_ptr& packet, Mob* source, Client* target) const +{ + if (packet) { + BuffIcon_Struct *buff = (BuffIcon_Struct*)packet->pBuffer; + if (target->GetID() == source->GetID()) + buff->type = 1; + else if (target->IsPet()) + buff->type = 2; + else if (target->HasGroup() && source->GetGroup() == target->GetGroup()) + buff->type = 4; + else if (target->IsClient()) + buff->type = 5; + else + buff->type = 7; + } +} + } // namespace Buff diff --git a/common/patches/sod.h b/common/patches/sod.h index cc4a31b7a..f9b4f3f89 100644 --- a/common/patches/sod.h +++ b/common/patches/sod.h @@ -69,8 +69,9 @@ public: SoD() = default; ~SoD() override = default; - std::unique_ptr MakeLegacyBuffsPacket(Mob* mob, bool for_target, - bool clear_buffs) const override; + std::unique_ptr RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove, + bool buff_timers_suspended, const std::vector& slots) const override; + void SetRefreshType(std::unique_ptr& packet, Mob* source, Client* target) const override; }; } // namespace Buff diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index 35d907e5f..509b7e64c 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -4019,12 +4019,9 @@ void Titanium::ResolveArguments(uint32_t id, std::array& args) c } // namespace Message namespace Buff { -std::unique_ptr Titanium::MakeLegacyBuffsPacket(Mob* mob, bool for_target, bool clear_buffs) const -{ - return nullptr; -} -std::unique_ptr Titanium::LegacyBuffDefinition(Mob* mob, Buffs_Struct& buff, int slot) const +std::unique_ptr Titanium::BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, + bool fade) const { auto outapp = std::make_unique(OP_BuffDefinition, sizeof(SpellBuffPacket_Struct)); SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer; @@ -4052,18 +4049,12 @@ std::unique_ptr Titanium::LegacyBuffDefinition(Mob* mob, Bu sbf->buff.z = buff.caston_z; sbf->slotid = slot; - sbf->bufffade = 0; + sbf->bufffade = fade; return outapp; } -std::unique_ptr Titanium::BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, - bool fade) const -{ - return nullptr; -} - -std::unique_ptr Titanium::RefreshBuffs(EmuOpcode opcode, Mob* mob, int32_t timer, bool remove, +std::unique_ptr Titanium::RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove, bool buff_timers_suspended, const std::vector& slots) const { return nullptr; diff --git a/common/patches/titanium.h b/common/patches/titanium.h index 3e5439a04..8b9ec5ed4 100644 --- a/common/patches/titanium.h +++ b/common/patches/titanium.h @@ -85,13 +85,9 @@ public: Titanium() = default; ~Titanium() override = default; - std::unique_ptr MakeLegacyBuffsPacket(Mob* mob, bool for_target, - bool clear_buffs) const override; - std::unique_ptr LegacyBuffDefinition(Mob* mob, Buffs_Struct& buff, int slot) const override; - - std::unique_ptr - BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, bool fade) const override; - std::unique_ptr RefreshBuffs(EmuOpcode opcode, Mob* mob, int32_t timer, bool remove, + std::unique_ptr BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, + bool fade) const override; + std::unique_ptr RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove, bool buff_timers_suspended, const std::vector& slots) const override; void SetRefreshType(std::unique_ptr& packet, Mob* source, Client* target) const override; }; diff --git a/common/patches/tob.cpp b/common/patches/tob.cpp index 8a8c2e4a5..fc49947e6 100644 --- a/common/patches/tob.cpp +++ b/common/patches/tob.cpp @@ -5613,7 +5613,6 @@ std::unique_ptr TOB::InterruptSpellOther(Mob* sender, uint3 } // namespace Message namespace Buff { -// std::unique_ptr TOB::MakeLegacyBuffsPacket(Mob* mob, bool for_target, bool clear_buffs) const { return nullptr; } std::unique_ptr TOB::BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, bool fade) const { @@ -5641,7 +5640,7 @@ std::unique_ptr TOB::BuffDefinition(Mob* mob, const Buffs_S affect->affect.flags = 0; affect->affect.spell_id = buff.spellid; affect->affect.duration = buff.ticsremaining; - affect->affect.initial_duration = buff.ticsremaining; // this isn't correct, it's the total duration + affect->affect.initial_duration = buff.ticsremaining; // TODO: this isn't correct, it's the total duration affect->affect.hit_count = buff.hit_number; affect->affect.viral_timer = 0; affect->affect.modifier = static_cast(buff.instrument_mod) / 10.f; @@ -5667,7 +5666,7 @@ std::unique_ptr TOB::BuffDefinition(Mob* mob, const Buffs_S return packet; } -std::unique_ptr TOB::RefreshBuffs(EmuOpcode opcode, Mob* mob, int32_t timer, bool remove, +std::unique_ptr TOB::RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove, bool buff_timers_suspended, const std::vector& slots) const { Buffs_Struct* buffs = mob->GetBuffs(); @@ -5692,8 +5691,8 @@ std::unique_ptr TOB::RefreshBuffs(EmuOpcode opcode, Mob* mo SerializeBuffer buffer(buffer_size); buffer.WriteUInt32(mob->GetID()); - buffer.WriteInt32(timer); - buffer.WriteUInt8(slots.empty() ? 1 : 0); // 1 indicates all buffs on the player (0 to add or remove a single buff) + buffer.WriteInt32(mob->GetRemainingTicTime()); + buffer.WriteUInt8(slots.empty() ? 1 : 0); // 1 indicates all buffs on the mob (0 to add or remove a single buff) buffer.WriteUInt16(send_slots.size()); for (uint32_t slot : send_slots) { @@ -5713,18 +5712,20 @@ std::unique_ptr 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(std::unique_ptr& packet, Mob* source, Client* target) const { - unsigned char* type = &packet->pBuffer[packet->size - 2]; + if (packet) { + unsigned char* type = &packet->pBuffer[packet->size - 2]; - if (target->GetID() == source->GetID()) - *type = 1; - else if (target->IsPet()) - *type = 2; - else if (target->HasGroup() && source->GetGroup() == target->GetGroup()) - *type = 4; - else if (target->IsClient()) - *type = 5; - else - *type = 7; + if (target->GetID() == source->GetID()) + *type = 1; + else if (target->IsPet()) + *type = 2; + else if (target->HasGroup() && source->GetGroup() == target->GetGroup()) + *type = 4; + else if (target->IsClient()) + *type = 5; + else + *type = 7; + } } } // namespace Buff diff --git a/common/patches/tob.h b/common/patches/tob.h index c90dc122e..19129815a 100644 --- a/common/patches/tob.h +++ b/common/patches/tob.h @@ -65,12 +65,9 @@ public: TOB() = default; ~TOB() override = default; - // std::unique_ptr MakeLegacyBuffsPacket(Mob* mob, bool for_target, - // bool clear_buffs) const override; - std::unique_ptr BuffDefinition(Mob* mob, const Buffs_Struct& buff, int slot, bool fade) const override; - std::unique_ptr RefreshBuffs(EmuOpcode opcode, Mob* mob, int32_t timer, bool remove, + std::unique_ptr RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove, bool buff_timers_suspended, const std::vector& slots) const override; void SetRefreshType(std::unique_ptr& packet, Mob* source, Client* target) const override; }; diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 1599b02eb..5fe20c8a0 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -5239,21 +5239,15 @@ namespace UF namespace Buff { -std::unique_ptr UF::MakeLegacyBuffsPacket(Mob* mob, bool for_target, bool clear_buffs) const +std::unique_ptr UF::RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove, + bool buff_timers_suspended, const std::vector& slots) 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(); - } + buff_count = mob->GetMaxTotalSlots(); Buffs_Struct* buffs = mob->GetBuffs(); @@ -5264,7 +5258,7 @@ std::unique_ptr UF::MakeLegacyBuffsPacket(Mob* mob, bool fo } //Create it for a targeting window, else create it for a create buff packet. - auto outapp = std::make_unique(for_target ? OP_RefreshTargetBuffs : OP_RefreshBuffs, + auto outapp = std::make_unique(opcode, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count); BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer; @@ -5272,12 +5266,8 @@ std::unique_ptr UF::MakeLegacyBuffsPacket(Mob* mob, bool fo 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->type = mob->IsClient() ? 5 : 7; buff->name_lengths = 0; // hacky shit uint32 index = 0; diff --git a/common/patches/uf.h b/common/patches/uf.h index 5332f2ff3..9c0eb7a1c 100644 --- a/common/patches/uf.h +++ b/common/patches/uf.h @@ -69,8 +69,8 @@ public: UF() = default; ~UF() override = default; - std::unique_ptr MakeLegacyBuffsPacket(Mob* mob, bool for_target, - bool clear_buffs) const override; + std::unique_ptr RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove, + bool buff_timers_suspended, const std::vector& slots) const override; }; } // namespace Buff diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 16643fd7f..c20856598 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -935,8 +935,7 @@ void Client::CompleteConnect() delete pack; } - if (IsClient()) - Buff::SendLegacyBuffsPacket(CastToClient(), this, false); + Buff::SendFullBuffRefresh(this); // TODO: load these states // We at least will set them to the correct state for now @@ -15108,7 +15107,7 @@ void Client::Handle_OP_TargetMouse(const EQApplicationPacket *app) if (nt) { SetTarget(nt); - Buff::SendLegacyBuffsPacket(this, nt); + Buff::SendFullBuffRefresh(nt); } else { diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 5db30f9ad..953ebdcde 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -2309,8 +2309,7 @@ void Client::ClearHover() entity_list.QueueClients(this, outapp, false); safe_delete(outapp); - if (IsClient()) - Buff::SendLegacyBuffsPacket(CastToClient(), this, false); + Buff::SendFullBuffRefresh(this); dead = false; } diff --git a/zone/client_version.h b/zone/client_version.h index e9ea3eb7f..28a4af480 100644 --- a/zone/client_version.h +++ b/zone/client_version.h @@ -19,6 +19,7 @@ namespace ClientPatch { using ClientList = std::unordered_map; template using ComponentGetter = std::function; using SendPredicate = std::function; +using MutatePacket = std::function&, Client*)>; template requires std::is_member_function_pointer_v @@ -106,7 +107,7 @@ static void FastQueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args) } } -static auto QueueClientsByTarget(Mob* sender, bool ackreq, bool HoTT, const SendPredicate& ShouldSend) +static auto QueueClientsByTarget(Mob* sender, bool ackreq, bool HoTT, const SendPredicate& should_send, const MutatePacket& mutate) { return [=](Fun fun, const ComponentGetter component, Args&&... args) requires std::is_member_function_pointer_v @@ -115,17 +116,18 @@ static auto QueueClientsByTarget(Mob* sender, bool ackreq, bool HoTT, const Send std::array, EQ::versions::ClientVersionCount> build_packets; 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(c->ClientVersion())); - if (!packet) - if (auto comp = component(c); comp != nullptr) - packet = std::invoke(fun, comp, std::forward(args)...); + Mob* Target = c->GetTarget(); + if ((Target == sender || (HoTT && Target != nullptr && Target->GetTarget() == sender)) && + (Target == c || should_send(c))) { + auto& packet = build_packets.at(static_cast(c->ClientVersion())); + if (!packet) + if (auto comp = component(c); comp != nullptr) + packet = std::invoke(fun, comp, std::forward(args)...); - if (packet) - c->QueuePacket(packet.get(), ackreq, Client::CLIENT_CONNECTED); - } + mutate(packet, c); + + if (packet) + c->QueuePacket(packet.get(), ackreq, Client::CLIENT_CONNECTED); } } } @@ -203,7 +205,7 @@ static bool ShouldSendTargetBuffs(Client* c) // 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)) { + 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"); @@ -233,22 +235,66 @@ static bool ShouldSendTargetBuffs(Client* c) return false; } -inline void SendLegacyBuffsPacket(Client* c, Mob* sender, bool for_target = true, bool clear_buffs = false) +inline void SendFullBuffRefresh(Mob* sender, bool remove = false, bool ackreq = true) { - ClientPatch::FastQueuePacket(c, &IBuff::MakeLegacyBuffsPacket, GetComponent(c), sender, for_target, clear_buffs); + bool suspended = zone->BuffTimersSuspended(); + std::vector slots; + + // first, send to self if self is client + if (sender->IsClient()) { + Client* c = sender->CastToClient(); + ClientPatch::FastQueuePacket(c, &IBuff::RefreshBuffs, GetComponent(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(); + ClientPatch::FastQueuePacket(c, &IBuff::RefreshBuffs, GetComponent(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& packet, Client* c) { + GetComponent(c)->SetRefreshType(packet, sender, c); + }; + + ClientPatch::QueueClientsByTarget(sender, ackreq, false, ShouldSendTargetBuffs, mutate)( + &IBuff::RefreshBuffs, GetComponent, 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) + ClientPatch::QueueClientsByTarget(sender, ackreq, true, + [](Client* c) { return !ShouldSendTargetBuffs(c); }, mutate)( + &IBuff::RefreshBuffs, GetComponent, OP_RefreshTargetBuffs, sender, true, suspended, slots); } -inline void SendLegacyBuffsPacketToClients(Mob* sender, bool ackreq = true, bool HoTT = false, bool clear_buffs = false) +inline void SendSingleBuffChange(Mob* sender, const Buffs_Struct& buff, int slot, bool remove = false, bool ackreq = true) { - ClientPatch::QueueClientsByTarget(sender, ackreq, HoTT, ShouldSendTargetBuffs)( - &IBuff::MakeLegacyBuffsPacket, GetComponent, sender, true, clear_buffs); -} + bool suspended = zone->BuffTimersSuspended(); + std::vector slots = { static_cast(slot) }; -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); + // first, send to self if self is client, which takes the definition and the refresh + if (sender->IsClient()) { + Client* c = sender->CastToClient(); + ClientPatch::FastQueuePacket(c, &IBuff::BuffDefinition, GetComponent(c), sender, buff, slot, remove); + ClientPatch::FastQueuePacket(c, &IBuff::RefreshBuffs, GetComponent(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(); + ClientPatch::FastQueuePacket(c, &IBuff::RefreshBuffs, GetComponent(c), OP_RefreshPetBuffs, sender, remove, suspended, slots); + } + } + + auto mutate = [sender](std::unique_ptr& packet, Client* c) { + GetComponent(c)->SetRefreshType(packet, sender, c); + }; + + ClientPatch::QueueClientsByTarget(sender, ackreq, false, ShouldSendTargetBuffs, mutate)( + &IBuff::RefreshBuffs, GetComponent, OP_RefreshTargetBuffs, sender, remove, suspended, slots); } } // namespace Buff diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index cfb3b8960..c7718bbad 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -152,8 +152,7 @@ bool Mob::SpellEffect(Mob* caster, int32 spell_id, float partial, int level_over if (spells[spell_id].endurance_upkeep > 0) SetEndurUpkeep(true); - if (IsClient()) - Buff::SendLegacyBuffsPacket(CastToClient(), this, false); + Buff::SendFullBuffRefresh(this); } if (IsClient()) { @@ -812,7 +811,7 @@ bool Mob::SpellEffect(Mob* caster, int32 spell_id, float partial, int level_over // This was done in AddBuff, but we were not a pet yet, so // the target windows didn't get updated. - Buff::SendLegacyBuffsPacketToClients(this); + Buff::SendFullBuffRefresh(this); if(caster->IsClient()){ auto app = new EQApplicationPacket(OP_Charm, sizeof(Charm_Struct)); @@ -4432,7 +4431,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) // no longer see the buffs on the old pet. // QueueClientsByTarget preserves GM and leadership cases. - Buff::SendCharmDroppedBuffsPacket(this); + Buff::SendFullBuffRefresh(this, true); if (IsAIControlled()) { @@ -4656,17 +4655,8 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) RemoveNimbusEffect(spells[buffs[slot].spellid].nimbus_effect); buffs[slot].spellid = SPELL_UNKNOWN; - if(IsPet() && GetOwner() && GetOwner()->IsClient()) { - SendPetBuffsToClient(); - } - - Buff::SendLegacyBuffsPacketToClients(this); - - if (IsClient() && GetTarget() == this) - Buff::SendLegacyBuffsPacket(CastToClient(), this); - - if (IsClient()) - Buff::SendLegacyBuffsPacket(CastToClient(), this, false); + Buff::SendSingleBuffChange(this, buffs[slot], slot, true); + Buff::SendFullBuffRefresh(this); // we will eventually call CalcBonuses() even if we skip it right here, so should correct itself if we still have them degenerating_effects = false; diff --git a/zone/spells.cpp b/zone/spells.cpp index e54e63cb8..8edaa7548 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3741,13 +3741,8 @@ int Mob::AddBuff(Mob *caster, int32 spell_id, int duration, int32 level_override } LogSpells("Buff [{}] added to slot [{}] with caster level [{}]", spell_id, emptyslot, caster_level); - if (IsPet() && GetOwner() && GetOwner()->IsClient()) - SendPetBuffsToClient(); - - Buff::SendLegacyBuffsPacketToClients(this); - - if (IsClient() && GetTarget() == this) - Buff::SendLegacyBuffsPacket(CastToClient(), this); + Buff::SendSingleBuffChange(this, buffs[emptyslot], emptyslot); + Buff::SendFullBuffRefresh(this); // recalculate bonuses since we stripped/added buffs CalcBonuses();