Moved formatted message into the new tob patch and cleaned up a bit

This commit is contained in:
dannuic 2026-04-22 16:11:01 -06:00
parent 46dce8499f
commit 79be47430c
18 changed files with 256 additions and 150 deletions

View File

@ -135,6 +135,7 @@ set(common_sources
util/directory.cpp
util/uuid.cpp
zone_store.cpp
links.cpp
)
set(repositories
@ -733,9 +734,8 @@ set(common_headers
util/memory_stream.h
util/uuid.h
version.h
zone_store.h
links.h
links.cpp
zone_store.h
links.h
)
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Source Files" FILES ${common_sources})

View File

@ -651,43 +651,6 @@ namespace TOB
FINISH_ENCODE();
}
ENCODE(OP_FormattedMessage)
{
EQApplicationPacket* in = *p;
*p = nullptr;
FormattedMessage_Struct* emu = (FormattedMessage_Struct*)in->pBuffer;
char* old_message_ptr = (char*)in->pBuffer;
old_message_ptr += sizeof(FormattedMessage_Struct);
std::string old_message_array[9];
for (int i = 0; i < 9; ++i) {
if (*old_message_ptr == 0) { break; }
old_message_array[i] = old_message_ptr;
old_message_ptr += old_message_array[i].length() + 1;
}
SerializeBuffer buffer;
buffer.WriteUInt32(0); // This is a string written like the message arrays
buffer.WriteUInt8(emu->unknown0);
buffer.WriteUInt32(emu->string_id);
buffer.WriteUInt32(emu->type);
for (int i = 0; i < 9; ++i) {
std::string new_message;
ServerToTOBConvertLinks(new_message, old_message_array[i]);
buffer.WriteLengthString(new_message);
}
auto outapp = new EQApplicationPacket(OP_FormattedMessage, buffer.size());
outapp->WriteData(buffer.buffer(), buffer.size());
dest->FastQueuePacket(&outapp, ack_req);
delete in;
}
ENCODE(OP_GMTraining) {
ENCODE_LENGTH_EXACT(GMTrainee_Struct);
SETUP_DIRECT_ENCODE(GMTrainee_Struct, structs::GMTrainee_Struct);

View File

@ -24,7 +24,6 @@ E(OP_DeleteSpawn)
E(OP_DisciplineUpdate)
E(OP_ExpansionInfo)
E(OP_ExpUpdate)
E(OP_FormattedMessage)
E(OP_GMTraining)
E(OP_GMTrainSkillConfirm)
E(OP_GroundSpawn)

View File

@ -1,9 +1,9 @@
set(patch_sources
client_version.cpp
client_version.cpp
)
set(patch_headers
client_version.h
client_version.h
)
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Source Files" FILES ${patch_sources})

View File

@ -32,8 +32,10 @@
using Version = EQ::versions::ClientVersion;
using namespace ZoneClient;
struct ClientComponents {
explicit ClientComponents(Version version) : version(version) {
struct ClientComponents
{
explicit ClientComponents(Version version) : version(version)
{
switch (version) {
case Version::TOB:
messageComponent = std::make_shared<Message::TOB>();
@ -63,7 +65,8 @@ struct ClientComponents {
std::shared_ptr<Message::IMessage> messageComponent;
};
static const ClientComponents& GetComponents(Version version) {
static const ClientComponents& GetComponents(Version version)
{
static const std::unordered_map<Version, ClientComponents> patches = [] {
std::unordered_map<Version, ClientComponents> p;
p.emplace(Version::Titanium, Version::Titanium);
@ -71,7 +74,7 @@ static const ClientComponents& GetComponents(Version version) {
p.emplace(Version::SoD, Version::SoD);
p.emplace(Version::UF, Version::UF);
p.emplace(Version::RoF, Version::RoF);
p.emplace(Version::RoF2,Version::RoF2);
p.emplace(Version::RoF2, Version::RoF2);
p.emplace(Version::TOB, Version::TOB);
return p;
}();
@ -79,13 +82,14 @@ static const ClientComponents& GetComponents(Version version) {
return patches.at(version);
}
const std::shared_ptr<Message::IMessage>& ClientPatch::GetMessageComponent(Version version) {
const std::shared_ptr<Message::IMessage>& ClientPatch::GetMessageComponent(Version version)
{
return GetComponents(version).messageComponent;
}
void Client::SetClientVersion(Version client_version)
{
m_ClientVersion = client_version;
m_ClientVersion = client_version;
m_ClientVersionBit = EQ::versions::ConvertClientVersionToClientVersionBit(client_version);
m_messageComponent = GetComponents(client_version).messageComponent;
}

View File

@ -21,7 +21,8 @@ public:
static const std::shared_ptr<Message::IMessage>& GetMessageComponent(EQ::versions::ClientVersion version);
template<typename Fun, typename... Args>
static void QueuePacket(Client* c, Fun fun, Args&&... args) {
static void QueuePacket(Client* c, Fun fun, Args&&... args)
{
static_assert(std::is_member_function_pointer_v<Fun>);
EQApplicationPacket* app = std::invoke(fun, c->GetMessageComponent().get(), std::forward<Args>(args)...);
if (app != nullptr) {
@ -31,10 +32,11 @@ public:
}
// packet generator queue functions
static auto QueueClients(Mob* sender, bool ignore_sender = false, bool ackreq = true) {
static auto QueueClients(Mob* sender, bool ignore_sender = false, bool ackreq = true)
{
return [=]<typename Fun, typename... Args>(Fun fun, Args&&... args) {
static_assert(std::is_member_function_pointer_v<Fun>);
std::map<EQ::versions::ClientVersion, EQApplicationPacket*> build_packets;
std::unordered_map<EQ::versions::ClientVersion, EQApplicationPacket*> build_packets;
auto client_list = entity_list.GetClientList();
for (auto [_, ent] : client_list) {
@ -54,9 +56,11 @@ public:
};
}
static auto QueueCloseClients(Mob* sender, bool ignore_sender = false, float distance = 200,
Mob* skipped_mob = nullptr, bool is_ack_required = true,
eqFilterType filter = FilterNone) {
static auto QueueCloseClients(
Mob* sender, bool ignore_sender = false, float distance = 200,
Mob* skipped_mob = nullptr, bool is_ack_required = true,
eqFilterType filter = FilterNone)
{
if (distance <= 0) distance = zone->GetClientUpdateRange();
return [=]<typename Fun, typename... Args>(Fun fun, Args&&... args) {
@ -64,15 +68,16 @@ public:
QueueClients(sender, ignore_sender, is_ack_required)(fun, std::forward<Args>(args)...);
} else {
float distance_squared = distance * distance;
std::map<EQ::versions::ClientVersion, EQApplicationPacket*> build_packets;
std::unordered_map<EQ::versions::ClientVersion, EQApplicationPacket*> build_packets;
for (auto& [_, mob] : sender->GetCloseMobList(distance)) {
if (mob && mob->IsClient()) {
Client* client = mob->CastToClient();
if ((!ignore_sender || client != sender) &&
client != skipped_mob &&
DistanceSquared(client->GetPosition(), sender->GetPosition()) < distance_squared &&
client->Connected() && client->ShouldGetPacket(sender, filter)) {
if ((!ignore_sender || client != sender)
&& client != skipped_mob
&& DistanceSquared(client->GetPosition(), sender->GetPosition()) < distance_squared
&& client->Connected()
&& client->ShouldGetPacket(sender, filter)) {
auto [packet, _] = build_packets.try_emplace(
client->ClientVersion(),
std::invoke(fun, GetMessageComponent(client->ClientVersion()).get(), std::forward<Args>(args)...));

View File

@ -1,18 +1,18 @@
set(message_component_sources
titanium.cpp
rof2.cpp
tob.cpp
titanium.cpp
rof2.cpp
tob.cpp
)
set(message_component_headers
IMessage.h
titanium.h
sof.h
sod.h
uf.h
rof.h
rof2.h
tob.h
IMessage.h
titanium.h
sof.h
sod.h
uf.h
rof.h
rof2.h
tob.h
)
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Source Files" FILES ${message_component_sources})

View File

@ -26,8 +26,8 @@ class Mob;
class EQApplicationPacket;
namespace ZoneClient::Message {
class IMessage {
class IMessage
{
public:
constexpr IMessage() {}
constexpr virtual ~IMessage() {}
@ -35,19 +35,19 @@ public:
// these two are the basic string message packets
virtual EQApplicationPacket* Simple(uint32_t color, uint32_t id) const = 0;
virtual EQApplicationPacket* Formatted(uint32_t color, uint32_t id,
const char* a1 = nullptr, const char* a2 = nullptr, const char* a3 = nullptr,
const char* a4 = nullptr, const char* a5 = nullptr, const char* a6 = nullptr,
const char* a7 = nullptr, const char* a8 = nullptr, const char* a9 = nullptr) const = 0;
const char* a1 = nullptr, const char* a2 = nullptr, const char* a3 = nullptr,
const char* a4 = nullptr, const char* a5 = nullptr, const char* a6 = nullptr,
const char* a7 = nullptr, const char* a8 = nullptr, const char* a9 = nullptr) const = 0;
// These aren't technically messages, but they use the same format and are similar enough to include here
virtual EQApplicationPacket* InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override = "") const = 0;
virtual EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override = "") const = 0;
const char* spell_name_override = "") const = 0;
virtual EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id,
uint32_t spell_id, const char* spell_name_override = "") const = 0;
// Everything else is specializations of logic needed to build strings that differ between patches
virtual EQApplicationPacket* Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const = 0;
virtual EQApplicationPacket* FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const = 0;
virtual EQApplicationPacket* FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id,
const char* caster) const = 0;
};
} // namespace Zone::Message

View File

@ -20,11 +20,10 @@
#include "zone/patch/components/message/uf.h"
namespace ZoneClient::Message {
class RoF : public UF {
class RoF : public UF
{
public:
constexpr RoF() {}
constexpr ~RoF() override {}
};
} // namespace Zone::Message

View File

@ -20,11 +20,10 @@
#include "zone/patch/components/message/rof.h"
namespace ZoneClient::Message {
class RoF2 : public RoF {
class RoF2 : public RoF
{
public:
constexpr RoF2() {}
constexpr ~RoF2() override {}
};
} // namespace Zone::Message

View File

@ -20,11 +20,10 @@
#include "zone/patch/components/message/sof.h"
namespace ZoneClient::Message {
class SoD : public SoF {
class SoD : public SoF
{
public:
constexpr SoD() {}
constexpr ~SoD() override {}
};
} // namespace Zone::Message

View File

@ -20,11 +20,10 @@
#include "zone/patch/components/message/titanium.h"
namespace ZoneClient::Message {
class SoF : public Titanium {
class SoF : public Titanium
{
public:
constexpr SoF() {}
constexpr ~SoF() override {}
};
} // namespace Zone::Message

View File

@ -24,7 +24,8 @@
#include "common/serialize_buffer.h"
namespace ZoneClient::Message {
EQApplicationPacket* Titanium::Simple(uint32_t color, uint32_t id) const {
EQApplicationPacket* Titanium::Simple(uint32_t color, uint32_t id) const
{
uint32_t string_id = ResolveID(id);
if (string_id > 0) {
auto outapp = new EQApplicationPacket(OP_SimpleMessage, sizeof(SimpleMessage_Struct));
@ -39,26 +40,25 @@ EQApplicationPacket* Titanium::Simple(uint32_t color, uint32_t id) const {
return nullptr;
}
EQApplicationPacket* Titanium::Formatted(uint32_t color, uint32_t id,
const char* a1, const char* a2, const char* a3,
const char* a4, const char* a5, const char* a6,
const char* a7, const char* a8, const char* a9) const {
EQApplicationPacket* Titanium::Formatted(
uint32_t color, uint32_t id,
const char* a1, const char* a2, const char* a3,
const char* a4, const char* a5, const char* a6,
const char* a7, const char* a8, const char* a9) const
{
uint32_t string_id = ResolveID(id);
if (string_id > 0) {
if (!a1)
return Simple(color, id);
const char* args[] = {a1, a2, a3, a4, a5, a6, a7, a8, a9};
SerializeBuffer buf(20);
buf.WriteInt32(0);
buf.WriteInt32(string_id);
buf.WriteInt32(color);
for (const auto* arg : args) {
if (!arg)
break;
buf.WriteString(arg);
for (const auto* a : {a1, a2, a3, a4, a5, a6, a7, a8, a9}) {
if (a != nullptr)
buf.WriteString(a);
}
buf.WriteInt8(0);
@ -69,8 +69,10 @@ EQApplicationPacket* Titanium::Formatted(uint32_t color, uint32_t id,
return nullptr;
}
EQApplicationPacket* Titanium::InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const {
EQApplicationPacket* Titanium::InterruptSpell(
uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const
{
auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct));
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
ic->messageid = ResolveID(message);
@ -80,8 +82,10 @@ EQApplicationPacket* Titanium::InterruptSpell(uint32_t message, uint32_t spawn_i
return outapp;
}
EQApplicationPacket* Titanium::InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const {
EQApplicationPacket* Titanium::InterruptSpellOther(
Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const
{
auto name = sender->GetCleanName();
auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(name) + 1);
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
@ -91,19 +95,21 @@ EQApplicationPacket* Titanium::InterruptSpellOther(Mob* sender, uint32_t message
return outapp;
}
EQApplicationPacket* Titanium::Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const {
EQApplicationPacket* Titanium::Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const
{
return Simple(type, message);
}
EQApplicationPacket* Titanium::FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const {
EQApplicationPacket* Titanium::FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const
{
return Formatted(type, message, caster);
}
// A value of 0 means that the string isn't mapped in this client, valid string ids start at 1
uint32_t Titanium::ResolveID(uint32_t id) const {
uint32_t Titanium::ResolveID(uint32_t id) const
{
// passthrough — string IDs are defined at the base client level;
// override in patches where IDs need remapping
return id;
}
} // namespace ZoneClient::Message

View File

@ -20,8 +20,8 @@
#include "zone/patch/components/message/IMessage.h"
namespace ZoneClient::Message {
class Titanium : public IMessage {
class Titanium : public IMessage
{
public:
constexpr Titanium() {}
constexpr ~Titanium() override {}
@ -29,20 +29,20 @@ public:
EQApplicationPacket* Simple(uint32_t color, uint32_t id) const override;
EQApplicationPacket* Formatted(uint32_t color, uint32_t id,
const char* a1 = nullptr, const char* a2 = nullptr, const char* a3 = nullptr,
const char* a4 = nullptr, const char* a5 = nullptr, const char* a6 = nullptr,
const char* a7 = nullptr, const char* a8 = nullptr, const char* a9 = nullptr) const override;
const char* a1 = nullptr, const char* a2 = nullptr, const char* a3 = nullptr,
const char* a4 = nullptr, const char* a5 = nullptr, const char* a6 = nullptr,
const char* a7 = nullptr, const char* a8 = nullptr, const char* a9 = nullptr) const override;
EQApplicationPacket* InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override = "") const override;
const char* spell_name_override = "") const override;
EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override = "") const override;
const char* spell_name_override = "") const override;
EQApplicationPacket* Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const override;
EQApplicationPacket* FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const override;
EQApplicationPacket* FizzleOther(uint32_t type, uint32_t message,
uint32_t spell_id, const char* caster) const override;
protected:
virtual uint32_t ResolveID(uint32_t id) const;
};
} // namespace Zone::Message

View File

@ -20,12 +20,13 @@
#include "common/links.h"
namespace ZoneClient::Message {
struct TOBStringIDs {
struct TOBStringIDs
{
static constexpr uint32_t DisarmedTrap = 1458; // You successfully disarmed the trap
};
uint32_t TOB::ResolveID(uint32_t id) const {
uint32_t TOB::ResolveID(uint32_t id) const
{
switch (id) {
case YOU_FLURRY:
case BOW_DOUBLE_DAMAGE:
@ -72,10 +73,134 @@ uint32_t TOB::ResolveID(uint32_t id) const {
}
}
EQApplicationPacket* TOB::InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override) const {
// TOB is the first patch to fully support links in the client. This helper function is therefore internal to TOB
// because any future patches would default to the TOB message strings
static void ServerToTOBConvertLinks(std::string& message_out, const std::string& message_in)
{
if (message_in.find('\x12') == std::string::npos) {
message_out = message_in;
return;
}
auto segments = Strings::Split(message_in, '\x12');
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
auto etag = std::stoi(segments[segment_iter].substr(0, 1));
switch (etag) {
case 0: {
size_t index = 1;
auto item_id = segments[segment_iter].substr(index, 5);
index += 5;
auto aug1 = segments[segment_iter].substr(index, 5);
index += 5;
auto aug2 = segments[segment_iter].substr(index, 5);
index += 5;
auto aug3 = segments[segment_iter].substr(index, 5);
index += 5;
auto aug4 = segments[segment_iter].substr(index, 5);
index += 5;
auto aug5 = segments[segment_iter].substr(index, 5);
index += 5;
auto aug6 = segments[segment_iter].substr(index, 5);
index += 5;
auto is_evolving = segments[segment_iter].substr(index, 1);
index += 1;
auto evolutionGroup = segments[segment_iter].substr(index, 4);
index += 4;
auto evolutionLevel = segments[segment_iter].substr(index, 2);
index += 2;
auto ornamentationIconID = segments[segment_iter].substr(index, 5);
index += 5;
auto itemHash = segments[segment_iter].substr(index, 8);
index += 8;
auto text = segments[segment_iter].substr(index);
message_out.push_back('\x12');
message_out.push_back('0'); //etag item
message_out.append(item_id);
message_out.append(aug1);
message_out.append("00000");
message_out.append(aug2);
message_out.append("00000");
message_out.append(aug3);
message_out.append("00000");
message_out.append(aug4);
message_out.append("00000");
message_out.append(aug5);
message_out.append("00000");
message_out.append(aug6);
message_out.append("00000");
message_out.append(is_evolving);
message_out.append(evolutionGroup);
message_out.append(evolutionLevel);
message_out.append(ornamentationIconID);
message_out.append("00000");
message_out.append(itemHash);
message_out.append(text);
message_out.push_back('\x12');
break;
}
default:
//unsupported etag right now; just pass it as is
message_out.push_back('\x12');
message_out.append(segments[segment_iter]);
message_out.push_back('\x12');
break;
}
} else {
message_out.append(segments[segment_iter]);
}
}
}
EQApplicationPacket* TOB::Formatted(uint32_t color, uint32_t id, const char* a1, const char* a2, const char* a3,
const char* a4, const char* a5, const char* a6, const char* a7, const char* a8, const char* a9) const
{
uint32_t string_id = ResolveID(id);
if (string_id > 0) {
SerializeBuffer buffer(49);
// 49 is the minimum size needed for this packet since each arg writes at least 4 bytes
buffer.WriteUInt32(0);
// This is a string written like the message arrays, but it seems to be discarded by the client
buffer.WriteUInt8(0); // 0 is a zone packet, 1 is a world packet -- these are always sent from zone from here
buffer.WriteUInt32(string_id);
buffer.WriteUInt32(color);
for (auto a : {a1, a2, a3, a4, a5, a6, a7, a8, a9}) {
if (a != nullptr) {
std::string new_message;
ServerToTOBConvertLinks(new_message, a);
buffer.WriteLengthString(new_message);
} else
buffer.WriteUInt32(0);
}
return new EQApplicationPacket(OP_FormattedMessage, std::move(buffer));
}
return nullptr;
}
EQApplicationPacket* TOB::InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const
{
std::string spell_name = spell_name_override == nullptr || *spell_name_override == '\0'
? GetSpellName(spell_id)
: spell_name_override;
? GetSpellName(spell_id)
: spell_name_override;
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);
@ -90,15 +215,17 @@ EQApplicationPacket* TOB::InterruptSpell(uint32_t message, uint32_t spawn_id, ui
}
EQApplicationPacket* TOB::InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const {
const char* spell_name_override) const
{
std::string spell_name = spell_name_override == nullptr || *spell_name_override == '\0'
? GetSpellName(spell_id)
: spell_name_override;
? GetSpellName(spell_id)
: spell_name_override;
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);
auto name = sender->GetCleanName();
auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(name) + spell_link.size() + 2);
auto outapp = new EQApplicationPacket(OP_InterruptCast,
sizeof(InterruptCast_Struct) + strlen(name) + spell_link.size() + 2);
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
ic->messageid = ResolveID(message);
ic->spawnid = spawn_id;
@ -107,14 +234,16 @@ EQApplicationPacket* TOB::InterruptSpellOther(Mob* sender, uint32_t message, uin
return outapp;
}
EQApplicationPacket* TOB::Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const {
EQApplicationPacket* TOB::Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const
{
std::string spell_name(GetSpellName(spell_id));
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);
return Formatted(type, message, spell_link.c_str());
}
EQApplicationPacket* TOB::FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const {
EQApplicationPacket* TOB::FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const
{
std::string spell_name(GetSpellName(spell_id));
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);

View File

@ -20,21 +20,27 @@
#include "zone/patch/components/message/rof2.h"
namespace ZoneClient::Message {
class TOB : public RoF2 {
class TOB : public RoF2
{
public:
constexpr TOB() {}
constexpr ~TOB() override {}
EQApplicationPacket* Formatted(uint32_t color, uint32_t id,
const char* a1 = nullptr, const char* a2 = nullptr, const char* a3 = nullptr,
const char* a4 = nullptr, const char* a5 = nullptr, const char* a6 = nullptr,
const char* a7 = nullptr, const char* a8 = nullptr, const char* a9 = nullptr) const override;
EQApplicationPacket* InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const override;
const char* spell_name_override) const override;
EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const override;
const char* spell_name_override) const override;
EQApplicationPacket* Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const override;
EQApplicationPacket* FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const override;
EQApplicationPacket*
FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const override;
protected:
uint32_t ResolveID(uint32_t id) const override;
};
} // namespace Zone::Message

View File

@ -20,11 +20,10 @@
#include "patch/components/message/sod.h"
namespace ZoneClient::Message {
class UF : public SoD {
class UF : public SoD
{
public:
constexpr UF() {}
constexpr ~UF() override {}
};
} // namespace Zone::Message

View File

@ -80,6 +80,7 @@
#include "common/rulesys.h"
#include "common/spdat.h"
#include "common/strings.h"
#include "patch/client_version.h"
#include "zone/bot.h"
#include "zone/client.h"
#include "zone/fastmath.h"
@ -94,10 +95,6 @@
#include <algorithm>
#include <cassert>
#include "common/links.h"
#include "common/packet_dump.h"
#include "patch/client_version.h"
extern Zone *zone;
extern volatile bool is_zone_loaded;
extern WorldServer worldserver;
@ -337,15 +334,17 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
StopCasting();
if (IsClient())
ZoneClient::ClientPatch::QueuePacket(CastToClient(), &ZoneClient::Message::IMessage::Fizzle,
Chat::SpellFailure, fizzle_msg, spell_id);
ZoneClient::ClientPatch::QueuePacket(
CastToClient(), &ZoneClient::Message::IMessage::Fizzle,
Chat::SpellFailure, fizzle_msg, spell_id);
/**
* Song Failure message
*/
ZoneClient::ClientPatch::QueueCloseClients(this, true, RuleI(Range, SpellMessages),
nullptr, true,
IsClient() ? FilterPCSpells : FilterNPCSpells)(
ZoneClient::ClientPatch::QueueCloseClients(
this, true, RuleI(Range, SpellMessages),
nullptr, true,
IsClient() ? FilterPCSpells : FilterNPCSpells)(
&ZoneClient::Message::IMessage::FizzleOther, Chat::SpellFailure,
fizzle_msg == MISS_NOTE ? MISSED_NOTE_OTHER : SPELL_FIZZLE_OTHER, spell_id, GetName());