[Saylinks] Implement Auto Saylink Injection (#1525)

* Implement auto saylink injection

* Cover Lua say since it takes a different code path
This commit is contained in:
Chris Miles 2021-09-12 22:08:30 -05:00 committed by GitHub
parent 94c1a50cc8
commit 6b93130c13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 112 additions and 30 deletions

View File

@ -598,6 +598,8 @@ RULE_INT(Chat, IntervalDurationMS, 60000, "Interval length in milliseconds")
RULE_INT(Chat, KarmaUpdateIntervalMS, 1200000, "Karma update interval in milliseconds") RULE_INT(Chat, KarmaUpdateIntervalMS, 1200000, "Karma update interval in milliseconds")
RULE_INT(Chat, KarmaGlobalChatLimit, 72, "Amount of karma you need to be able to talk in ooc/auction/chat below the level limit") RULE_INT(Chat, KarmaGlobalChatLimit, 72, "Amount of karma you need to be able to talk in ooc/auction/chat below the level limit")
RULE_INT(Chat, GlobalChatLevelLimit, 8, "Level limit you need to of reached to talk in ooc/auction/chat if your karma is too low") RULE_INT(Chat, GlobalChatLevelLimit, 8, "Level limit you need to of reached to talk in ooc/auction/chat if your karma is too low")
RULE_BOOL(Chat, AutoInjectSaylinksToSay, true, "Automatically injects saylinks into dialogue that has [brackets in them]")
RULE_BOOL(Chat, AutoInjectSaylinksToClientMessage, true, "Automatically injects saylinks into dialogue that has [brackets in them]")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Merchant) RULE_CATEGORY(Merchant)

View File

