diff --git a/data/sql/updates/db_world/2019_01_11_00.sql b/data/sql/updates/db_world/2019_01_11_00.sql new file mode 100644 index 000000000..5e65cd433 --- /dev/null +++ b/data/sql/updates/db_world/2019_01_11_00.sql @@ -0,0 +1,39 @@ +-- DB update 2019_01_10_00 -> 2019_01_11_00 +DROP PROCEDURE IF EXISTS `updateDb`; +DELIMITER // +CREATE PROCEDURE updateDb () +proc:BEGIN DECLARE OK VARCHAR(100) DEFAULT 'FALSE'; +SELECT COUNT(*) INTO @COLEXISTS +FROM information_schema.COLUMNS +WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'version_db_world' AND COLUMN_NAME = '2019_01_10_00'; +IF @COLEXISTS = 0 THEN LEAVE proc; END IF; +START TRANSACTION; +ALTER TABLE version_db_world CHANGE COLUMN 2019_01_10_00 2019_01_11_00 bit; +SELECT sql_rev INTO OK FROM version_db_world WHERE sql_rev = '1547165890320901800'; IF OK <> 'FALSE' THEN LEAVE proc; END IF; +-- +-- START UPDATING QUERIES +-- + +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1547165890320901800'); + +DELETE FROM `trinity_string` WHERE `entry` BETWEEN 5062 AND 5071; +INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES +(5062, 'You will now read %s conversations.'), +(5063, 'Stopped spying %s.'), +(5064, '%s is already being followed by: %s'), +(5065, 'Following %s\'s group, you will now read each player\'s conversations.'), +(5066, 'Stopped spying %s\'s group.'), +(5067, 'You are not spying %s\'s group.'), +(5068, 'Cleared all followed players.'), +(5069, '[ v ]==== Current spy list ====[ v ]'), +(5070, '[SPY] %s whispers %s: %s'), +(5071, '[SPY] %s tells group: %s'); + +-- +-- END UPDATING QUERIES +-- +COMMIT; +END // +DELIMITER ; +CALL updateDb(); +DROP PROCEDURE IF EXISTS `updateDb`; diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index f74b4926d..e8d71efb8 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1146,7 +1146,19 @@ enum TrinityStrings LANG_COMMAND_MUTEHISTORY_EMPTY = 5060, LANG_COMMAND_MUTEHISTORY_OUTPUT = 5061, - // Room for more Trinity strings 5062-9999 + // Spy command + LANG_COMMAND_SPY_FOLLOWING = 5062, + LANG_COMMAND_SPY_UNFOLLOW = 5063, + LANG_COMMAND_SPY_ALREADY_FOLLOWED_BY = 5064, + LANG_COMMAND_SPY_FOLLOWING_GROUP = 5065, + LANG_COMMAND_SPY_UNFOLLOW_GROUP = 5066, + LANG_COMMAND_SPY_NOT_FOLLOWING_GROUP = 5067, + LANG_COMMAND_SPY_CLEARED = 5068, + LANG_COMMAND_SPY_LIST = 5069, + LANG_COMMAND_SPY_WHISPERS_PLAYER = 5070, + LANG_COMMAND_SPY_TELLS_GROUP = 5071, + + // Room for more Trinity strings 5072-9999 // Level requirement notifications LANG_SAY_REQ = 6604, diff --git a/src/server/scripts/Commands/CMakeLists.txt b/src/server/scripts/Commands/CMakeLists.txt index f1e5aa493..556e421c0 100644 --- a/src/server/scripts/Commands/CMakeLists.txt +++ b/src/server/scripts/Commands/CMakeLists.txt @@ -37,8 +37,9 @@ set(scripts_STAT_SRCS Commands/cs_quest.cpp Commands/cs_reload.cpp Commands/cs_reset.cpp - Commands/cs_tele.cpp + Commands/cs_spy.cpp Commands/cs_server.cpp + Commands/cs_tele.cpp Commands/cs_ticket.cpp Commands/cs_titles.cpp Commands/cs_wp.cpp diff --git a/src/server/scripts/Commands/cs_spy.cpp b/src/server/scripts/Commands/cs_spy.cpp new file mode 100644 index 000000000..d1da812c8 --- /dev/null +++ b/src/server/scripts/Commands/cs_spy.cpp @@ -0,0 +1,279 @@ +#include "ScriptPCH.h" +#include "Channel.h" +#include "Language.h" +#include "Group.h" + +// Maps to store followed players +std::map gmListening; +std::map gmListeningGroup; + +class chat_spy_script : public PlayerScript +{ +public: + chat_spy_script() : PlayerScript("chat_spy_script") { } + + void OnChat(Player *sender, uint32 /*type*/, uint32 lang, std::string& msg, Player *receiver) + { + if (gmListening.size() > 0 && lang != LANG_ADDON) + { + // if the sender or the receiver is being followed + Player* gm = GetGmFromList(sender); + if (!gm) + gm = GetGmFromList(receiver); + + if (gm) + { + ChatHandler(gm->GetSession()).PSendSysMessage(LANG_COMMAND_SPY_WHISPERS_PLAYER, + sender->GetName().c_str(), receiver ? receiver->GetName().c_str() : "", msg.c_str()); + } + } + } + + void OnChat(Player* sender, uint32 /*type*/, uint32 lang, std::string& msg, Group* group) + { + if(gmListeningGroup.size() > 0 && lang != LANG_ADDON) + if(Player* gm = GetGmFromGroupList(group)) + ChatHandler(gm->GetSession()).PSendSysMessage(LANG_COMMAND_SPY_TELLS_GROUP, + sender->GetName().c_str(), msg.c_str()); + } + + Player* GetGmFromList(Player* from) + { + std::map::const_iterator itr = gmListening.find(from->GetGUIDLow()); + return itr != gmListening.end() ? sObjectMgr->GetPlayerByLowGUID(itr->second) : NULL; + } + + Player* GetGmFromGroupList(Group* group) + { + std::map::const_iterator itr = gmListeningGroup.find(group->GetLowGUID()); + return itr != gmListeningGroup.end() ? sObjectMgr->GetPlayerByLowGUID(itr->second) : NULL; + } +}; + +class chat_spy_commandscript : public CommandScript +{ +public: + chat_spy_commandscript() : CommandScript("chat_spy_commandscript") { } + + std::vector GetCommands() const override + { + static std::vector spyCommandTable = + { + { "follow", SEC_GAMEMASTER, false, &HandleSpyFollowCommand, ""}, + { "groupfollow", SEC_ADMINISTRATOR, false, &HandleSpyFollowGroupCommand, ""}, + { "unfollow", SEC_GAMEMASTER, false, &HandleSpyUnFollowCommand, ""}, + { "groupunfollow", SEC_ADMINISTRATOR, false, &HandleSpyUnFollowGroupCommand, ""}, + { "clear", SEC_GAMEMASTER, false, &HandleSpyClearCommand, ""}, + { "status", SEC_GAMEMASTER, false, &HandleSpyStatusCommand, ""} + }; + + static std::vector commandTable = + { + { "spy", SEC_GAMEMASTER, false, NULL, "", spyCommandTable} + }; + + return commandTable; + } + + static bool HandleSpyFollowCommand(ChatHandler* handler, const char* args) + { + if(!*args) + return false; + + char *cName = strtok ((char*)args, " "); + if(!cName) + return false; + + std::string pTarget = args; + if(!normalizePlayerName(pTarget)) + { + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + return true; + } + + if(Player* target = ObjectAccessor::FindPlayer(sObjectMgr->GetPlayerGUIDByName(pTarget.c_str()))) + { + std::map::const_iterator itr = gmListening.find(target->GetGUIDLow()); + if(itr != gmListening.end()) + { + if(Player* gm = sObjectMgr->GetPlayerByLowGUID(itr->second)) + { + handler->PSendSysMessage(LANG_COMMAND_SPY_ALREADY_FOLLOWED_BY, target->GetName().c_str(), gm->GetName().c_str()); + return true; + } + + gmListening[target->GetGUIDLow()] = handler->GetSession()->GetPlayer()->GetGUIDLow(); + handler->PSendSysMessage(LANG_COMMAND_SPY_FOLLOWING, target->GetName().c_str()); + } + } + else + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + + return true; + } + + static bool HandleSpyFollowGroupCommand(ChatHandler* handler, const char* args) + { + if(!*args) + return false; + + char *cName = strtok ((char*)args," "); + if(!cName) + return false; + + std::string pTarget = args; + if(!normalizePlayerName(pTarget)) + { + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + return true; + } + + if(Player* target = ObjectAccessor::FindPlayer(sObjectMgr->GetPlayerGUIDByName(pTarget.c_str()))) + { + if(Group* group = target->GetGroup()) + { + std::map::const_iterator itr = gmListeningGroup.find(group->GetLowGUID()); + if(itr != gmListeningGroup.end()) + { + if(Player* gm = sObjectMgr->GetPlayerByLowGUID(itr->second)) + { + handler->PSendSysMessage(LANG_COMMAND_SPY_ALREADY_FOLLOWED_BY, target->GetName().c_str(), gm->GetName().c_str()); + return true; + } + + gmListeningGroup[group->GetLowGUID()] = handler->GetSession()->GetPlayer()->GetGUIDLow(); + handler->PSendSysMessage(LANG_COMMAND_SPY_FOLLOWING_GROUP, target->GetName().c_str()); + } + } + else + handler->PSendSysMessage(LANG_NOT_IN_GROUP, target->GetName().c_str()); + } + else + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + + return true; + } + + static bool HandleSpyUnFollowCommand(ChatHandler* handler, const char* args) + { + if(!*args) + return false; + + char *cName = strtok ((char*)args," "); + if(!cName) + return false; + + std::string pTarget = args; + if(!normalizePlayerName(pTarget)) + { + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + return true; + } + + if(Player* target = ObjectAccessor::FindPlayer(sObjectMgr->GetPlayerGUIDByName(pTarget.c_str()))) + { + handler->PSendSysMessage(LANG_COMMAND_SPY_UNFOLLOW, cName); + if(gmListening.find(target->GetGUIDLow()) != gmListening.end()) + gmListening.erase(target->GetGUIDLow()); + } + else + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + return true; + } + + static bool HandleSpyUnFollowGroupCommand(ChatHandler* handler, const char* args) + { + if(!*args) + return false; + + char *cName = strtok ((char*)args," "); + if(!cName) + return false; + + std::string pTarget = args; + if(!normalizePlayerName(pTarget)) + { + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + return true; + } + + if(Player* target = ObjectAccessor::FindPlayer(sObjectMgr->GetPlayerGUIDByName(pTarget.c_str()))) + { + if(Group* group = target->GetGroup()) + { + if(gmListeningGroup.find(group->GetLowGUID()) != gmListening.end()) + { + gmListeningGroup.erase(group->GetLowGUID()); + handler->PSendSysMessage(LANG_COMMAND_SPY_UNFOLLOW_GROUP, cName); + } + else + handler->PSendSysMessage(LANG_COMMAND_SPY_NOT_FOLLOWING_GROUP, cName); + } + else + handler->PSendSysMessage(LANG_NOT_IN_GROUP, target->GetName().c_str()); + } + else + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + return true; + } + + static bool HandleSpyClearCommand(ChatHandler* handler, const char* /*args*/) + { + gmListening.clear(); + handler->SendSysMessage(LANG_COMMAND_SPY_CLEARED); + return true; + } + + static bool HandleSpyStatusCommand(ChatHandler* handler, const char* /*args*/) + { + uint32 guidlow = handler->GetSession()->GetPlayer()->GetGUIDLow(); + std::map::iterator next; + handler->SendSysMessage(LANG_COMMAND_SPY_LIST); + + for(std::map::iterator itr = gmListening.begin(); itr != gmListening.end(); itr = next) + { + // There's the possibility that itr is erased, so we save it + next = itr; + ++next; + if(itr->second == guidlow) + { + if(Player* target = ObjectAccessor::FindPlayer(itr->first)) + handler->PSendSysMessage("%s", target->GetName().c_str()); + else // clear offline players + gmListening.erase(itr); + } + } + + return true; + } + +}; + +class chat_spy_logout_cleaner : public PlayerScript +{ +public: + chat_spy_logout_cleaner() : PlayerScript("chat_spy_logout_cleaner") { } + + void OnLogout(Player* player) + { + if(player && player->IsGameMaster()) + { + uint32 guidlow = player->GetGUIDLow(); + std::map::iterator next; + for(std::map::iterator itr = gmListening.begin(); itr != gmListening.end(); itr = next) + { + next = itr; // Save a reference to the next one + ++next; + if(itr->second == guidlow) + gmListening.erase(itr); + } + } + } +}; + +void AddSC_spy_scripts() +{ + new chat_spy_script(); + new chat_spy_commandscript(); + new chat_spy_logout_cleaner(); +} diff --git a/src/server/scripts/ScriptLoader.cpp b/src/server/scripts/ScriptLoader.cpp index c44a3adca..ace810c5f 100644 --- a/src/server/scripts/ScriptLoader.cpp +++ b/src/server/scripts/ScriptLoader.cpp @@ -54,6 +54,7 @@ void AddSC_reload_commandscript(); void AddSC_reset_commandscript(); void AddSC_server_commandscript(); void AddSC_spectator_commandscript(); +void AddSC_spy_scripts(); void AddSC_tele_commandscript(); void AddSC_ticket_commandscript(); void AddSC_titles_commandscript();