diff --git a/common/ruletypes.h b/common/ruletypes.h index 37bf96711..9457313ec 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -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, 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_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(Merchant) diff --git a/common/say_link.cpp b/common/say_link.cpp index b47897112..d5083384b 100644 --- a/common/say_link.cpp +++ b/common/say_link.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) 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; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software 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()); return linker.GenerateLink(); -} \ No newline at end of file +} + +std::string EQ::SayLinkEngine::InjectSaylinksIfNotExist(const char *message) +{ + std::string new_message = message; + + int link_index = 0; + std::vector 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_index) + ); + + link_index++; + } + + // pop links onto anchors + link_index = 0; + for (auto &link: links) { + find_replace( + new_message, + fmt::format("", link_index), + fmt::format("[{}]", link) + ); + link_index++; + } + + return new_message; +} diff --git a/common/say_link.h b/common/say_link.h index c0ea5a235..982b9ec58 100644 --- a/common/say_link.h +++ b/common/say_link.h @@ -1,17 +1,17 @@ /* EQEMu: Everquest Server Emulator - + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) 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 the Free Software Foundation; version 2 of the License. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY except by those people which sell it, which are required to give you total support for your newly bought product; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -105,6 +105,7 @@ namespace EQ void Reset(); + static std::string InjectSaylinksIfNotExist(const char *message); private: void generate_body(); void generate_text(); diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 89125d713..a8c14d669 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -1593,7 +1593,7 @@ XS(XS__addldonpoints) { dXSARGS; if (items != 2) Perl_croak(aTHX_ "Usage: quest::addldonpoints(uint32 theme_id, int points)"); - + uint32 theme_id = (uint32) SvUV(ST(0)); int points = (int) SvIV(ST(1)); quest_manager.addldonpoints(theme_id, points); @@ -6483,7 +6483,7 @@ XS(XS__gethexcolorcode) { sv_setpv(TARG, hex_color_code.c_str()); XSprePUSH; PUSHTARG; - XSRETURN(1); + XSRETURN(1); } XS(XS__getaaexpmodifierbycharid); @@ -6491,7 +6491,7 @@ XS(XS__getaaexpmodifierbycharid) { dXSARGS; if (items != 2) Perl_croak(aTHX_ "Usage: quest::getaaexpmodifierbycharid(uint32 character_id, uint32 zone_id)"); - + dXSTARG; double aa_modifier; uint32 character_id = (uint32) SvUV(ST(0)); @@ -6507,7 +6507,7 @@ XS(XS__getexpmodifierbycharid) { dXSARGS; if (items != 2) Perl_croak(aTHX_ "Usage: quest::getexpmodifierbycharid(uint32 character_id, uint32 zone_id)"); - + dXSTARG; double exp_modifier; uint32 character_id = (uint32) SvUV(ST(0)); @@ -6870,7 +6870,7 @@ XS(XS__getspellstat) { uint8 slot = 0; if (items == 3) slot = (uint8) SvUV(ST(2)); - + stat_value = quest_manager.getspellstat(spell_id, stat_identifier, slot); XSprePUSH; diff --git a/zone/entity.cpp b/zone/entity.cpp index 53477e5d7..12898f0ea 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -4185,8 +4185,10 @@ bool Entity::CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z, return false; } -void EntityList::QuestJournalledSayClose(Mob *sender, float dist, const char *mobname, const char *message, - Journal::Options &opts) +void EntityList::QuestJournalledSayClose( + Mob *sender, float dist, const char *mobname, const char *message, + Journal::Options &opts +) { 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); 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); diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 6eff81a0c..b37841e73 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -755,7 +755,15 @@ double Lua_Mob::GetSize() { void Lua_Mob::Message(int type, const char *message) { 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) { @@ -2747,7 +2755,7 @@ luabind::scope lua_register_mob() { .def("GetNimbusEffect2", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect2) .def("GetNimbusEffect3", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect3) .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("HasTwoHanderEquipped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHanderEquipped) .def("GetHerosForgeModel", (int32(Lua_Mob::*)(uint8))&Lua_Mob::GetHerosForgeModel) diff --git a/zone/mob.cpp b/zone/mob.cpp index 287bdad92..902c19140 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -2923,10 +2923,19 @@ void Mob::Say(const char *format, ...) talker = this; } - entity_list.MessageCloseString( - talker, false, 200, 10, - GENERIC_SAY, GetCleanName(), buf - ); + if (RuleB(Chat, AutoInjectSaylinksToSay)) { + std::string new_message = EQ::SayLinkEngine::InjectSaylinksIfNotExist(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 + ); + } } // diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index 24a9ec3b9..6f48c4cd8 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -989,7 +989,7 @@ XS(XS_Mob_BuffCount) { VALIDATE_THIS_IS_MOB; RETVAL = THIS->BuffCount(); XSprePUSH; - PUSHu((UV) RETVAL); + PUSHu((UV) RETVAL); } XSRETURN(1); } @@ -2620,7 +2620,15 @@ XS(XS_Mob_Message) { uint32 type = (uint32) SvUV(ST(1)); char *message = (char *) SvPV_nolen(ST(2)); 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; } @@ -6016,7 +6024,7 @@ XS(XS_Mob_GetClassName) { XSprePUSH; PUSHTARG; } - XSRETURN(1); + XSRETURN(1); } XS(XS_Mob_GetRaceName); @@ -6039,7 +6047,7 @@ XS(XS_Mob_GetRaceName) { XS(XS_Mob_DeleteBucket); XS(XS_Mob_DeleteBucket) { - dXSARGS; + dXSARGS; if (items != 2) 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) { - dXSARGS; + dXSARGS; if (items != 2) 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) { - dXSARGS; + dXSARGS; if (items != 2) 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) { - dXSARGS; + dXSARGS; if (items != 1) 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) { - dXSARGS; + dXSARGS; if (items != 2) 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) { - dXSARGS; + dXSARGS; 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 { @@ -6146,7 +6154,7 @@ XS(XS_Mob_SetBucket) { } XS(XS_Mob_IsHorse); -XS(XS_Mob_IsHorse) { +XS(XS_Mob_IsHorse) { dXSARGS; if (items != 1) Perl_croak(aTHX_ "Usage: Mob::IsHorse(THIS)"); // @categories Script Utility