rendered paste bodyAllows players to log in their other characters as bots on same account and order their bots to do their bidding.diff -r b8345ca16d48 src/game/CharacterHandler.cpp--- a/src/game/CharacterHandler.cpp Thu Jan 01 09:22:46 2009 -0500+++ b/src/game/CharacterHandler.cpp Thu Jan 01 10:42:07 2009 -0500@@ -115,6 +115,25 @@ return; } session->HandlePlayerLogin((LoginQueryHolder*)holder);+ }+ void HandlePlayerBotLoginCallback(QueryResult * /*dummy*/, SqlQueryHolder * holder)+ {+ if (!holder) return;++ LoginQueryHolder* lqh = (LoginQueryHolder*) holder;++ WorldSession *session = sWorld.FindSession(lqh->GetAccountId());++ if (! session)+ {+ delete holder;+ return;+ }++ WorldSession *botSession = new WorldSession(lqh->GetAccountId(), NULL, 0, true, 0, LOCALE_enUS);+ botSession->m_Address = "bot";+ botSession->HandlePlayerLogin(lqh);+ (session->m_playerBots)[lqh->GetGuid()] = botSession->_player; } } chrHandler; @@ -1087,3 +1106,23 @@ data << uint64(guid); SendPacket(&data); }++Player* WorldSession::GetPlayerBot(uint64 playerGuid)+{+ PlayerBotMap::const_iterator it = m_playerBots.find(playerGuid);+ return (it == m_playerBots.end()) ? 0 : it->second;+}++void WorldSession::AddPlayerBot(uint64 playerGuid)+{+ // has bot already been added?+ if (GetPlayerBot(playerGuid) != 0) return;++ LoginQueryHolder *holder = new LoginQueryHolder(GetAccountId(), playerGuid);+ if(!holder->Initialize())+ {+ delete holder; // delete all unprocessed queries+ return;+ }+ CharacterDatabase.DelayQueryHolder(&chrHandler, &CharacterHandler::HandlePlayerBotLoginCallback, holder);+}diff -r b8345ca16d48 src/game/Chat.cpp--- a/src/game/Chat.cpp Thu Jan 01 09:22:46 2009 -0500+++ b/src/game/Chat.cpp Thu Jan 01 10:42:07 2009 -0500@@ -143,7 +143,7 @@ { "modify", SEC_GAMEMASTER, false, &ChatHandler::HandleWpModifyCommand, "", NULL }, { "event", SEC_GAMEMASTER, false, &ChatHandler::HandleWpEventCommand, "", NULL }, { "unload", SEC_GAMEMASTER, false, &ChatHandler::HandleWpUnLoadPathCommand, "", NULL },- + { NULL, 0, false, NULL, "", NULL } }; @@ -529,11 +529,11 @@ { "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable }, { "gobject", SEC_GAMEMASTER, false, NULL, "", gobjectCommandTable }, { "honor", SEC_GAMEMASTER, false, NULL, "", honorCommandTable },- + //wp commands { "path", SEC_GAMEMASTER, false, NULL, "", wpCommandTable }, { "loadpath", SEC_ADMINISTRATOR, false, &ChatHandler::HandleReloadAllPaths, "", NULL },- + { "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable }, { "reload", SEC_ADMINISTRATOR, true, NULL, "", reloadCommandTable }, { "list", SEC_ADMINISTRATOR, true, NULL, "", listCommandTable },@@ -548,7 +548,7 @@ { "aura", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuraCommand, "", NULL }, { "unaura", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnAuraCommand, "", NULL },- { "nameannounce", SEC_MODERATOR, false, &ChatHandler::HandleNameAnnounceCommand, "", NULL }, + { "nameannounce", SEC_MODERATOR, false, &ChatHandler::HandleNameAnnounceCommand, "", NULL }, { "gmnameannounce", SEC_MODERATOR, false, &ChatHandler::HandleGMNameAnnounceCommand, "", NULL }, { "announce", SEC_MODERATOR, true, &ChatHandler::HandleAnnounceCommand, "", NULL }, { "gmannounce", SEC_MODERATOR, true, &ChatHandler::HandleGMAnnounceCommand, "", NULL },@@ -616,14 +616,16 @@ { "sendmessage", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMessageCommand, "", NULL }, { "playall", SEC_ADMINISTRATOR, false, &ChatHandler::HandlePlayAllCommand, "", NULL }, { "repairitems", SEC_GAMEMASTER, false, &ChatHandler::HandleRepairitemsCommand, "", NULL },- { "freeze", SEC_ADMINISTRATOR, false, &ChatHandler::HandleFreezeCommand, "", NULL }, - { "unfreeze", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnFreezeCommand, "", NULL }, - { "listfreeze", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListFreezeCommand, "", NULL }, - { "flusharenapoints", SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL }, + { "freeze", SEC_ADMINISTRATOR, false, &ChatHandler::HandleFreezeCommand, "", NULL },+ { "unfreeze", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnFreezeCommand, "", NULL },+ { "listfreeze", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListFreezeCommand, "", NULL },+ { "flusharenapoints", SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL }, { "possess", SEC_ADMINISTRATOR, false, &ChatHandler::HandlePossessCommand, "", NULL }, { "unpossess", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnPossessCommand, "", NULL }, { "bindsight", SEC_ADMINISTRATOR, false, &ChatHandler::HandleBindSightCommand, "", NULL }, { "unbindsight", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnbindSightCommand, "", NULL },++ { "bot", SEC_PLAYER, false, &ChatHandler::HandlePlayerbotCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } };diff -r b8345ca16d48 src/game/Chat.h--- a/src/game/Chat.h Thu Jan 01 09:22:46 2009 -0500+++ b/src/game/Chat.h Thu Jan 01 10:42:07 2009 -0500@@ -72,7 +72,7 @@ int ParseCommands(const char* text); virtual char const* GetName() const;- + protected: explicit ChatHandler() : m_session(NULL) {} // for CLI subclass @@ -406,7 +406,7 @@ bool HandleResetAllCommand(const char * args); - + // GM ticket command handlers bool HandleGMTicketListCommand(const char* args); bool HandleGMTicketListOnlineCommand(const char* args);@@ -428,7 +428,7 @@ bool HandlePasswordCommand(const char* args); bool HandleLockAccountCommand(const char* args); bool HandleRespawnCommand(const char* args);- + //New Wp Commands bool HandleWpAddCommand(const char* args); bool HandleWpLoadPathCommand(const char* args);@@ -481,6 +481,8 @@ bool HandleBindSightCommand(const char* args); bool HandleUnbindSightCommand(const char* args); + bool HandlePlayerbotCommand(const char* args);+ Player* getSelectedPlayer(); Creature* getSelectedCreature(); Unit* getSelectedUnit();@@ -503,7 +505,7 @@ void SetSentErrorMessage(bool val){ sentErrorMessage = val;}; private: WorldSession * m_session; // != NULL for chat command call and NULL for CLI command- + // common global flag static bool load_command_table; bool sentErrorMessage;diff -r b8345ca16d48 src/game/Level0.cpp--- a/src/game/Level0.cpp Thu Jan 01 09:22:46 2009 -0500+++ b/src/game/Level0.cpp Thu Jan 01 10:42:07 2009 -0500@@ -23,6 +23,7 @@ #include "WorldPacket.h" #include "WorldSession.h" #include "World.h"+#include "ObjectMgr.h" #include "Player.h" #include "Opcodes.h" #include "Chat.h"@@ -265,3 +266,38 @@ PSendSysMessage(LANG_MOTD_CURRENT, sWorld.GetMotd()); return true; }++bool ChatHandler::HandlePlayerbotCommand(const char* args)+{+ if (!*args)+ {+ SendSysMessage(LANG_USE_BOL);+ return true;+ }++ char *cmd = strtok ((char*)args, " ");+ char *charname = strtok (NULL, " ");++ if (!cmd || !charname)+ return false;++ std::string cmdStr = cmd;+ std::string charnameStr = charname;++ uint64 guid = objmgr.GetPlayerGUIDByName(charnameStr.c_str());+ if(!guid)+ {+ SendSysMessage(LANG_PLAYER_NOT_FOUND);+ SetSentErrorMessage(true);+ return false;+ }++ if (cmdStr == "add" || cmdStr == "login") {+ m_session->AddPlayerBot(guid);+ }+ else if (cmdStr == "remove" || cmdStr == "logout") {+ m_session->LogoutPlayerBot(guid, true);+ }++ return true;+}diff -r b8345ca16d48 src/game/Player.cpp--- a/src/game/Player.cpp Thu Jan 01 09:22:46 2009 -0500+++ b/src/game/Player.cpp Thu Jan 01 10:42:07 2009 -0500@@ -268,7 +268,7 @@ m_divider = 0; m_ExtraFlags = 0;- + // players always accept if(GetSession()->GetSecurity() == SEC_PLAYER) SetAcceptWhispers(true);@@ -6173,7 +6173,7 @@ { // Check if allowed to receive it in current map uint8 MapType = sWorld.getConfig(CONFIG_PVP_TOKEN_MAP_TYPE);- if( (MapType == 1 && !InBattleGround() && !HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP)) + if( (MapType == 1 && !InBattleGround() && !HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP)) || (MapType == 2 && !HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP)) || (MapType == 3 && !InBattleGround()) ) return true;@@ -7963,7 +7963,7 @@ data << uint32(2474) << uint32(50); //: ally / horde slider percentage, 100 for ally, 0 for horde // show only in direct vicinity! data << uint32(2473) << uint32(0); //: ally / horde slider display // show only in direct vicinity! data << uint32(0x9a8) << uint32(0x0); // 20 // show the neutral stadium icon // 2472- data << uint32(0x9a7) << uint32(0x0); // 21 // show the ally stadium icon // 2471 + data << uint32(0x9a7) << uint32(0x0); // 21 // show the ally stadium icon // 2471 data << uint32(0x9a6) << uint32(0x1); // 22 // show the horde stadium icon // 2470 } }@@ -8056,7 +8056,7 @@ data << uint32(0x9e1) << uint32(0x0); // 10 //2529 data << uint32(0x9e0) << uint32(0x0); // 11 data << uint32(0x9df) << uint32(0x0); // 12- data << uint32(0xa5d) << uint32(0x1); // 13 //2653 + data << uint32(0xa5d) << uint32(0x1); // 13 //2653 data << uint32(0xa5c) << uint32(0x0); // 14 //2652 east beacon neutral data << uint32(0xa5b) << uint32(0x1); // 15 horde data << uint32(0xa5a) << uint32(0x0); // 16 ally@@ -8072,7 +8072,7 @@ data << uint32(0xa00) << uint32(0x0); // 26 // 2560 data << uint32(0x9ff) << uint32(0x1); // 27 data << uint32(0x9fe) << uint32(0x0); // 28- data << uint32(0x9fd) << uint32(0x0); // 29 + data << uint32(0x9fd) << uint32(0x0); // 29 data << uint32(0x9fc) << uint32(0x1); // 30 data << uint32(0x9fb) << uint32(0x0); // 31 data << uint32(0xa62) << uint32(0x0); // 32 // 2658@@ -15453,7 +15453,7 @@ // save pet (hunter pet level and experience and all type pets health/mana). if(Pet* pet = GetPet()) pet->SavePetToDB(PET_SAVE_AS_CURRENT);- + //to prevent access to DB we should cache some data, which is used very often CachePlayerInfoMap::iterator _iter = objmgr.m_mPlayerInfoMap.find(GetGUIDLow()); if(_iter != objmgr.m_mPlayerInfoMap.end())//skip new players@@ -16286,6 +16286,43 @@ language = LANG_UNIVERSAL; // whispers should always be readable Player *rPlayer = objmgr.GetPlayer(receiver);++ if (rPlayer->GetSession()->GetRemoteAddress() == "bot")+ {+ // if message is not from the player controlling the bot, auto reply and ignore+ if (!(rPlayer->GetSession()->GetAccountId() == GetSession()->GetAccountId()))+ {+ WorldPacket data(SMSG_MESSAGECHAT, 200);+ WorldSession* masterSession = sWorld.FindSession(rPlayer->GetSession()->GetAccountId());+ std::string msg = "I can't talk to you. Please speak to my master ";+ msg += masterSession->GetPlayerName();+ rPlayer->BuildPlayerChat(&data, CHAT_MSG_REPLY, msg, language);+ GetSession()->SendPacket(&data);+ }+ else if (text == "follow")+ {+ rPlayer->GetMotionMaster()->Clear();+ float angle = (float) (M_PI - (M_PI / urand(1,50))); // generates random float between 0 number less then 3.14+ float dist = (float) urand(1,6); // generates random float between 1 and 6+ rPlayer->GetMotionMaster()->MoveFollow(this, dist, angle);+ }+ else if (text == "stay")+ {+ rPlayer->GetMotionMaster()->Clear();+ }+ else if (text == "assist")+ {+ rPlayer->Attack(getAttackerForHelper(), true);+ }+ else+ {+ WorldPacket data(SMSG_MESSAGECHAT, 200);+ std::string msg = "Sorry master. Please speak in terms I can understand such as: follow, stay, assist";+ rPlayer->BuildPlayerChat(&data, CHAT_MSG_REPLY, msg, language);+ GetSession()->SendPacket(&data);+ }+ return;+ } // when player you are whispering to is dnd, he cannot receive your message, unless you are in gm mode if(!rPlayer->isDND() || isGameMaster())@@ -19041,7 +19078,7 @@ // Remove any previous possession from the target if (target->isPossessedByPlayer()) ((Player*)target->GetCharmer())->RemovePossess(false);- else if (target->isCharmed()) + else if (target->isCharmed()) target->UncharmSelf(); // Target isn't possessed, but charmed; uncharm before possessing // Remove our previous possession@@ -19180,13 +19217,13 @@ target->GetMotionMaster()->Clear(); target->GetMotionMaster()->MoveTargetedHome(); }- } + } else { target->GetMotionMaster()->Clear(); target->GetMotionMaster()->MoveTargetedHome(); }- + // Add high amount of threat on the player if(attack) target->AddThreat(this, 1000000.0f);diff -r b8345ca16d48 src/game/WorldSession.cpp--- a/src/game/WorldSession.cpp Thu Jan 01 09:22:46 2009 -0500+++ b/src/game/WorldSession.cpp Thu Jan 01 10:42:07 2009 -0500@@ -241,6 +241,13 @@ /// %Log the player out void WorldSession::LogoutPlayer(bool Save) {+ // log out any PlayerBots owned in this WorldSession+ PlayerBotMap::const_iterator it = m_playerBots.begin();+ for(PlayerBotMap::const_iterator itr = m_playerBots.begin(); itr != m_playerBots.end(); ++itr) {+ uint64 guid = itr->first;+ LogoutPlayerBot(guid, Save);+ }+ // finish pending transfers before starting the logout while(_player && _player->IsBeingTeleported()) HandleMoveWorldportAckOpcode();@@ -324,7 +331,8 @@ ///- Reset the online field in the account table // no point resetting online in character table here as Player::SaveToDB() will set it to 1 since player has not been removed from world at this stage //No SQL injection as AccountID is uint32- loginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = '%u'", GetAccountId());+ if (m_Address != "bot")+ loginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = '%u'", GetAccountId()); ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members Guild *guild = objmgr.GetGuildById(_player->GetGuildId());@@ -396,6 +404,9 @@ _player->CleanupsBeforeDelete(); // do some cleanup before deleting to prevent crash at crossreferences to already deleted data sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ());++ uint32 guid = _player->GetGUIDLow();+ delete _player; _player = NULL; @@ -405,8 +416,7 @@ ///- Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline //No SQL injection as AccountId is uint32- CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = '%u'",- GetAccountId());+ CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE guid = '%u'", guid); sLog.outDebug( "SESSION: Sent SMSG_LOGOUT_COMPLETE Message" ); } @@ -525,3 +535,17 @@ SendPacket(&packet); } }++void WorldSession::LogoutPlayerBot(uint64 guid, bool Save)+{+ Player* botPlayerPtr = GetPlayerBot(guid);++ if (botPlayerPtr)+ {+ WorldSession * botWorldSessionPtr = botPlayerPtr->m_session;+ botPlayerPtr = NULL;+ m_playerBots.erase(guid); // deletes bot player ptr inside this WorldSession PlayerBotMap+ botWorldSessionPtr->LogoutPlayer(Save); // this will delete the bot Player object+ delete botWorldSessionPtr; // finally delete the bot's WorldSession+ }+}diff -r b8345ca16d48 src/game/WorldSession.h--- a/src/game/WorldSession.h Thu Jan 01 09:22:46 2009 -0500+++ b/src/game/WorldSession.h Thu Jan 01 10:42:07 2009 -0500@@ -75,6 +75,10 @@ public: WorldSession(uint32 id, WorldSocket *sock, uint32 sec, uint8 expansion, time_t mute_time, LocaleConstant locale); ~WorldSession();++ void AddPlayerBot(uint64 guid);+ void LogoutPlayerBot(uint64 guid, bool Save);+ Player* GetPlayerBot(uint64 guid); bool PlayerLoading() const { return m_playerLoading; } bool PlayerLogout() const { return m_playerLogout; }@@ -275,7 +279,7 @@ void HandleGMTicketDeleteOpcode(WorldPacket& recvPacket); void HandleGMTicketGetTicketOpcode(WorldPacket& recvPacket); void HandleGMTicketSystemStatusOpcode(WorldPacket& recvPacket);- + //void HandleGMSurveySubmit(WorldPacket& recvPacket); void HandleTogglePvP(WorldPacket& recvPacket);@@ -653,6 +657,9 @@ int m_sessionDbLocaleIndex; uint32 m_latency; + typedef UNORDERED_MAP<uint64, Player*> PlayerBotMap;+ PlayerBotMap m_playerBots;+ ZThread::LockedQueue<WorldPacket*,ZThread::FastMutex> _recvQueue; }; #endif