[8449] Deprecate healing/damage item mods and merge internal data in to spell power.
[getmangos.git] / src / game / BattleGroundHandler.cpp
blob9a080c53fce6fa344f9705f40da9d6a38973e8e1
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 uint64 guid;
38 recv_data >> guid;
39 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid)));
41 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
42 if (!unit)
43 return;
45 if(!unit->isBattleMaster()) // it's not battlemaster
46 return;
48 // Stop the npc if moving
49 unit->StopMoving();
51 BattleGroundTypeId bgTypeId = sBattleGroundMgr.GetBattleMasterBG(unit->GetEntry());
53 if (!_player->GetBGAccessByLevel(bgTypeId))
55 // temp, must be gossip message...
56 SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR);
57 return;
60 SendBattlegGroundList(guid, bgTypeId);
63 void WorldSession::SendBattlegGroundList( uint64 guid, BattleGroundTypeId bgTypeId )
65 WorldPacket data;
66 sBattleGroundMgr.BuildBattleGroundListPacket(&data, guid, _player, bgTypeId, 0);
67 SendPacket( &data );
70 void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket & recv_data )
72 uint64 guid;
73 uint32 bgTypeId_;
74 uint32 instanceId;
75 uint8 joinAsGroup;
76 bool isPremade = false;
77 Group * grp;
79 recv_data >> guid; // battlemaster guid
80 recv_data >> bgTypeId_; // battleground type id (DBC id)
81 recv_data >> instanceId; // instance id, 0 if First Available selected
82 recv_data >> joinAsGroup; // join as group
84 if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
86 sLog.outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u",bgTypeId_,_player->GetGUIDLow());
87 return;
90 BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
92 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid)));
94 // can do this, since it's battleground, not arena
95 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, 0);
97 // ignore if player is already in BG
98 if (_player->InBattleGround())
99 return;
101 // get bg instance or bg template if instance not found
102 BattleGround *bg = NULL;
103 if (instanceId)
104 bg = sBattleGroundMgr.GetBattleGroundThroughClientInstance(instanceId, bgTypeId);
106 if (!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))
108 sLog.outError("Battleground: no available bg / template found");
109 return;
112 // check queueing conditions
113 if (!joinAsGroup)
115 // check Deserter debuff
116 if (!_player->CanJoinToBattleground())
118 WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
119 data << uint32(0xFFFFFFFE);
120 _player->GetSession()->SendPacket(&data);
121 return;
123 // check if already in queue
124 if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
125 //player is already in this queue
126 return;
127 // check if has free queue slots
128 if (!_player->HasFreeBattleGroundQueueId())
129 return;
131 else
133 grp = _player->GetGroup();
134 // no group found, error
135 if (!grp)
136 return;
137 uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
138 isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam());
139 if (err != BG_JOIN_ERR_OK)
141 SendBattleGroundOrArenaJoinError(err);
142 return;
145 // if we're here, then the conditions to join a bg are met. We can proceed in joining.
147 // _player->GetGroup() was already checked, grp is already initialized
148 GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, isPremade, 0);
149 uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
150 if (joinAsGroup /* && _player->GetGroup()*/)
152 sLog.outDebug("Battleground: the following players are joining as group:");
153 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
155 Player *member = itr->getSource();
156 if(!member) continue; // this should never happen
158 uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue
160 WorldPacket data;
161 // send status packet (in queue)
162 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
163 member->GetSession()->SendPacket(&data);
164 sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
165 member->GetSession()->SendPacket(&data);
166 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
167 sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
169 sLog.outDebug("Battleground: group end");
171 else
173 // already checked if queueSlot is valid, now just get it
174 uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
176 WorldPacket data;
177 // send status packet (in queue)
178 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
179 SendPacket(&data);
181 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
182 sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
184 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
185 if (!ginfo->IsInvitedToBGInstanceGUID)
186 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true);
189 void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ )
191 // empty opcode
192 sLog.outDebug("WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message");
194 BattleGround *bg = _player->GetBattleGround();
195 if(!bg) // can't be received if player not in battleground
196 return;
198 switch( bg->GetTypeID() )
200 case BATTLEGROUND_WS:
202 uint32 count1 = 0; //always constant zero?
203 uint32 count2 = 0; //count of next fields
205 Player *ali_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID());
206 if (ali_plr)
207 ++count2;
209 Player *horde_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID());
210 if (horde_plr)
211 ++count2;
213 WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2));
214 data << count1; // alliance flag holders count - obsolete, now always 0
215 /*for(uint8 i = 0; i < count1; ++i)
217 data << uint64(0); // guid
218 data << (float)0; // x
219 data << (float)0; // y
221 data << count2; // horde flag holders count - obsolete, now count of next fields
222 if (ali_plr)
224 data << (uint64)ali_plr->GetGUID();
225 data << (float)ali_plr->GetPositionX();
226 data << (float)ali_plr->GetPositionY();
228 if (horde_plr)
230 data << (uint64)horde_plr->GetGUID();
231 data << (float)horde_plr->GetPositionX();
232 data << (float)horde_plr->GetPositionY();
235 SendPacket(&data);
237 break;
238 case BATTLEGROUND_EY:
239 //TODO : fix me!
240 break;
241 case BATTLEGROUND_AB:
242 case BATTLEGROUND_AV:
244 //for other BG types - send default
245 WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4));
246 data << uint32(0);
247 data << uint32(0);
248 SendPacket(&data);
250 break;
251 default:
252 //maybe it is sent also in arena - do nothing
253 break;
257 void WorldSession::HandlePVPLogDataOpcode( WorldPacket & /*recv_data*/ )
259 sLog.outDebug( "WORLD: Recvd MSG_PVP_LOG_DATA Message");
261 BattleGround *bg = _player->GetBattleGround();
262 if (!bg)
263 return;
265 WorldPacket data;
266 sBattleGroundMgr.BuildPvpLogDataPacket(&data, bg);
267 SendPacket(&data);
269 sLog.outDebug( "WORLD: Sent MSG_PVP_LOG_DATA Message");
272 void WorldSession::HandleBattlefieldListOpcode( WorldPacket &recv_data )
274 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message");
276 uint32 bgTypeId;
277 recv_data >> bgTypeId; // id from DBC
279 uint8 fromWhere;
280 recv_data >> fromWhere; // 0 - battlemaster, 1 - UI
282 BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
283 if (!bl)
285 sLog.outError("Battleground: invalid bgtype received.");
286 return;
289 WorldPacket data;
290 sBattleGroundMgr.BuildBattleGroundListPacket(&data, 0, _player, BattleGroundTypeId(bgTypeId), fromWhere);
291 SendPacket( &data );
294 void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data )
296 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message");
298 uint8 type; // arenatype if arena
299 uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
300 uint32 instanceId;
301 uint32 bgTypeId_; // type id from dbc
302 uint16 unk; // 0x1F90 constant?
303 uint8 action; // enter battle 0x1, leave queue 0x0
305 recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action;
307 if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
309 sLog.outError("Battleground: invalid bgtype (%u) received.", bgTypeId_);
310 // update battleground slots for the player to fix his UI and sent data.
311 // this is a HACK, I don't know why the client starts sending invalid packets in the first place.
312 // it usually happens with extremely high latency (if debugging / stepping in the code for example)
313 if (_player->InBattleGroundQueue())
315 // update all queues, send invitation info if player is invited, queue info if queued
316 for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
318 BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
319 if (!bgQueueTypeId)
320 continue;
321 BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
322 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
323 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
324 // if the player is not in queue, continue or no group information - this should never happen
325 if (itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo)
326 continue;
328 BattleGround * bg = NULL;
329 // get possibly needed data from groupinfo
330 uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
331 uint8 status = 0;
333 if (!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
335 // not invited to bg, get template
336 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
337 status = STATUS_WAIT_QUEUE;
339 else
341 // get the bg we're invited to
342 bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
343 status = STATUS_WAIT_JOIN;
346 // if bg not found, then continue, don't invite if already in the instance
347 if (!bg || (_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID()))
348 continue;
350 // re - invite player with proper data
351 WorldPacket data;
352 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype);
353 SendPacket(&data);
356 return;
359 //get GroupQueueInfo from BattleGroundQueue
360 BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
361 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type);
362 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
363 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
364 if (itrPlayerStatus == qpMap.end())
366 sLog.outError("Battleground: itrplayerstatus not found.");
367 return;
370 instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
371 // if action == 1, then instanceId is required
372 if (!instanceId && action == 1)
374 sLog.outError("Battleground: instance not found.");
375 return;
378 BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId);
380 // bg template might and must be used in case of leaving queue, when instance is not created yet
381 if (!bg && action == 0)
382 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
383 if (!bg)
385 sLog.outError("Battleground: bg_template not found for type id %u.", bgTypeId);
386 return;
389 if (_player->InBattleGroundQueue())
391 //we must use temporary variables, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function!
392 uint32 team = itrPlayerStatus->second.GroupInfo->Team;
393 uint32 arenaType = itrPlayerStatus->second.GroupInfo->ArenaType;
394 uint32 isRated = itrPlayerStatus->second.GroupInfo->IsRated;
395 uint32 rating = itrPlayerStatus->second.GroupInfo->ArenaTeamRating;
396 uint32 opponentsRating = itrPlayerStatus->second.GroupInfo->OpponentsTeamRating;
398 //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
399 if (action == 1 && arenaType == 0)
401 //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
402 if (!_player->CanJoinToBattleground())
404 //send bg command result to show nice message
405 WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
406 data2 << uint32(0xFFFFFFFE);
407 _player->GetSession()->SendPacket(&data2);
408 action = 0;
409 sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
411 //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
412 if (_player->getLevel() > bg->GetMaxLevel())
414 sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
415 action = 0;
418 uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
419 WorldPacket data;
420 switch( action )
422 case 1: // port to battleground
423 if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
424 return; // cheating?
426 _player->SetBattleGroundEntryPoint();
428 // resurrect the player
429 if (!_player->isAlive())
431 _player->ResurrectPlayer(1.0f);
432 _player->SpawnCorpseBones();
434 // stop taxi flight at port
435 if (_player->isInFlight())
437 _player->GetMotionMaster()->MovementExpired();
438 _player->m_taxi.ClearTaxiDestinations();
441 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType());
442 _player->GetSession()->SendPacket(&data);
443 // remove battleground queue status from BGmgr
444 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);
445 // this is still needed here if battleground "jumping" shouldn't add deserter debuff
446 // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new
447 if (BattleGround *currentBg = _player->GetBattleGround())
448 currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
450 // set the destination instance id
451 _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId);
452 // set the destination team
453 _player->SetBGTeam(team);
454 // bg->HandleBeforeTeleportToBattleGround(_player);
455 sBattleGroundMgr.SendToBattleGround(_player, instanceId, bgTypeId);
456 // add only in HandleMoveWorldPortAck()
457 // bg->AddPlayer(_player,team);
458 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);
459 break;
460 case 0: // leave queue
461 // if player leaves rated arena match before match start, it is counted as he played but he lost
462 if (isRated)
464 ArenaTeam * at = objmgr.GetArenaTeamById(team);
465 if (at)
467 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), opponentsRating);
468 at->MemberLost(_player, opponentsRating);
469 at->SaveToDB();
472 _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
473 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
474 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);
475 // player left queue, we should update it - do not update Arena Queue
476 if (!arenaType)
477 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenaType, isRated, rating);
478 SendPacket(&data);
479 sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId);
480 break;
481 default:
482 sLog.outError("Battleground port: unknown action %u", action);
483 break;
488 void WorldSession::HandleLeaveBattlefieldOpcode( WorldPacket & /*recv_data*/ )
490 sLog.outDebug( "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message");
492 //uint8 unk1, unk2;
493 //uint32 bgTypeId; // id from DBC
494 //uint16 unk3;
496 //recv_data >> unk1 >> unk2 >> bgTypeId >> unk3; - no used currently
498 //if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating? but not important in this case
499 // return;
501 // not allow leave battleground in combat
502 if (_player->isInCombat())
503 if (BattleGround* bg = _player->GetBattleGround())
504 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
505 return;
507 _player->LeaveBattleground();
510 void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
512 // empty opcode
513 sLog.outDebug( "WORLD: Battleground status" );
515 WorldPacket data;
516 // we must update all queues here
517 BattleGround *bg = NULL;
518 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
520 BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
521 if (!bgQueueTypeId)
522 continue;
523 BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
524 uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId);
525 if (bgTypeId == _player->GetBattleGroundTypeId())
527 bg = _player->GetBattleGround();
528 //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
529 //so i must use bg pointer to get that information
530 if (bg && bg->GetArenaType() == arenaType)
532 // this line is checked, i only don't know if GetStartTime is changing itself after bg end!
533 // send status in BattleGround
534 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType);
535 SendPacket(&data);
536 continue;
539 //we are sending update to player about queue - he can be invited there!
540 //get GroupQueueInfo for queue status
541 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
542 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
543 if (itrPlayerStatus == qpMap.end())
544 continue;
545 if (itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
547 bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
548 if (!bg)
549 continue;
550 uint32 remainingTime = getMSTimeDiff(getMSTime(), itrPlayerStatus->second.GroupInfo->RemoveInviteTime);
551 // send status invited to BattleGround
552 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType);
553 SendPacket(&data);
555 else
557 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
558 if (!bg)
559 continue;
560 uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
561 // send status in BattleGround Queue
562 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(itrPlayerStatus->second.GroupInfo->JoinTime, getMSTime()), arenaType);
563 SendPacket(&data);
568 void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
570 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY");
572 BattleGround *bg = _player->GetBattleGround();
573 if (!bg)
574 return;
576 uint64 guid;
577 recv_data >> guid;
579 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
580 if (!unit)
581 return;
583 if(!unit->isSpiritService()) // it's not spirit service
584 return;
586 sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, guid);
589 void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data )
591 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE");
593 BattleGround *bg = _player->GetBattleGround();
594 if (!bg)
595 return;
597 uint64 guid;
598 recv_data >> guid;
600 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
601 if (!unit)
602 return;
604 if(!unit->isSpiritService()) // it's not spirit service
605 return;
607 bg->AddPlayerToResurrectQueue(guid, _player->GetGUID());
610 void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data )
612 sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
613 //recv_data.hexlike();
615 uint64 guid; // arena Battlemaster guid
616 uint8 arenaslot; // 2v2, 3v3 or 5v5
617 uint8 asGroup; // asGroup
618 uint8 isRated; // isRated
619 Group * grp;
621 recv_data >> guid >> arenaslot >> asGroup >> isRated;
623 // ignore if we already in BG or BG queue
624 if (_player->InBattleGround())
625 return;
627 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
628 if (!unit)
629 return;
631 if(!unit->isBattleMaster()) // it's not battle master
632 return;
634 uint8 arenatype = 0;
635 uint32 arenaRating = 0;
637 switch(arenaslot)
639 case 0:
640 arenatype = ARENA_TYPE_2v2;
641 break;
642 case 1:
643 arenatype = ARENA_TYPE_3v3;
644 break;
645 case 2:
646 arenatype = ARENA_TYPE_5v5;
647 break;
648 default:
649 sLog.outError("Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot);
650 return;
653 //check existance
654 BattleGround* bg = NULL;
655 if (!(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)))
657 sLog.outError("Battleground: template bg (all arenas) not found");
658 return;
661 BattleGroundTypeId bgTypeId = bg->GetTypeID();
662 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype);
664 // check queueing conditions
665 if (!asGroup)
667 // check if already in queue
668 if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
669 //player is already in this queue
670 return;
671 // check if has free queue slots
672 if (!_player->HasFreeBattleGroundQueueId())
673 return;
675 else
677 grp = _player->GetGroup();
678 // no group found, error
679 if (!grp)
680 return;
681 uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot);
682 if (err != BG_JOIN_ERR_OK)
684 SendBattleGroundOrArenaJoinError(err);
685 return;
689 uint32 ateamId = 0;
691 if (isRated)
693 ateamId = _player->GetArenaTeamId(arenaslot);
694 // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
695 ArenaTeam * at = objmgr.GetArenaTeamById(ateamId);
696 if (!at)
698 _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
699 return;
701 // get the team rating for queueing
702 arenaRating = at->GetRating();
703 // the arenateam id must match for everyone in the group
704 // get the personal ratings for queueing
705 uint32 avg_pers_rating = 0;
706 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
708 Player *member = itr->getSource();
710 // calc avg personal rating
711 avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaslot*6) + 5);
714 if (arenatype)
715 avg_pers_rating /= arenatype;
717 // 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
718 if (avg_pers_rating + 150 < arenaRating)
719 arenaRating = avg_pers_rating;
722 GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId);
723 uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
724 if (asGroup)
726 sLog.outDebug("Battleground: arena join as group start");
727 if (isRated)
728 sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype);
729 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
731 Player *member = itr->getSource();
732 if(!member) continue;
734 uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue
736 WorldPacket data;
737 // send status packet (in queue)
738 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
739 member->GetSession()->SendPacket(&data);
740 sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
741 member->GetSession()->SendPacket(&data);
742 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
743 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());
745 sLog.outDebug("Battleground: arena join as group end");
746 if (isRated)
747 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true);
749 else
751 uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
753 WorldPacket data;
754 // send status packet (in queue)
755 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
756 SendPacket(&data);
757 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
758 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());
760 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating);
763 void WorldSession::HandleReportPvPAFK( WorldPacket & recv_data )
765 uint64 playerGuid;
766 recv_data >> playerGuid;
767 Player *reportedPlayer = objmgr.GetPlayer(playerGuid);
769 if (!reportedPlayer)
771 sLog.outDebug("WorldSession::HandleReportPvPAFK: player not found");
772 return;
775 sLog.outDebug("WorldSession::HandleReportPvPAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName());
777 reportedPlayer->ReportedAfkBy(_player);
780 void WorldSession::SendBattleGroundOrArenaJoinError(uint8 err)
782 WorldPacket data;
783 int32 msg;
784 switch (err)
786 case BG_JOIN_ERR_OFFLINE_MEMBER:
787 msg = LANG_BG_GROUP_OFFLINE_MEMBER;
788 break;
789 case BG_JOIN_ERR_GROUP_TOO_MANY:
790 msg = LANG_BG_GROUP_TOO_LARGE;
791 break;
792 case BG_JOIN_ERR_MIXED_FACTION:
793 msg = LANG_BG_GROUP_MIXED_FACTION;
794 break;
795 case BG_JOIN_ERR_MIXED_LEVELS:
796 msg = LANG_BG_GROUP_MIXED_LEVELS;
797 break;
798 case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
799 msg = LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE;
800 break;
801 case BG_JOIN_ERR_GROUP_DESERTER:
802 msg = LANG_BG_GROUP_MEMBER_DESERTER;
803 break;
804 case BG_JOIN_ERR_ALL_QUEUES_USED:
805 msg = LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS;
806 break;
807 case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
808 case BG_JOIN_ERR_MIXED_ARENATEAM:
809 default:
810 return;
811 break;
813 ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(msg), NULL);
814 SendPacket(&data);
815 return;