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
+1 -1
View File
@@ -135,6 +135,7 @@ set(common_sources
util/directory.cpp util/directory.cpp
util/uuid.cpp util/uuid.cpp
zone_store.cpp zone_store.cpp
links.cpp
) )
set(repositories set(repositories
@@ -735,7 +736,6 @@ set(common_headers
version.h version.h
zone_store.h zone_store.h
links.h links.h
links.cpp
) )
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Source Files" FILES ${common_sources}) source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Source Files" FILES ${common_sources})
-37
View File
@@ -651,43 +651,6 @@ namespace TOB
FINISH_ENCODE(); 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(OP_GMTraining) {
ENCODE_LENGTH_EXACT(GMTrainee_Struct); ENCODE_LENGTH_EXACT(GMTrainee_Struct);
SETUP_DIRECT_ENCODE(GMTrainee_Struct, structs::GMTrainee_Struct); SETUP_DIRECT_ENCODE(GMTrainee_Struct, structs::GMTrainee_Struct);
-1
View File
@@ -24,7 +24,6 @@ E(OP_DeleteSpawn)
E(OP_DisciplineUpdate) E(OP_DisciplineUpdate)
E(OP_ExpansionInfo) E(OP_ExpansionInfo)
E(OP_ExpUpdate) E(OP_ExpUpdate)
E(OP_FormattedMessage)
E(OP_GMTraining) E(OP_GMTraining)
E(OP_GMTrainSkillConfirm) E(OP_GMTrainSkillConfirm)
E(OP_GroundSpawn) E(OP_GroundSpawn)
+9 -5
View File
@@ -32,8 +32,10 @@
using Version = EQ::versions::ClientVersion; using Version = EQ::versions::ClientVersion;
using namespace ZoneClient; using namespace ZoneClient;
struct ClientComponents { struct ClientComponents
explicit ClientComponents(Version version) : version(version) { {
explicit ClientComponents(Version version) : version(version)
{
switch (version) { switch (version) {
case Version::TOB: case Version::TOB:
messageComponent = std::make_shared<Message::TOB>(); messageComponent = std::make_shared<Message::TOB>();
@@ -63,7 +65,8 @@ struct ClientComponents {
std::shared_ptr<Message::IMessage> messageComponent; 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 = [] { static const std::unordered_map<Version, ClientComponents> patches = [] {
std::unordered_map<Version, ClientComponents> p; std::unordered_map<Version, ClientComponents> p;
p.emplace(Version::Titanium, Version::Titanium); 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::SoD, Version::SoD);
p.emplace(Version::UF, Version::UF); p.emplace(Version::UF, Version::UF);
p.emplace(Version::RoF, Version::RoF); p.emplace(Version::RoF, Version::RoF);
p.emplace(Version::RoF2,Version::RoF2); p.emplace(Version::RoF2, Version::RoF2);
p.emplace(Version::TOB, Version::TOB); p.emplace(Version::TOB, Version::TOB);
return p; return p;
}(); }();
@@ -79,7 +82,8 @@ static const ClientComponents& GetComponents(Version version) {
return patches.at(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; return GetComponents(version).messageComponent;
} }
+15 -10
View File
@@ -21,7 +21,8 @@ public:
static const std::shared_ptr<Message::IMessage>& GetMessageComponent(EQ::versions::ClientVersion version); static const std::shared_ptr<Message::IMessage>& GetMessageComponent(EQ::versions::ClientVersion version);
template<typename Fun, typename... Args> 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>); static_assert(std::is_member_function_pointer_v<Fun>);
EQApplicationPacket* app = std::invoke(fun, c->GetMessageComponent().get(), std::forward<Args>(args)...); EQApplicationPacket* app = std::invoke(fun, c->GetMessageComponent().get(), std::forward<Args>(args)...);
if (app != nullptr) { if (app != nullptr) {
@@ -31,10 +32,11 @@ public:
} }
// packet generator queue functions // 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) { return [=]<typename Fun, typename... Args>(Fun fun, Args&&... args) {
static_assert(std::is_member_function_pointer_v<Fun>); 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(); auto client_list = entity_list.GetClientList();
for (auto [_, ent] : client_list) { for (auto [_, ent] : client_list) {
@@ -54,9 +56,11 @@ public:
}; };
} }
static auto QueueCloseClients(Mob* sender, bool ignore_sender = false, float distance = 200, static auto QueueCloseClients(
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)
{
if (distance <= 0) distance = zone->GetClientUpdateRange(); if (distance <= 0) distance = zone->GetClientUpdateRange();
return [=]<typename Fun, typename... Args>(Fun fun, Args&&... args) { 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)...); QueueClients(sender, ignore_sender, is_ack_required)(fun, std::forward<Args>(args)...);
} else { } else {
float distance_squared = distance * distance; 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)) { for (auto& [_, mob] : sender->GetCloseMobList(distance)) {
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 && && DistanceSquared(client->GetPosition(), sender->GetPosition()) < distance_squared
client->Connected() && client->ShouldGetPacket(sender, filter)) { && client->Connected()
&& client->ShouldGetPacket(sender, filter)) {
auto [packet, _] = build_packets.try_emplace( auto [packet, _] = build_packets.try_emplace(
client->ClientVersion(), client->ClientVersion(),
std::invoke(fun, GetMessageComponent(client->ClientVersion()).get(), std::forward<Args>(args)...)); std::invoke(fun, GetMessageComponent(client->ClientVersion()).get(), std::forward<Args>(args)...));
+6 -6
View File
@@ -26,8 +26,8 @@ class Mob;
class EQApplicationPacket; class EQApplicationPacket;
namespace ZoneClient::Message { namespace ZoneClient::Message {
class IMessage
class IMessage { {
public: public:
constexpr IMessage() {} constexpr IMessage() {}
constexpr virtual ~IMessage() {} constexpr virtual ~IMessage() {}
@@ -42,12 +42,12 @@ public:
// These aren't technically messages, but they use the same format and are similar enough to include here // 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, virtual EQApplicationPacket* InterruptSpell(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, virtual EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id,
const char* spell_name_override = "") const = 0; 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 // 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* 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 } // namespace Zone::Message
+2 -3
View File
@@ -20,11 +20,10 @@
#include "zone/patch/components/message/uf.h" #include "zone/patch/components/message/uf.h"
namespace ZoneClient::Message { namespace ZoneClient::Message {
class RoF : public UF
class RoF : public UF { {
public: public:
constexpr RoF() {} constexpr RoF() {}
constexpr ~RoF() override {} constexpr ~RoF() override {}
}; };
} // namespace Zone::Message } // namespace Zone::Message
+2 -3
View File
@@ -20,11 +20,10 @@
#include "zone/patch/components/message/rof.h" #include "zone/patch/components/message/rof.h"
namespace ZoneClient::Message { namespace ZoneClient::Message {
class RoF2 : public RoF
class RoF2 : public RoF { {
public: public:
constexpr RoF2() {} constexpr RoF2() {}
constexpr ~RoF2() override {} constexpr ~RoF2() override {}
}; };
} // namespace Zone::Message } // namespace Zone::Message
+2 -3
View File
@@ -20,11 +20,10 @@
#include "zone/patch/components/message/sof.h" #include "zone/patch/components/message/sof.h"
namespace ZoneClient::Message { namespace ZoneClient::Message {
class SoD : public SoF
class SoD : public SoF { {
public: public:
constexpr SoD() {} constexpr SoD() {}
constexpr ~SoD() override {} constexpr ~SoD() override {}
}; };
} // namespace Zone::Message } // namespace Zone::Message
+2 -3
View File
@@ -20,11 +20,10 @@
#include "zone/patch/components/message/titanium.h" #include "zone/patch/components/message/titanium.h"
namespace ZoneClient::Message { namespace ZoneClient::Message {
class SoF : public Titanium
class SoF : public Titanium { {
public: public:
constexpr SoF() {} constexpr SoF() {}
constexpr ~SoF() override {} constexpr ~SoF() override {}
}; };
} // namespace Zone::Message } // namespace Zone::Message
+23 -17
View File
@@ -24,7 +24,8 @@
#include "common/serialize_buffer.h" #include "common/serialize_buffer.h"
namespace ZoneClient::Message { 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); uint32_t string_id = ResolveID(id);
if (string_id > 0) { if (string_id > 0) {
auto outapp = new EQApplicationPacket(OP_SimpleMessage, sizeof(SimpleMessage_Struct)); 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; return nullptr;
} }
EQApplicationPacket* Titanium::Formatted(uint32_t color, uint32_t id, EQApplicationPacket* Titanium::Formatted(
uint32_t color, uint32_t id,
const char* a1, const char* a2, const char* a3, const char* a1, const char* a2, const char* a3,
const char* a4, const char* a5, const char* a6, const char* a4, const char* a5, const char* a6,
const char* a7, const char* a8, const char* a9) const { const char* a7, const char* a8, const char* a9) const
{
uint32_t string_id = ResolveID(id); uint32_t string_id = ResolveID(id);
if (string_id > 0) { if (string_id > 0) {
if (!a1) if (!a1)
return Simple(color, id); return Simple(color, id);
const char* args[] = {a1, a2, a3, a4, a5, a6, a7, a8, a9};
SerializeBuffer buf(20); SerializeBuffer buf(20);
buf.WriteInt32(0); buf.WriteInt32(0);
buf.WriteInt32(string_id); buf.WriteInt32(string_id);
buf.WriteInt32(color); buf.WriteInt32(color);
for (const auto* arg : args) { for (const auto* a : {a1, a2, a3, a4, a5, a6, a7, a8, a9}) {
if (!arg) if (a != nullptr)
break; buf.WriteString(a);
buf.WriteString(arg);
} }
buf.WriteInt8(0); buf.WriteInt8(0);
@@ -69,8 +69,10 @@ EQApplicationPacket* Titanium::Formatted(uint32_t color, uint32_t id,
return nullptr; return nullptr;
} }
EQApplicationPacket* Titanium::InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id, EQApplicationPacket* Titanium::InterruptSpell(
const char* spell_name_override) const { 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 outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct));
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer); auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
ic->messageid = ResolveID(message); ic->messageid = ResolveID(message);
@@ -80,8 +82,10 @@ EQApplicationPacket* Titanium::InterruptSpell(uint32_t message, uint32_t spawn_i
return outapp; return outapp;
} }
EQApplicationPacket* Titanium::InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id, EQApplicationPacket* Titanium::InterruptSpellOther(
const char* spell_name_override) const { Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const
{
auto name = sender->GetCleanName(); auto name = sender->GetCleanName();
auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(name) + 1); auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(name) + 1);
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer); auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
@@ -91,19 +95,21 @@ EQApplicationPacket* Titanium::InterruptSpellOther(Mob* sender, uint32_t message
return outapp; 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); 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); 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 // 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; // passthrough — string IDs are defined at the base client level;
// override in patches where IDs need remapping // override in patches where IDs need remapping
return id; return id;
} }
} // namespace ZoneClient::Message } // namespace ZoneClient::Message
+4 -4
View File
@@ -20,8 +20,8 @@
#include "zone/patch/components/message/IMessage.h" #include "zone/patch/components/message/IMessage.h"
namespace ZoneClient::Message { namespace ZoneClient::Message {
class Titanium : public IMessage
class Titanium : public IMessage { {
public: public:
constexpr Titanium() {} constexpr Titanium() {}
constexpr ~Titanium() override {} constexpr ~Titanium() override {}
@@ -39,10 +39,10 @@ public:
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* 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: protected:
virtual uint32_t ResolveID(uint32_t id) const; virtual uint32_t ResolveID(uint32_t id) const;
}; };
} // namespace Zone::Message } // namespace Zone::Message
+137 -8
View File
@@ -20,12 +20,13 @@
#include "common/links.h" #include "common/links.h"
namespace ZoneClient::Message { namespace ZoneClient::Message {
struct TOBStringIDs
struct TOBStringIDs { {
static constexpr uint32_t DisarmedTrap = 1458; // You successfully disarmed the trap 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) { switch (id) {
case YOU_FLURRY: case YOU_FLURRY:
case BOW_DOUBLE_DAMAGE: case BOW_DOUBLE_DAMAGE:
@@ -72,7 +73,131 @@ 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' std::string spell_name = spell_name_override == nullptr || *spell_name_override == '\0'
? GetSpellName(spell_id) ? GetSpellName(spell_id)
: spell_name_override; : spell_name_override;
@@ -90,7 +215,8 @@ 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, 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' std::string spell_name = spell_name_override == nullptr || *spell_name_override == '\0'
? GetSpellName(spell_id) ? GetSpellName(spell_id)
: spell_name_override; : spell_name_override;
@@ -98,7 +224,8 @@ EQApplicationPacket* TOB::InterruptSpellOther(Mob* sender, uint32_t message, uin
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name); std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);
auto name = sender->GetCleanName(); 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); auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
ic->messageid = ResolveID(message); ic->messageid = ResolveID(message);
ic->spawnid = spawn_id; ic->spawnid = spawn_id;
@@ -107,14 +234,16 @@ EQApplicationPacket* TOB::InterruptSpellOther(Mob* sender, uint32_t message, uin
return outapp; 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_name(GetSpellName(spell_id));
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name); std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);
return Formatted(type, message, spell_link.c_str()); 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_name(GetSpellName(spell_id));
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name); std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);
+9 -3
View File
@@ -20,21 +20,27 @@
#include "zone/patch/components/message/rof2.h" #include "zone/patch/components/message/rof2.h"
namespace ZoneClient::Message { namespace ZoneClient::Message {
class TOB : public RoF2 { class TOB : public RoF2
{
public: public:
constexpr TOB() {} constexpr TOB() {}
constexpr ~TOB() override {} 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, 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, 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* 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: protected:
uint32_t ResolveID(uint32_t id) const override; uint32_t ResolveID(uint32_t id) const override;
}; };
} // namespace Zone::Message } // namespace Zone::Message
+2 -3
View File
@@ -20,11 +20,10 @@
#include "patch/components/message/sod.h" #include "patch/components/message/sod.h"
namespace ZoneClient::Message { namespace ZoneClient::Message {
class UF : public SoD
class UF : public SoD { {
public: public:
constexpr UF() {} constexpr UF() {}
constexpr ~UF() override {} constexpr ~UF() override {}
}; };
} // namespace Zone::Message } // namespace Zone::Message
+5 -6
View File
@@ -80,6 +80,7 @@
#include "common/rulesys.h" #include "common/rulesys.h"
#include "common/spdat.h" #include "common/spdat.h"
#include "common/strings.h" #include "common/strings.h"
#include "patch/client_version.h"
#include "zone/bot.h" #include "zone/bot.h"
#include "zone/client.h" #include "zone/client.h"
#include "zone/fastmath.h" #include "zone/fastmath.h"
@@ -94,10 +95,6 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include "common/links.h"
#include "common/packet_dump.h"
#include "patch/client_version.h"
extern Zone *zone; extern Zone *zone;
extern volatile bool is_zone_loaded; extern volatile bool is_zone_loaded;
extern WorldServer worldserver; extern WorldServer worldserver;
@@ -337,13 +334,15 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
StopCasting(); StopCasting();
if (IsClient()) if (IsClient())
ZoneClient::ClientPatch::QueuePacket(CastToClient(), &ZoneClient::Message::IMessage::Fizzle, ZoneClient::ClientPatch::QueuePacket(
CastToClient(), &ZoneClient::Message::IMessage::Fizzle,
Chat::SpellFailure, fizzle_msg, spell_id); Chat::SpellFailure, fizzle_msg, spell_id);
/** /**
* Song Failure message * Song Failure message
*/ */
ZoneClient::ClientPatch::QueueCloseClients(this, true, RuleI(Range, SpellMessages), ZoneClient::ClientPatch::QueueCloseClients(
this, true, RuleI(Range, SpellMessages),
nullptr, true, nullptr, true,
IsClient() ? FilterPCSpells : FilterNPCSpells)( IsClient() ? FilterPCSpells : FilterNPCSpells)(
&ZoneClient::Message::IMessage::FizzleOther, Chat::SpellFailure, &ZoneClient::Message::IMessage::FizzleOther, Chat::SpellFailure,