void RandomPlayerbotMgr::OnPlayerLogin(Player* player) { for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (player == bot || player->GetPlayerbotAI()) continue; Group* group = bot->GetGroup(); if (!group) continue; for (GroupReference *gref = group->GetFirstMember(); gref; gref = gref->next()) { Player* member = gref->getSource(); PlayerbotAI* ai = bot->GetPlayerbotAI(); if (member == player && (!ai->GetMaster() || ai->GetMaster()->GetPlayerbotAI())) { ai->SetMaster(player); ai->ResetStrategies(); ai->TellMaster("Hello"); break; } } } if (!player->GetPlayerbotAI()) players.push_back(player); }
void PlayerbotMgr::OnBotLogin(Player * const bot) { // give the bot some AI, object is owned by the player class PlayerbotAI* ai = new PlayerbotAI(this, bot); bot->SetPlayerbotAI(ai); // tell the world session that they now manage this new bot m_playerBots[bot->GetObjectGuid()] = bot; // if bot is in a group and master is not in group then // have bot leave their group if (bot->GetGroup() && (m_master->GetGroup() == nullptr || m_master->GetGroup()->IsMember(bot->GetObjectGuid()) == false)) bot->RemoveFromGroup(); // sometimes master can lose leadership, pass leadership to master check const ObjectGuid masterGuid = m_master->GetObjectGuid(); if (m_master->GetGroup() && !m_master->GetGroup()->IsLeader(masterGuid)) // But only do so if one of the master's bots is leader for (PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); itr != GetPlayerBotsEnd(); itr++) { Player* bot = itr->second; if (m_master->GetGroup()->IsLeader(bot->GetObjectGuid())) { m_master->GetGroup()->ChangeLeader(masterGuid); break; } } }
void PlayerbotMgr::Stay() { for (PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); itr != GetPlayerBotsEnd(); ++itr) { Player* bot = itr->second; bot->GetMotionMaster()->Clear(); } }
void RandomPlayerbotMgr::HandleCommand(uint32 type, const string& text, Player& fromPlayer) { for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->HandleCommand(type, text, fromPlayer); } }
void PlayerbotMgr::RemoveAllBotsFromGroup() { for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); m_master->GetGroup() && it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (bot->IsInGroup(m_master)) m_master->GetGroup()->RemoveMember(bot->GetObjectGuid(), 0); } }
void PlayerbotMgr::LogoutAllBots() { while (true) { PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); if (itr == GetPlayerBotsEnd()) break; Player* bot= itr->second; LogoutPlayerBot(bot->GetGUID()); } }
void PlayerbotMgr::LogoutAllBots() { while (true) { PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); if (itr == GetPlayerBotsEnd()) break; Player* bot = itr->second; LogoutPlayerBot(bot->GetObjectGuid()); } RemoveAllBotsFromGroup(); }
void PlayerbotMgr::OnMasterLevelUp() { // give all bots the same level as the master so they stay current for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (bot->getLevel() < m_master->getLevel()) { bot->GiveLevel(m_master->getLevel()); bot->GetPlayerbotAI()->Levelup(); } } }
void PlayerbotMgr::LogoutAllBots() { while (true) { PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); if (itr == GetPlayerBotsEnd()) break; if (Player* bot = itr->second) { LogoutPlayerBot(bot->GetObjectGuid()); m_botCount--; } } RemoveAllBotsFromGroup(); ///-> If bot are logging out remove them group }
void PlayerbotMgr::OnBotLogin(Player* const bot) { // simulate client taking control WorldPacket* const pCMSG_SET_ACTIVE_MOVER = new WorldPacket(CMSG_SET_ACTIVE_MOVER, 8); *pCMSG_SET_ACTIVE_MOVER << bot->GetObjectGuid(); bot->GetSession()->QueuePacket(std::move(std::unique_ptr<WorldPacket>(pCMSG_SET_ACTIVE_MOVER))); WorldPacket* const pMSG_MOVE_FALL_LAND = new WorldPacket(MSG_MOVE_FALL_LAND, 28); *pMSG_MOVE_FALL_LAND << bot->GetMover()->m_movementInfo; bot->GetSession()->QueuePacket(std::move(std::unique_ptr<WorldPacket>(pMSG_MOVE_FALL_LAND))); // give the bot some AI, object is owned by the player class PlayerbotAI* ai = new PlayerbotAI(this, bot); bot->SetPlayerbotAI(ai); // tell the world session that they now manage this new bot m_playerBots[bot->GetObjectGuid()] = bot; // if bot is in a group and master is not in group then // have bot leave their group if (bot->GetGroup() && (m_master->GetGroup() == nullptr || m_master->GetGroup()->IsMember(bot->GetObjectGuid()) == false)) bot->RemoveFromGroup(); // sometimes master can lose leadership, pass leadership to master check const ObjectGuid masterGuid = m_master->GetObjectGuid(); if (m_master->GetGroup() && !m_master->GetGroup()->IsLeader(masterGuid)) { // But only do so if one of the master's bots is leader for (PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); itr != GetPlayerBotsEnd(); itr++) { Player* bot = itr->second; if (m_master->GetGroup()->IsLeader(bot->GetObjectGuid())) { m_master->GetGroup()->ChangeLeader(masterGuid); break; } } } }
void RandomPlayerbotMgr::OnPlayerLogout(Player* player) { for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; PlayerbotAI* ai = bot->GetPlayerbotAI(); if (player == ai->GetMaster()) { ai->SetMaster(NULL); ai->ResetStrategies(); } } if (!player->GetPlayerbotAI()) { vector<Player*>::iterator i = find(players.begin(), players.end(), player); if (i != players.end()) players.erase(i); } }
void PlayerbotMgr::HandleMasterIncomingPacket(const WorldPacket& packet) { switch (packet.GetOpcode()) { case CMSG_OFFER_PETITION: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid petitionGuid; ObjectGuid playerGuid; uint32 junk; p >> junk; // this is not petition type! p >> petitionGuid; // petition guid p >> playerGuid; // player guid Player* player = ObjectAccessor::FindPlayer(playerGuid); if (!player) return; uint32 petitionLowGuid = petitionGuid.GetCounter(); QueryResult* result = CharacterDatabase.PQuery("SELECT * FROM petition_sign WHERE playerguid = '%u' AND petitionguid = '%u'", player->GetGUIDLow(), petitionLowGuid); if (result) { ChatHandler(m_master).PSendSysMessage("%s has already signed the petition", player->GetName()); delete result; return; } CharacterDatabase.PExecute("INSERT INTO petition_sign (ownerguid,petitionguid, playerguid, player_account) VALUES ('%u', '%u', '%u','%u')", GetMaster()->GetGUIDLow(), petitionLowGuid, player->GetGUIDLow(), GetMaster()->GetSession()->GetAccountId()); p.Initialize(SMSG_PETITION_SIGN_RESULTS, (8 + 8 + 4)); p << ObjectGuid(petitionGuid); p << ObjectGuid(playerGuid); p << uint32(PETITION_SIGN_OK); // close at signer side GetMaster()->GetSession()->SendPacket(p); return; } case CMSG_ACTIVATETAXI: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid guid; std::vector<uint32> nodes; nodes.resize(2); uint8 delay = 9; p >> guid >> nodes[0] >> nodes[1]; // DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_ACTIVATETAXI from %d to %d", nodes[0], nodes[1]); for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { delay = delay + 3; Player* const bot = it->second; if (!bot) return; Group* group = bot->GetGroup(); if (!group) continue; Unit* target = ObjectAccessor::GetUnit(*bot, guid); bot->GetPlayerbotAI()->SetIgnoreUpdateTime(delay); bot->GetMotionMaster()->Clear(true); bot->GetMotionMaster()->MoveFollow(target, INTERACTION_DISTANCE, bot->GetOrientation()); bot->GetPlayerbotAI()->GetTaxi(guid, nodes); } return; } case CMSG_ACTIVATETAXIEXPRESS: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid guid; uint32 node_count; uint8 delay = 9; p >> guid; p.read_skip<uint32>(); p >> node_count; std::vector<uint32> nodes; for (uint32 i = 0; i < node_count; ++i) { uint32 node; p >> node; nodes.push_back(node); } if (nodes.empty()) return; // DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_ACTIVATETAXIEXPRESS from %d to %d", nodes.front(), nodes.back()); for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { delay = delay + 3; Player* const bot = it->second; if (!bot) return; Group* group = bot->GetGroup(); if (!group) continue; Unit* target = ObjectAccessor::GetUnit(*bot, guid); bot->GetPlayerbotAI()->SetIgnoreUpdateTime(delay); bot->GetMotionMaster()->Clear(true); bot->GetMotionMaster()->MoveFollow(target, INTERACTION_DISTANCE, bot->GetOrientation()); bot->GetPlayerbotAI()->GetTaxi(guid, nodes); } return; } // if master is logging out, log out all bots case CMSG_LOGOUT_REQUEST: { LogoutAllBots(); return; } // If master inspects one of his bots, give the master useful info in chat window // such as inventory that can be equipped case CMSG_INSPECT: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid guid; p >> guid; Player* const bot = GetPlayerBot(guid); if (bot) bot->GetPlayerbotAI()->SendNotEquipList(*bot); return; } // handle emotes from the master //case CMSG_EMOTE: case CMSG_TEXT_EMOTE: { WorldPacket p(packet); p.rpos(0); // reset reader uint32 emoteNum; p >> emoteNum; /* std::ostringstream out; out << "emote is: " << emoteNum; ChatHandler ch(m_master); ch.SendSysMessage(out.str().c_str()); */ switch (emoteNum) { case TEXTEMOTE_BOW: { // Buff anyone who bows before me. Useful for players not in bot's group // How do I get correct target??? //Player* const pPlayer = GetPlayerBot(m_master->GetSelection()); //if (pPlayer->GetPlayerbotAI()->GetClassAI()) // pPlayer->GetPlayerbotAI()->GetClassAI()->BuffPlayer(pPlayer); return; } /* case TEXTEMOTE_BONK: { Player* const pPlayer = GetPlayerBot(m_master->GetSelection()); if (!pPlayer || !pPlayer->GetPlayerbotAI()) return; PlayerbotAI* const pBot = pPlayer->GetPlayerbotAI(); ChatHandler ch(m_master); { std::ostringstream out; out << "CurrentTime: " << CurrentTime() << " m_ignoreAIUpdatesUntilTime: " << pBot->m_ignoreAIUpdatesUntilTime; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "m_CurrentlyCastingSpellId: " << pBot->m_CurrentlyCastingSpellId; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "IsBeingTeleported() " << pBot->GetPlayer()->IsBeingTeleported(); ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; bool tradeActive = (pBot->GetPlayer()->GetTrader()) ? true : false; out << "tradeActive: " << tradeActive; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "IsCharmed() " << pBot->getPlayer()->isCharmed(); ch.SendSysMessage(out.str().c_str()); } return; } */ case TEXTEMOTE_EAT: case TEXTEMOTE_DRINK: return; // emote to attack selected target case TEXTEMOTE_POINT: { ObjectGuid attackOnGuid = m_master->GetSelectionGuid(); if (!attackOnGuid) return; Unit* thingToAttack = ObjectAccessor::GetUnit(*m_master, attackOnGuid); if (!thingToAttack) return; Player* bot = 0; for (PlayerBotMap::iterator itr = m_playerBots.begin(); itr != m_playerBots.end(); ++itr) { bot = itr->second; if (bot->CanAttack(thingToAttack)) { if (!bot->IsWithinLOSInMap(thingToAttack)) bot->GetPlayerbotAI()->DoTeleport(*m_master); if (bot->IsWithinLOSInMap(thingToAttack)) bot->GetPlayerbotAI()->Attack(thingToAttack); } } return; } // emote to stay case TEXTEMOTE_STAND: { Player* const bot = GetPlayerBot(m_master->GetSelectionGuid()); if (bot) bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_STAY); else for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_STAY); } return; } // 324 is the followme emote (not defined in enum) // if master has bot selected then only bot follows, else all bots follow case 324: case TEXTEMOTE_WAVE: { Player* const bot = GetPlayerBot(m_master->GetSelectionGuid()); if (bot) bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_FOLLOW, m_master); else for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_FOLLOW, m_master); } return; } } return; } /* EMOTE ends here */ case CMSG_GAMEOBJ_USE: // Used by bots to turn in quest to GameObjects when also used by master { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid objGUID; p >> objGUID; for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; // If player and bot are on different maps: then player was teleported by GameObject // let's return and let playerbot summon do its job by teleporting bots if (bot->GetMap() != m_master->GetMap()) return; GameObject* obj = m_master->GetMap()->GetGameObject(objGUID); if (!obj) return; bot->GetPlayerbotAI()->FollowAutoReset(); if (obj->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) bot->GetPlayerbotAI()->TurnInQuests(obj); // add other go types here, i.e.: // GAMEOBJECT_TYPE_CHEST - loot quest items of chest } } break; case CMSG_QUESTGIVER_HELLO: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid npcGUID; p >> npcGUID; WorldObject* pNpc = m_master->GetMap()->GetWorldObject(npcGUID); if (!pNpc) return; // for all master's bots for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->FollowAutoReset(); bot->GetPlayerbotAI()->TurnInQuests(pNpc); } return; } // if master accepts a quest, bots should also try to accept quest case CMSG_QUESTGIVER_ACCEPT_QUEST: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid guid; uint32 quest; // uint32 unk1; p >> guid >> quest; // >> unk1; // DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_QUESTGIVER_ACCEPT_QUEST npc = %s, quest = %u, unk1 = %u", guid.GetString().c_str(), quest, unk1); Quest const* qInfo = sObjectMgr.GetQuestTemplate(quest); if (qInfo) for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->FollowAutoReset(); if (bot->GetQuestStatus(quest) == QUEST_STATUS_COMPLETE) bot->GetPlayerbotAI()->TellMaster("I already completed that quest."); else if (!bot->CanTakeQuest(qInfo, false)) { if (!bot->SatisfyQuestStatus(qInfo, false)) bot->GetPlayerbotAI()->TellMaster("I already have that quest."); else bot->GetPlayerbotAI()->TellMaster("I can't take that quest."); } else if (!bot->SatisfyQuestLog(false)) bot->GetPlayerbotAI()->TellMaster("My quest log is full."); else if (!bot->CanAddQuest(qInfo, false)) bot->GetPlayerbotAI()->TellMaster("I can't take that quest because it requires that I take items, but my bags are full!"); else { p.rpos(0); // reset reader bot->GetSession()->HandleQuestgiverAcceptQuestOpcode(p); bot->GetPlayerbotAI()->TellMaster("Got the quest."); // build needed items if quest contains any for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++) if (qInfo->ReqItemCount[i] > 0) { bot->GetPlayerbotAI()->SetQuestNeedItems(); break; } // build needed creatures if quest contains any for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) if (qInfo->ReqCreatureOrGOCount[i] > 0) { bot->GetPlayerbotAI()->SetQuestNeedCreatures(); break; } } } return; } case CMSG_AREATRIGGER: { WorldPacket p(packet); for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (!bot) continue; if (bot->IsWithinDistInMap(GetMaster(), 50)) { p.rpos(0); // reset reader bot->GetSession()->HandleAreaTriggerOpcode(p); } } return; } case CMSG_QUESTGIVER_COMPLETE_QUEST: { WorldPacket p(packet); p.rpos(0); // reset reader uint32 quest; ObjectGuid npcGUID; p >> npcGUID >> quest; // DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %s, quest = %u", npcGUID.GetString().c_str(), quest); WorldObject* pNpc = m_master->GetMap()->GetWorldObject(npcGUID); if (!pNpc) return; // for all master's bots for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->FollowAutoReset(); bot->GetPlayerbotAI()->TurnInQuests(pNpc); } return; } case CMSG_LOOT_ROLL: { WorldPacket p(packet); //WorldPacket packet for CMSG_LOOT_ROLL, (8+4+1) ObjectGuid Guid; uint32 itemSlot; uint8 rollType; p.rpos(0); //reset packet pointer p >> Guid; //guid of the lootable target p >> itemSlot; //loot index p >> rollType; //need,greed or pass on roll for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { uint32 choice = 0; Player* const bot = it->second; if (!bot) return; Group* group = bot->GetGroup(); if (!group) return; // check that the bot did not already vote if (rollType >= ROLL_NOT_EMITED_YET) return; Loot* loot = sLootMgr.GetLoot(bot, Guid); if (!loot) { sLog.outError("LootMgr::PlayerVote> Error cannot get loot object info!"); return; } LootItem* lootItem = loot->GetLootItemInSlot(itemSlot); ItemPrototype const* pProto = lootItem->itemProto; if (!pProto) return; if (bot->GetPlayerbotAI()->CanStore()) { if (bot->CanUseItem(pProto) == EQUIP_ERR_OK && bot->GetPlayerbotAI()->IsItemUseful(lootItem->itemId)) choice = 1; // Need else if (bot->HasSkill(SKILL_ENCHANTING)) choice = 3; // Disenchant else choice = 2; // Greed } else choice = 0; // Pass sLootMgr.PlayerVote(bot, Guid, itemSlot, RollVote(choice)); } return; } // Handle GOSSIP activate actions, prior to GOSSIP select menu actions case CMSG_GOSSIP_HELLO: { // DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_GOSSIP_HELLO"); WorldPacket p(packet); //WorldPacket packet for CMSG_GOSSIP_HELLO, (8) ObjectGuid guid; p.rpos(0); //reset packet pointer p >> guid; for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (!bot) continue; bot->GetPlayerbotAI()->FollowAutoReset(); Creature* pCreature = bot->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); if (!pCreature) { DEBUG_LOG("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_GOSSIP_HELLO %s not found or you can't interact with him.", guid.GetString().c_str()); continue; } GossipMenuItemsMapBounds pMenuItemBounds = sObjectMgr.GetGossipMenuItemsMapBounds(pCreature->GetCreatureInfo()->GossipMenuId); for (GossipMenuItemsMap::const_iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr) { uint32 npcflags = pCreature->GetUInt32Value(UNIT_NPC_FLAGS); if (!(itr->second.npc_option_npcflag & npcflags)) continue; switch (itr->second.option_id) { case GOSSIP_OPTION_TAXIVENDOR: { // bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_TAXIVENDOR"); bot->GetSession()->SendLearnNewTaxiNode(pCreature); break; } case GOSSIP_OPTION_QUESTGIVER: { // bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_QUESTGIVER"); bot->GetPlayerbotAI()->TurnInQuests(pCreature); break; } case GOSSIP_OPTION_VENDOR: { // bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_VENDOR"); if (!botConfig.GetBoolDefault("PlayerbotAI.SellGarbage", true)) continue; // changed the SellGarbage() function to support ch.SendSysMessaage() bot->GetPlayerbotAI()->SellGarbage(*bot); break; } case GOSSIP_OPTION_STABLEPET: { // bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_STABLEPET"); break; } case GOSSIP_OPTION_AUCTIONEER: { // bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_AUCTIONEER"); break; } case GOSSIP_OPTION_BANKER: { // bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_BANKER"); break; } case GOSSIP_OPTION_INNKEEPER: { // bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_INNKEEPER"); break; } } } } return; } case CMSG_SPIRIT_HEALER_ACTIVATE: { // DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_SPIRIT_HEALER_ACTIVATE SpiritHealer is resurrecting the Player %s",m_master->GetName()); for (PlayerBotMap::iterator itr = m_playerBots.begin(); itr != m_playerBots.end(); ++itr) { Player* const bot = itr->second; Group* grp = bot->GetGroup(); if (grp) grp->RemoveMember(bot->GetObjectGuid(), 1); } return; } case CMSG_LIST_INVENTORY: { if (!botConfig.GetBoolDefault("PlayerbotAI.SellGarbage", true)) return; WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid npcGUID; p >> npcGUID; Object* const pNpc = (WorldObject*) m_master->GetObjectByTypeMask(npcGUID, TYPEMASK_CREATURE_OR_GAMEOBJECT); if (!pNpc) return; // for all master's bots for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (!bot->IsInMap(static_cast<WorldObject*>(pNpc))) { bot->GetPlayerbotAI()->TellMaster("I'm too far away to sell items!"); continue; } else { // changed the SellGarbage() function to support ch.SendSysMessaage() bot->GetPlayerbotAI()->FollowAutoReset(); bot->GetPlayerbotAI()->SellGarbage(*bot); } } return; } /* case CMSG_NAME_QUERY: case MSG_MOVE_START_FORWARD: case MSG_MOVE_STOP: case MSG_MOVE_SET_FACING: case MSG_MOVE_START_STRAFE_LEFT: case MSG_MOVE_START_STRAFE_RIGHT: case MSG_MOVE_STOP_STRAFE: case MSG_MOVE_START_BACKWARD: case MSG_MOVE_HEARTBEAT: case CMSG_STANDSTATECHANGE: case CMSG_QUERY_TIME: case CMSG_CREATURE_QUERY: case CMSG_GAMEOBJECT_QUERY: case MSG_MOVE_JUMP: case MSG_MOVE_FALL_LAND: return;*/ default: { /*const char* oc = LookupOpcodeName(packet.GetOpcode()); // ChatHandler ch(m_master); // ch.SendSysMessage(oc); std::ostringstream out; out << "masterin: " << oc; sLog.outError(out.str().c_str()); */ } } }
void PlayerbotMgr::HandleMasterIncomingPacket(const WorldPacket& packet) { switch (packet.GetOpcode()) { // if master is logging out, log out all bots case CMSG_LOGOUT_REQUEST: { LogoutAllBots(); return; } // If master inspects one of his bots, give the master useful info in chat window // such as inventory that can be equipped case CMSG_INSPECT: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid guid; p >> guid; Player* const bot = GetPlayerBot(guid); if (bot) bot->GetPlayerbotAI()->SendNotEquipList(*bot); return; } // handle emotes from the master //case CMSG_EMOTE: case CMSG_TEXT_EMOTE: { WorldPacket p(packet); p.rpos(0); // reset reader uint32 emoteNum; p >> emoteNum; /* std::ostringstream out; out << "emote is: " << emoteNum; ChatHandler ch(m_master); ch.SendSysMessage(out.str().c_str()); */ switch (emoteNum) { case TEXTEMOTE_BOW: { // Buff anyone who bows before me. Useful for players not in bot's group // How do I get correct target??? //Player* const pPlayer = GetPlayerBot(m_master->GetSelection()); //if (pPlayer->GetPlayerbotAI()->GetClassAI()) // pPlayer->GetPlayerbotAI()->GetClassAI()->BuffPlayer(pPlayer); return; } /* case TEXTEMOTE_BONK: { Player* const pPlayer = GetPlayerBot(m_master->GetSelection()); if (!pPlayer || !pPlayer->GetPlayerbotAI()) return; PlayerbotAI* const pBot = pPlayer->GetPlayerbotAI(); ChatHandler ch(m_master); { std::ostringstream out; out << "time(0): " << time(0) << " m_ignoreAIUpdatesUntilTime: " << pBot->m_ignoreAIUpdatesUntilTime; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "m_TimeDoneEating: " << pBot->m_TimeDoneEating << " m_TimeDoneDrinking: " << pBot->m_TimeDoneDrinking; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "m_CurrentlyCastingSpellId: " << pBot->m_CurrentlyCastingSpellId; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "IsBeingTeleported() " << pBot->GetPlayer()->IsBeingTeleported(); ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; bool tradeActive = (pBot->GetPlayer()->GetTrader()) ? true : false; out << "tradeActive: " << tradeActive; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "IsCharmed() " << pBot->getPlayer()->isCharmed(); ch.SendSysMessage(out.str().c_str()); } return; } */ case TEXTEMOTE_EAT: case TEXTEMOTE_DRINK: { for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->Feast(); } return; } // emote to attack selected target case TEXTEMOTE_POINT: { ObjectGuid attackOnGuid = m_master->GetSelectionGuid(); if (attackOnGuid.IsEmpty()) return; Unit* thingToAttack = ObjectAccessor::GetUnit(*m_master, attackOnGuid); if (!thingToAttack) return; Player *bot = 0; for (PlayerBotMap::iterator itr = m_playerBots.begin(); itr != m_playerBots.end(); ++itr) { bot = itr->second; if (!bot->IsFriendlyTo(thingToAttack) && bot->IsWithinLOSInMap(thingToAttack)) bot->GetPlayerbotAI()->GetCombatTarget(thingToAttack); } return; } // emote to stay case TEXTEMOTE_STAND: { Player* const bot = GetPlayerBot(m_master->GetSelectionGuid()); if (bot) bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_STAY); else for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_STAY); } return; } // 324 is the followme emote (not defined in enum) // if master has bot selected then only bot follows, else all bots follow case 324: case TEXTEMOTE_WAVE: { Player* const bot = GetPlayerBot(m_master->GetSelectionGuid()); if (bot) bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_FOLLOW, m_master); else for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_FOLLOW, m_master); } return; } } return; } /* EMOTE ends here */ case CMSG_GAMEOBJ_USE: // not sure if we still need this one case CMSG_GAMEOBJ_REPORT_USE: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid objGUID; p >> objGUID; GameObject *obj = (m_master && m_master->GetMap()) ? m_master->GetMap()->GetGameObject(objGUID) : NULL; if (!obj) return; for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (obj->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) bot->GetPlayerbotAI()->TurnInQuests(obj); // add other go types here, i.e.: // GAMEOBJECT_TYPE_CHEST - loot quest items of chest } } break; // if master talks to an NPC case CMSG_GOSSIP_HELLO: case CMSG_QUESTGIVER_HELLO: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid npcGUID; p >> npcGUID; WorldObject* pNpc = (m_master && m_master->GetMap()) ? m_master->GetMap()->GetWorldObject(npcGUID) : NULL; if (!pNpc) return; // for all master's bots for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->TurnInQuests(pNpc); } return; } // if master accepts a quest, bots should also try to accept quest case CMSG_QUESTGIVER_ACCEPT_QUEST: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid guid; uint32 quest; p >> guid >> quest; Quest const* qInfo = sObjectMgr.GetQuestTemplate(quest); if (qInfo) for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (bot->GetQuestStatus(quest) == QUEST_STATUS_COMPLETE) bot->GetPlayerbotAI()->TellMaster("I already completed that quest."); else if (!bot->CanTakeQuest(qInfo, false)) { if (!bot->SatisfyQuestStatus(qInfo, false)) bot->GetPlayerbotAI()->TellMaster("I already have that quest."); else bot->GetPlayerbotAI()->TellMaster("I can't take that quest."); } else if (!bot->SatisfyQuestLog(false)) bot->GetPlayerbotAI()->TellMaster("My quest log is full."); else if (!bot->CanAddQuest(qInfo, false)) bot->GetPlayerbotAI()->TellMaster("I can't take that quest because it requires that I take items, but my bags are full!"); else { p.rpos(0); // reset reader bot->GetSession()->HandleQuestgiverAcceptQuestOpcode(p); bot->GetPlayerbotAI()->TellMaster("Got the quest."); } } return; } case CMSG_LOOT_ROLL: { WorldPacket p(packet); //WorldPacket packet for CMSG_LOOT_ROLL, (8+4+1) ObjectGuid Guid; uint32 NumberOfPlayers; uint8 rollType; p.rpos(0); //reset packet pointer p >> Guid; //guid of the item rolled p >> NumberOfPlayers; //number of players invited to roll p >> rollType; //need,greed or pass on roll for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { uint32 choice = urand(0, 3); //returns 0,1,2 or 3 Player* const bot = it->second; if (!bot) return; Group* group = bot->GetGroup(); if (!group) return; group->CountRollVote(bot, Guid, NumberOfPlayers, RollVote(choice)); switch (choice) { case ROLL_NEED: bot->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED, 1); break; case ROLL_GREED: bot->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED, 1); break; } } return; } case CMSG_REPAIR_ITEM: { WorldPacket p(packet); // WorldPacket packet for CMSG_REPAIR_ITEM, (8+8+1) sLog.outDebug("PlayerbotMgr: CMSG_REPAIR_ITEM"); ObjectGuid npcGUID; uint64 itemGUID; uint8 guildBank; p.rpos(0); //reset packet pointer p >> npcGUID; p >> itemGUID; // Not used for bot but necessary opcode data retrieval p >> guildBank; // Flagged if guild repair selected for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (!bot) return; Group* group = bot->GetGroup(); // check if bot is a member of group if (!group) return; Creature *unit = bot->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR); if (!unit) // Check if NPC can repair bot or not { sLog.outDebug("PlayerbotMgr: HandleRepairItemOpcode - Unit (GUID: %s) not found or you can't interact with him.", npcGUID.GetString().c_str()); return; } // remove fake death if (bot->hasUnitState(UNIT_STAT_DIED)) bot->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); // reputation discount float discountMod = bot->GetReputationPriceDiscount(unit); uint32 TotalCost = 0; if (itemGUID) // Handle redundant feature (repair individual item) for bot { sLog.outDebug("ITEM: Repair single item is not applicable for %s", bot->GetName()); continue; } else // Handle feature (repair all items) for bot { sLog.outDebug("ITEM: Repair all items, npcGUID = %s", npcGUID.GetString().c_str()); TotalCost = bot->DurabilityRepairAll(true, discountMod, guildBank > 0 ? true : false); } if (guildBank) // Handle guild repair { uint32 GuildId = bot->GetGuildId(); if (!GuildId) return; Guild *pGuild = sGuildMgr.GetGuildById(GuildId); if (!pGuild) return; pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, bot->GetGUIDLow(), TotalCost); pGuild->SendMoneyInfo(bot->GetSession(), bot->GetGUIDLow()); } } return; } case CMSG_SPIRIT_HEALER_ACTIVATE: { // sLog.outDebug("SpiritHealer is resurrecting the Player %s",m_master->GetName()); for (PlayerBotMap::iterator itr = m_playerBots.begin(); itr != m_playerBots.end(); ++itr) { Player* const bot = itr->second; Group *grp = bot->GetGroup(); if (grp) grp->RemoveMember(bot->GetObjectGuid(), 1); } return; } /* case CMSG_NAME_QUERY: case MSG_MOVE_START_FORWARD: case MSG_MOVE_STOP: case MSG_MOVE_SET_FACING: case MSG_MOVE_START_STRAFE_LEFT: case MSG_MOVE_START_STRAFE_RIGHT: case MSG_MOVE_STOP_STRAFE: case MSG_MOVE_START_BACKWARD: case MSG_MOVE_HEARTBEAT: case CMSG_STANDSTATECHANGE: case CMSG_QUERY_TIME: case CMSG_CREATURE_QUERY: case CMSG_GAMEOBJECT_QUERY: case MSG_MOVE_JUMP: case MSG_MOVE_FALL_LAND: return; default: { const char* oc = LookupOpcodeName(packet.GetOpcode()); // ChatHandler ch(m_master); // ch.SendSysMessage(oc); std::ostringstream out; out << "masterin: " << oc; sLog.outError(out.str().c_str()); } */ } }
/// Update the WorldSession (triggered by World update) bool WorldSession::Update(uint32 diff) { /// Update Timeout timer. UpdateTimeOutTime(diff); ///- Before we process anything: /// If necessary, kick the player from the character select screen if (IsConnectionIdle()) m_Socket->CloseSocket(); ///- Retrieve packets from the receive queue and call the appropriate handlers /// not proccess packets if socket already closed WorldPacket* packet; while (m_Socket && !m_Socket->IsClosed() && _recvQueue.next(packet)) { /*#if 1 sLog.outError("MOEP: %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); #endif*/ if (packet->GetOpcode() >= NUM_MSG_TYPES) { sLog.outError("SESSION: received non-existed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); } else { OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; try { switch (opHandle.status) { case STATUS_LOGGEDIN: if (!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets if (!m_playerRecentlyLogout) LogUnexpectedOpcode(packet, "the player has not logged in yet"); } else if (_player->IsInWorld()) { (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); // PlayerBot mod: if this player has bots let the // botAI see the masters packet if(!m_playerBots.empty()) PlayerbotAI::HandleMasterIncomingPacket(*packet, *this); } // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT: if (!_player && !m_playerRecentlyLogout) { LogUnexpectedOpcode(packet, "the player has not logged in yet and not recently logout"); } else { // not expected _player or must checked in packet hanlder (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } break; case STATUS_TRANSFER: if (!_player) LogUnexpectedOpcode(packet, "the player has not logged in yet"); else if (_player->IsInWorld()) LogUnexpectedOpcode(packet, "the player is still in world"); else { (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } break; case STATUS_AUTHED: // prevent cheating with skip queue wait if (m_inQueue) { LogUnexpectedOpcode(packet, "the player not pass queue yet"); break; } // single from authed time opcodes send in to after logout time // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes. if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL) m_playerRecentlyLogout = false; (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); break; case STATUS_NEVER: /* sLog.outError("SESSION: received not allowed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); */ break; } } catch(ByteBufferException &) { sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); if (sLog.IsOutDebug()) { sLog.outDebug("Dumping error causing packet:"); packet->hexlike(); } } } delete packet; } time_t currTime = time(NULL); ///- If necessary, log the player out if (ShouldLogOut(currTime) && !m_playerLoading) LogoutPlayer(true); //PlayerBot mod - Process player bot packets //The PlayerbotAI class adds to the packet queue to simulate a real player //since Playerbots are known to the World obj only its master's //WorldSession object we need to process all master's bot's packets. for(PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); itr != GetPlayerBotsEnd(); ++itr) { Player *const botPlayer = itr->second; WorldSession *const pBotWorldSession = botPlayer->GetSession(); if(botPlayer->IsBeingTeleportedFar()) { pBotWorldSession->HandleMoveWorldportAckOpcode(); } else if(botPlayer->IsInWorld()) { WorldPacket *packet; while(pBotWorldSession->_recvQueue.next(packet)) { OpcodeHandler &opHandle = opcodeTable[packet->GetOpcode()]; (pBotWorldSession->*opHandle.handler)(*packet); delete packet; } } } ///- Cleanup socket pointer if need if (m_Socket && m_Socket->IsClosed()) { m_Socket->RemoveReference(); m_Socket = NULL; } if (!m_Socket) return false; //Will remove this session from the world session map return true; }
/// %Log the player out void WorldSession::LogoutPlayer(bool Save) { if (!_player) return; if (_player->IsMounted()) _player->Unmount(); // PlayerBot mod: log out all playerbots owned by this character //while(!m_playerBots.empty()) // LogoutPlayerBot(m_playerBots.begin()->first, Save); PlayerBotMap m_pBots; uint8 m_botCount = 0; for(PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); itr != GetPlayerBotsEnd(); ++itr) { Player *bot = itr->second; (m_pBots)[itr->first] = bot; ++m_botCount; } // Create a solo bind for player if player is currently in group in instance with all bots Group *m_Group = _player->GetGroup(); bool rebound = false; if(m_botCount > 0 && m_Group && m_botCount == m_Group->GetMembersCount()-1) if (InstanceSave *save = sInstanceSaveManager.GetInstanceSave(_player->GetInstanceId())) { _player->BindToInstance(save, false); save->SetCanReset(false); rebound = true; } for(PlayerBotMap::const_iterator itr2 = m_pBots.begin(); itr2 != m_pBots.end(); ++itr2) { Player *botPlayer = itr2->second; if (!botPlayer) continue; LogoutPlayerBot(botPlayer->GetGUID(), Save); } if (rebound) _player->m_InstanceValid = true; // finish pending transfers before starting the logout while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; m_playerSave = Save; if (_player) { sLFGMgr.Leave(_player); GetPlayer()->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); GetPlayer()->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); GetPlayer()->GetSession()->SendLfgUpdateSearch(false); if (uint64 lguid = GetPlayer()->GetLootGUID()) DoLootRelease(lguid); ///- If the player just died before logging out, make him appear as a ghost //FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) { _player->getHostileRefManager().deleteReferences(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (!_player->getAttackers().empty()) { _player->CombatStop(); _player->getHostileRefManager().setOnlineOfflineState(false); _player->RemoveAllAurasOnDeath(); // build set of player who attack _player or who have pet attacking of _player std::set<Player*> aset; for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) { Unit* owner = (*itr)->GetOwner(); // including player controlled case if (owner) { if (owner->GetTypeId() == TYPEID_PLAYER) aset.insert(owner->ToPlayer()); } else if ((*itr)->GetTypeId() == TYPEID_PLAYER) aset.insert((Player*)(*itr)); } _player->SetPvPDeath(!aset.empty()); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); // give honor to all attackers from set like group case for (std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) (*itr)->RewardHonor(_player,aset.size()); // give bg rewards and update counters like kill by first from attackers // this can't be called for all attackers. if (!aset.empty()) if (BattleGround *bg = _player->GetBattleGround()) bg->HandleKillPlayer(_player,*aset.begin()); } else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION _player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); //_player->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } //drop a flag if player is carrying it if (BattleGround *bg = _player->GetBattleGround()) bg->EventPlayerLoggedOut(_player); ///- Teleport to home if the player is in an invalid instance if ((!_player->m_InstanceValid && !_player->isGameMaster()) || (_player->IsPlayerbot() && _player->GetMap()->IsDungeon())) _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); sOutdoorPvPMgr.HandlePlayerLeaveZone(_player,_player->GetZoneId()); for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) { if (BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i)) { _player->RemoveBattleGroundQueueId(bgQueueTypeId); sBattleGroundMgr.m_BattleGroundQueues[ bgQueueTypeId ].RemovePlayer(_player->GetGUID(), true); } } // Repop at GraveYard or other player far teleport will prevent saving player because of not present map // Teleport player immediately for correct player save while (_player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); ///- 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()); if (guild) { guild->SetMemberStats(_player->GetGUID()); guild->UpdateLogoutTime(_player->GetGUID()); guild->BroadcastEvent(GE_SIGNED_OFF, _player->GetGUID(), 1, _player->GetName(), "", ""); } ///- Remove pet _player->RemovePet(NULL,PET_SAVE_AS_CURRENT, true); ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if (Save) { uint32 eslot; for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j) { eslot = j - BUYBACK_SLOT_START; _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0); } _player->SaveToDB(); } ///- Leave all channels before player delete... _player->CleanupChannels(); ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. _player->UninviteFromGroup(); // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) if ((_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) || (_player->IsPlayerbot() && _player->GetGroup())) _player->RemoveFromGroup(); ///- Send update to group and reset stored max enchanting level if (_player->GetGroup()) { _player->GetGroup()->SendUpdate(); _player->GetGroup()->ResetMaxEnchantingLevel(); } ///- Broadcast a logout message to the player's friends sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ()); ///- Remove the player from the world // the player may not be in the world when logging out // e.g if he got disconnected during a transfer to another map // calls to GetMap in this case may cause crashes _player->CleanupsBeforeDelete(); sLog.outChar("Account: %d (IP: %s) Logout Character:[%s] (GUID: %u)", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName() ,_player->GetGUIDLow()); Map* _map = _player->GetMap(); uint32 guid = _player->GetGUIDLow(); _map->Remove(_player, true); SetPlayer(NULL); // deleted in Remove call ///- Send the 'logout complete' packet to the client WorldPacket data(SMSG_LOGOUT_COMPLETE, 0); SendPacket(&data); ///- 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'", guid); sLog.outDebug("SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); } //Hook for OnLogout Event sScriptMgr.OnLogout(_player); m_playerLogout = false; m_playerSave = false; m_playerRecentlyLogout = true; LogoutRequest(0); }
void PlayerbotMgr::HandleMasterIncomingPacket(const WorldPacket& packet) { switch (packet.GetOpcode()) { // if master is logging out, log out all bots case CMSG_LOGOUT_REQUEST: { LogoutAllBots(); return; } // If master inspects one of his bots, give the master useful info in chat window // such as inventory that can be equipped case CMSG_INSPECT: { WorldPacket p(packet); p.rpos(0); // reset reader uint64 guid; p >> guid; Player* const bot = GetPlayerBot(guid); if (bot) bot->GetPlayerbotAI()->SendNotEquipList(*bot); return; } // handle emotes from the master //case CMSG_EMOTE: case CMSG_TEXT_EMOTE: { WorldPacket p(packet); p.rpos(0); // reset reader uint32 emoteNum; p >> emoteNum; /* std::ostringstream out; out << "emote is: " << emoteNum; ChatHandler ch(m_master); ch.SendSysMessage(out.str().c_str()); */ switch (emoteNum) { case TEXTEMOTE_BOW: { // Buff anyone who bows before me. Useful for players not in bot's group // How do I get correct target??? //Player* const pPlayer = GetPlayerBot(m_master->GetSelection()); //if (pPlayer->GetPlayerbotAI()->GetClassAI()) // pPlayer->GetPlayerbotAI()->GetClassAI()->BuffPlayer(pPlayer); return; } /* case TEXTEMOTE_BONK: { Player* const pPlayer = GetPlayerBot(m_master->GetSelection()); if (!pPlayer || !pPlayer->GetPlayerbotAI()) return; PlayerbotAI* const pBot = pPlayer->GetPlayerbotAI(); ChatHandler ch(m_master); { std::ostringstream out; out << "time(0): " << time(0) << " m_ignoreAIUpdatesUntilTime: " << pBot->m_ignoreAIUpdatesUntilTime; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "m_TimeDoneEating: " << pBot->m_TimeDoneEating << " m_TimeDoneDrinking: " << pBot->m_TimeDoneDrinking; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "m_CurrentlyCastingSpellId: " << pBot->m_CurrentlyCastingSpellId; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "IsBeingTeleported() " << pBot->GetPlayer()->IsBeingTeleported(); ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; bool tradeActive = (pBot->GetPlayer()->GetTrader()) ? true : false; out << "tradeActive: " << tradeActive; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "IsCharmed() " << pBot->getPlayer()->isCharmed(); ch.SendSysMessage(out.str().c_str()); } return; } */ case TEXTEMOTE_EAT: case TEXTEMOTE_DRINK: { for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->Feast(); } return; } // emote to attack selected target case TEXTEMOTE_POINT: { uint64 attackOnGuid = m_master->GetSelection(); if( !attackOnGuid ) return; Unit* thingToAttack = ObjectAccessor::GetUnit(*m_master, attackOnGuid); if( !thingToAttack ) return; Player *bot = 0; for( PlayerBotMap::iterator itr=m_playerBots.begin(); itr!=m_playerBots.end(); ++itr ) { bot = itr->second; if (!bot->IsFriendlyTo(thingToAttack) && bot->IsWithinLOSInMap(thingToAttack)) bot->GetPlayerbotAI()->GetCombatTarget( thingToAttack ); } return; } // emote to stay case TEXTEMOTE_STAND: { Player* const bot = GetPlayerBot(m_master->GetSelection()); if (bot) bot->GetPlayerbotAI()->SetMovementOrder( PlayerbotAI::MOVEMENT_STAY ); else { for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->SetMovementOrder( PlayerbotAI::MOVEMENT_STAY ); } } return; } // 324 is the followme emote (not defined in enum) // if master has bot selected then only bot follows, else all bots follow case 324: case TEXTEMOTE_WAVE: { Player* const bot = GetPlayerBot(m_master->GetSelection()); if (bot) bot->GetPlayerbotAI()->SetMovementOrder( PlayerbotAI::MOVEMENT_FOLLOW, m_master ); else { for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->SetMovementOrder( PlayerbotAI::MOVEMENT_FOLLOW, m_master); } } return; } } return; } /* EMOTE ends here */ // if master talks to an NPC case CMSG_SET_SELECTION: //case CMSG_GOSSIP_HELLO: //case CMSG_QUESTGIVER_HELLO: { WorldPacket p(packet); p.rpos(0); // reset reader uint64 npcGUID; p >> npcGUID; Object* const pNpc = ObjectAccessor::GetObjectByTypeMask(*m_master, npcGUID, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); if (!pNpc) return; // for all master's bots for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (!bot->IsInMap((WorldObject*) pNpc)) bot->GetPlayerbotAI()->TellMaster("hey you are turning in quests without me!"); else { bot->SetSelection(npcGUID); // auto complete every completed quest this NPC has bot->PrepareQuestMenu(npcGUID); QuestMenu& questMenu = bot->PlayerTalkClass->GetQuestMenu(); for (uint32 iI = 0; iI < questMenu.MenuItemCount(); ++iI) { QuestMenuItem const& qItem = questMenu.GetItem(iI); uint32 questID = qItem.m_qId; Quest const* pQuest = objmgr.GetQuestTemplate(questID); std::ostringstream out; std::string questTitle = pQuest->GetTitle(); bot->GetPlayerbotAI()->QuestLocalization(questTitle, questID); QuestStatus status = bot->GetQuestStatus(questID); // if quest is complete, turn it in if (status == QUEST_STATUS_COMPLETE) { // if bot hasn't already turned quest in if (! bot->GetQuestRewardStatus(questID)) { // auto reward quest if no choice in reward if (pQuest->GetRewChoiceItemsCount() == 0) { if (bot->CanRewardQuest(pQuest, false)) { bot->RewardQuest(pQuest, 0, pNpc, false); out << "Quest complete: |cff808080|Hquest:" << questID << ':' << pQuest->GetQuestLevel() << "|h[" << questTitle << "]|h|r"; } else { out << "|cffff0000Unable to turn quest in:|r |cff808080|Hquest:" << questID << ':' << pQuest->GetQuestLevel() << "|h[" << questTitle << "]|h|r"; } } // auto reward quest if one item as reward else if (pQuest->GetRewChoiceItemsCount() == 1) { int rewardIdx = 0; ItemPrototype const *pRewardItem = objmgr.GetItemPrototype(pQuest->RewChoiceItemId[rewardIdx]); std::string itemName = pRewardItem->Name1; bot->GetPlayerbotAI()->ItemLocalization(itemName, pRewardItem->ItemId); if (bot->CanRewardQuest(pQuest, rewardIdx, false)) { bot->RewardQuest(pQuest, rewardIdx, pNpc, true); std::string itemName = pRewardItem->Name1; bot->GetPlayerbotAI()->ItemLocalization(itemName, pRewardItem->ItemId); out << "Quest complete: " << " |cff808080|Hquest:" << questID << ':' << pQuest->GetQuestLevel() << "|h[" << questTitle << "]|h|r reward: |cffffffff|Hitem:" << pRewardItem->ItemId << ":0:0:0:0:0:0:0" << "|h[" << itemName << "]|h|r"; } else { out << "|cffff0000Unable to turn quest in:|r " << "|cff808080|Hquest:" << questID << ':' << pQuest->GetQuestLevel() << "|h[" << questTitle << "]|h|r" << " reward: |cffffffff|Hitem:" << pRewardItem->ItemId << ":0:0:0:0:0:0:0" << "|h[" << itemName << "]|h|r"; } } // else multiple rewards - let master pick else { out << "What reward should I take for |cff808080|Hquest:" << questID << ':' << pQuest->GetQuestLevel() << "|h[" << questTitle << "]|h|r? "; for (uint8 i=0; i < pQuest->GetRewChoiceItemsCount(); ++i) { ItemPrototype const * const pRewardItem = objmgr.GetItemPrototype(pQuest->RewChoiceItemId[i]); std::string itemName = pRewardItem->Name1; bot->GetPlayerbotAI()->ItemLocalization(itemName, pRewardItem->ItemId); out << "|cffffffff|Hitem:" << pRewardItem->ItemId << ":0:0:0:0:0:0:0" << "|h[" << itemName << "]|h|r"; } } } } else if (status == QUEST_STATUS_INCOMPLETE) { out << "|cffff0000Quest incomplete:|r " << " |cff808080|Hquest:" << questID << ':' << pQuest->GetQuestLevel() << "|h[" << questTitle << "]|h|r"; } else if (status == QUEST_STATUS_AVAILABLE){ out << "|cff00ff00Quest available:|r " << " |cff808080|Hquest:" << questID << ':' << pQuest->GetQuestLevel() << "|h[" << questTitle << "]|h|r"; } if (! out.str().empty()) bot->GetPlayerbotAI()->TellMaster(out.str()); } } } return; } // if master accepts a quest, bots should also try to accept quest case CMSG_QUESTGIVER_ACCEPT_QUEST: { WorldPacket p(packet); p.rpos(0); // reset reader uint64 guid; uint32 quest; p >> guid >> quest; Quest const* qInfo = objmgr.GetQuestTemplate(quest); if (qInfo) { for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (bot->GetQuestStatus(quest) == QUEST_STATUS_COMPLETE) bot->GetPlayerbotAI()->TellMaster("I already completed that quest."); else if (! bot->CanTakeQuest(qInfo, false)) { if (! bot->SatisfyQuestStatus(qInfo, false)) bot->GetPlayerbotAI()->TellMaster("I already have that quest."); else bot->GetPlayerbotAI()->TellMaster("I can't take that quest."); } else if (! bot->SatisfyQuestLog(false)) bot->GetPlayerbotAI()->TellMaster("My quest log is full."); else if (! bot->CanAddQuest(qInfo, false)) bot->GetPlayerbotAI()->TellMaster("I can't take that quest because it requires that I take items, but my bags are full!"); else { p.rpos(0); // reset reader bot->GetSession()->HandleQuestgiverAcceptQuestOpcode(p); bot->GetPlayerbotAI()->TellMaster("Got the quest."); } } } return; } /* case CMSG_NAME_QUERY: case MSG_MOVE_START_FORWARD: case MSG_MOVE_STOP: case MSG_MOVE_SET_FACING: case MSG_MOVE_START_STRAFE_LEFT: case MSG_MOVE_START_STRAFE_RIGHT: case MSG_MOVE_STOP_STRAFE: case MSG_MOVE_START_BACKWARD: case MSG_MOVE_HEARTBEAT: case CMSG_STANDSTATECHANGE: case CMSG_QUERY_TIME: case CMSG_CREATURE_QUERY: case CMSG_GAMEOBJECT_QUERY: case MSG_MOVE_JUMP: case MSG_MOVE_FALL_LAND: return; default: { const char* oc = LookupOpcodeName(packet.GetOpcode()); // ChatHandler ch(m_master); // ch.SendSysMessage(oc); std::ostringstream out; out << "masterin: " << oc; sLog.outError(out.str().c_str()); } */ } }
void PlayerbotMgr::HandleMasterIncomingPacket(const WorldPacket& packet) { switch (packet.GetOpcode()) { case CMSG_ACTIVATETAXI: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid guid; std::vector<uint32> nodes; nodes.resize(2); uint8 delay = 9; p >> guid >> nodes[0] >> nodes[1]; DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_ACTIVATETAXI from %d to %d", nodes[0], nodes[1]); for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { delay = delay + 3; Player* const bot = it->second; if (!bot) return; Group* group = bot->GetGroup(); if (!group) continue; Unit *target = ObjectAccessor::GetUnit(*bot, guid); bot->GetPlayerbotAI()->SetIgnoreUpdateTime(delay); bot->GetMotionMaster()->Clear(true); bot->GetMotionMaster()->MoveFollow(target, INTERACTION_DISTANCE, bot->GetOrientation()); bot->GetPlayerbotAI()->GetTaxi(guid, nodes); } return; } case CMSG_ACTIVATETAXIEXPRESS: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid guid; uint32 node_count; uint8 delay = 9; p >> guid; p.read_skip<uint32>(); p >> node_count; std::vector<uint32> nodes; for (uint32 i = 0; i < node_count; ++i) { uint32 node; p >> node; nodes.push_back(node); } if (nodes.empty()) return; DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_ACTIVATETAXIEXPRESS from %d to %d", nodes.front(), nodes.back()); for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { delay = delay + 3; Player* const bot = it->second; if (!bot) return; Group* group = bot->GetGroup(); if (!group) continue; Unit *target = ObjectAccessor::GetUnit(*bot, guid); bot->GetPlayerbotAI()->SetIgnoreUpdateTime(delay); bot->GetMotionMaster()->Clear(true); bot->GetMotionMaster()->MoveFollow(target, INTERACTION_DISTANCE, bot->GetOrientation()); bot->GetPlayerbotAI()->GetTaxi(guid, nodes); } return; } case CMSG_MOVE_SPLINE_DONE: { DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_MOVE_SPLINE_DONE"); WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid guid; // used only for proper packet read MovementInfo movementInfo; // used only for proper packet read p >> guid.ReadAsPacked(); p >> movementInfo; p >> Unused<uint32>(); // unk for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (!bot) return; // in taxi flight packet received in 2 case: // 1) end taxi path in far (multi-node) flight // 2) switch from one map to other in case multi-map taxi path // we need process only (1) uint32 curDest = bot->m_taxi.GetTaxiDestination(); if (!curDest) return; TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); // far teleport case if (curDestNode && curDestNode->map_id != bot->GetMapId()) { if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) { // short preparations to continue flight FlightPathMovementGenerator* flight = (FlightPathMovementGenerator *) (bot->GetMotionMaster()->top()); flight->Interrupt(*bot); // will reset at map landing flight->SetCurrentNodeAfterTeleport(); TaxiPathNodeEntry const& node = flight->GetPath()[flight->GetCurrentNode()]; flight->SkipCurrentNode(); bot->TeleportTo(curDestNode->map_id, node.x, node.y, node.z, bot->GetOrientation()); } return; } uint32 destinationnode = bot->m_taxi.NextTaxiDestination(); if (destinationnode > 0) // if more destinations to go { // current source node for next destination uint32 sourcenode = bot->m_taxi.GetTaxiSource(); // Add to taximask middle hubs in taxicheat mode (to prevent having player with disabled taxicheat and not having back flight path) if (bot->isTaxiCheater()) if (bot->m_taxi.SetTaximaskNode(sourcenode)) { WorldPacket data(SMSG_NEW_TAXI_PATH, 0); bot->GetSession()->SendPacket(&data); } DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_MOVE_SPLINE_DONE Taxi has to go from %u to %u", sourcenode, destinationnode); uint32 mountDisplayId = sObjectMgr.GetTaxiMountDisplayId(sourcenode, bot->GetTeam()); uint32 path, cost; sObjectMgr.GetTaxiPath(sourcenode, destinationnode, path, cost); if (path && mountDisplayId) bot->GetSession()->SendDoFlight(mountDisplayId, path, 1); // skip start fly node else bot->m_taxi.ClearTaxiDestinations(); // clear problematic path and next } else /* std::ostringstream out; out << "Destination reached" << bot->GetName(); ChatHandler ch(m_master); ch.SendSysMessage(out.str().c_str()); */ bot->m_taxi.ClearTaxiDestinations(); // Destination, clear source node } return; } // if master is logging out, log out all bots case CMSG_LOGOUT_REQUEST: { LogoutAllBots(); return; } // If master inspects one of his bots, give the master useful info in chat window // such as inventory that can be equipped case CMSG_INSPECT: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid guid; p >> guid; Player* const bot = GetPlayerBot(guid); if (bot) bot->GetPlayerbotAI()->SendNotEquipList(*bot); return; } // handle emotes from the master //case CMSG_EMOTE: case CMSG_TEXT_EMOTE: { WorldPacket p(packet); p.rpos(0); // reset reader uint32 emoteNum; p >> emoteNum; /* std::ostringstream out; out << "emote is: " << emoteNum; ChatHandler ch(m_master); ch.SendSysMessage(out.str().c_str()); */ switch (emoteNum) { case TEXTEMOTE_BOW: { // Buff anyone who bows before me. Useful for players not in bot's group // How do I get correct target??? //Player* const pPlayer = GetPlayerBot(m_master->GetSelection()); //if (pPlayer->GetPlayerbotAI()->GetClassAI()) // pPlayer->GetPlayerbotAI()->GetClassAI()->BuffPlayer(pPlayer); return; } /* case TEXTEMOTE_BONK: { Player* const pPlayer = GetPlayerBot(m_master->GetSelection()); if (!pPlayer || !pPlayer->GetPlayerbotAI()) return; PlayerbotAI* const pBot = pPlayer->GetPlayerbotAI(); ChatHandler ch(m_master); { std::ostringstream out; out << "CurrentTime: " << CurrentTime() << " m_ignoreAIUpdatesUntilTime: " << pBot->m_ignoreAIUpdatesUntilTime; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "m_TimeDoneEating: " << pBot->m_TimeDoneEating << " m_TimeDoneDrinking: " << pBot->m_TimeDoneDrinking; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "m_CurrentlyCastingSpellId: " << pBot->m_CurrentlyCastingSpellId; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "IsBeingTeleported() " << pBot->GetPlayer()->IsBeingTeleported(); ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; bool tradeActive = (pBot->GetPlayer()->GetTrader()) ? true : false; out << "tradeActive: " << tradeActive; ch.SendSysMessage(out.str().c_str()); } { std::ostringstream out; out << "IsCharmed() " << pBot->getPlayer()->isCharmed(); ch.SendSysMessage(out.str().c_str()); } return; } */ case TEXTEMOTE_EAT: case TEXTEMOTE_DRINK: return; // emote to attack selected target case TEXTEMOTE_POINT: { ObjectGuid attackOnGuid = m_master->GetSelectionGuid(); if (!attackOnGuid) return; Unit* thingToAttack = ObjectAccessor::GetUnit(*m_master, attackOnGuid); if (!thingToAttack) return; Player* bot = 0; for (PlayerBotMap::iterator itr = m_playerBots.begin(); itr != m_playerBots.end(); ++itr) { bot = itr->second; if (!bot->IsFriendlyTo(thingToAttack)) { if (!bot->IsWithinLOSInMap(thingToAttack)) { bot->GetPlayerbotAI()->TellMaster("Trying to attack something, but I'm too far away!"); bot->GetPlayerbotAI()->DoTeleport(*m_master); } if (bot->IsWithinLOSInMap(thingToAttack)) bot->GetPlayerbotAI()->Attack(thingToAttack); } } return; } // emote to stay case TEXTEMOTE_STAND: { Player* const bot = GetPlayerBot(m_master->GetSelectionGuid()); if (bot) bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_STAY); else for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_STAY); } return; } // 324 is the followme emote (not defined in enum) // if master has bot selected then only bot follows, else all bots follow case 324: case TEXTEMOTE_WAVE: { Player* const bot = GetPlayerBot(m_master->GetSelectionGuid()); if (bot) bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_FOLLOW, m_master); else for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->SetMovementOrder(PlayerbotAI::MOVEMENT_FOLLOW, m_master); } return; } } return; } /* EMOTE ends here */ case CMSG_GAMEOBJ_USE: // not sure if we still need this one { DEBUG_LOG("PlayerbotMgr: CMSG_GAMEOBJ_USE"); WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid objGUID; p >> objGUID; for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; GameObject *obj = m_master->GetMap()->GetGameObject(objGUID); if (!obj) return; // add other go types here, i.e.: // GAMEOBJECT_TYPE_CHEST - loot quest items of chest if (obj->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) { bot->GetPlayerbotAI()->TurnInQuests(obj); // auto accept every available quest this NPC has bot->PrepareQuestMenu(objGUID); QuestMenu& questMenu = bot->PlayerTalkClass->GetQuestMenu(); for (uint32 iI = 0; iI < questMenu.MenuItemCount(); ++iI) { QuestMenuItem const& qItem = questMenu.GetItem(iI); uint32 questID = qItem.m_qId; if (!bot->GetPlayerbotAI()->AddQuest(questID, obj)) DEBUG_LOG("Couldn't take quest"); } } } } break; case CMSG_QUESTGIVER_HELLO: { DEBUG_LOG("PlayerbotMgr: CMSG_QUESTGIVER_HELLO"); WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid npcGUID; p >> npcGUID; WorldObject* pNpc = m_master->GetMap()->GetWorldObject(npcGUID); if (!pNpc) return; // for all master's bots for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->TurnInQuests(pNpc); } return; } // if master accepts a quest, bots should also try to accept quest case CMSG_QUESTGIVER_ACCEPT_QUEST: { WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid guid; uint32 quest; uint32 unk1; p >> guid >> quest; DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_QUESTGIVER_ACCEPT_QUEST npc = %s, quest = %u", guid.GetString().c_str(), quest); Quest const* qInfo = sObjectMgr.GetQuestTemplate(quest); if (qInfo) for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (bot->GetQuestStatus(quest) == QUEST_STATUS_COMPLETE) bot->GetPlayerbotAI()->TellMaster("I already completed that quest."); else if (!bot->CanTakeQuest(qInfo, false)) { if (!bot->SatisfyQuestStatus(qInfo, false)) bot->GetPlayerbotAI()->TellMaster("I already have that quest."); else bot->GetPlayerbotAI()->TellMaster("I can't take that quest."); } else if (!bot->SatisfyQuestLog(false)) bot->GetPlayerbotAI()->TellMaster("My quest log is full."); else if (!bot->CanAddQuest(qInfo, false)) bot->GetPlayerbotAI()->TellMaster("I can't take that quest because it requires that I take items, but my bags are full!"); else { p.rpos(0); // reset reader bot->GetSession()->HandleQuestgiverAcceptQuestOpcode(p); bot->GetPlayerbotAI()->TellMaster("Got the quest."); // build needed items if quest contains any for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++) if (qInfo->ReqItemCount[i] > 0) { bot->GetPlayerbotAI()->SetQuestNeedItems(); break; } // build needed creatures if quest contains any for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) if (qInfo->ReqCreatureOrGOCount[i] > 0) { bot->GetPlayerbotAI()->SetQuestNeedCreatures(); break; } } } return; } case CMSG_AREATRIGGER: { WorldPacket p(packet); for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; p.rpos(0); // reset reader bot->GetSession()->HandleAreaTriggerOpcode(p); } return; } case CMSG_QUESTGIVER_COMPLETE_QUEST: { WorldPacket p(packet); p.rpos(0); // reset reader uint32 quest; ObjectGuid npcGUID; p >> npcGUID >> quest; DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %s, quest = %u", npcGUID.GetString().c_str(), quest); WorldObject* pNpc = m_master->GetMap()->GetWorldObject(npcGUID); if (!pNpc) return; // for all master's bots for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; bot->GetPlayerbotAI()->TurnInQuests(pNpc); } return; } case CMSG_LOOT_ROLL: { WorldPacket p(packet); //WorldPacket packet for CMSG_LOOT_ROLL, (8+4+1) ObjectGuid Guid; uint32 itemSlot; uint8 rollType; p.rpos(0); //reset packet pointer p >> Guid; //guid of the lootable target p >> itemSlot; //loot index p >> rollType; //need,greed or pass on roll for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { uint32 choice = 0; Player* const bot = it->second; if (!bot) return; Group* group = bot->GetGroup(); if (!group) return; // check that the bot did not already vote if (rollType >= ROLL_NOT_EMITED_YET) return; Loot* loot = sLootMgr.GetLoot(bot, Guid); if (!loot) { sLog.outError("LootMgr::PlayerVote> Error cannot get loot object info!"); return; } LootItem* lootItem = loot->GetLootItemInSlot(itemSlot); ItemPrototype const *pProto = lootItem->itemProto; if (!pProto) return; if (bot->GetPlayerbotAI()->CanStore()) { if (bot->CanUseItem(pProto) == EQUIP_ERR_OK && bot->GetPlayerbotAI()->IsItemUseful(lootItem->itemId)) choice = 1; // Need else choice = 2; // Greed } else choice = 0; // Pass sLootMgr.PlayerVote(bot, Guid, itemSlot, RollVote(choice)); } return; } // Handle GOSSIP activate actions, prior to GOSSIP select menu actions case CMSG_GOSSIP_HELLO: { DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_GOSSIP_HELLO"); WorldPacket p(packet); //WorldPacket packet for CMSG_GOSSIP_HELLO, (8) ObjectGuid guid; p.rpos(0); //reset packet pointer p >> guid; for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (!bot) continue; Creature *pCreature = bot->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); if (!pCreature) { DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_GOSSIP_HELLO %s not found or you can't interact with him.", guid.GetString().c_str()); continue; } GossipMenuItemsMapBounds pMenuItemBounds = sObjectMgr.GetGossipMenuItemsMapBounds(pCreature->GetCreatureInfo()->GossipMenuId); for (GossipMenuItemsMap::const_iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr) { uint32 npcflags = pCreature->GetUInt32Value(UNIT_NPC_FLAGS); if (!(itr->second.npc_option_npcflag & npcflags)) continue; switch (itr->second.option_id) { case GOSSIP_OPTION_TAXIVENDOR: { //bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_TAXIVENDOR"); bot->GetSession()->SendLearnNewTaxiNode(pCreature); break; } case GOSSIP_OPTION_QUESTGIVER: { //bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_QUESTGIVER"); bot->GetPlayerbotAI()->TurnInQuests(pCreature); break; } case GOSSIP_OPTION_VENDOR: { //bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_VENDOR"); if (!botConfig.GetBoolDefault("PlayerbotAI.SellGarbage", true)) return; bot->GetPlayerbotAI()->SellGarbage(); break; } case GOSSIP_OPTION_STABLEPET: { //bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_STABLEPET"); break; } case GOSSIP_OPTION_AUCTIONEER: { //bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_AUCTIONEER"); break; } case GOSSIP_OPTION_BANKER: { //bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_BANKER"); break; } case GOSSIP_OPTION_INNKEEPER: { //bot->GetPlayerbotAI()->TellMaster("PlayerbotMgr:GOSSIP_OPTION_INNKEEPER"); break; } } } } return; } case CMSG_SPIRIT_HEALER_ACTIVATE: { // DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_SPIRIT_HEALER_ACTIVATE SpiritHealer is resurrecting the Player %s",m_master->GetName()); for (PlayerBotMap::iterator itr = m_playerBots.begin(); itr != m_playerBots.end(); ++itr) { Player* const bot = itr->second; Group *grp = bot->GetGroup(); if (grp) grp->RemoveMember(bot->GetObjectGuid(), 1); } return; } case CMSG_LIST_INVENTORY: { if (!botConfig.GetBoolDefault("PlayerbotAI.SellGarbage", true)) return; WorldPacket p(packet); p.rpos(0); // reset reader ObjectGuid npcGUID; p >> npcGUID; Object* const pNpc = (WorldObject *) m_master->GetObjectByTypeMask(npcGUID, TYPEMASK_CREATURE_OR_GAMEOBJECT); if (!pNpc) return; // for all master's bots for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (!bot->IsInMap(static_cast<WorldObject *>(pNpc))) { bot->GetPlayerbotAI()->TellMaster("I'm too far away to sell items!"); continue; } else bot->GetPlayerbotAI()->SellGarbage(); } return; } /* case CMSG_NAME_QUERY: case MSG_MOVE_START_FORWARD: case MSG_MOVE_STOP: case MSG_MOVE_SET_FACING: case MSG_MOVE_START_STRAFE_LEFT: case MSG_MOVE_START_STRAFE_RIGHT: case MSG_MOVE_STOP_STRAFE: case MSG_MOVE_START_BACKWARD: case MSG_MOVE_HEARTBEAT: case CMSG_STANDSTATECHANGE: case CMSG_QUERY_TIME: case CMSG_CREATURE_QUERY: case CMSG_GAMEOBJECT_QUERY: case MSG_MOVE_JUMP: case MSG_MOVE_FALL_LAND: return;*/ default: { /*const char* oc = LookupOpcodeName(packet.GetOpcode()); // ChatHandler ch(m_master); // ch.SendSysMessage(oc); std::ostringstream out; out << "masterin: " << oc; sLog.outError(out.str().c_str()); */ } } }