mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-05 20:22:28 +00:00
Simplified user interface
This commit is contained in:
parent
83e29f96d7
commit
63c33ea4d6
@ -3812,10 +3812,10 @@ void Client::MessageString(uint32 type, uint32 string_id, uint32 distance)
|
||||
return;
|
||||
|
||||
if (distance > 0)
|
||||
ZoneClient::ClientPatch::QueueCloseClients(this, false, distance)(
|
||||
&ZoneClient::Message::IMessage::Simple, type, string_id);
|
||||
ZoneClient::Message::CloseMessageString(this, false, static_cast<float>(distance))(
|
||||
type, string_id);
|
||||
else
|
||||
ZoneClient::ClientPatch::QueuePacket(this, &ZoneClient::Message::IMessage::Simple, type, string_id);
|
||||
ZoneClient::Message::MessageString(this, type, string_id);
|
||||
}
|
||||
|
||||
//
|
||||
@ -3825,9 +3825,9 @@ void Client::MessageString(uint32 type, uint32 string_id, uint32 distance)
|
||||
// This hack sucks but it's gonna work for now.
|
||||
//
|
||||
void Client::MessageString(uint32 type, uint32 string_id, const char* message1,
|
||||
const char* message2,const char* message3,const char* message4,
|
||||
const char* message5,const char* message6,const char* message7,
|
||||
const char* message8,const char* message9, uint32 distance)
|
||||
const char* message2, const char* message3, const char* message4,
|
||||
const char* message5, const char* message6, const char* message7,
|
||||
const char* message8, const char* message9, uint32 distance)
|
||||
{
|
||||
if (GetFilter(FilterSpellDamage) == FilterHide && type == Chat::NonMelee)
|
||||
return;
|
||||
@ -3844,14 +3844,10 @@ void Client::MessageString(uint32 type, uint32 string_id, const char* message1,
|
||||
type = 4;
|
||||
|
||||
if (distance > 0)
|
||||
ZoneClient::ClientPatch::QueueCloseClients(this, false, distance)(
|
||||
&ZoneClient::Message::IMessage::Formatted, type, string_id,
|
||||
message1, message2, message3, message4, message5,
|
||||
message6, message7, message8, message9);
|
||||
ZoneClient::Message::CloseMessageString(this, false, static_cast<float>(distance))(type, string_id, message1,
|
||||
message2, message3, message4, message5, message6, message7, message8, message9);
|
||||
else
|
||||
ZoneClient::ClientPatch::QueuePacket(
|
||||
this, &ZoneClient::Message::IMessage::Formatted, type, string_id,
|
||||
message1, message2, message3, message4, message5,
|
||||
ZoneClient::Message::MessageString(this, type, string_id, message1, message2, message3, message4, message5,
|
||||
message6, message7, message8, message9);
|
||||
}
|
||||
|
||||
|
||||
@ -7,24 +7,25 @@
|
||||
#include <memory>
|
||||
|
||||
#include "common/emu_versions.h"
|
||||
#include "components/message/IMessage.h"
|
||||
|
||||
#include "zone/client.h"
|
||||
#include "zone/mob.h"
|
||||
|
||||
namespace ZoneClient {
|
||||
|
||||
namespace Message { class IMessage; }
|
||||
|
||||
// store all static functions for the different patches here
|
||||
class ClientPatch {
|
||||
public:
|
||||
using ClientList = std::unordered_map<uint16, Client*>;
|
||||
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)
|
||||
template<typename Fun, typename Obj, typename... Args>
|
||||
static void QueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args)
|
||||
{
|
||||
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, obj, std::forward<Args>(args)...);
|
||||
if (app != nullptr) {
|
||||
c->QueuePacket(app);
|
||||
delete app;
|
||||
@ -34,8 +35,9 @@ public:
|
||||
// packet generator queue functions
|
||||
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>);
|
||||
return [=]<typename Fun, typename Obj, typename... Args>(Fun fun, std::function<Obj*(const Client*)> component_getter, Args&&... args) {
|
||||
static_assert(std::is_member_function_pointer_v<Fun> && "Function is required to be a member function");
|
||||
|
||||
std::unordered_map<EQ::versions::ClientVersion, EQApplicationPacket*> build_packets;
|
||||
std::unordered_map<uint16, Client*> client_list = entity_list.GetClientList();
|
||||
|
||||
@ -43,7 +45,7 @@ public:
|
||||
if (!ignore_sender || ent != sender) {
|
||||
auto [packet, _] = build_packets.try_emplace(
|
||||
ent->ClientVersion(),
|
||||
std::invoke(fun, GetMessageComponent(ent->ClientVersion()).get(), std::forward<Args>(args)...));
|
||||
std::invoke(fun, component_getter(ent), std::forward<Args>(args)...));
|
||||
|
||||
if (packet->second != nullptr)
|
||||
ent->QueuePacket(packet->second, ackreq, Client::CLIENT_CONNECTED);
|
||||
@ -61,11 +63,13 @@ public:
|
||||
Mob* skipped_mob = nullptr, bool is_ack_required = true,
|
||||
eqFilterType filter = FilterNone)
|
||||
{
|
||||
if (distance <= 0) distance = zone->GetClientUpdateRange();
|
||||
if (distance <= 0) distance = static_cast<float>(zone->GetClientUpdateRange());
|
||||
|
||||
return [=]<typename Fun, typename Obj, typename... Args>(Fun fun, std::function<Obj*(const Client*)> component_getter, Args&&... args) {
|
||||
static_assert(std::is_member_function_pointer_v<Fun> && "Function is required to be a member function");
|
||||
|
||||
return [=]<typename Fun, typename... Args>(Fun fun, Args&&... args) {
|
||||
if (sender == nullptr) {
|
||||
QueueClients(sender, ignore_sender, is_ack_required)(fun, std::forward<Args>(args)...);
|
||||
QueueClients(sender, ignore_sender, is_ack_required)(fun, component_getter, std::forward<Args>(args)...);
|
||||
} else {
|
||||
float distance_squared = distance * distance;
|
||||
std::unordered_map<EQ::versions::ClientVersion, EQApplicationPacket*> build_packets;
|
||||
@ -80,7 +84,7 @@ public:
|
||||
&& client->ShouldGetPacket(sender, filter)) {
|
||||
auto [packet, _] = build_packets.try_emplace(
|
||||
client->ClientVersion(),
|
||||
std::invoke(fun, GetMessageComponent(client->ClientVersion()).get(), std::forward<Args>(args)...));
|
||||
std::invoke(fun, component_getter(client), std::forward<Args>(args)...));
|
||||
|
||||
if (packet->second != nullptr)
|
||||
client->QueuePacket(packet->second, is_ack_required, Client::CLIENT_CONNECTED);
|
||||
|
||||
@ -17,7 +17,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "patch/client_version.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// Migration path: replace string_ids.h usage with ID enum values one call site at a time.
|
||||
|
||||
@ -26,28 +28,73 @@ class Mob;
|
||||
class EQApplicationPacket;
|
||||
|
||||
namespace ZoneClient::Message {
|
||||
|
||||
template<typename... Args>
|
||||
concept AllConstChar = (std::is_convertible_v<Args, const char*> && ...);
|
||||
|
||||
class IMessage
|
||||
{
|
||||
public:
|
||||
IMessage() {}
|
||||
virtual ~IMessage() {}
|
||||
IMessage() = default;
|
||||
virtual ~IMessage() = default;
|
||||
|
||||
// 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;
|
||||
[[nodiscard]] virtual EQApplicationPacket* Simple(uint32_t color, uint32_t id) const = 0;
|
||||
[[nodiscard]] virtual EQApplicationPacket* Formatted(uint32_t color, uint32_t id, const std::array<const char*, 9>& args) 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* InterruptSpell(uint32_t message, uint32_t spawn_id, const char* spell_link) 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;
|
||||
const char* name, const char* spell_link) const = 0;
|
||||
};
|
||||
} // namespace Zone::Message
|
||||
|
||||
static std::function GetComponent = [](const Client* c) -> IMessage* {
|
||||
return ClientPatch::GetMessageComponent(c->GetClientVersion()).get();
|
||||
};
|
||||
|
||||
// Helper functions to wrap the packet construction in sends
|
||||
template <AllConstChar... Args>
|
||||
requires (sizeof...(Args) <= 9)
|
||||
void MessageString(Client* c, uint32_t type, uint32_t id, Args&&... args)
|
||||
{
|
||||
if constexpr (sizeof...(Args) == 0) {
|
||||
ClientPatch::QueuePacket(c, &IMessage::Simple, c->GetMessageComponent().get(), type, id);
|
||||
} else {
|
||||
std::array<const char*, 9> a = {args...};
|
||||
ClientPatch::QueuePacket(c, &IMessage::Formatted, c->GetMessageComponent().get(), type, id, a);
|
||||
}
|
||||
}
|
||||
|
||||
static auto CloseMessageString(
|
||||
Mob* sender, bool ignore_sender = false, float distance = 200.f,
|
||||
Mob* skipped_mob = nullptr, bool is_ack_required = true,
|
||||
eqFilterType filter = FilterNone)
|
||||
{
|
||||
return [=]<AllConstChar... Args>(uint32_t type, uint32_t id, Args&&... args) {
|
||||
static_assert(sizeof...(Args) <= 9, "Too many arguments");
|
||||
|
||||
auto queue_close_clients = ClientPatch::QueueCloseClients(sender, ignore_sender, distance, skipped_mob,
|
||||
is_ack_required, filter);
|
||||
|
||||
if constexpr (sizeof...(Args) == 0) {
|
||||
return queue_close_clients(&IMessage::Simple, GetComponent, type, id);
|
||||
} else {
|
||||
std::array<const char*, 9> a = {args...};
|
||||
return queue_close_clients(&IMessage::Formatted, GetComponent, type, id, a);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
inline void InterruptSpell(Client* c, uint32_t message, uint32_t spawn_id, const char* spell_link)
|
||||
{
|
||||
ClientPatch::QueuePacket(c, &IMessage::InterruptSpell, c->GetMessageComponent().get(), message, spawn_id, spell_link);
|
||||
}
|
||||
|
||||
inline void InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, const char* name, const char* spell_link)
|
||||
{
|
||||
ClientPatch::QueueCloseClients(sender, true, RuleI(Range, SongMessages), nullptr, true,
|
||||
sender->IsClient() ? FilterPCSpells : FilterNPCSpells)(
|
||||
&IMessage::InterruptSpellOther, GetComponent, sender, message, spawn_id, name, spell_link);
|
||||
}
|
||||
|
||||
} // namespace ZoneClient::Message
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "common/serialize_buffer.h"
|
||||
|
||||
namespace ZoneClient::Message {
|
||||
|
||||
EQApplicationPacket* Titanium::Simple(uint32_t color, uint32_t id) const
|
||||
{
|
||||
uint32_t string_id = ResolveID(id);
|
||||
@ -41,27 +42,26 @@ EQApplicationPacket* Titanium::Simple(uint32_t color, uint32_t id) 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 color, uint32_t id, const std::array<const char*, 9>& args) const
|
||||
{
|
||||
uint32_t string_id = ResolveID(id);
|
||||
if (string_id > 0) {
|
||||
if (!a1)
|
||||
std::array<const char*, 9> resolved_args = args;
|
||||
ResolveArguments(id, resolved_args);
|
||||
if (!resolved_args[0])
|
||||
return Simple(color, id);
|
||||
|
||||
SerializeBuffer buf(20);
|
||||
buf.WriteInt32(0);
|
||||
buf.WriteInt32(string_id);
|
||||
buf.WriteInt32(color);
|
||||
buf.WriteUInt32(0);
|
||||
buf.WriteUInt32(string_id);
|
||||
buf.WriteUInt32(color);
|
||||
|
||||
for (const auto* a : {a1, a2, a3, a4, a5, a6, a7, a8, a9}) {
|
||||
for (const auto* a : resolved_args) {
|
||||
if (a != nullptr)
|
||||
buf.WriteString(a);
|
||||
}
|
||||
|
||||
buf.WriteInt8(0);
|
||||
buf.WriteUInt8(0);
|
||||
|
||||
return new EQApplicationPacket(OP_FormattedMessage, std::move(buf));
|
||||
}
|
||||
@ -69,9 +69,7 @@ EQApplicationPacket* Titanium::Formatted(
|
||||
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, const char* spell_link) const
|
||||
{
|
||||
auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct));
|
||||
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
|
||||
@ -82,11 +80,9 @@ EQApplicationPacket* Titanium::InterruptSpell(
|
||||
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, const char* name,
|
||||
const char* spell_link) const
|
||||
{
|
||||
const char* name = sender->GetCleanName();
|
||||
auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(name) + 1);
|
||||
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
|
||||
ic->messageid = ResolveID(message);
|
||||
@ -95,16 +91,6 @@ EQApplicationPacket* Titanium::InterruptSpellOther(
|
||||
return outapp;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
@ -112,4 +98,20 @@ uint32_t Titanium::ResolveID(uint32_t id) const
|
||||
// override in patches where IDs need remapping
|
||||
return id;
|
||||
}
|
||||
|
||||
void Titanium::ResolveArguments(uint32_t id, std::array<const char*, 9>& args) const
|
||||
{
|
||||
switch (id) {
|
||||
case SPELL_FIZZLE:
|
||||
case MISS_NOTE:
|
||||
args[0] = nullptr; // drop spell link
|
||||
break;
|
||||
case SPELL_FIZZLE_OTHER:
|
||||
case MISSED_NOTE_OTHER:
|
||||
args[1] = nullptr; // drop spell link
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // namespace ZoneClient::Message
|
||||
|
||||
@ -23,26 +23,18 @@ namespace ZoneClient::Message {
|
||||
class Titanium : public IMessage
|
||||
{
|
||||
public:
|
||||
Titanium() {}
|
||||
~Titanium() override {}
|
||||
Titanium() = default;
|
||||
~Titanium() override = default;
|
||||
|
||||
EQApplicationPacket* Simple(uint32_t color, uint32_t id) const override;
|
||||
[[nodiscard]] EQApplicationPacket* Simple(uint32_t color, uint32_t id) const override;
|
||||
[[nodiscard]] EQApplicationPacket* Formatted(uint32_t color, uint32_t id, const std::array<const char*, 9>& args) 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;
|
||||
|
||||
EQApplicationPacket* InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
|
||||
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;
|
||||
|
||||
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* InterruptSpell(uint32_t message, uint32_t spawn_id, const char* spell_link) const override;
|
||||
EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, const char* name,
|
||||
const char* spell_link) const override;
|
||||
|
||||
protected:
|
||||
virtual uint32_t ResolveID(uint32_t id) const;
|
||||
[[nodiscard]] virtual uint32_t ResolveID(uint32_t id) const;
|
||||
virtual void ResolveArguments(uint32_t id, std::array<const char*, 9>& args) const;
|
||||
};
|
||||
} // namespace Zone::Message
|
||||
} // namespace ZoneClient::Message
|
||||
|
||||
@ -73,6 +73,21 @@ uint32_t TOB::ResolveID(uint32_t id) const
|
||||
}
|
||||
}
|
||||
|
||||
void TOB::ResolveArguments(uint32_t id, std::array<const char*, 9>& args) const
|
||||
{
|
||||
switch (id) {
|
||||
case SPELL_FIZZLE:
|
||||
case MISS_NOTE:
|
||||
case SPELL_FIZZLE_OTHER:
|
||||
case MISSED_NOTE_OTHER:
|
||||
// take all arguments (spell link)
|
||||
break;
|
||||
default:
|
||||
RoF2::ResolveArguments(id, args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
@ -167,11 +182,18 @@ static void ServerToTOBConvertLinks(std::string& message_out, const std::string&
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
EQApplicationPacket* TOB::Formatted(uint32_t color, uint32_t id, const std::array<const char*, 9>& args) const
|
||||
// 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) {
|
||||
std::array<const char*, 9> resolved_args = args;
|
||||
ResolveArguments(id, resolved_args);
|
||||
if (!resolved_args[0])
|
||||
return Simple(color, id);
|
||||
|
||||
SerializeBuffer buffer(49);
|
||||
// 49 is the minimum size needed for this packet since each arg writes at least 4 bytes
|
||||
buffer.WriteUInt32(0);
|
||||
@ -180,7 +202,7 @@ EQApplicationPacket* TOB::Formatted(uint32_t color, uint32_t id, const char* a1,
|
||||
buffer.WriteUInt32(string_id);
|
||||
buffer.WriteUInt32(color);
|
||||
|
||||
for (auto a : {a1, a2, a3, a4, a5, a6, a7, a8, a9}) {
|
||||
for (auto a : resolved_args) {
|
||||
if (a != nullptr) {
|
||||
std::string new_message;
|
||||
ServerToTOBConvertLinks(new_message, a);
|
||||
@ -195,16 +217,8 @@ EQApplicationPacket* TOB::Formatted(uint32_t color, uint32_t id, const char* a1,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EQApplicationPacket* TOB::InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
|
||||
const char* spell_name_override) const
|
||||
EQApplicationPacket* TOB::InterruptSpell(uint32_t message, uint32_t spawn_id, const char* spell_link) const
|
||||
{
|
||||
std::string spell_name = spell_name_override == nullptr || *spell_name_override == '\0'
|
||||
? GetSpellName(spell_id)
|
||||
: spell_name_override;
|
||||
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spell_id, spell_name_override);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(spell_link) + 1);
|
||||
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
|
||||
ic->messageid = ResolveID(message);
|
||||
@ -215,17 +229,9 @@ EQApplicationPacket* TOB::InterruptSpell(uint32_t message, uint32_t spawn_id, ui
|
||||
return outapp;
|
||||
}
|
||||
|
||||
EQApplicationPacket* TOB::InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
|
||||
const char* spell_name_override) const
|
||||
EQApplicationPacket* TOB::InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, const char* name,
|
||||
const char* spell_link) const
|
||||
{
|
||||
std::string spell_name = spell_name_override == nullptr || *spell_name_override == '\0'
|
||||
? GetSpellName(spell_id)
|
||||
: spell_name_override;
|
||||
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spell_id);
|
||||
|
||||
const char* name = sender->GetCleanName();
|
||||
auto outapp = new EQApplicationPacket(OP_InterruptCast,
|
||||
sizeof(InterruptCast_Struct) + strlen(name) + strlen(spell_link) + 2);
|
||||
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
|
||||
@ -236,23 +242,4 @@ 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
|
||||
{
|
||||
std::string spell_name(GetSpellName(spell_id));
|
||||
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spell_id);
|
||||
|
||||
return Formatted(type, message, spell_link);
|
||||
}
|
||||
|
||||
EQApplicationPacket* TOB::FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const
|
||||
{
|
||||
std::string spell_name(GetSpellName(spell_id));
|
||||
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spell_id);
|
||||
|
||||
return Formatted(type, message, caster, spell_link);
|
||||
}
|
||||
} // namespace Zone::Message
|
||||
} // namespace ZoneClient::Message
|
||||
|
||||
@ -26,21 +26,13 @@ public:
|
||||
TOB() {}
|
||||
~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;
|
||||
[[nodiscard]] EQApplicationPacket* Formatted(uint32_t color, uint32_t id, const std::array<const char*, 9>& args) const override;
|
||||
|
||||
EQApplicationPacket* InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
|
||||
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;
|
||||
|
||||
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* InterruptSpell(uint32_t message, uint32_t spawn_id, const char* spell_link) const override;
|
||||
EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, const char* name, const char* spell_link) const override;
|
||||
|
||||
protected:
|
||||
uint32_t ResolveID(uint32_t id) const override;
|
||||
[[nodiscard]] uint32_t ResolveID(uint32_t id) const override;
|
||||
void ResolveArguments(uint32_t id, std::array<const char*, 9>& args) const override;
|
||||
};
|
||||
} // namespace Zone::Message
|
||||
} // namespace ZoneClient::Message
|
||||
|
||||
@ -95,6 +95,9 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
#include "common/links.h"
|
||||
#include "patch/components/message/IMessage.h"
|
||||
|
||||
extern Zone *zone;
|
||||
extern volatile bool is_zone_loaded;
|
||||
extern WorldServer worldserver;
|
||||
@ -333,20 +336,18 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
Mob::SetMana(GetMana() - use_mana); // We send StopCasting which will update mana
|
||||
StopCasting();
|
||||
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spell_id);
|
||||
|
||||
if (IsClient())
|
||||
ZoneClient::ClientPatch::QueuePacket(
|
||||
CastToClient(), &ZoneClient::Message::IMessage::Fizzle,
|
||||
Chat::SpellFailure, fizzle_msg, spell_id);
|
||||
ZoneClient::Message::MessageString(CastToClient(), Chat::SpellFailure, fizzle_msg, spell_link);
|
||||
|
||||
/**
|
||||
* Song Failure message
|
||||
*/
|
||||
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());
|
||||
ZoneClient::Message::CloseMessageString(this, true, RuleI(Range, SpellMessages),
|
||||
nullptr, true, IsClient() ? FilterPCSpells : FilterNPCSpells)(
|
||||
Chat::SpellFailure, fizzle_msg == MISS_NOTE ? MISSED_NOTE_OTHER : SPELL_FIZZLE_OTHER, GetName(), spell_link);
|
||||
|
||||
TryTriggerOnCastRequirement();
|
||||
return false;
|
||||
@ -1301,10 +1302,9 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
|
||||
if (IsClient() && message != SONG_ENDS)
|
||||
{
|
||||
// the interrupt message
|
||||
ZoneClient::ClientPatch::QueuePacket(
|
||||
CastToClient(), &ZoneClient::Message::IMessage::InterruptSpell,
|
||||
message, GetID(), spellid, "");
|
||||
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spellid);
|
||||
ZoneClient::Message::InterruptSpell(CastToClient(), message, GetID(), spell_link);
|
||||
SendSpellBarEnable(spellid);
|
||||
}
|
||||
|
||||
@ -1330,10 +1330,9 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
|
||||
}
|
||||
|
||||
// this is the actual message, it works the same as a formatted message
|
||||
ZoneClient::ClientPatch::QueueCloseClients(
|
||||
this, true, RuleI(Range, SongMessages), nullptr, true,
|
||||
IsClient() ? FilterPCSpells : FilterNPCSpells)(
|
||||
&ZoneClient::Message::IMessage::InterruptSpellOther, this, message_other, GetID(), spellid, "");
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spellid);
|
||||
ZoneClient::Message::InterruptSpellOther(this, message_other, GetID(), GetCleanName(), spell_link);
|
||||
}
|
||||
|
||||
// this is like interrupt, just it doesn't spam interrupt packets to everyone
|
||||
@ -7269,11 +7268,11 @@ void Mob::DoBardCastingFromItemClick(bool is_casting_bard_song, uint32 cast_time
|
||||
Known bug: When a bard uses an augment with a clicky that has a cast time, the cast won't display. This issue only affects bards.
|
||||
*/
|
||||
if (is_casting_bard_song) {
|
||||
//For spells with cast times. Cancel song cast, stop pusling and start item cast.
|
||||
//For spells with cast times. Cancel song cast, stop pulsing and start item cast.
|
||||
if (cast_time != 0) {
|
||||
ZoneClient::ClientPatch::QueuePacket(
|
||||
CastToClient(), &ZoneClient::Message::IMessage::InterruptSpell,
|
||||
SONG_ENDS, GetID(), spell_id, "");
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spell_id);
|
||||
ZoneClient::Message::InterruptSpell(CastToClient(), SONG_ENDS, GetID(), spell_link);
|
||||
|
||||
ZeroCastingVars();
|
||||
ZeroBardPulseVars();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user