Just a few renames.
[getmangos.git] / src / game / BattleGroundHandler.cpp
blob3bff36f188030da9829cbf9ba177b18ad3ed2c91
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "WorldPacket.h"
21 #include "Opcodes.h"
22 #include "Log.h"
23 #include "Player.h"
24 #include "ObjectMgr.h"
25 #include "WorldSession.h"
26 #include "ObjectAccessor.h"
27 #include "Object.h"
28 #include "Chat.h"
29 #include "BattleGroundMgr.h"
30 #include "BattleGroundWS.h"
31 #include "BattleGround.h"
32 #include "ArenaTeam.h"
33 #include "Language.h"
35 void WorldSession::HandleBattlemasterHelloOpcode( WorldPacket & recv_data )
37 CHECK_PACKET_SIZE(recv_data, 8);
39 uint64 guid;
40 recv_data >> guid;
41 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from: " I64FMT, guid);
43 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
44 if (!unit)
45 return;
47 if(!unit->isBattleMaster()) // it's not battlemaster
48 return;
50 // Stop the npc if moving
51 unit->StopMoving();
53 BattleGroundTypeId bgTypeId = sBattleGroundMgr.GetBattleMasterBG(unit->GetEntry());
55 if (!_player->GetBGAccessByLevel(bgTypeId))
57 // temp, must be gossip message...
58 SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR);
59 return;
62 SendBattlegGroundList(guid, bgTypeId);
65 void WorldSession::SendBattlegGroundList( uint64 guid, BattleGroundTypeId bgTypeId )
67 WorldPacket data;
68 sBattleGroundMgr.BuildBattleGroundListPacket(&data, guid, _player, bgTypeId, 0);
69 SendPacket( &data );
72 void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket & recv_data )
74 CHECK_PACKET_SIZE(recv_data, 8+4+4+1);
76 uint64 guid;
77 uint32 bgTypeId_;
78 uint32 instanceId;
79 uint8 joinAsGroup;
80 bool isPremade = false;
81 Group * grp;
83 recv_data >> guid; // battlemaster guid
84 recv_data >> bgTypeId_; // battleground type id (DBC id)
85 recv_data >> instanceId; // instance id, 0 if First Available selected
86 recv_data >> joinAsGroup; // join as group
88 if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
90 sLog.outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u",bgTypeId_,_player->GetGUIDLow());
91 return;
94 BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
96 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT, guid);
98 // can do this, since it's battleground, not arena
99 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, 0);
101 // ignore if player is already in BG
102 if (_player->InBattleGround())
103 return;
105 // get bg instance or bg template if instance not found
106 BattleGround *bg = NULL;
107 if (instanceId)
108 bg = sBattleGroundMgr.GetBattleGroundThroughClientInstance(instanceId, bgTypeId);
110 if (!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))
112 sLog.outError("Battleground: no available bg / template found");
113 return;
116 // check queueing conditions
117 if (!joinAsGroup)
119 // check Deserter debuff
120 if (!_player->CanJoinToBattleground())
122 WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
123 data << uint32(0xFFFFFFFE);
124 _player->GetSession()->SendPacket(&data);
125 return;
127 // check if already in queue
128 if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
129 //player is already in this queue
130 return;
131 // check if has free queue slots
132 if (!_player->HasFreeBattleGroundQueueId())
133 return;
135 else
137 grp = _player->GetGroup();
138 // no group found, error
139 if (!grp)
140 return;
141 uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
142 isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam());
143 if (err != BG_JOIN_ERR_OK)
145 SendBattleGroundOrArenaJoinError(err);
146 return;
149 // if we're here, then the conditions to join a bg are met. We can proceed in joining.
151 // _player->GetGroup() was already checked, grp is already initialized
152 GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, isPremade, 0);
153 uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
154 if (joinAsGroup /* && _player->GetGroup()*/)
156 sLog.outDebug("Battleground: the following players are joining as group:");
157 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
159 Player *member = itr->getSource();
160 if(!member) continue; // this should never happen
162 uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue
164 // store entry point coords (same as leader entry point)
165 member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
167 WorldPacket data;
168 // send status packet (in queue)
169 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
170 member->GetSession()->SendPacket(&data);
171 sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
172 member->GetSession()->SendPacket(&data);
173 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
174 sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
176 sLog.outDebug("Battleground: group end");
178 else
180 // already checked if queueSlot is valid, now just get it
181 uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
182 // store entry point coords
183 _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
185 WorldPacket data;
186 // send status packet (in queue)
187 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
188 SendPacket(&data);
190 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
191 sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
193 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
194 if (!ginfo->IsInvitedToBGInstanceGUID)
195 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true);
198 void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ )
200 // empty opcode
201 sLog.outDebug("WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message");
203 BattleGround *bg = _player->GetBattleGround();
204 if(!bg) // can't be received if player not in battleground
205 return;
207 switch( bg->GetTypeID() )
209 case BATTLEGROUND_WS:
211 uint32 count1 = 0; //always constant zero?
212 uint32 count2 = 0; //count of next fields
214 Player *ali_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID());
215 if (ali_plr)
216 ++count2;
218 Player *horde_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID());
219 if (horde_plr)
220 ++count2;
222 WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2));
223 data << count1; // alliance flag holders count - obsolete, now always 0
224 /*for(uint8 i = 0; i < count1; ++i)
226 data << uint64(0); // guid
227 data << (float)0; // x
228 data << (float)0; // y
230 data << count2; // horde flag holders count - obsolete, now count of next fields
231 if (ali_plr)
233 data << (uint64)ali_plr->GetGUID();
234 data << (float)ali_plr->GetPositionX();
235 data << (float)ali_plr->GetPositionY();
237 if (horde_plr)
239 data << (uint64)horde_plr->GetGUID();
240 data << (float)horde_plr->GetPositionX();
241 data << (float)horde_plr->GetPositionY();
244 SendPacket(&data);
246 break;
247 case BATTLEGROUND_EY:
248 //TODO : fix me!
249 break;
250 case BATTLEGROUND_AB:
251 case BATTLEGROUND_AV:
253 //for other BG types - send default
254 WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4));
255 data << uint32(0);
256 data << uint32(0);
257 SendPacket(&data);
259 break;
260 default:
261 //maybe it is sent also in arena - do nothing
262 break;
266 void WorldSession::HandlePVPLogDataOpcode( WorldPacket & /*recv_data*/ )
268 sLog.outDebug( "WORLD: Recvd MSG_PVP_LOG_DATA Message");
270 BattleGround *bg = _player->GetBattleGround();
271 if (!bg)
272 return;
274 WorldPacket data;
275 sBattleGroundMgr.BuildPvpLogDataPacket(&data, bg);
276 SendPacket(&data);
278 sLog.outDebug( "WORLD: Sent MSG_PVP_LOG_DATA Message");
281 void WorldSession::HandleBattlefieldListOpcode( WorldPacket &recv_data )
283 CHECK_PACKET_SIZE(recv_data, 4 + 1);
285 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message");
287 uint32 bgTypeId;
288 recv_data >> bgTypeId; // id from DBC
290 uint8 fromWhere;
291 recv_data >> fromWhere; // 0 - battlemaster, 1 - UI
293 BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
294 if (!bl)
296 sLog.outError("Battleground: invalid bgtype received.");
297 return;
300 WorldPacket data;
301 sBattleGroundMgr.BuildBattleGroundListPacket(&data, 0, _player, BattleGroundTypeId(bgTypeId), fromWhere);
302 SendPacket( &data );
305 void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data )
307 CHECK_PACKET_SIZE(recv_data, 1+1+4+2+1);
309 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message");
311 uint8 type; // arenatype if arena
312 uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
313 uint32 instanceId;
314 uint32 bgTypeId_; // type id from dbc
315 uint16 unk; // 0x1F90 constant?
316 uint8 action; // enter battle 0x1, leave queue 0x0
318 recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action;
320 if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
322 sLog.outError("Battleground: invalid bgtype (%u) received.", bgTypeId_);
323 // update battleground slots for the player to fix his UI and sent data.
324 // this is a HACK, I don't know why the client starts sending invalid packets in the first place.
325 // it usually happens with extremely high latency (if debugging / stepping in the code for example)
326 if (_player->InBattleGroundQueue())
328 // update all queues, send invitation info if player is invited, queue info if queued
329 for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
331 BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
332 if (!bgQueueTypeId)
333 continue;
334 BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
335 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
336 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
337 // if the player is not in queue, continue or no group information - this should never happen
338 if (itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo)
339 continue;
341 BattleGround * bg = NULL;
342 // get possibly needed data from groupinfo
343 uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
344 uint8 status = 0;
346 if (!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
348 // not invited to bg, get template
349 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
350 status = STATUS_WAIT_QUEUE;
352 else
354 // get the bg we're invited to
355 bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
356 status = STATUS_WAIT_JOIN;
359 // if bg not found, then continue, don't invite if already in the instance
360 if (!bg || (_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID()))
361 continue;
363 // re - invite player with proper data
364 WorldPacket data;
365 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype);
366 SendPacket(&data);
369 return;
372 //get GroupQueueInfo from BattleGroundQueue
373 BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
374 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type);
375 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
376 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
377 if (itrPlayerStatus == qpMap.end())
379 sLog.outError("Battleground: itrplayerstatus not found.");
380 return;
383 instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
384 // if action == 1, then instanceId is required
385 if (!instanceId && action == 1)
387 sLog.outError("Battleground: instance not found.");
388 return;
391 BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId);
393 // bg template might and must be used in case of leaving queue, when instance is not created yet
394 if (!bg && action == 0)
395 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
396 if (!bg)
398 sLog.outError("Battleground: bg_template not found for type id %u.", bgTypeId);
399 return;
402 if (_player->InBattleGroundQueue())
404 //we must use temporary variables, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function!
405 uint32 team = itrPlayerStatus->second.GroupInfo->Team;
406 uint32 arenaType = itrPlayerStatus->second.GroupInfo->ArenaType;
407 uint32 isRated = itrPlayerStatus->second.GroupInfo->IsRated;
408 uint32 rating = itrPlayerStatus->second.GroupInfo->ArenaTeamRating;
409 uint32 opponentsRating = itrPlayerStatus->second.GroupInfo->OpponentsTeamRating;
411 //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
412 if (action == 1 && arenaType == 0)
414 //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
415 if (!_player->CanJoinToBattleground())
417 //send bg command result to show nice message
418 WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
419 data2 << uint32(0xFFFFFFFE);
420 _player->GetSession()->SendPacket(&data2);
421 action = 0;
422 sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
424 //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
425 if (_player->getLevel() > bg->GetMaxLevel())
427 sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
428 action = 0;
431 uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
432 WorldPacket data;
433 switch( action )
435 case 1: // port to battleground
436 if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
437 return; // cheating?
438 // resurrect the player
439 if (!_player->isAlive())
441 _player->ResurrectPlayer(1.0f);
442 _player->SpawnCorpseBones();
444 // stop taxi flight at port
445 if (_player->isInFlight())
447 _player->GetMotionMaster()->MovementExpired();
448 _player->m_taxi.ClearTaxiDestinations();
451 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType());
452 _player->GetSession()->SendPacket(&data);
453 // remove battleground queue status from BGmgr
454 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);
455 // this is still needed here if battleground "jumping" shouldn't add deserter debuff
456 // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new
457 if (BattleGround *currentBg = _player->GetBattleGround())
458 currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
460 // set the destination instance id
461 _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId);
462 // set the destination team
463 _player->SetBGTeam(team);
464 // bg->HandleBeforeTeleportToBattleGround(_player);
465 sBattleGroundMgr.SendToBattleGround(_player, instanceId, bgTypeId);
466 // add only in HandleMoveWorldPortAck()
467 // bg->AddPlayer(_player,team);
468 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);
469 break;
470 case 0: // leave queue
471 // if player leaves rated arena match before match start, it is counted as he played but he lost
472 if (isRated)
474 ArenaTeam * at = objmgr.GetArenaTeamById(team);
475 if (at)
477 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), opponentsRating);
478 at->MemberLost(_player, opponentsRating);
479 at->SaveToDB();
482 _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
483 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
484 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);
485 // player left queue, we should update it - do not update Arena Queue
486 if (!arenaType)
487 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenaType, isRated, rating);
488 SendPacket(&data);
489 sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId);
490 break;
491 default:
492 sLog.outError("Battleground port: unknown action %u", action);
493 break;
498 void WorldSession::HandleLeaveBattlefieldOpcode( WorldPacket & /*recv_data*/ )
500 //CHECK_PACKET_SIZE(recv_data, 1+1+4+2);
502 sLog.outDebug( "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message");
504 //uint8 unk1, unk2;
505 //uint32 bgTypeId; // id from DBC
506 //uint16 unk3;
508 //recv_data >> unk1 >> unk2 >> bgTypeId >> unk3; - no used currently
510 //if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating? but not important in this case
511 // return;
513 // not allow leave battleground in combat
514 if (_player->isInCombat())
515 if (BattleGround* bg = _player->GetBattleGround())
516 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
517 return;
519 _player->LeaveBattleground();
522 void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
524 // empty opcode
525 sLog.outDebug( "WORLD: Battleground status" );
527 WorldPacket data;
528 // we must update all queues here
529 BattleGround *bg = NULL;
530 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
532 BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
533 if (!bgQueueTypeId)
534 continue;
535 BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
536 uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId);
537 if (bgTypeId == _player->GetBattleGroundTypeId())
539 bg = _player->GetBattleGround();
540 //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
541 //so i must use bg pointer to get that information
542 if (bg && bg->GetArenaType() == arenaType)
544 // this line is checked, i only don't know if GetStartTime is changing itself after bg end!
545 // send status in BattleGround
546 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType);
547 SendPacket(&data);
548 continue;
551 //we are sending update to player about queue - he can be invited there!
552 //get GroupQueueInfo for queue status
553 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
554 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
555 if (itrPlayerStatus == qpMap.end())
556 continue;
557 if (itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
559 bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
560 if (!bg)
561 continue;
562 uint32 remainingTime = getMSTimeDiff(getMSTime(), itrPlayerStatus->second.GroupInfo->RemoveInviteTime);
563 // send status invited to BattleGround
564 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType);
565 SendPacket(&data);
567 else
569 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
570 if (!bg)
571 continue;
572 uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
573 // send status in BattleGround Queue
574 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(itrPlayerStatus->second.GroupInfo->JoinTime, getMSTime()), arenaType);
575 SendPacket(&data);
580 void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
582 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY");
584 CHECK_PACKET_SIZE(recv_data, 8);
586 BattleGround *bg = _player->GetBattleGround();
587 if (!bg)
588 return;
590 uint64 guid;
591 recv_data >> guid;
593 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
594 if (!unit)
595 return;
597 if(!unit->isSpiritService()) // it's not spirit service
598 return;
600 sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, guid);
603 void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data )
605 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE");
607 CHECK_PACKET_SIZE(recv_data, 8);
609 BattleGround *bg = _player->GetBattleGround();
610 if (!bg)
611 return;
613 uint64 guid;
614 recv_data >> guid;
616 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
617 if (!unit)
618 return;
620 if(!unit->isSpiritService()) // it's not spirit service
621 return;
623 bg->AddPlayerToResurrectQueue(guid, _player->GetGUID());
626 void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data )
628 CHECK_PACKET_SIZE(recv_data, 8+1+1+1);
630 sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
631 recv_data.hexlike();
633 // ignore if we already in BG or BG queue
634 if (_player->InBattleGround())
635 return;
637 uint64 guid; // arena Battlemaster guid
638 uint8 arenaslot; // 2v2, 3v3 or 5v5
639 uint8 asGroup; // asGroup
640 uint8 isRated; // isRated
641 Group * grp;
643 recv_data >> guid >> arenaslot >> asGroup >> isRated;
645 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
646 if (!unit)
647 return;
649 if(!unit->isBattleMaster()) // it's not battle master
650 return;
652 uint8 arenatype = 0;
653 uint32 arenaRating = 0;
655 switch(arenaslot)
657 case 0:
658 arenatype = ARENA_TYPE_2v2;
659 break;
660 case 1:
661 arenatype = ARENA_TYPE_3v3;
662 break;
663 case 2:
664 arenatype = ARENA_TYPE_5v5;
665 break;
666 default:
667 sLog.outError("Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot);
668 return;
671 //check existance
672 BattleGround* bg = NULL;
673 if (!(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)))
675 sLog.outError("Battleground: template bg (all arenas) not found");
676 return;
679 BattleGroundTypeId bgTypeId = bg->GetTypeID();
680 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype);
682 // check queueing conditions
683 if (!asGroup)
685 // check if already in queue
686 if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
687 //player is already in this queue
688 return;
689 // check if has free queue slots
690 if (!_player->HasFreeBattleGroundQueueId())
691 return;
693 else
695 grp = _player->GetGroup();
696 // no group found, error
697 if (!grp)
698 return;
699 uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot);
700 if (err != BG_JOIN_ERR_OK)
702 SendBattleGroundOrArenaJoinError(err);
703 return;
707 uint32 ateamId = 0;
709 if (isRated)
711 ateamId = _player->GetArenaTeamId(arenaslot);
712 // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
713 ArenaTeam * at = objmgr.GetArenaTeamById(ateamId);
714 if (!at)
716 _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
717 return;
719 // get the team rating for queueing
720 arenaRating = at->GetRating();
721 // the arenateam id must match for everyone in the group
722 // get the personal ratings for queueing
723 uint32 avg_pers_rating = 0;
724 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
726 Player *member = itr->getSource();
728 // calc avg personal rating
729 avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaslot*6) + 5);
732 if (arenatype)
733 avg_pers_rating /= arenatype;
735 // if avg personal rating is more than 150 points below the teams rating, the team will be queued against an opponent matching or similar to the average personal rating
736 if (avg_pers_rating + 150 < arenaRating)
737 arenaRating = avg_pers_rating;
740 GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId);
741 uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
742 if (asGroup)
744 sLog.outDebug("Battleground: arena join as group start");
745 if (isRated)
746 sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype);
747 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
749 Player *member = itr->getSource();
750 if(!member) continue;
752 uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue
754 // store entry point coords (same as leader entry point)
755 member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
757 WorldPacket data;
758 // send status packet (in queue)
759 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
760 member->GetSession()->SendPacket(&data);
761 sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
762 member->GetSession()->SendPacket(&data);
763 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
764 sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
766 sLog.outDebug("Battleground: arena join as group end");
767 if (isRated)
768 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true);
770 else
772 uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
774 // store entry point coords
775 _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
777 WorldPacket data;
778 // send status packet (in queue)
779 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
780 SendPacket(&data);
781 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
782 sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
784 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating);
787 void WorldSession::HandleReportPvPAFK( WorldPacket & recv_data )
789 CHECK_PACKET_SIZE(recv_data, 8);
791 uint64 playerGuid;
792 recv_data >> playerGuid;
793 Player *reportedPlayer = objmgr.GetPlayer(playerGuid);
795 if (!reportedPlayer)
797 sLog.outDebug("WorldSession::HandleReportPvPAFK: player not found");
798 return;
801 sLog.outDebug("WorldSession::HandleReportPvPAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName());
803 reportedPlayer->ReportedAfkBy(_player);
806 void WorldSession::SendBattleGroundOrArenaJoinError(uint8 err)
808 WorldPacket data;
809 int32 msg;
810 switch (err)
812 case BG_JOIN_ERR_OFFLINE_MEMBER:
813 msg = LANG_BG_GROUP_OFFLINE_MEMBER;
814 break;
815 case BG_JOIN_ERR_GROUP_TOO_MANY:
816 msg = LANG_BG_GROUP_TOO_LARGE;
817 break;
818 case BG_JOIN_ERR_MIXED_FACTION:
819 msg = LANG_BG_GROUP_MIXED_FACTION;
820 break;
821 case BG_JOIN_ERR_MIXED_LEVELS:
822 msg = LANG_BG_GROUP_MIXED_LEVELS;
823 break;
824 case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
825 msg = LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE;
826 break;
827 case BG_JOIN_ERR_GROUP_DESERTER:
828 msg = LANG_BG_GROUP_MEMBER_DESERTER;
829 break;
830 case BG_JOIN_ERR_ALL_QUEUES_USED:
831 msg = LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS;
832 break;
833 case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
834 case BG_JOIN_ERR_MIXED_ARENATEAM:
835 default:
836 return;
837 break;
839 ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(msg), NULL);
840 SendPacket(&data);
841 return;