/*
* Copyright (C) 2008-2014 TrinityCore
* Copyright (C) 2005-2009 MaNGOS
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#include "Common.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "ArenaTeamMgr.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "ArenaTeam.h"
#include "BattlegroundMgr.h"
#include "Battleground.h"
#include "Chat.h"
#include "Language.h"
#include "Log.h"
#include "Player.h"
#include "Object.h"
#include "Opcodes.h"
#include "DisableMgr.h"
#include "Group.h"
void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket& recvData)
{
ObjectGuid guid;
recvData >> guid;
TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from %s", guid.ToString().c_str());
Creature* unit = GetPlayer()->GetMap()->GetCreature(guid);
if (!unit)
return;
if (!unit->IsBattleMaster()) // it's not battlemaster
return;
// Stop the npc if moving
unit->StopMoving();
BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(unit->GetEntry());
if (!_player->GetBGAccessByLevel(bgTypeId))
{
// temp, must be gossip message...
SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR);
return;
}
SendBattleGroundList(guid, bgTypeId);
}
void WorldSession::SendBattleGroundList(ObjectGuid guid, BattlegroundTypeId bgTypeId)
{
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundListPacket(&data, guid, _player, bgTypeId);
SendPacket(&data);
}
void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
{
uint32 bgTypeId_;
uint32 instanceId;
uint8 asGroup;
bool isPremade = false;
Group* grp = NULL;
ObjectGuid guid;
recvData >> instanceId; // Instance Id
guid[2] = recvData.ReadBit();
guid[0] = recvData.ReadBit();
guid[3] = recvData.ReadBit();
guid[1] = recvData.ReadBit();
guid[5] = recvData.ReadBit();
asGroup = recvData.ReadBit(); // As Group
guid[4] = recvData.ReadBit();
guid[6] = recvData.ReadBit();
guid[7] = recvData.ReadBit();
recvData.ReadByteSeq(guid[2]);
recvData.ReadByteSeq(guid[6]);
recvData.ReadByteSeq(guid[4]);
recvData.ReadByteSeq(guid[3]);
recvData.ReadByteSeq(guid[7]);
recvData.ReadByteSeq(guid[0]);
recvData.ReadByteSeq(guid[5]);
recvData.ReadByteSeq(guid[1]);
//extract from guid
bgTypeId_ = uint64(guid.GetCounter()) & 0xFFFFFFFF;
if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
{
TC_LOG_ERROR("network", "Battleground: invalid bgtype (%u) received. possible cheater? %s", bgTypeId_, _player->GetGUID().ToString().c_str());
return;
}
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, NULL))
{
ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED);
return;
}
BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_);
TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from %s", guid.ToString().c_str());
// can do this, since it's battleground, not arena
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, 0);
BattlegroundQueueTypeId bgQueueTypeIdRandom = BattlegroundMgr::BGQueueTypeId(BATTLEGROUND_RB, 0);
// ignore if player is already in BG
if (_player->InBattleground())
return;
// get bg instance or bg template if instance not found
Battleground* bg = NULL;
if (instanceId)
bg = sBattlegroundMgr->GetBattlegroundThroughClientInstance(instanceId, bgTypeId);
if (!bg)
bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
if (!bg)
return;
// expected bracket entry
PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel());
if (!bracketEntry)
return;
GroupJoinBattlegroundResult err = ERR_BATTLEGROUND_NONE;
// check queue conditions
if (!asGroup)
{
if (GetPlayer()->isUsingLfg())
{
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_LFG_CANT_USE_BATTLEGROUND);
GetPlayer()->GetSession()->SendPacket(&data);
return;
}
// check Deserter debuff
if (!_player->CanJoinToBattleground(bg))
{
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS);
_player->GetSession()->SendPacket(&data);
return;
}
if (_player->GetBattlegroundQueueIndex(bgQueueTypeIdRandom) < PLAYER_MAX_BATTLEGROUND_QUEUES)
{
// player is already in random queue
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_IN_RANDOM_BG);
_player->GetSession()->SendPacket(&data);
return;
}
if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB)
{
// player is already in queue, can't start random queue
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_IN_NON_RANDOM_BG);
_player->GetSession()->SendPacket(&data);
return;
}
// check if already in queue
if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
// player is already in this queue
return;
// check if has free queue slots
if (!_player->HasFreeBattlegroundQueueId())
{
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_BATTLEGROUND_TOO_MANY_QUEUES);
_player->GetSession()->SendPacket(&data);
return;
}
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId);
// add joined time data
_player->AddBattlegroundQueueJoinTime(bgTypeId, ginfo->JoinTime);
WorldPacket data; // send status packet (in queue)
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_WAIT_QUEUE, avgTime, ginfo->JoinTime, ginfo->ArenaType);
SendPacket(&data);
TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue type %u bg type %u, %s, NAME %s",
bgQueueTypeId, bgTypeId, _player->GetGUID().ToString().c_str(), _player->GetName().c_str());
}
else
{
grp = _player->GetGroup();
if (!grp)
return;
if (grp->GetLeaderGUID() != _player->GetGUID())
return;
err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam());
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = NULL;
uint32 avgTime = 0;
if (!err)
{
TC_LOG_DEBUG("bg.battleground", "Battleground: the following players are joining as group:");
ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
}
for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* member = itr->GetSource();
if (!member)
continue; // this should never happen
if (err)
{
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, err);
member->GetSession()->SendPacket(&data);
continue;
}
// add to queue
uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId);
// add joined time data
member->AddBattlegroundQueueJoinTime(bgTypeId, ginfo->JoinTime);
WorldPacket data; // send status packet (in queue)
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, member, queueSlot, STATUS_WAIT_QUEUE, avgTime, ginfo->JoinTime, ginfo->ArenaType);
member->GetSession()->SendPacket(&data);
TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue type %u bg type %u, %s, NAME %s",
bgQueueTypeId, bgTypeId, member->GetGUID().ToString().c_str(), member->GetName().c_str());
}
TC_LOG_DEBUG("bg.battleground", "Battleground: group end");
}
sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
}
void WorldSession::HandleBattlegroundPlayerPositionsOpcode(WorldPacket& /*recvData*/)
{
TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEGROUND_PLAYER_POSITIONS Message");
Battleground* bg = _player->GetBattleground();
if (!bg) // can't be received if player not in battleground
return;
uint32 acount = 0;
uint32 hcount = 0;
Player* aplr = NULL;
Player* hplr = NULL;
ObjectGuid guid = bg->GetFlagPickerGUID(TEAM_ALLIANCE);
if (!guid.IsEmpty())
{
aplr = ObjectAccessor::FindPlayer(guid);
if (aplr)
++acount;
}
guid = bg->GetFlagPickerGUID(TEAM_HORDE);
if (!guid.IsEmpty())
{
hplr = ObjectAccessor::FindPlayer(guid);
if (hplr)
++hcount;
}
ObjectGuid aguid = aplr ? aplr->GetGUID() : ObjectGuid::Empty;
ObjectGuid hguid = hplr ? hplr->GetGUID() : ObjectGuid::Empty;
WorldPacket data(SMSG_BATTLEFIELD_PLAYER_POSITIONS);
data.WriteBits(acount, 22);
for (uint8 i = 0; i < acount; i++)
{
data.WriteBit(aguid[3]);
data.WriteBit(aguid[5]);
data.WriteBit(aguid[1]);
data.WriteBit(aguid[6]);
data.WriteBit(aguid[7]);
data.WriteBit(aguid[0]);
data.WriteBit(aguid[2]);
data.WriteBit(aguid[4]);
}
data.WriteBits(hcount, 22);
for (uint8 i = 0; i < hcount; i++)
{
data.WriteBit(hguid[6]);
data.WriteBit(hguid[5]);
data.WriteBit(hguid[4]);
data.WriteBit(hguid[7]);
data.WriteBit(hguid[2]);
data.WriteBit(hguid[1]);
data.WriteBit(hguid[0]);
data.WriteBit(hguid[3]);
}
data.FlushBits();
for (uint8 i = 0; i < hcount; i++)
{
data.WriteByteSeq(hguid[2]);
data.WriteByteSeq(hguid[1]);
data << float(hplr->GetPositionY());
data.WriteByteSeq(hguid[5]);
data.WriteByteSeq(hguid[4]);
data.WriteByteSeq(hguid[7]);
data.WriteByteSeq(hguid[0]);
data.WriteByteSeq(hguid[6]);
data.WriteByteSeq(hguid[3]);
data << float(hplr->GetPositionX());
}
for (uint8 i = 0; i < acount; i++)
{
data.WriteByteSeq(aguid[6]);
data << float(aplr->GetPositionX());
data.WriteByteSeq(aguid[5]);
data.WriteByteSeq(aguid[3]);
data << float(aplr->GetPositionY());
data.WriteByteSeq(aguid[1]);
data.WriteByteSeq(aguid[7]);
data.WriteByteSeq(aguid[0]);
data.WriteByteSeq(aguid[2]);
data.WriteByteSeq(aguid[4]);
}
SendPacket(&data);
}
void WorldSession::HandlePVPLogDataOpcode(WorldPacket & /*recvData*/)
{
TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_PVP_LOG_DATA Message");
Battleground* bg = _player->GetBattleground();
if (!bg)
return;
// Prevent players from sending BuildPvpLogDataPacket in an arena except for when sent in BattleGround::EndBattleGround.
if (bg->isArena())
return;
WorldPacket data;
bg->BuildPvPLogDataPacket(data);
SendPacket(&data);
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_PVP_LOG_DATA Message");
}
void WorldSession::HandleBattlefieldListOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message");
uint32 bgTypeId;
recvData >> bgTypeId; // id from DBC
BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
if (!bl)
{
TC_LOG_DEBUG("bg.battleground", "BattlegroundHandler: invalid bgtype (%u) with player (Name: %s, %s) received.", bgTypeId, _player->GetName().c_str(), _player->GetGUID().ToString().c_str());
return;
}
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundListPacket(&data, ObjectGuid::Empty, _player, BattlegroundTypeId(bgTypeId));
SendPacket(&data);
}
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 (%s) has a deserter debuff, do not port him to battleground!", _player->GetName().c_str(), _player->GetGUID().ToString().c_str());
}
//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 (%s) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!",
_player->GetName().c_str(), _player->GetGUID().ToString().c_str(), _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 (%s) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), 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 %s by opponents rating: %u, because he has left queue!", _player->GetGUID().ToString().c_str(), ginfo.OpponentsTeamRating);
at->MemberLost(_player, ginfo.OpponentsMatchmakerRating);
at->SaveToDB();
}
}
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_NONE, _player->GetBattlegroundQueueJoinTime(bgTypeId), 0, ginfo.ArenaType);
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 (%s) left queue for bgtype %u, queue type %u.", _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), bg->GetTypeID(), bgQueueTypeId);
}
}
void WorldSession::HandleBattlefieldLeaveOpcode(WorldPacket& /*recvData*/)
{
TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEFIELD_LEAVE Message");
// not allow leave battleground in combat
if (_player->IsInCombat())
if (Battleground* bg = _player->GetBattleground())
if (bg->GetStatus() != STATUS_WAIT_LEAVE)
return;
_player->LeaveBattleground();
}
void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/)
{
// empty opcode
TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEFIELD_STATUS Message");
WorldPacket data;
// we must update all queues here
Battleground* bg = NULL;
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i);
if (!bgQueueTypeId)
continue;
BattlegroundTypeId bgTypeId = BattlegroundMgr::BGTemplateId(bgQueueTypeId);
uint8 arenaType = BattlegroundMgr::BGArenaType(bgQueueTypeId);
if (bgTypeId == _player->GetBattlegroundTypeId())
{
bg = _player->GetBattleground();
//i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
//so i must use bg pointer to get that information
if (bg && bg->GetArenaType() == arenaType)
{
// this line is checked, i only don't know if GetElapsedTime() is changing itself after bg end!
// send status in Battleground
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, GetPlayer(), i, STATUS_IN_PROGRESS, _player->GetBattlegroundQueueJoinTime(bgTypeId), bg->GetElapsedTime(), arenaType);
SendPacket(&data);
continue;
}
}
//we are sending update to player about queue - he can be invited there!
//get GroupQueueInfo for queue status
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo ginfo;
if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo))
continue;
if (ginfo.IsInvitedToBGInstanceGUID)
{
bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
if (!bg)
continue;
// send status invited to Battleground
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, GetPlayer(), i, STATUS_WAIT_JOIN, getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime), _player->GetBattlegroundQueueJoinTime(bgTypeId), arenaType);
SendPacket(&data);
}
else
{
bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
if (!bg)
continue;
// expected bracket entry
PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel());
if (!bracketEntry)
continue;
uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId());
// send status in Battleground Queue
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, GetPlayer(), i, STATUS_WAIT_QUEUE, avgTime, _player->GetBattlegroundQueueJoinTime(bgTypeId), arenaType);
SendPacket(&data);
}
}
}
void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
uint8 arenaslot; // 2v2, 3v3 or 5v5
recvData >> arenaslot;
// ignore if we already in BG or BG queue
if (_player->InBattleground())
return;
uint32 arenaRating = 0;
uint32 matchmakerRating = 0;
uint8 arenatype = ArenaTeam::GetTypeBySlot(arenaslot);
//check existance
Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(BATTLEGROUND_AA);
if (!bg)
{
TC_LOG_ERROR("network", "Battleground: template bg (all arenas) not found");
return;
}
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, BATTLEGROUND_AA, NULL))
{
ChatHandler(this).PSendSysMessage(LANG_ARENA_DISABLED);
return;
}
BattlegroundTypeId bgTypeId = bg->GetTypeID();
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenatype);
PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel());
if (!bracketEntry)
return;
GroupJoinBattlegroundResult err = ERR_BATTLEGROUND_NONE;
Group* grp = _player->GetGroup();
// no group found, error
if (!grp)
return;
if (grp->GetLeaderGUID() != _player->GetGUID())
return;
uint32 ateamId = _player->GetArenaTeamId(arenaslot);
// check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ateamId);
if (!at)
{
_player->GetSession()->SendNotInArenaTeamPacket(arenatype);
return;
}
// get the team rating for queueing
arenaRating = at->GetRating();
matchmakerRating = at->GetAverageMMR(grp);
// the arenateam id must match for everyone in the group
if (arenaRating <= 0)
arenaRating = 1;
BattlegroundQueue &bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
uint32 avgTime = 0;
GroupQueueInfo* ginfo = NULL;
err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, arenatype, arenatype, true, arenaslot);
if (!err)
{
TC_LOG_DEBUG("bg.battleground", "Battleground: arena team id %u, leader %s queued with matchmaker rating %u for type %u", _player->GetArenaTeamId(arenaslot), _player->GetName().c_str(), matchmakerRating, arenatype);
ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, arenatype, true, false, arenaRating, matchmakerRating, ateamId);
avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
}
for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* member = itr->GetSource();
if (!member)
continue;
if (err)
{
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, err);
member->GetSession()->SendPacket(&data);
continue;
}
// add to queue
uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId);
// add joined time data
member->AddBattlegroundQueueJoinTime(bgTypeId, ginfo->JoinTime);
WorldPacket data; // send status packet (in queue)
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, member, queueSlot, STATUS_WAIT_QUEUE, avgTime, ginfo->JoinTime, arenatype);
member->GetSession()->SendPacket(&data);
TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for arena as group bg queue type %u bg type %u, %s, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUID().ToString().c_str(), member->GetName().c_str());
}
sBattlegroundMgr->ScheduleQueueUpdate(matchmakerRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
}
void WorldSession::HandleReportPvPAFK(WorldPacket& recvData)
{
ObjectGuid playerGuid;
recvData >> playerGuid;
Player* reportedPlayer = ObjectAccessor::FindPlayer(playerGuid);
if (!reportedPlayer)
{
TC_LOG_DEBUG("bg.battleground", "WorldSession::HandleReportPvPAFK: player not found");
return;
}
TC_LOG_DEBUG("bg.battleground", "WorldSession::HandleReportPvPAFK: %s reported %s", _player->GetName().c_str(), reportedPlayer->GetName().c_str());
reportedPlayer->ReportedAfkBy(_player);
}
void WorldSession::HandleRequestRatedBgInfo(WorldPacket & recvData)
{
TC_LOG_DEBUG("network", "WORLD: CMSG_REQUEST_RATED_BG_INFO");
uint8 unk;
recvData >> unk;
TC_LOG_DEBUG("bg.battleground", "WorldSession::HandleRequestRatedBgInfo: unk = %u", unk);
/// @Todo: perfome research in this case
/// The unk fields are related to arenas
WorldPacket data(SMSG_RATED_BG_STATS, 72);
data << uint32(0); // BgWeeklyWins20vs20
data << uint32(0); // BgWeeklyPlayed20vs20
data << uint32(0); // BgWeeklyPlayed15vs15
data << uint32(0);
data << uint32(0); // BgWeeklyWins10vs10
data << uint32(0);
data << uint32(0);
data << uint32(0);
data << uint32(0); // BgWeeklyWins15vs15
data << uint32(0);
data << uint32(0);
data << uint32(0);
data << uint32(0);
data << uint32(0);
data << uint32(0);
data << uint32(0); // BgWeeklyPlayed10vs10
data << uint32(0);
data << uint32(0);
SendPacket(&data);
}
void WorldSession::HandleRequestPvpOptions(WorldPacket& /*recvData*/)
{
TC_LOG_DEBUG("network", "WORLD: CMSG_REQUEST_PVP_OPTIONS_ENABLED");
/// @Todo: perfome research in this case
WorldPacket data(SMSG_PVP_OPTIONS_ENABLED, 1);
data.WriteBit(1);
data.WriteBit(1); // WargamesEnabled
data.WriteBit(1);
data.WriteBit(1); // RatedBGsEnabled
data.WriteBit(1); // RatedArenasEnabled
data.FlushBits();
SendPacket(&data);
}
void WorldSession::HandleRequestPvpReward(WorldPacket& /*recvData*/)
{
TC_LOG_DEBUG("network", "WORLD: CMSG_REQUEST_PVP_REWARDS");
_player->SendPvpRewards();
}
void WorldSession::HandleRequestRatedBgStats(WorldPacket& /*recvData*/)
{
TC_LOG_DEBUG("network", "WORLD: CMSG_REQUEST_RATED_BG_STATS");
WorldPacket data(SMSG_BATTLEFIELD_RATED_INFO, 29);
data << uint32(0); // Reward
data << uint8(3); // unk
data << uint32(0); // unk
data << uint32(0); // unk
data << _player->GetCurrencyWeekCap(CURRENCY_TYPE_CONQUEST_META_RBG, true);
data << uint32(0); // unk
data << uint32(0); // unk
data << _player->GetCurrency(CURRENCY_TYPE_CONQUEST_POINTS, true);
SendPacket(&data);
}