Expanded message patch to specialize fizzle messages

This commit is contained in:
dannuic
2026-04-22 12:10:18 -06:00
parent 2c4cb14a6c
commit 46dce8499f
10 changed files with 86 additions and 108 deletions
+40 -62
View File
@@ -44,6 +44,8 @@
#include "common/spdat.h" #include "common/spdat.h"
#include "common/strings.h" #include "common/strings.h"
#include "common/zone_store.h" #include "common/zone_store.h"
#include "patch/client_version.h"
#include "patch/components/message/IMessage.h"
#include "zone/bot_command.h" #include "zone/bot_command.h"
#include "zone/cheat_manager.h" #include "zone/cheat_manager.h"
#include "zone/command.h" #include "zone/command.h"
@@ -66,8 +68,6 @@
#include <cstdio> #include <cstdio>
#include <cstdarg> #include <cstdarg>
#include "patch/client_version.h"
extern QueryServ* QServ; extern QueryServ* QServ;
extern EntityList entity_list; extern EntityList entity_list;
extern Zone* zone; extern Zone* zone;
@@ -1794,7 +1794,7 @@ void Client::Message(uint32 type, const char* message, ...) {
} }
void Client::FilteredMessage(Mob *sender, uint32 type, eqFilterType filter, const char* message, ...) { void Client::FilteredMessage(Mob *sender, uint32 type, eqFilterType filter, const char* message, ...) {
if (!FilteredMessageCheck(sender, filter)) if (!ShouldGetPacket(sender, filter))
return; return;
va_list argptr; va_list argptr;
@@ -3876,50 +3876,49 @@ void Client::MessageString(const CZClientMessageString_Struct* msg)
} }
} }
// helper function, returns true if we should see the message // helper function, returns true if the client should get the packet based on the filter and sender
bool Client::FilteredMessageCheck(Mob *sender, eqFilterType filter) bool Client::ShouldGetPacket(Mob *sender, eqFilterType filter)
{ {
eqFilterMode mode = GetFilter(filter); eqFilterMode mode = GetFilter(filter);
// easy ones first
if (mode == FilterShow) {
return true;
} else if (mode == FilterHide) {
return false;
}
if (sender != this && mode == FilterShowSelfOnly) { // easy ones first
if (mode == FilterShow)
return true;
if (mode == FilterHide)
return false; return false;
} else if (sender) {
if (mode == FilterShowGroupOnly) { if (sender != this && mode == FilterShowSelfOnly)
auto g = GetGroup(); return false;
auto r = GetRaid();
if (g) { if (sender != nullptr && mode == FilterShowGroupOnly) {
if (g->IsGroupMember(sender)) { if (sender == this)
return true; return true;
}
} else if (r && sender->IsClient()) { auto g = GetGroup();
auto rgid1 = r->GetGroup(this); if (g && g->IsGroupMember(sender))
auto rgid2 = r->GetGroup(sender->CastToClient()); return true;
if (rgid1 != RAID_GROUPLESS && rgid1 == rgid2) {
return true; auto r = GetRaid();
} if (r && sender->IsClient()) {
} else { auto rgid1 = r->GetGroup(this);
return false; auto rgid2 = r->GetGroup(sender->CastToClient());
} if (rgid1 != RAID_GROUPLESS && rgid1 == rgid2)
return true;
} else {
return false;
} }
} }
// we passed our checks // fallback case (send by default)
return true; return true;
} }
void Client::FilteredMessageString(Mob *sender, uint32 type, void Client::FilteredMessageString(Mob *sender, uint32 type,
eqFilterType filter, uint32 string_id) eqFilterType filter, uint32 string_id)
{ {
if (!FilteredMessageCheck(sender, filter)) if (ShouldGetPacket(sender, filter))
return; MessageString(type, string_id);
MessageString(type, string_id);
} }
void Client::FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter, uint32 string_id, void Client::FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter, uint32 string_id,
@@ -3927,37 +3926,16 @@ void Client::FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter
const char *message4, const char *message5, const char *message6, const char *message4, const char *message5, const char *message6,
const char *message7, const char *message8, const char *message9) const char *message7, const char *message8, const char *message9)
{ {
if (!FilteredMessageCheck(sender, filter))
return;
if (type == Chat::Emote)
type = 4;
if (!message1) { if (!message1) {
FilteredMessageString(sender, type, filter, string_id); // use the simple message instead FilteredMessageString(sender, type, filter, string_id); // use the simple message instead
return; } else if (ShouldGetPacket(sender, filter)) {
if (type == Chat::Emote)
type = 4;
MessageString(
type, string_id, message1, message2, message3, message4,
message5, message6, message7, message8, message9);
} }
const char *message_arg[] = {
message1, message2, message3, message4, message5,
message6, message7, message8, message9
};
SerializeBuffer buf(20);
buf.WriteInt32(0); // unknown
buf.WriteInt32(string_id);
buf.WriteInt32(type);
for (auto &m : message_arg) {
if (m == nullptr)
break;
buf.WriteString(m);
}
buf.WriteInt8(0); // prevent oob in packet translation, maybe clean that up sometime
auto outapp = std::make_unique<EQApplicationPacket>(OP_FormattedMessage, std::move(buf));
QueuePacket(outapp.get());
} }
void Client::Tell_StringID(uint32 string_id, const char *who, const char *message) void Client::Tell_StringID(uint32 string_id, const char *who, const char *message)
+1 -2
View File
@@ -16,7 +16,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "patch/components/message/IMessage.h"
class Client; class Client;
class EQApplicationPacket; class EQApplicationPacket;
@@ -348,7 +347,7 @@ public:
void MessageString(uint32 type, uint32 string_id, uint32 distance = 0) override; void MessageString(uint32 type, uint32 string_id, uint32 distance = 0) override;
void MessageString(uint32 type, uint32 string_id, const char* message,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0, uint32 distance = 0) override; void MessageString(uint32 type, uint32 string_id, const char* message,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0, uint32 distance = 0) override;
void MessageString(const CZClientMessageString_Struct* msg); void MessageString(const CZClientMessageString_Struct* msg);
bool FilteredMessageCheck(Mob *sender, eqFilterType filter); bool ShouldGetPacket(Mob *sender, eqFilterType filter);
void FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter, uint32 string_id); void FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter, uint32 string_id);
void FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter, void FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter,
uint32 string_id, const char *message1, const char *message2 = nullptr, uint32 string_id, const char *message1, const char *message2 = nullptr,
+8 -15
View File
@@ -42,6 +42,7 @@ public:
auto [packet, _] = build_packets.try_emplace( auto [packet, _] = build_packets.try_emplace(
ent->ClientVersion(), ent->ClientVersion(),
std::invoke(fun, GetMessageComponent(ent->ClientVersion()).get(), std::forward<Args>(args)...)); std::invoke(fun, GetMessageComponent(ent->ClientVersion()).get(), std::forward<Args>(args)...));
if (packet->second != nullptr) if (packet->second != nullptr)
ent->QueuePacket(packet->second, ackreq, Client::CLIENT_CONNECTED); ent->QueuePacket(packet->second, ackreq, Client::CLIENT_CONNECTED);
} }
@@ -71,21 +72,13 @@ public:
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->Connected() && client->ShouldGetPacket(sender, filter)) {
eqFilterMode client_filter = client->GetFilter(filter); auto [packet, _] = build_packets.try_emplace(
if (filter == FilterNone || client_filter == FilterShow || client->ClientVersion(),
(client_filter == FilterShowGroupOnly && std::invoke(fun, GetMessageComponent(client->ClientVersion()).get(), std::forward<Args>(args)...));
(sender == client || (client->GetGroup() && client->GetGroup()->IsGroupMember(
sender)))) || if (packet->second != nullptr)
(client_filter == FilterShowSelfOnly && client == sender) client->QueuePacket(packet->second, is_ack_required, Client::CLIENT_CONNECTED);
) {
auto [packet, _] = build_packets.try_emplace(
client->ClientVersion(),
std::invoke(fun, GetMessageComponent(client->ClientVersion()).get(),
std::forward<Args>(args)...));
if (packet->second != nullptr)
client->QueuePacket(packet->second, is_ack_required, Client::CLIENT_CONNECTED);
}
} }
} }
} }
+2 -1
View File
@@ -46,7 +46,8 @@ public:
const char* spell_name_override = "") const = 0; 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(Mob* m, 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;
}; };
} // namespace Zone::Message } // namespace Zone::Message
+6 -2
View File
@@ -91,8 +91,12 @@ EQApplicationPacket* Titanium::InterruptSpellOther(Mob* sender, uint32_t message
return outapp; return outapp;
} }
EQApplicationPacket* Titanium::Fizzle(Mob* m, 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 nullptr; 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 // A value of 0 means that the string isn't mapped in this client, valid string ids start at 1
+2 -1
View File
@@ -38,7 +38,8 @@ public:
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(Mob* m, 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;
protected: protected:
virtual uint32_t ResolveID(uint32_t id) const; virtual uint32_t ResolveID(uint32_t id) const;
+13
View File
@@ -107,4 +107,17 @@ 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 {
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 {
std::string spell_name(GetSpellName(spell_id));
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);
return Formatted(type, message, caster, spell_link.c_str());
}
} // namespace Zone::Message } // namespace Zone::Message
+3
View File
@@ -30,6 +30,9 @@ public:
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* 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;
}; };
+9 -23
View File
@@ -336,35 +336,21 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
Mob::SetMana(GetMana() - use_mana); // We send StopCasting which will update mana Mob::SetMana(GetMana() - use_mana); // We send StopCasting which will update mana
StopCasting(); StopCasting();
// TODO: can handle spell name overrides here if (IsClient())
std::string spell_name(GetSpellName(spell_id)); ZoneClient::ClientPatch::QueuePacket(CastToClient(), &ZoneClient::Message::IMessage::Fizzle,
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name); Chat::SpellFailure, fizzle_msg, spell_id);
// pre-TOB clients will just discard the extra argument here, so don't worry about patching them out in patches
MessageString(Chat::SpellFailure, fizzle_msg, spell_link.c_str());
/** /**
* Song Failure message * Song Failure message
* pre-TOB clients will just discard the extra argument here, so don't worry about patching them out in patches
*/ */
entity_list.FilteredMessageCloseString( ZoneClient::ClientPatch::QueueCloseClients(this, true, RuleI(Range, SpellMessages),
this, nullptr, true,
true, IsClient() ? FilterPCSpells : FilterNPCSpells)(
RuleI(Range, SpellMessages), &ZoneClient::Message::IMessage::FizzleOther, Chat::SpellFailure,
Chat::SpellFailure, fizzle_msg == MISS_NOTE ? MISSED_NOTE_OTHER : SPELL_FIZZLE_OTHER, spell_id, GetName());
(IsClient() ? FilterPCSpells : FilterNPCSpells),
(fizzle_msg == MISS_NOTE ? MISSED_NOTE_OTHER : SPELL_FIZZLE_OTHER),
0,
/*
MessageFormat: A missed note brings %1's song to a close! (TOB: A missed note brings %1's %2 to a close!)
MessageFormat: %1's spell fizzles! (TOB: %1's %2 spell fizzles!)
*/
GetName(),
spell_link.c_str()
);
TryTriggerOnCastRequirement(); TryTriggerOnCastRequirement();
return(false); return false;
} }
SaveSpellLoc(); SaveSpellLoc();
+2 -2
View File
@@ -66,9 +66,9 @@
#define FISHING_SUCCESS_FISH_NAME 421 //You caught %1! #define FISHING_SUCCESS_FISH_NAME 421 //You caught %1!
#define FISHING_SPILL_BEER 171 //You spill your beer while bringing in your line. #define FISHING_SPILL_BEER 171 //You spill your beer while bringing in your line.
#define FISHING_LOST_BAIT 172 //You lost your bait! #define FISHING_LOST_BAIT 172 //You lost your bait!
#define SPELL_FIZZLE 173 //Your spell fizzles! // TODO: TOB - Your %1 spell fizzles! #define SPELL_FIZZLE 173 //Your spell fizzles!
#define MUST_EQUIP_ITEM 179 //You cannot use this item unless it is equipped. #define MUST_EQUIP_ITEM 179 //You cannot use this item unless it is equipped.
#define MISS_NOTE 180 //You miss a note, bringing your song to a close! // TODO: TOB - You miss a note, bringing your %1 to a close! #define MISS_NOTE 180 //You miss a note, bringing your song to a close!
#define CANNOT_USE_ITEM 181 //Your race, class, or deity cannot use this item. // TODO: TOB moved this: 6611 Your class, deity, and/or race may not equip %1. #define CANNOT_USE_ITEM 181 //Your race, class, or deity cannot use this item. // TODO: TOB moved this: 6611 Your class, deity, and/or race may not equip %1.
#define ITEM_OUT_OF_CHARGES 182 //Item is out of charges. #define ITEM_OUT_OF_CHARGES 182 //Item is out of charges.
#define ALREADY_ON_A_MOUNT 189 //You are already on a mount. #define ALREADY_ON_A_MOUNT 189 //You are already on a mount.