@ -1,5 +1,5 @@
/* EQEMu: Everquest Server Emulator /* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -11,7 +11,7 @@
are required to give you total support for your newly bought product; are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@ -339,4 +339,48 @@ std::string EQ::SayLinkEngine::GenerateQuestSaylink(std::string saylink_text, bo
linker.SetProxyText(link_name.c_str()); linker.SetProxyText(link_name.c_str());
return linker.GenerateLink(); return linker.GenerateLink();
} }
std::string EQ::SayLinkEngine::InjectSaylinksIfNotExist(const char *message)
{
std::string new_message = message;
int link_index = 0;
std::vector<std::string> links = {};
// loop through brackets until none exist
while (new_message.find('[') != std::string::npos && new_message.find(']') != std::string::npos) {
std::string bracket_message = get_between(new_message, "[", "]");
// already a saylink
// todo: improve this later
if (!bracket_message.empty() && bracket_message.length() > 50) {
links.emplace_back(bracket_message);
}
else {
links.emplace_back(EQ::SayLinkEngine::GenerateQuestSaylink(bracket_message, false, bracket_message));
}
// replace with anchor
find_replace(
new_message,
fmt::format("[{}]", bracket_message),
fmt::format("<link:{}>", link_index)
);
link_index++;
}
// pop links onto anchors
link_index = 0;
for (auto &link: links) {
find_replace(
new_message,
fmt::format("<link:{}>", link_index),
fmt::format("[{}]", link)
);
link_index++;
}
return new_message;
}

View File

@ -1,17 +1,17 @@
/* EQEMu: Everquest Server Emulator /* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product; are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@ -105,6 +105,7 @@ namespace EQ
void Reset(); void Reset();
static std::string InjectSaylinksIfNotExist(const char *message);
private: private:
void generate_body(); void generate_body();
void generate_text(); void generate_text();

View File

@ -1593,7 +1593,7 @@ XS(XS__addldonpoints) {
dXSARGS; dXSARGS;
if (items != 2) if (items != 2)
Perl_croak(aTHX_ "Usage: quest::addldonpoints(uint32 theme_id, int points)"); Perl_croak(aTHX_ "Usage: quest::addldonpoints(uint32 theme_id, int points)");
uint32 theme_id = (uint32) SvUV(ST(0)); uint32 theme_id = (uint32) SvUV(ST(0));
int points = (int) SvIV(ST(1)); int points = (int) SvIV(ST(1));
quest_manager.addldonpoints(theme_id, points); quest_manager.addldonpoints(theme_id, points);
@ -6483,7 +6483,7 @@ XS(XS__gethexcolorcode) {
sv_setpv(TARG, hex_color_code.c_str()); sv_setpv(TARG, hex_color_code.c_str());
XSprePUSH; XSprePUSH;
PUSHTARG; PUSHTARG;
XSRETURN(1); XSRETURN(1);
} }
XS(XS__getaaexpmodifierbycharid); XS(XS__getaaexpmodifierbycharid);
@ -6491,7 +6491,7 @@ XS(XS__getaaexpmodifierbycharid) {
dXSARGS; dXSARGS;
if (items != 2) if (items != 2)
Perl_croak(aTHX_ "Usage: quest::getaaexpmodifierbycharid(uint32 character_id, uint32 zone_id)"); Perl_croak(aTHX_ "Usage: quest::getaaexpmodifierbycharid(uint32 character_id, uint32 zone_id)");
dXSTARG; dXSTARG;
double aa_modifier; double aa_modifier;
uint32 character_id = (uint32) SvUV(ST(0)); uint32 character_id = (uint32) SvUV(ST(0));
@ -6507,7 +6507,7 @@ XS(XS__getexpmodifierbycharid) {
dXSARGS; dXSARGS;
if (items != 2) if (items != 2)
Perl_croak(aTHX_ "Usage: quest::getexpmodifierbycharid(uint32 character_id, uint32 zone_id)"); Perl_croak(aTHX_ "Usage: quest::getexpmodifierbycharid(uint32 character_id, uint32 zone_id)");
dXSTARG; dXSTARG;
double exp_modifier; double exp_modifier;
uint32 character_id = (uint32) SvUV(ST(0)); uint32 character_id = (uint32) SvUV(ST(0));
@ -6870,7 +6870,7 @@ XS(XS__getspellstat) {
uint8 slot = 0; uint8 slot = 0;
if (items == 3) if (items == 3)
slot = (uint8) SvUV(ST(2)); slot = (uint8) SvUV(ST(2));
stat_value = quest_manager.getspellstat(spell_id, stat_identifier, slot); stat_value = quest_manager.getspellstat(spell_id, stat_identifier, slot);
XSprePUSH; XSprePUSH;

View File

@ -4185,8 +4185,10 @@ bool Entity::CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z,
return false; return false;
} }
void EntityList::QuestJournalledSayClose(Mob *sender, float dist, const char *mobname, const char *message, void EntityList::QuestJournalledSayClose(
Journal::Options &opts) Mob *sender, float dist, const char *mobname, const char *message,
Journal::Options &opts
)
{ {
SerializeBuffer buf(sizeof(SpecialMesgHeader_Struct) + 12 + 64 + 64); SerializeBuffer buf(sizeof(SpecialMesgHeader_Struct) + 12 + 64 + 64);
@ -4199,7 +4201,15 @@ void EntityList::QuestJournalledSayClose(Mob *sender, float dist, const char *mo
buf.WriteInt32(0); // location, client doesn't seem to do anything with this buf.WriteInt32(0); // location, client doesn't seem to do anything with this
buf.WriteInt32(0); buf.WriteInt32(0);
buf.WriteInt32(0); buf.WriteInt32(0);
buf.WriteString(message);
// auto inject saylinks (say)
if (RuleB(Chat, AutoInjectSaylinksToSay)) {
std::string new_message = EQ::SayLinkEngine::InjectSaylinksIfNotExist(message);
buf.WriteString(new_message);
}
else {
buf.WriteString(message);
}
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf); auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);

View File

@ -755,7 +755,15 @@ double Lua_Mob::GetSize() {
void Lua_Mob::Message(int type, const char *message) { void Lua_Mob::Message(int type, const char *message) {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->Message(type, message);
// auto inject saylinks
if (RuleB(Chat, AutoInjectSaylinksToClientMessage)) {
std::string new_message = EQ::SayLinkEngine::InjectSaylinksIfNotExist(message);
self->Message(type, new_message.c_str());
}
else {
self->Message(type, message);
}
} }
void Lua_Mob::MessageString(int type, int string_id, uint32 distance) { void Lua_Mob::MessageString(int type, int string_id, uint32 distance) {
@ -2747,7 +2755,7 @@ luabind::scope lua_register_mob() {
.def("GetNimbusEffect2", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect2) .def("GetNimbusEffect2", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect2)
.def("GetNimbusEffect3", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect3) .def("GetNimbusEffect3", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect3)
.def("IsTargetable", (bool(Lua_Mob::*)(void))&Lua_Mob::IsTargetable) .def("IsTargetable", (bool(Lua_Mob::*)(void))&Lua_Mob::IsTargetable)
.def("HasShieldEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasShieldEquiped) .def("HasShieldEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasShieldEquiped)
.def("HasTwoHandBluntEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHandBluntEquiped) .def("HasTwoHandBluntEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHandBluntEquiped)
.def("HasTwoHanderEquipped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHanderEquipped) .def("HasTwoHanderEquipped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHanderEquipped)
.def("GetHerosForgeModel", (int32(Lua_Mob::*)(uint8))&Lua_Mob::GetHerosForgeModel) .def("GetHerosForgeModel", (int32(Lua_Mob::*)(uint8))&Lua_Mob::GetHerosForgeModel)

View File

@ -2923,10 +2923,19 @@ void Mob::Say(const char *format, ...)
talker = this; talker = this;
} }
entity_list.MessageCloseString( if (RuleB(Chat, AutoInjectSaylinksToSay)) {
talker, false, 200, 10, std::string new_message = EQ::SayLinkEngine::InjectSaylinksIfNotExist(buf);
GENERIC_SAY, GetCleanName(), buf entity_list.MessageCloseString(
); talker, false, 200, 10,
GENERIC_SAY, GetCleanName(), new_message.c_str()
);
}
else {
entity_list.MessageCloseString(
talker, false, 200, 10,
GENERIC_SAY, GetCleanName(), buf
);
}
} }
// //

View File

@ -989,7 +989,7 @@ XS(XS_Mob_BuffCount) {
VALIDATE_THIS_IS_MOB; VALIDATE_THIS_IS_MOB;
RETVAL = THIS->BuffCount(); RETVAL = THIS->BuffCount();
XSprePUSH; XSprePUSH;
PUSHu((UV) RETVAL); PUSHu((UV) RETVAL);
} }
XSRETURN(1); XSRETURN(1);
} }
@ -2620,7 +2620,15 @@ XS(XS_Mob_Message) {
uint32 type = (uint32) SvUV(ST(1)); uint32 type = (uint32) SvUV(ST(1));
char *message = (char *) SvPV_nolen(ST(2)); char *message = (char *) SvPV_nolen(ST(2));
VALIDATE_THIS_IS_MOB; VALIDATE_THIS_IS_MOB;
THIS->Message(type, message);
// auto inject saylinks
if (RuleB(Chat, AutoInjectSaylinksToClientMessage)) {
std::string new_message = EQ::SayLinkEngine::InjectSaylinksIfNotExist(message);
THIS->Message(type, new_message.c_str());
}
else {
THIS->Message(type, message);
}
} }
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
@ -6016,7 +6024,7 @@ XS(XS_Mob_GetClassName) {
XSprePUSH; XSprePUSH;
PUSHTARG; PUSHTARG;
} }
XSRETURN(1); XSRETURN(1);
} }
XS(XS_Mob_GetRaceName); XS(XS_Mob_GetRaceName);
@ -6039,7 +6047,7 @@ XS(XS_Mob_GetRaceName) {
XS(XS_Mob_DeleteBucket); XS(XS_Mob_DeleteBucket);
XS(XS_Mob_DeleteBucket) { XS(XS_Mob_DeleteBucket) {
dXSARGS; dXSARGS;
if (items != 2) if (items != 2)
Perl_croak(aTHX_ "Usage: Mob::DeleteBucket(THIS, std::string bucket_name)"); // @categories Script Utility Perl_croak(aTHX_ "Usage: Mob::DeleteBucket(THIS, std::string bucket_name)"); // @categories Script Utility
{ {
@ -6053,7 +6061,7 @@ XS(XS_Mob_DeleteBucket) {
XS(XS_Mob_GetBucket); XS(XS_Mob_GetBucket);
XS(XS_Mob_GetBucket) { XS(XS_Mob_GetBucket) {
dXSARGS; dXSARGS;
if (items != 2) if (items != 2)
Perl_croak(aTHX_ "Usage: Mob::GetBucket(THIS, std::string bucket_name)"); // @categories Script Utility Perl_croak(aTHX_ "Usage: Mob::GetBucket(THIS, std::string bucket_name)"); // @categories Script Utility
{ {
@ -6072,7 +6080,7 @@ XS(XS_Mob_GetBucket) {
XS(XS_Mob_GetBucketExpires); XS(XS_Mob_GetBucketExpires);
XS(XS_Mob_GetBucketExpires) { XS(XS_Mob_GetBucketExpires) {
dXSARGS; dXSARGS;
if (items != 2) if (items != 2)
Perl_croak(aTHX_ "Usage: Mob::GetBucketExpires(THIS, std::string bucket_name)"); // @categories Script Utility Perl_croak(aTHX_ "Usage: Mob::GetBucketExpires(THIS, std::string bucket_name)"); // @categories Script Utility
{ {
@ -6091,7 +6099,7 @@ XS(XS_Mob_GetBucketExpires) {
XS(XS_Mob_GetBucketKey); XS(XS_Mob_GetBucketKey);
XS(XS_Mob_GetBucketKey) { XS(XS_Mob_GetBucketKey) {
dXSARGS; dXSARGS;
if (items != 1) if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::GetBucketKey(THIS)"); // @categories Script Utility Perl_croak(aTHX_ "Usage: Mob::GetBucketKey(THIS)"); // @categories Script Utility
{ {
@ -6109,7 +6117,7 @@ XS(XS_Mob_GetBucketKey) {
XS(XS_Mob_GetBucketRemaining); XS(XS_Mob_GetBucketRemaining);
XS(XS_Mob_GetBucketRemaining) { XS(XS_Mob_GetBucketRemaining) {
dXSARGS; dXSARGS;
if (items != 2) if (items != 2)
Perl_croak(aTHX_ "Usage: Mob::GetBucketRemaining(THIS, std::string bucket_name)"); // @categories Script Utility Perl_croak(aTHX_ "Usage: Mob::GetBucketRemaining(THIS, std::string bucket_name)"); // @categories Script Utility
{ {
@ -6128,7 +6136,7 @@ XS(XS_Mob_GetBucketRemaining) {
XS(XS_Mob_SetBucket); XS(XS_Mob_SetBucket);
XS(XS_Mob_SetBucket) { XS(XS_Mob_SetBucket) {
dXSARGS; dXSARGS;
if (items < 3 || items > 4) if (items < 3 || items > 4)
Perl_croak(aTHX_ "Usage: Mob::SetBucket(THIS, std::string bucket_name, std::string bucket_value, [std::string expiration])"); // @categories Script Utility Perl_croak(aTHX_ "Usage: Mob::SetBucket(THIS, std::string bucket_name, std::string bucket_value, [std::string expiration])"); // @categories Script Utility
{ {
@ -6146,7 +6154,7 @@ XS(XS_Mob_SetBucket) {
} }
XS(XS_Mob_IsHorse); XS(XS_Mob_IsHorse);
XS(XS_Mob_IsHorse) { XS(XS_Mob_IsHorse) {
dXSARGS; dXSARGS;
if (items != 1) if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::IsHorse(THIS)"); // @categories Script Utility Perl_croak(aTHX_ "Usage: Mob::IsHorse(THIS)"); // @categories Script Utility