[7918] Improve portability in work with uint64 string format specifiers and in code...
[getmangos.git] / src / game / BattleGroundHandler.cpp
blob680d630ad89f3ea2e72689085fcd949f875a2897
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 (GUID: %u TypeId:%u)", GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(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);
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 (GUID: %u TypeId:%u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(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 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
106 if (!unit)
107 return;
109 if(!unit->isBattleMaster()) // it's not battlemaster
110 return;
112 // get bg instance or bg template if instance not found
113 BattleGround *bg = NULL;
114 if (instanceId)
115 bg = sBattleGroundMgr.GetBattleGroundThroughClientInstance(instanceId, bgTypeId);
117 if (!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))
119 sLog.outError("Battleground: no available bg / template found");
120 return;
123 // check queueing conditions
124 if (!joinAsGroup)
126 // check Deserter debuff
127 if (!_player->CanJoinToBattleground())
129 WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
130 data << uint32(0xFFFFFFFE);
131 _player->GetSession()->SendPacket(&data);
132 return;
134 // check if already in queue
135 if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
136 //player is already in this queue
137 return;
138 // check if has free queue slots
139 if (!_player->HasFreeBattleGroundQueueId())
140 return;
142 else
144 grp = _player->GetGroup();
145 // no group found, error
146 if (!grp)
147 return;
148 uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
149 isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam());
150 if (err != BG_JOIN_ERR_OK)
152 SendBattleGroundOrArenaJoinError(err);
153 return;
156 // if we're here, then the conditions to join a bg are met. We can proceed in joining.
158 // _player->GetGroup() was already checked, grp is already initialized
159 GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, isPremade, 0);
160 uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
161 if (joinAsGroup /* && _player->GetGroup()*/)
163 sLog.outDebug("Battleground: the following players are joining as group:");
164 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
166 Player *member = itr->getSource();
167 if(!member) continue; // this should never happen
169 uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue
171 // store entry point coords (same as leader entry point)
172 member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
174 WorldPacket data;
175 // send status packet (in queue)
176 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
177 member->GetSession()->SendPacket(&data);
178 sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
179 member->GetSession()->SendPacket(&data);
180 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
181 sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
183 sLog.outDebug("Battleground: group end");
185 else
187 // already checked if queueSlot is valid, now just get it
188 uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
189 // store entry point coords
190 _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
192 WorldPacket data;
193 // send status packet (in queue)
194 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
195 SendPacket(&data);
197 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
198 sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
200 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
201 if (!ginfo->IsInvitedToBGInstanceGUID)
202 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true);
205 void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ )
207 // empty opcode
208 sLog.outDebug("WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message");
210 BattleGround *bg = _player->GetBattleGround();
211 if(!bg) // can't be received if player not in battleground
212 return;
214 switch( bg->GetTypeID() )
216 case BATTLEGROUND_WS:
218 uint32 count1 = 0; //always constant zero?
219 uint32 count2 = 0; //count of next fields
221 Player *ali_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID());
222 if (ali_plr)
223 ++count2;
225 Player *horde_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID());
226 if (horde_plr)
227 ++count2;
229 WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2));
230 data << count1; // alliance flag holders count - obsolete, now always 0
231 /*for(uint8 i = 0; i < count1; ++i)
233 data << uint64(0); // guid
234 data << (float)0; // x
235 data << (float)0; // y
237 data << count2; // horde flag holders count - obsolete, now count of next fields
238 if (ali_plr)
240 data << (uint64)ali_plr->GetGUID();
241 data << (float)ali_plr->GetPositionX();
242 data << (float)ali_plr->GetPositionY();
244 if (horde_plr)
246 data << (uint64)horde_plr->GetGUID();
247 data << (float)horde_plr->GetPositionX();
248 data << (float)horde_plr->GetPositionY();
251 SendPacket(&data);
253 break;
254 case BATTLEGROUND_EY:
255 //TODO : fix me!
256 break;
257 case BATTLEGROUND_AB:
258 case BATTLEGROUND_AV:
260 //for other BG types - send default
261 WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4));
262 data << uint32(0);
263 data << uint32(0);
264 SendPacket(&data);
266 break;
267 default:
268 //maybe it is sent also in arena - do nothing
269 break;
273 void WorldSession::HandlePVPLogDataOpcode( WorldPacket & /*recv_data*/ )
275 sLog.outDebug( "WORLD: Recvd MSG_PVP_LOG_DATA Message");
277 BattleGround *bg = _player->GetBattleGround();
278 if (!bg)
279 return;
281 WorldPacket data;
282 sBattleGroundMgr.BuildPvpLogDataPacket(&data, bg);
283 SendPacket(&data);
285 sLog.outDebug( "WORLD: Sent MSG_PVP_LOG_DATA Message");
288 void WorldSession::HandleBattlefieldListOpcode( WorldPacket &recv_data )
290 CHECK_PACKET_SIZE(recv_data, 4);
292 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message");
294 uint32 bgTypeId;
295 recv_data >> bgTypeId; // id from DBC
297 BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
298 if (!bl)
300 sLog.outError("Battleground: invalid bgtype received.");
301 return;
304 WorldPacket data;
305 sBattleGroundMgr.BuildBattleGroundListPacket(&data, _player->GetGUID(), _player, BattleGroundTypeId(bgTypeId));
306 SendPacket( &data );
309 void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data )
311 CHECK_PACKET_SIZE(recv_data, 1+1+4+2+1);
313 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message");
315 uint8 type; // arenatype if arena
316 uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
317 uint32 instanceId;
318 uint32 bgTypeId_; // type id from dbc
319 uint16 unk; // 0x1F90 constant?
320 uint8 action; // enter battle 0x1, leave queue 0x0
322 recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action;
324 if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
326 sLog.outError("Battleground: invalid bgtype (%u) received.", bgTypeId_);
327 // update battleground slots for the player to fix his UI and sent data.
328 // this is a HACK, I don't know why the client starts sending invalid packets in the first place.
329 // it usually happens with extremely high latency (if debugging / stepping in the code for example)
330 if (_player->InBattleGroundQueue())
332 // update all queues, send invitation info if player is invited, queue info if queued
333 for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
335 BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
336 if (!bgQueueTypeId)
337 continue;
338 BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
339 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
340 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
341 // if the player is not in queue, continue or no group information - this should never happen
342 if (itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo)
343 continue;
345 BattleGround * bg = NULL;
346 // get possibly needed data from groupinfo
347 uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
348 uint8 status = 0;
350 if (!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
352 // not invited to bg, get template
353 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
354 status = STATUS_WAIT_QUEUE;
356 else
358 // get the bg we're invited to
359 bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
360 status = STATUS_WAIT_JOIN;
363 // if bg not found, then continue, don't invite if already in the instance
364 if (!bg || (_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID()))
365 continue;
367 // re - invite player with proper data
368 WorldPacket data;
369 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype);
370 SendPacket(&data);
373 return;
376 //get GroupQueueInfo from BattleGroundQueue
377 BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
378 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type);
379 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
380 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
381 if (itrPlayerStatus == qpMap.end())
383 sLog.outError("Battleground: itrplayerstatus not found.");
384 return;
387 instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
388 // if action == 1, then instanceId is required
389 if (!instanceId && action == 1)
391 sLog.outError("Battleground: instance not found.");
392 return;
395 BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId);
397 // bg template might and must be used in case of leaving queue, when instance is not created yet
398 if (!bg && action == 0)
399 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
400 if (!bg)
402 sLog.outError("Battleground: bg_template not found for type id %u.", bgTypeId);
403 return;
406 if (_player->InBattleGroundQueue())
408 //we must use temporary variables, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function!
409 uint32 team = itrPlayerStatus->second.GroupInfo->Team;
410 uint32 arenaType = itrPlayerStatus->second.GroupInfo->ArenaType;
411 uint32 isRated = itrPlayerStatus->second.GroupInfo->IsRated;
412 uint32 rating = itrPlayerStatus->second.GroupInfo->ArenaTeamRating;
413 uint32 opponentsRating = itrPlayerStatus->second.GroupInfo->OpponentsTeamRating;
415 //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
416 if (action == 1 && arenaType == 0)
418 //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
419 if (!_player->CanJoinToBattleground())
421 //send bg command result to show nice message
422 WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
423 data2 << uint32(0xFFFFFFFE);
424 _player->GetSession()->SendPacket(&data2);
425 action = 0;
426 sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
428 //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
429 if (_player->getLevel() > bg->GetMaxLevel())
431 sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
432 action = 0;
435 uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
436 WorldPacket data;
437 switch( action )
439 case 1: // port to battleground
440 if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
441 return; // cheating?
442 // resurrect the player
443 if (!_player->isAlive())
445 _player->ResurrectPlayer(1.0f);
446 _player->SpawnCorpseBones();
448 // stop taxi flight at port
449 if (_player->isInFlight())
451 _player->GetMotionMaster()->MovementExpired();
452 _player->m_taxi.ClearTaxiDestinations();
455 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType());
456 _player->GetSession()->SendPacket(&data);
457 // remove battleground queue status from BGmgr
458 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);
459 // this is still needed here if battleground "jumping" shouldn't add deserter debuff
460 // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new
461 if (BattleGround *currentBg = _player->GetBattleGround())
462 currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
464 // set the destination instance id
465 _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId);
466 // set the destination team
467 _player->SetBGTeam(team);
468 // bg->HandleBeforeTeleportToBattleGround(_player);
469 sBattleGroundMgr.SendToBattleGround(_player, instanceId, bgTypeId);
470 // add only in HandleMoveWorldPortAck()
471 // bg->AddPlayer(_player,team);
472 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);
473 break;
474 case 0: // leave queue
475 // if player leaves rated arena match before match start, it is counted as he played but he lost
476 if (isRated)
478 ArenaTeam * at = objmgr.GetArenaTeamById(team);
479 if (at)
481 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), opponentsRating);
482 at->MemberLost(_player, opponentsRating);
483 at->SaveToDB();
486 _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
487 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
488 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);
489 // player left queue, we should update it - do not update Arena Queue
490 if (!arenaType)
491 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenaType, isRated, rating);
492 SendPacket(&data);
493 sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId);
494 break;
495 default:
496 sLog.outError("Battleground port: unknown action %u", action);
497 break;
502 void WorldSession::HandleLeaveBattlefieldOpcode( WorldPacket & /*recv_data*/ )
504 //CHECK_PACKET_SIZE(recv_data, 1+1+4+2);
506 sLog.outDebug( "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message");
508 //uint8 unk1, unk2;
509 //uint32 bgTypeId; // id from DBC
510 //uint16 unk3;
512 //recv_data >> unk1 >> unk2 >> bgTypeId >> unk3; - no used currently
514 //if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating? but not important in this case
515 // return;
517 // not allow leave battleground in combat
518 if (_player->isInCombat())
519 if (BattleGround* bg = _player->GetBattleGround())
520 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
521 return;
523 _player->LeaveBattleground();
526 void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
528 // empty opcode
529 sLog.outDebug( "WORLD: Battleground status" );
531 WorldPacket data;
532 // we must update all queues here
533 BattleGround *bg = NULL;
534 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
536 BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
537 if (!bgQueueTypeId)
538 continue;
539 BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
540 uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId);
541 if (bgTypeId == _player->GetBattleGroundTypeId())
543 bg = _player->GetBattleGround();
544 //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
545 //so i must use bg pointer to get that information
546 if (bg && bg->GetArenaType() == arenaType)
548 // this line is checked, i only don't know if GetStartTime is changing itself after bg end!
549 // send status in BattleGround
550 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType);
551 SendPacket(&data);
552 continue;
555 //we are sending update to player about queue - he can be invited there!
556 //get GroupQueueInfo for queue status
557 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
558 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
559 if (itrPlayerStatus == qpMap.end())
560 continue;
561 if (itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
563 bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
564 if (!bg)
565 continue;
566 uint32 remainingTime = getMSTimeDiff(getMSTime(), itrPlayerStatus->second.GroupInfo->RemoveInviteTime);
567 // send status invited to BattleGround
568 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType);
569 SendPacket(&data);
571 else
573 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
574 if (!bg)
575 continue;
576 uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
577 // send status in BattleGround Queue
578 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(itrPlayerStatus->second.GroupInfo->JoinTime, getMSTime()), arenaType);
579 SendPacket(&data);
584 void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
586 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY");
588 CHECK_PACKET_SIZE(recv_data, 8);
590 BattleGround *bg = _player->GetBattleGround();
591 if (!bg)
592 return;
594 uint64 guid;
595 recv_data >> guid;
597 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
598 if (!unit)
599 return;
601 if(!unit->isSpiritService()) // it's not spirit service
602 return;
604 sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, guid);
607 void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data )
609 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE");
611 CHECK_PACKET_SIZE(recv_data, 8);
613 BattleGround *bg = _player->GetBattleGround();
614 if (!bg)
615 return;
617 uint64 guid;
618 recv_data >> guid;
620 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
621 if (!unit)
622 return;
624 if(!unit->isSpiritService()) // it's not spirit service
625 return;
627 bg->AddPlayerToResurrectQueue(guid, _player->GetGUID());
630 void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data )
632 CHECK_PACKET_SIZE(recv_data, 8+1+1+1);
634 sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
635 recv_data.hexlike();
637 // ignore if we already in BG or BG queue
638 if (_player->InBattleGround())
639 return;
641 uint64 guid; // arena Battlemaster guid
642 uint8 arenaslot; // 2v2, 3v3 or 5v5
643 uint8 asGroup; // asGroup
644 uint8 isRated; // isRated
645 Group * grp;
647 recv_data >> guid >> arenaslot >> asGroup >> isRated;
649 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
650 if (!unit)
651 return;
653 if(!unit->isBattleMaster()) // it's not battle master
654 return;
656 uint8 arenatype = 0;
657 uint32 arenaRating = 0;
659 switch(arenaslot)
661 case 0:
662 arenatype = ARENA_TYPE_2v2;
663 break;
664 case 1:
665 arenatype = ARENA_TYPE_3v3;
666 break;
667 case 2:
668 arenatype = ARENA_TYPE_5v5;
669 break;
670 default:
671 sLog.outError("Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot);
672 return;
675 //check existance
676 BattleGround* bg = NULL;
677 if (!(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)))
679 sLog.outError("Battleground: template bg (all arenas) not found");
680 return;
683 BattleGroundTypeId bgTypeId = bg->GetTypeID();
684 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype);
686 // check queueing conditions
687 if (!asGroup)
689 // check if already in queue
690 if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
691 //player is already in this queue
692 return;
693 // check if has free queue slots
694 if (!_player->HasFreeBattleGroundQueueId())
695 return;
697 else
699 grp = _player->GetGroup();
700 // no group found, error
701 if (!grp)
702 return;
703 uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot);
704 if (err != BG_JOIN_ERR_OK)
706 SendBattleGroundOrArenaJoinError(err);
707 return;
711 uint32 ateamId = 0;
713 if (isRated)
715 ateamId = _player->GetArenaTeamId(arenaslot);
716 // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
717 ArenaTeam * at = objmgr.GetArenaTeamById(ateamId);
718 if (!at)
720 _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
721 return;
723 // get the team rating for queueing
724 arenaRating = at->GetRating();
725 // the arenateam id must match for everyone in the group
726 // get the personal ratings for queueing
727 uint32 avg_pers_rating = 0;
728 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
730 Player *member = itr->getSource();
732 // calc avg personal rating
733 avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaslot*6) + 5);
736 if (arenatype)
737 avg_pers_rating /= arenatype;
739 // 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
740 if (avg_pers_rating + 150 < arenaRating)
741 arenaRating = avg_pers_rating;
744 GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId);
745 uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
746 if (asGroup)
748 sLog.outDebug("Battleground: arena join as group start");
749 if (isRated)
750 sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype);
751 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
753 Player *member = itr->getSource();
754 if(!member) continue;
756 uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue
758 // store entry point coords (same as leader entry point)
759 member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
761 WorldPacket data;
762 // send status packet (in queue)
763 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
764 member->GetSession()->SendPacket(&data);
765 sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
766 member->GetSession()->SendPacket(&data);
767 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
768 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());
770 sLog.outDebug("Battleground: arena join as group end");
771 if (isRated)
772 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true);
774 else
776 uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
778 // store entry point coords
779 _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
781 WorldPacket data;
782 // send status packet (in queue)
783 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
784 SendPacket(&data);
785 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
786 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());
788 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating);
791 void WorldSession::HandleReportPvPAFK( WorldPacket & recv_data )
793 CHECK_PACKET_SIZE(recv_data, 8);
795 uint64 playerGuid;
796 recv_data >> playerGuid;
797 Player *reportedPlayer = objmgr.GetPlayer(playerGuid);
799 if (!reportedPlayer)
801 sLog.outDebug("WorldSession::HandleReportPvPAFK: player not found");
802 return;
805 sLog.outDebug("WorldSession::HandleReportPvPAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName());
807 reportedPlayer->ReportedAfkBy(_player);
810 void WorldSession::SendBattleGroundOrArenaJoinError(uint8 err)
812 WorldPacket data;
813 int32 msg;
814 switch (err)
816 case BG_JOIN_ERR_OFFLINE_MEMBER:
817 msg = LANG_BG_GROUP_OFFLINE_MEMBER;
818 break;
819 case BG_JOIN_ERR_GROUP_TOO_MANY:
820 msg = LANG_BG_GROUP_TOO_LARGE;
821 break;
822 case BG_JOIN_ERR_MIXED_FACTION:
823 msg = LANG_BG_GROUP_MIXED_FACTION;
824 break;
825 case BG_JOIN_ERR_MIXED_LEVELS:
826 msg = LANG_BG_GROUP_MIXED_LEVELS;
827 break;
828 case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
829 msg = LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE;
830 break;
831 case BG_JOIN_ERR_GROUP_DESERTER:
832 msg = LANG_BG_GROUP_MEMBER_DESERTER;
833 break;
834 case BG_JOIN_ERR_ALL_QUEUES_USED:
835 msg = LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS;
836 break;
837 case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
838 case BG_JOIN_ERR_MIXED_ARENATEAM:
839 default:
840 return;
841 break;
843 ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(msg), NULL);
844 SendPacket(&data);
845 return;