void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket &recv_data) { //sLog.outDebug("BATTLEGROUND: Recieved CMSG_BATTLEFIELD_STATUS packet."); if(!GetPlayer()->m_bgInBattleground || GetPlayer()->GetCurrentBattleground() == NULL) { WorldPacket pkt; pkt.Initialize(SMSG_BATTLEFIELD_STATUS); pkt << uint32(0x00) << uint32(0x00); SendPacket(&pkt); return; } WorldPacket * pkt; Battleground * bg = GetPlayer()->GetCurrentBattleground(); uint32 CurrentTime = uint32(time(NULL)); pkt = sBattlegroundMgr.BuildBattlegroundStatusPacket(0, bg->GetBattlegroundType(), bg->GetInstanceID(), 3, CurrentTime, 0); SendPacket(pkt); delete pkt; }
void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); uint8 action; // enter battle 128, leave queue 0 // then goes uint64 that we sent to client in SMSG_BATTLEFIELD_STATUS3 uint32 bgTypeId_; // type id from dbc uint32 type; // arenatype if arena recv_data >> action >> bgTypeId_ >> type; if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { sLog->outError("BattlegroundHandler: invalid bgtype (%u) received.", bgTypeId_); return; } if (!_player->InBattlegroundQueue()) { sLog->outError("BattlegroundHandler: Invalid CMSG_BATTLEFIELD_PORT received from player (%u), he is not in bg_queue.", _player->GetGUIDLow()); return; } //get GroupQueueInfo from BattlegroundQueue BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, (uint8)type); BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue::RemovePlayer() function GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) { sLog->outError("BattlegroundHandler: itrplayerstatus not found."); return; } // if action == 1, then instanceId is required if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) { sLog->outError("BattlegroundHandler: instance not found."); return; } Battleground *bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); // bg template might and must be used in case of leaving queue, when instance is not created yet if (!bg && action == 0) bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) { sLog->outError("BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); return; } // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it if (action == 1 && ginfo.ArenaType == 0) { //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue if (!_player->CanJoinToBattleground()) { //send bg command result to show nice message WorldPacket data2; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data2, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); _player->GetSession()->SendPacket(&data2); action = 0; sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); } //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue if (_player->getLevel() > bg->GetMaxLevel()) { sLog->outError("Battleground: Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID()); action = 0; } } uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); WorldPacket data; switch(action >> 7) { case 1: // port to battleground if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId)) return; // cheating? if (!_player->InBattleground()) _player->SetBattlegroundEntryPoint(); // resurrect the player if (!_player->isAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } // stop taxi flight at port if (_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); _player->CleanupAfterTaxiFlight(); } sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr bgQueue.RemovePlayer(_player->GetGUID(), false); // this is still needed here if battleground "jumping" shouldn't add deserter debuff // also this is required to prevent stuck at old battleground after SetBattlegroundId set to new if (Battleground *currentBg = _player->GetBattleground()) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); // set the destination instance id _player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId); // set the destination team _player->SetBGTeam(ginfo.Team); // bg->HandleBeforeTeleportToBattleground(_player); sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); // add only in HandleMoveWorldPortAck() // bg->AddPlayer(_player, team); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); break; case 0: // leave queue // if player leaves rated arena match before match start, it is counted as he played but he lost if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID) { ArenaTeam * at = sObjectMgr->GetArenaTeamById(ginfo.Team); if (at) { sLog->outDebug(LOG_FILTER_BATTLEGROUND, "UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), ginfo.OpponentsTeamRating); at->MemberLost(_player, ginfo.OpponentsMatchmakerRating); at->SaveToDB(); } } _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); bgQueue.RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it - do not update Arena Queue if (!ginfo.ArenaType) sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); SendPacket(&data); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); break; default: sLog->outError("Battleground port: unknown action %u", action); break; } }
void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) { uint8 type; // arenatype if arena uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 uint32 bgTypeId_; // type id from dbc uint16 unk; // 0x1F90 constant? uint8 action; // enter battle 0x1, leave queue 0x0 recvData >> type >> unk2 >> bgTypeId_ >> unk >> action; if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Invalid BgType!", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); return; } if (!_player->InBattlegroundQueue()) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Player not in queue!", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); return; } //get GroupQueueInfo from BattlegroundQueue BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, type); BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue::RemovePlayer() function GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Player not in queue (No player Group Info)!", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); return; } // if action == 1, then instanceId is required if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Player is not invited to any bg!", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); return; } Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); if (!bg) { if (action) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Cant find BG with id %u!", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action, ginfo.IsInvitedToBGInstanceGUID); return; } bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) { TC_LOG_ERROR("network", "BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); return; } } TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u.", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it if (action == 1 && ginfo.ArenaType == 0) { //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue if (!_player->CanJoinToBattleground(bg)) { //send bg command result to show nice message WorldPacket data2; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data2, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); _player->GetSession()->SendPacket(&data2); action = 0; TC_LOG_DEBUG("bg.battleground", "Player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName().c_str(), _player->GetGUIDLow()); } //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue if (_player->getLevel() > bg->GetMaxLevel()) { TC_LOG_ERROR("network", "Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", _player->GetName().c_str(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID()); action = 0; } } uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); WorldPacket data; if (action) { // check Freeze debuff if (_player->HasAura(9454)) return; if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId)) return; // cheating? if (!_player->InBattleground()) _player->SetBattlegroundEntryPoint(); // resurrect the player if (!_player->IsAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } // stop taxi flight at port if (_player->IsInFlight()) { _player->GetMotionMaster()->MovementExpired(); _player->CleanupAfterTaxiFlight(); } sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), ginfo.Team); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr bgQueue.RemovePlayer(_player->GetGUID(), false); // this is still needed here if battleground "jumping" shouldn't add deserter debuff // also this is required to prevent stuck at old battleground after SetBattlegroundId set to new if (Battleground* currentBg = _player->GetBattleground()) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); // set the destination instance id _player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId); // set the destination team _player->SetBGTeam(ginfo.Team); // bg->HandleBeforeTeleportToBattleground(_player); sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); // add only in HandleMoveWorldPortAck() // bg->AddPlayer(_player, team); TC_LOG_DEBUG("bg.battleground", "Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName().c_str(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); } else // leave queue { if (bg->isArena() && bg->GetStatus() > STATUS_WAIT_QUEUE) return; // if player leaves rated arena match before match start, it is counted as he played but he lost if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID) { ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ginfo.Team); if (at) { TC_LOG_DEBUG("bg.battleground", "UPDATING memberLost's personal arena rating for %s by opponents rating: %u, because he has left queue!", _player->GetGUID().ToString().c_str(), ginfo.OpponentsTeamRating); at->MemberLost(_player, ginfo.OpponentsMatchmakerRating); at->SaveToDB(); } } _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0); bgQueue.RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it - do not update Arena Queue if (!ginfo.ArenaType) sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); SendPacket(&data); TC_LOG_DEBUG("bg.battleground", "Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName().c_str(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); } }
void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); uint32 time; uint32 queueSlot; uint32 unk; uint8 action; // enter battle 0x1, leave queue 0x0 ObjectGuid guid; recvData >> time; recvData >> queueSlot; recvData >> unk; guid[0] = recvData.ReadBit(); guid[1] = recvData.ReadBit(); guid[5] = recvData.ReadBit(); guid[6] = recvData.ReadBit(); guid[7] = recvData.ReadBit(); guid[4] = recvData.ReadBit(); guid[3] = recvData.ReadBit(); guid[2] = recvData.ReadBit(); action = recvData.ReadBit(); recvData.ReadByteSeq(guid[1]); recvData.ReadByteSeq(guid[3]); recvData.ReadByteSeq(guid[5]); recvData.ReadByteSeq(guid[7]); recvData.ReadByteSeq(guid[0]); recvData.ReadByteSeq(guid[2]); recvData.ReadByteSeq(guid[6]); recvData.ReadByteSeq(guid[4]); if (!_player->InBattlegroundQueue()) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u. Player not in queue!", GetPlayerInfo().c_str(), queueSlot, unk, time, action); return; } BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(queueSlot); if (bgQueueTypeId == BATTLEGROUND_QUEUE_NONE) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u. Invalid queueSlot!", GetPlayerInfo().c_str(), queueSlot, unk, time, action); return; } BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue::RemovePlayer() function GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u. Player not in queue (No player Group Info)!", GetPlayerInfo().c_str(), queueSlot, unk, time, action); return; } // if action == 1, then instanceId is required if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u. Player is not invited to any bg!", GetPlayerInfo().c_str(), queueSlot, unk, time, action); return; } BattlegroundTypeId bgTypeId = BattlegroundMgr::BGTemplateId(bgQueueTypeId); // BGTemplateId returns BATTLEGROUND_AA when it is arena queue. // Do instance id search as there is no AA bg instances. Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId == BATTLEGROUND_AA ? BATTLEGROUND_TYPE_NONE : bgTypeId); if (!bg) { if (action) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u. Cant find BG with id %u!", GetPlayerInfo().c_str(), queueSlot, unk, time, action, ginfo.IsInvitedToBGInstanceGUID); return; } bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) { TC_LOG_ERROR("network", "BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); return; } } TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u.", GetPlayerInfo().c_str(), queueSlot, unk, time, action); // get real bg type bgTypeId = bg->GetTypeID(); // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it if (action == 1 && ginfo.ArenaType == 0) { //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue if (!_player->CanJoinToBattleground(bg)) { //send bg command result to show nice message WorldPacket data2; sBattlegroundMgr->BuildStatusFailedPacket(&data2, bg, _player, 0, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); _player->GetSession()->SendPacket(&data2); action = 0; TC_LOG_DEBUG("bg.battleground", "Player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName().c_str(), _player->GetGUIDLow()); } //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue if (_player->getLevel() > bg->GetMaxLevel()) { TC_LOG_DEBUG("network", "Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", _player->GetName().c_str(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID()); action = 0; } } WorldPacket data; if (action) { if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId)) return; // cheating? if (!_player->InBattleground()) _player->SetBattlegroundEntryPoint(); // resurrect the player if (!_player->IsAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } // stop taxi flight at port if (_player->IsInFlight()) { _player->GetMotionMaster()->MovementExpired(); _player->CleanupAfterTaxiFlight(); } sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_IN_PROGRESS, _player->GetBattlegroundQueueJoinTime(bgTypeId), bg->GetElapsedTime(), bg->GetArenaType()); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr bgQueue.RemovePlayer(_player->GetGUID(), false); // this is still needed here if battleground "jumping" shouldn't add deserter debuff // also this is required to prevent stuck at old battleground after SetBattlegroundId set to new if (Battleground* currentBg = _player->GetBattleground()) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); // set the destination instance id _player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId); // set the destination team _player->SetBGTeam(ginfo.Team); // bg->HandleBeforeTeleportToBattleground(_player); sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); // add only in HandleMoveWorldPortAck() // bg->AddPlayer(_player, team); TC_LOG_DEBUG("bg.battleground", "Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName().c_str(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); } else // leave queue { // if player leaves rated arena match before match start, it is counted as he played but he lost if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID) { ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ginfo.Team); if (at) { TC_LOG_DEBUG("bg.battleground", "UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), ginfo.OpponentsTeamRating); at->MemberLost(_player, ginfo.OpponentsMatchmakerRating); at->SaveToDB(); } } sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_NONE, _player->GetBattlegroundQueueJoinTime(bgTypeId), 0, 0); SendPacket(&data); _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs bgQueue.RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it - do not update Arena Queue if (!ginfo.ArenaType) sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); TC_LOG_DEBUG("bg.battleground", "Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName().c_str(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); } }
void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); uint32 time; uint32 queueSlot; // guessed uint32 unk; // type id from dbc uint8 action; // enter battle 0x1, leave queue 0x0 ObjectGuid guid; recvData >> unk; recvData >> queueSlot; recvData >> time; guid[0] = recvData.ReadBit(); guid[5] = recvData.ReadBit(); guid[3] = recvData.ReadBit(); guid[2] = recvData.ReadBit(); guid[4] = recvData.ReadBit(); guid[1] = recvData.ReadBit(); action = recvData.ReadBit(); guid[6] = recvData.ReadBit(); guid[7] = recvData.ReadBit(); recvData.FlushBits(); uint8 byteOrder[8] = {0, 3, 4, 7, 1, 5, 6, 2}; recvData.ReadBytesSeq(guid, byteOrder); if (!_player->InBattlegroundQueue()) { sLog->outDebug(LOG_FILTER_BATTLEGROUND, "BattlegroundHandler: Invalid CMSG_BATTLEFIELD_PORT received from player (Name: %s, GUID: %u), he is not in bg_queue.", _player->GetName(), _player->GetGUIDLow()); return; } if (queueSlot > PLAYER_MAX_BATTLEGROUND_QUEUES) { sLog->OutPandashan("HandleBattleFieldPortOpcode queueSlot %u", queueSlot); return; } BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(queueSlot); if (bgQueueTypeId == BATTLEGROUND_QUEUE_NONE) { sLog->outDebug(LOG_FILTER_BATTLEGROUND, "BattlegroundHandler: invalid queueSlot (%u) received.", queueSlot); return; } if (bgQueueTypeId > MAX_BATTLEGROUND_QUEUE_TYPES) { sLog->OutPandashan("HandleBattleFieldPortOpcode bgQueueTypeId %u", bgQueueTypeId); return; } BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue::RemovePlayer() function GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) { sLog->outError(LOG_FILTER_NETWORKIO, "BattlegroundHandler: itrplayerstatus not found."); return; } // if action == 1, then instanceId is required if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) { sLog->outError(LOG_FILTER_NETWORKIO, "BattlegroundHandler: instance not found."); return; } BattlegroundTypeId bgTypeId = BattlegroundMgr::BGTemplateId(bgQueueTypeId); // BGTemplateId returns BATTLEGROUND_AA when it is arena queue. // Do instance id search as there is no AA bg instances. Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId == BATTLEGROUND_AA ? BATTLEGROUND_TYPE_NONE : bgTypeId); // bg template might and must be used in case of leaving queue, when instance is not created yet if (!bg && action == 0) bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) { sLog->outError(LOG_FILTER_NETWORKIO, "BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); return; } // get real bg type bgTypeId = bg->GetTypeID(); // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it if (action == 1 && ginfo.ArenaType == 0) { //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue if (!_player->CanJoinToBattleground()) { //send bg command result to show nice message WorldPacket data2; sBattlegroundMgr->BuildStatusFailedPacket(&data2, bg, _player, 0, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); _player->GetSession()->SendPacket(&data2); action = 0; sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); } //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue if (_player->getLevel() > bg->GetMaxLevel()) { sLog->outError(LOG_FILTER_NETWORKIO, "Battleground: Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID()); action = 0; } } WorldPacket data; switch (action) { case 1: // port to battleground if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId)) return; // cheating? if (!_player->InBattleground()) _player->SetBattlegroundEntryPoint(); // resurrect the player if (!_player->isAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } // stop taxi flight at port if (_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); _player->CleanupAfterTaxiFlight(); } sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_IN_PROGRESS, _player->GetBattlegroundQueueJoinTime(bgTypeId), bg->GetElapsedTime(), bg->GetArenaType()); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr bgQueue.RemovePlayer(_player->GetGUID(), false); // this is still needed here if battleground "jumping" shouldn't add deserter debuff // also this is required to prevent stuck at old battleground after SetBattlegroundId set to new if (Battleground* currentBg = _player->GetBattleground()) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); // set the destination instance id _player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId); // set the destination team _player->SetBGTeam(ginfo.Team); // bg->HandleBeforeTeleportToBattleground(_player); sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); // add only in HandleMoveWorldPortAck() // bg->AddPlayer(_player, team); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); break; case 0: // leave queue if (bg->isArena() && bg->GetStatus() > STATUS_WAIT_QUEUE) return; // if player leaves rated arena match before match start, it is counted as he played but he lost if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID) { ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ginfo.Team); if (at) { sLog->outDebug(LOG_FILTER_BATTLEGROUND, "UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), ginfo.OpponentsTeamRating); at->MemberLost(_player, ginfo.OpponentsMatchmakerRating); at->SaveToDB(); } } sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_NONE, _player->GetBattlegroundQueueJoinTime(bgTypeId), 0, 0); SendPacket(&data); _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs bgQueue.RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it - do not update Arena Queue if (!ginfo.ArenaType) sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); break; default: sLog->outError(LOG_FILTER_NETWORKIO, "Battleground port: unknown action %u", action); break; } }
bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) { player->PlayerTalkClass->ClearMenus(); if (!ArenaWatcherEnable && (!ArenaWatcherOnlyGM || player->IsGameMaster())) return true; if (action <= GOSSIP_OFFSET) { bool bracketExists = false; uint8 playerCount = action - GOSSIP_ACTION_INFO_DEF; for (uint8 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId) { if (!BattlegroundMgr::IsArenaType(BattlegroundTypeId(bgTypeId))) continue; BattlegroundData* arenas = sBattlegroundMgr->GetAllBattlegroundsWithTypeId(BattlegroundTypeId(bgTypeId)); if (!arenas || arenas->m_Battlegrounds.empty()) continue; for (BattlegroundContainer::const_iterator itr = arenas->m_Battlegrounds.begin(); itr != arenas->m_Battlegrounds.end(); ++itr) { Map* map = itr->second->FindBgMap(); if (!map) continue; if (!(itr->second->GetStatus() & 2)) { continue; } if (itr->second->GetArenaType() != playerCount) continue; if (ArenaWatcherOnlyRated && !itr->second->isRated()) continue; if (itr->second->isRated()) { ArenaTeam* teamOne = sArenaTeamMgr->GetArenaTeamById(itr->second->GetArenaTeamIdByIndex(0)); ArenaTeam* teamTwo = sArenaTeamMgr->GetArenaTeamById(itr->second->GetArenaTeamIdByIndex(1)); if (teamOne && teamTwo) { char gossipTextFormat[100]; snprintf(gossipTextFormat, 100, "%s : %s (%u) vs. %s (%u)", map->GetMapName(), teamOne->GetName().c_str(), teamOne->GetRating(), teamTwo->GetName().c_str(), teamTwo->GetRating()); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, gossipTextFormat, GOSSIP_SENDER_MAIN + bgTypeId, itr->first + GOSSIP_OFFSET); } } else { char gossipTextFormat[100]; snprintf(gossipTextFormat, 100, "[%u] %s : %u vs. %u", itr->first, map->GetMapName(), playerCount, playerCount); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, gossipTextFormat, GOSSIP_SENDER_MAIN + bgTypeId, itr->first + GOSSIP_OFFSET); } bracketExists = true; } } if (bracketExists) player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); else { sCreatureTextMgr->SendChat(creature, SAY_NOT_FOUND_BRACKET, player->GetGUID()); player->PlayerTalkClass->ClearMenus(); player->CLOSE_GOSSIP_MENU(); } } else { uint32 arenaId = action - GOSSIP_OFFSET; uint32 bgTypeId = sender - GOSSIP_SENDER_MAIN; BattlegroundData* arenas = sBattlegroundMgr->GetAllBattlegroundsWithTypeId(BattlegroundTypeId(bgTypeId)); if (!arenas || arenas->m_Battlegrounds.empty()) return false; if (arenas->m_Battlegrounds[arenaId]) { Battleground* bg = arenas->m_Battlegrounds[arenaId]; if (bg->GetStatus() == STATUS_NONE) { sCreatureTextMgr->SendChat(creature, SAY_ARENA_NOT_IN_PROGRESS, player->GetGUID()); player->PlayerTalkClass->ClearMenus(); player->CLOSE_GOSSIP_MENU(); return false; } float x = 0.0f, y = 0.0f, z = 0.0f; switch (bg->GetMapId()) { case 617: x = 1299.046f; y = 784.825f; z = 9.338f; break; case 618: x = 763.5f; y = -284; z = 28.276f; break; case 572: x = 1285.810547f; y = 1667.896851f; z = 39.957642f; break; case 562: x = 6238.930176f; y = 262.963470f; z = 0.889519f; break; case 559: x = 4055.504395f; y = 2919.660645f; z = 13.611241f; break; default: player->PlayerTalkClass->ClearMenus(); player->CLOSE_GOSSIP_MENU(); return false; } player->SetBattlegroundId(bg->GetInstanceID(), bg->GetTypeID()); player->SetBattlegroundEntryPoint(); ArenaWatcherStart(player); player->TeleportTo(bg->GetMapId(), x, y, z, player->GetOrientation()); ArenaWatcherAfterTeleport(player); } } return true; }
bool ChallengeMgr::InviteGroupsToArena(Player *leader1, Player *leader2, ArenaChallengeType type) { uint8 arenatype = (type == ARENA_CHALLENGE_TYPE_1v1) ? ARENA_CHALLENGE_TYPE_2v2 : type; uint32 matchmakerRating = 0; //check existance Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(BATTLEGROUND_AA); if (!bg) { sLog->outError("Battleground: template bg (all arenas) not found"); return false; } BattlegroundTypeId bgTypeId = bg->GetTypeID(); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenatype); PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), 80); if (!bracketEntry) return false; GroupQueueInfo *group1, *group2; if (type == ARENA_CHALLENGE_TYPE_1v1) { group1 = CreateGroupQueueInfo(leader1, bgTypeId, arenatype); group2 = CreateGroupQueueInfo(leader2, bgTypeId, arenatype); } else { group1 = CreateGroupQueueInfo(leader1->GetGroup(), bgTypeId, arenatype); group2 = CreateGroupQueueInfo(leader2->GetGroup(), bgTypeId, arenatype); } if (!group1 || !group2) return false; for (std::map<uint64, PlayerQueueInfo*>::iterator itr = group1->Players.begin(); itr != group1->Players.end(); ++itr) { Player *player = ObjectAccessor::FindPlayer(itr->first); if (!player) return false; if (!CanInvitePlayer(player, bgQueueTypeId)) return false; } for (std::map<uint64, PlayerQueueInfo*>::iterator itr = group2->Players.begin(); itr != group2->Players.end(); ++itr) { Player *player = ObjectAccessor::FindPlayer(itr->first); if (!player) return false; if (!CanInvitePlayer(player, bgQueueTypeId)) return false; } sBattlegroundMgr->ScheduleQueueUpdate(matchmakerRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); Battleground *arena = sBattlegroundMgr->CreateNewBattleground(bgTypeId, bracketEntry, arenatype, true); arena->SetRated(false); if (type == ARENA_CHALLENGE_TYPE_1v1) arena->Set1vs1(true); for (std::map<uint64, PlayerQueueInfo*>::iterator itr = group1->Players.begin(); itr != group1->Players.end(); ++itr) { Player *player = ObjectAccessor::FindPlayer(itr->first); if (!player) return false; uint32 queueSlot = player->AddBattlegroundQueueId(bgQueueTypeId); WorldPacket data; // send status packet (in queue) sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype); player->GetSession()->SendPacket(&data); player->challengeData->bg = arena; player->challengeData->ginfo = CreateGroupQueueInfo(player, bgTypeId, arenatype); player->challengeData->ginfo->IsInvitedToBGInstanceGUID = arena->GetInstanceID(); player->challengeData->ginfo->Team = ALLIANCE; } for (std::map<uint64, PlayerQueueInfo*>::iterator itr = group2->Players.begin(); itr != group2->Players.end(); ++itr) { Player *player = ObjectAccessor::FindPlayer(itr->first); if (!player) return false; uint32 queueSlot = player->AddBattlegroundQueueId(bgQueueTypeId); WorldPacket data; // send status packet (in queue) sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype); player->GetSession()->SendPacket(&data); player->challengeData->bg = arena; player->challengeData->ginfo = CreateGroupQueueInfo(player, bgTypeId, arenatype); player->challengeData->ginfo->IsInvitedToBGInstanceGUID = arena->GetInstanceID(); player->challengeData->ginfo->Team = HORDE; } InviteGroupToArena(group1, arena, ALLIANCE); InviteGroupToArena(group2, arena, HORDE); arena->StartBattleground(); if (!sBattlegroundMgr->HasBattleground(arena)) sBattlegroundMgr->AddBattleground(group1->IsInvitedToBGInstanceGUID, bgTypeId, arena); return true; }
void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) { uint8 arenaType; // arenatype if arena uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 uint32 bgTypeId_; // type id from dbc uint16 unk; // 0x1F90 constant? uint8 action; // enter battle 0x1, leave queue 0x0 recvData >> arenaType >> unk2 >> bgTypeId_ >> unk >> action; // bgTypeId not valid if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) return; // player not in any queue, so can't really answer if (!_player->InBattlegroundQueue()) return; // get BattlegroundQueue for received BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenaType); BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); // get group info from queue GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) return; // to accept, player must be invited to particular battleground id if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) return; Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID); // use template if leaving queue (instance might not be created yet) if (!bg && action == 0) bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) return; // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; // safety checks if (action == 1 && ginfo.ArenaType == 0) { // can't join with deserter, check it here right before joining to be sure if (!_player->CanJoinToBattleground()) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); SendPacket(&data); action = 0; } if (_player->getLevel() > bg->GetMaxLevel()) action = 0; } // get player queue slot index for this bg (can be in up to 2 queues at the same time) uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); WorldPacket data; switch (action) { case 1: // accept { // set entry point if not in battleground if (!_player->InBattleground()) _player->SetEntryPoint(); // resurrect the player if (!_player->IsAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } // remove player from all bg queues for (uint32 qslot = 0; qslot < PLAYER_MAX_BATTLEGROUND_QUEUES; ++qslot) if (BattlegroundQueueTypeId q = _player->GetBattlegroundQueueTypeId(qslot)) { BattlegroundQueue& queue = sBattlegroundMgr->GetBattlegroundQueue(q); queue.RemovePlayer(_player->GetGUID(), (bgQueueTypeId == q), qslot); _player->RemoveBattlegroundQueueId(q); } // send status packet sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), ginfo.teamId); SendPacket(&data); _player->SetBattlegroundId(bg->GetInstanceID(), bg->GetBgTypeID(), queueSlot, true, bgTypeId == BATTLEGROUND_RB, ginfo.teamId); sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); } break; case 0: // leave queue { bgQueue.RemovePlayer(_player->GetGUID(), false, queueSlot); _player->RemoveBattlegroundQueueId(bgQueueTypeId); } break; default: break; } }
bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) { player->PlayerTalkClass->ClearMenus(); uint8 mode = ARENA_TYPE_2v2; if (action == (GOSSIP_ACTION_INFO_DEF + 3)) // 3v3 mode = ARENA_TYPE_3v3; if (action == (GOSSIP_ACTION_INFO_DEF + 5)) // 5v5 mode = ARENA_TYPE_5v5; if (action <= GOSSIP_OFFSET) { BattlegroundSet arenasSet = sBattlegroundMgr->GetAllBattlegroundsWithTypeId(BATTLEGROUND_AA); // Check for matches of chosen type bool bracketMatchs = false; for (BattlegroundSet::const_iterator itr = arenasSet.begin(); itr != arenasSet.end(); ++itr) { if (Battleground* bg = itr->second) { if (bg->GetArenaType() == mode) { bracketMatchs = true; break; } } } if (!bracketMatchs) { std::stringstream errMsg; errMsg << "Sorry " << player->GetName() << ", There are no current matches of the type you selected."; creature->MonsterWhisper(errMsg.str().c_str(), player->GetGUID()); player->PlayerTalkClass->ClearMenus(); player->CLOSE_GOSSIP_MENU(); } else { // team 1 and 2! for (BattlegroundSet::const_iterator itr = arenasSet.begin(); itr != arenasSet.end(); ++itr) { if (Battleground* bg = itr->second) { ArenaTeam* teamOne = sArenaTeamMgr->GetArenaTeamById(bg->GetArenaTeamIdByIndex(0)); ArenaTeam* teamTwo = sArenaTeamMgr->GetArenaTeamById(bg->GetArenaTeamIdByIndex(1)); if (teamOne && teamTwo) { std::stringstream gossipItem; gossipItem << teamOne->GetName() << " ("; gossipItem << teamOne->GetRating() << ") VS "; gossipItem << teamTwo->GetName() << " ("; gossipItem << teamTwo->GetRating() << ")"; player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, gossipItem.str(), GOSSIP_SENDER_MAIN + 1, itr->first + GOSSIP_OFFSET); } } } player->PlayerTalkClass->SendGossipMenu(player->GetGossipTextId(creature), creature->GetGUID()); } } else { uint32 arenaId = action - GOSSIP_OFFSET; // Don't really bother about WPE injection here, we are allowing pretty much any arena selection BattlegroundSet arenasSet = sBattlegroundMgr->GetAllBattlegroundsWithTypeId(BATTLEGROUND_AA); if (arenasSet[arenaId] != NULL) { Battleground* arenaChosen = arenasSet[arenaId]; // spectator crap if (arenaChosen->GetStatus() != STATUS_NONE && arenaChosen->GetStatus() != STATUS_IN_PROGRESS) { std::stringstream errMsg; errMsg << "Sorry " << player->GetName() << ", the chosen arena has ended"; creature->MonsterWhisper(errMsg.str().c_str(), player->GetGUID()); player->PlayerTalkClass->ClearMenus(); player->CLOSE_GOSSIP_MENU(); return false; } // OK. In the case of a selected arena, we teleport in the center of the arena. player->SetBattlegroundId(arenaChosen->GetInstanceID(), arenaChosen->GetTypeID()); player->SetBattlegroundEntryPoint(); float x, y, z; switch (arenaChosen->GetMapId()) { case 617: x = 1299.046f; y = 784.825f; z = 9.338f; break; // Dalaran Sewers case 618: x = 763.5f; y = -284; z = 28.276f; break; // Ring of Valor case 572: x = 1285.810547f; y = 1667.896851f; z = 39.957642f; break; // Ruins of Lordearon case 562: x = 6238.930176f; y = 262.963470f; z = 0.889519f; break; // Blade's Edge Arena case 559: x = 4055.504395f; y = 2919.660645f; z = 13.611241f; break; // Nagrand Arena } player->SetGMVisible(false); // Make the player invisible. TODO: Use a custom spell in `spell_dbc` player->TeleportTo(arenaChosen->GetMapId(), x, y, z, player->GetOrientation()); } } return true; }
void WorldSession::HandleBattlegroundPlayerPortOpcode(WorldPacket& recv_data) { sLog.outDebug("WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); uint8 type; // arenatype if arena uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 uint32 instanceId; uint32 bgTypeId; // type id from dbc uint16 unk; // 0x1F90 constant? uint8 action; // enter battle 0x1, leave queue 0x0 recv_data >> type >> unk2 >> bgTypeId >> unk >> action; if (bgTypeId >= MAX_BATTLEGROUND_TYPES) { sLog.outError("Battleground: invalid bgtype received."); // update battleground slots for the player to fix his UI and sent data. // this is a HACK, I don't know why the client starts sending invalid packets in the first place. // it usually happens with extremely high latency (if debugging / stepping in the code for example) if (_player->InBattlegroundQueue()) { // update all queues, send invitation info if player is invited, queue info if queued for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) { uint32 queue_id = _player->GetBattlegroundQueueId(i); if (!queue_id) continue; BattlegroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattlegroundMgr.m_BattlegroundQueues[queue_id].m_QueuedPlayers[_player->GetBattlegroundQueueIdFromLevel()].find(_player->GetGUID()); // if the player is not in queue, contine if (itrPlayerStatus == sBattlegroundMgr.m_BattlegroundQueues[queue_id].m_QueuedPlayers[_player->GetBattlegroundQueueIdFromLevel()].end()) continue; // no group information, this should never happen if (!itrPlayerStatus->second.GroupInfo) continue; Battleground* bg = NULL; // get possibly needed data from groupinfo bgTypeId = itrPlayerStatus->second.GroupInfo->BgTypeId; uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType; uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated; uint8 status = 0; if (!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID) { // not invited to bg, get template bg = sBattlegroundMgr.GetBattlegroundTemplate(bgTypeId); status = STATUS_WAIT_QUEUE; } else { // get the bg we're invited to bg = sBattlegroundMgr.GetBattleground(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID); status = STATUS_WAIT_JOIN; } // if bg not found, then continue if (!bg) continue; // don't invite if already in the instance if (_player->InBattleground() && _player->GetBattleground() && _player->GetBattleground()->GetInstanceID() == bg->GetInstanceID()) continue; // re - invite player with proper data WorldPacket data; sBattlegroundMgr.BuildBattlegroundStatusPacket(&data, bg, itrPlayerStatus->second.GroupInfo->Team ? itrPlayerStatus->second.GroupInfo->Team : _player->GetTeam(), i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype, israted); SendPacket(&data); } } return; } uint32 bgQueueTypeId = 0; // get the bg what we were invited to BattlegroundQueue::QueuedPlayersMap::iterator itrPlayerStatus; bgQueueTypeId = sBattlegroundMgr.BGQueueTypeId(bgTypeId, type); itrPlayerStatus = sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattlegroundQueueIdFromLevel()].find(_player->GetGUID()); if (itrPlayerStatus == sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattlegroundQueueIdFromLevel()].end()) { sLog.outError("Battleground: itrplayerstatus not found."); return; } instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID; // if action == 1, then instanceId is _required_ if (!instanceId && action == 1) { sLog.outError("Battleground: instance not found."); return; } Battleground* bg = sBattlegroundMgr.GetBattleground(instanceId); // bg template might and must be used in case of leaving queue, when instance is not created yet if (!bg && action == 0) bg = sBattlegroundMgr.GetBattlegroundTemplate(bgTypeId); if (!bg) { sLog.outError("Battleground: bg not found."); return; } bgTypeId = bg->GetTypeID(); if (_player->InBattlegroundQueue()) { uint32 queueSlot = 0; uint32 team = 0; uint32 arenatype = 0; uint32 israted = 0; uint32 rating = 0; uint32 opponentsRating = 0; // get the team info from the queue BattlegroundQueue::QueuedPlayersMap::iterator pitr = sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattlegroundQueueIdFromLevel()].find(_player->GetGUID()); if (pitr != sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattlegroundQueueIdFromLevel()].end() && pitr->second.GroupInfo) { team = pitr->second.GroupInfo->Team; arenatype = pitr->second.GroupInfo->ArenaType; israted = pitr->second.GroupInfo->IsRated; rating = pitr->second.GroupInfo->ArenaTeamRating; opponentsRating = pitr->second.GroupInfo->OpponentsTeamRating; } else { sLog.outError("Battleground: Invalid player queue info!"); return; } // if player is trying to enter battleground (not arena) and he has deserter debuff, we must just remove him from queue if (arenatype == 0 && !_player->CanJoinToBattleground()) { sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); action = 0; } WorldPacket data; switch (action) { case 1: // port to battleground if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId)) return; // cheating? if (sWorld.getConfig(CONFIG_BATTLEGROUND_WRATH_LEAVE_MODE)) _player->SetBattlegroundEntryPoint(); // resurrect the player if (!_player->IsAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } // stop taxi flight at port if (_player->IsInFlight()) { _player->GetMotionMaster()->MovementExpired(); _player->CleanupAfterTaxiFlight(); } queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); sBattlegroundMgr.BuildBattlegroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime()); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false); // this is still needed here if battleground "jumping" shouldn't add deserter debuff // also this required to prevent stuck at old battleground after SetBattlegroundId set to new if (Battleground* currentBg = _player->GetBattleground()) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); // set the destination instance id _player->SetBattlegroundId(bg->GetInstanceID()); // set the destination team _player->SetBGTeam(team); // bg->HandleBeforeTeleportToBattleground(_player); sBattlegroundMgr.SendToBattleground(_player, instanceId); // add only in HandleMoveWorldPortAck() // bg->AddPlayer(_player,team); sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); break; case 0: // leave queue queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); /* if player leaves rated arena match before match start, it is counted as he played but he lost */ if (israted) { ArenaTeam* at = sObjectMgr.GetArenaTeamById(team); if (at) { sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), opponentsRating); at->MemberLost(_player, opponentsRating); at->SaveToDB(); } } _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs sBattlegroundMgr.BuildBattlegroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0); sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it, maybe now his group fits in sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattlegroundQueueIdFromLevel(), arenatype, israted, rating); SendPacket(&data); sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); break; default: sLog.outError("Battleground port: unknown action %u", action); break; } } }