[9033] Fixed percent mana regneration from spell 53228 and ranks buff.
[getmangos.git] / src / game / BattleGroundHandler.cpp
blob82fe63db0f88098f49df12c085d9aca3ddf97548
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 "Object.h"
27 #include "Chat.h"
28 #include "BattleGroundMgr.h"
29 #include "BattleGroundWS.h"
30 #include "BattleGround.h"
31 #include "ArenaTeam.h"
32 #include "Language.h"
33 #include "ScriptCalls.h"
35 void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket & recv_data)
37 uint64 guid;
38 recv_data >> guid;
40 sLog.outDebug("WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid)));
42 Creature *pCreature = GetPlayer()->GetMap()->GetCreature(guid);
44 if (!pCreature)
45 return;
47 if (!pCreature->isBattleMaster()) // it's not battlemaster
48 return;
50 // Stop the npc if moving
51 if (!pCreature->IsStopped())
52 pCreature->StopMoving();
54 BattleGroundTypeId bgTypeId = sBattleGroundMgr.GetBattleMasterBG(pCreature->GetEntry());
56 if (bgTypeId == BATTLEGROUND_TYPE_NONE)
57 return;
59 if (!_player->GetBGAccessByLevel(bgTypeId))
61 // temp, must be gossip message...
62 SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR);
63 return;
66 SendBattlegGroundList(guid, bgTypeId);
69 void WorldSession::SendBattlegGroundList( uint64 guid, BattleGroundTypeId bgTypeId )
71 WorldPacket data;
72 sBattleGroundMgr.BuildBattleGroundListPacket(&data, guid, _player, bgTypeId, 0);
73 SendPacket( &data );
76 void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket & recv_data )
78 uint64 guid;
79 uint32 bgTypeId_;
80 uint32 instanceId;
81 uint8 joinAsGroup;
82 bool isPremade = false;
83 Group * grp;
85 recv_data >> guid; // battlemaster guid
86 recv_data >> bgTypeId_; // battleground type id (DBC id)
87 recv_data >> instanceId; // instance id, 0 if First Available selected
88 recv_data >> joinAsGroup; // join as group
90 if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
92 sLog.outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u",bgTypeId_,_player->GetGUIDLow());
93 return;
96 BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
98 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid)));
100 // can do this, since it's battleground, not arena
101 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, 0);
103 // ignore if player is already in BG
104 if (_player->InBattleGround())
105 return;
107 // get bg instance or bg template if instance not found
108 BattleGround *bg = NULL;
109 if (instanceId)
110 bg = sBattleGroundMgr.GetBattleGroundThroughClientInstance(instanceId, bgTypeId);
112 if (!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))
114 sLog.outError("Battleground: no available bg / template found");
115 return;
118 // check queueing conditions
119 if (!joinAsGroup)
121 // check Deserter debuff
122 if (!_player->CanJoinToBattleground())
124 WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
125 data << uint32(0xFFFFFFFE);
126 _player->GetSession()->SendPacket(&data);
127 return;
129 // check if already in queue
130 if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
131 //player is already in this queue
132 return;
133 // check if has free queue slots
134 if (!_player->HasFreeBattleGroundQueueId())
135 return;
137 else
139 grp = _player->GetGroup();
140 // no group found, error
141 if (!grp)
142 return;
143 uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
144 isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam());
145 if (err != BG_JOIN_ERR_OK)
147 SendBattleGroundOrArenaJoinError(err);
148 return;
151 // if we're here, then the conditions to join a bg are met. We can proceed in joining.
153 // _player->GetGroup() was already checked, grp is already initialized
154 BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
155 if (joinAsGroup /* && _player->GetGroup()*/)
157 sLog.outDebug("Battleground: the following players are joining as group:");
158 GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, 0, false, isPremade, 0);
159 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel());
160 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
162 Player *member = itr->getSource();
163 if(!member) continue; // this should never happen
165 uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue
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 sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
175 sLog.outDebug("Battleground: group end");
177 else
179 GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, 0, false, isPremade, 0);
180 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel());
181 // already checked if queueSlot is valid, now just get it
182 uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
184 WorldPacket data;
185 // send status packet (in queue)
186 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
187 SendPacket(&data);
188 sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
190 sBattleGroundMgr.ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
193 void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ )
195 // empty opcode
196 sLog.outDebug("WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message");
198 BattleGround *bg = _player->GetBattleGround();
199 if(!bg) // can't be received if player not in battleground
200 return;
202 switch( bg->GetTypeID() )
204 case BATTLEGROUND_WS:
206 uint32 count1 = 0; //always constant zero?
207 uint32 count2 = 0; //count of next fields
209 Player *ali_plr = sObjectMgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID());
210 if (ali_plr)
211 ++count2;
213 Player *horde_plr = sObjectMgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID());
214 if (horde_plr)
215 ++count2;
217 WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2));
218 data << count1; // alliance flag holders count - obsolete, now always 0
219 /*for(uint8 i = 0; i < count1; ++i)
221 data << uint64(0); // guid
222 data << (float)0; // x
223 data << (float)0; // y
225 data << count2; // horde flag holders count - obsolete, now count of next fields
226 if (ali_plr)
228 data << (uint64)ali_plr->GetGUID();
229 data << (float)ali_plr->GetPositionX();
230 data << (float)ali_plr->GetPositionY();
232 if (horde_plr)
234 data << (uint64)horde_plr->GetGUID();
235 data << (float)horde_plr->GetPositionX();
236 data << (float)horde_plr->GetPositionY();
239 SendPacket(&data);
241 break;
242 case BATTLEGROUND_EY:
243 //TODO : fix me!
244 break;
245 case BATTLEGROUND_AB:
246 case BATTLEGROUND_AV:
248 //for other BG types - send default
249 WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4));
250 data << uint32(0);
251 data << uint32(0);
252 SendPacket(&data);
254 break;
255 default:
256 //maybe it is sent also in arena - do nothing
257 break;
261 void WorldSession::HandlePVPLogDataOpcode( WorldPacket & /*recv_data*/ )
263 sLog.outDebug( "WORLD: Recvd MSG_PVP_LOG_DATA Message");
265 BattleGround *bg = _player->GetBattleGround();
266 if (!bg)
267 return;
269 WorldPacket data;
270 sBattleGroundMgr.BuildPvpLogDataPacket(&data, bg);
271 SendPacket(&data);
273 sLog.outDebug( "WORLD: Sent MSG_PVP_LOG_DATA Message");
276 void WorldSession::HandleBattlefieldListOpcode( WorldPacket &recv_data )
278 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message");
280 uint32 bgTypeId;
281 recv_data >> bgTypeId; // id from DBC
283 uint8 fromWhere;
284 recv_data >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo)
286 uint8 unk1;
287 recv_data >> unk1; // unknown 3.2.2
289 BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
290 if (!bl)
292 sLog.outError("Battleground: invalid bgtype received.");
293 return;
296 WorldPacket data;
297 sBattleGroundMgr.BuildBattleGroundListPacket(&data, 0, _player, BattleGroundTypeId(bgTypeId), fromWhere);
298 SendPacket( &data );
301 void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data )
303 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message");
305 uint8 type; // arenatype if arena
306 uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
307 uint32 bgTypeId_; // type id from dbc
308 uint16 unk; // 0x1F90 constant?
309 uint8 action; // enter battle 0x1, leave queue 0x0
311 recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action;
313 if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
315 sLog.outError("BattlegroundHandler: invalid bgtype (%u) received.", bgTypeId_);
316 return;
318 if (!_player->InBattleGroundQueue())
320 sLog.outError("BattlegroundHandler: Invalid CMSG_BATTLEFIELD_PORT received from player (%u), he is not in bg_queue.", _player->GetGUIDLow());
321 return;
324 //get GroupQueueInfo from BattleGroundQueue
325 BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
326 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type);
327 BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
328 //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function
329 GroupQueueInfo ginfo;
330 if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo))
332 sLog.outError("BattlegroundHandler: itrplayerstatus not found.");
333 return;
335 // if action == 1, then instanceId is required
336 if (!ginfo.IsInvitedToBGInstanceGUID && action == 1)
338 sLog.outError("BattlegroundHandler: instance not found.");
339 return;
342 BattleGround *bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
344 // bg template might and must be used in case of leaving queue, when instance is not created yet
345 if (!bg && action == 0)
346 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
347 if (!bg)
349 sLog.outError("BattlegroundHandler: bg_template not found for type id %u.", bgTypeId);
350 return;
353 //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
354 if (action == 1 && ginfo.ArenaType == 0)
356 //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
357 if (!_player->CanJoinToBattleground())
359 //send bg command result to show nice message
360 WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
361 data2 << uint32(0xFFFFFFFE);
362 _player->GetSession()->SendPacket(&data2);
363 action = 0;
364 sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
366 //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
367 if (_player->getLevel() > bg->GetMaxLevel())
369 sLog.outError("Battleground: Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!",
370 _player->GetName(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID());
371 action = 0;
374 uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
375 WorldPacket data;
376 switch( action )
378 case 1: // port to battleground
379 if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
380 return; // cheating?
382 if (!_player->InBattleGround())
383 _player->SetBattleGroundEntryPoint();
385 // resurrect the player
386 if (!_player->isAlive())
388 _player->ResurrectPlayer(1.0f);
389 _player->SpawnCorpseBones();
391 // stop taxi flight at port
392 if (_player->isInFlight())
394 _player->GetMotionMaster()->MovementExpired();
395 _player->m_taxi.ClearTaxiDestinations();
398 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType());
399 _player->GetSession()->SendPacket(&data);
400 // remove battleground queue status from BGmgr
401 bgQueue.RemovePlayer(_player->GetGUID(), false);
402 // this is still needed here if battleground "jumping" shouldn't add deserter debuff
403 // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new
404 if (BattleGround *currentBg = _player->GetBattleGround())
405 currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
407 // set the destination instance id
408 _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId);
409 // set the destination team
410 _player->SetBGTeam(ginfo.Team);
411 // bg->HandleBeforeTeleportToBattleGround(_player);
412 sBattleGroundMgr.SendToBattleGround(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
413 // add only in HandleMoveWorldPortAck()
414 // bg->AddPlayer(_player,team);
415 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);
416 break;
417 case 0: // leave queue
418 // if player leaves rated arena match before match start, it is counted as he played but he lost
419 if (ginfo.IsRated)
421 ArenaTeam * at = sObjectMgr.GetArenaTeamById(ginfo.Team);
422 if (at)
424 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), ginfo.OpponentsTeamRating);
425 at->MemberLost(_player, ginfo.OpponentsTeamRating);
426 at->SaveToDB();
429 _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
430 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
431 bgQueue.RemovePlayer(_player->GetGUID(), true);
432 // player left queue, we should update it - do not update Arena Queue
433 if (!ginfo.ArenaType)
434 sBattleGroundMgr.ScheduleQueueUpdate(ginfo.ArenaTeamRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
435 SendPacket(&data);
436 sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId);
437 break;
438 default:
439 sLog.outError("Battleground port: unknown action %u", action);
440 break;
444 void WorldSession::HandleLeaveBattlefieldOpcode( WorldPacket & /*recv_data*/ )
446 sLog.outDebug( "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message");
448 //uint8 unk1, unk2;
449 //uint32 bgTypeId; // id from DBC
450 //uint16 unk3;
452 //recv_data >> unk1 >> unk2 >> bgTypeId >> unk3; - no used currently
454 //if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating? but not important in this case
455 // return;
457 // not allow leave battleground in combat
458 if (_player->isInCombat())
459 if (BattleGround* bg = _player->GetBattleGround())
460 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
461 return;
463 _player->LeaveBattleground();
466 void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
468 // empty opcode
469 sLog.outDebug( "WORLD: Battleground status" );
471 WorldPacket data;
472 // we must update all queues here
473 BattleGround *bg = NULL;
474 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
476 BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
477 if (!bgQueueTypeId)
478 continue;
479 BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
480 uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId);
481 if (bgTypeId == _player->GetBattleGroundTypeId())
483 bg = _player->GetBattleGround();
484 //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
485 //so i must use bg pointer to get that information
486 if (bg && bg->GetArenaType() == arenaType)
488 // this line is checked, i only don't know if GetStartTime is changing itself after bg end!
489 // send status in BattleGround
490 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType);
491 SendPacket(&data);
492 continue;
495 //we are sending update to player about queue - he can be invited there!
496 //get GroupQueueInfo for queue status
497 BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
498 GroupQueueInfo ginfo;
499 if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo))
500 continue;
501 if (ginfo.IsInvitedToBGInstanceGUID)
503 bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
504 if (!bg)
505 continue;
506 uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime);
507 // send status invited to BattleGround
508 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType);
509 SendPacket(&data);
511 else
513 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
514 if (!bg)
515 continue;
516 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, _player->GetBattleGroundQueueIdFromLevel());
517 // send status in BattleGround Queue
518 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType);
519 SendPacket(&data);
524 void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
526 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY");
528 BattleGround *bg = _player->GetBattleGround();
529 if (!bg)
530 return;
532 uint64 guid;
533 recv_data >> guid;
535 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
536 if (!unit)
537 return;
539 if(!unit->isSpiritService()) // it's not spirit service
540 return;
542 unit->SendAreaSpiritHealerQueryOpcode(GetPlayer());
545 void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data )
547 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE");
549 BattleGround *bg = _player->GetBattleGround();
550 if (!bg)
551 return;
553 uint64 guid;
554 recv_data >> guid;
556 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
557 if (!unit)
558 return;
560 if(!unit->isSpiritService()) // it's not spirit service
561 return;
563 Script->GossipHello(GetPlayer(), unit);
566 void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data )
568 sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
569 //recv_data.hexlike();
571 uint64 guid; // arena Battlemaster guid
572 uint8 arenaslot; // 2v2, 3v3 or 5v5
573 uint8 asGroup; // asGroup
574 uint8 isRated; // isRated
575 Group * grp;
577 recv_data >> guid >> arenaslot >> asGroup >> isRated;
579 // ignore if we already in BG or BG queue
580 if (_player->InBattleGround())
581 return;
583 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
584 if (!unit)
585 return;
587 if(!unit->isBattleMaster()) // it's not battle master
588 return;
590 uint8 arenatype = 0;
591 uint32 arenaRating = 0;
593 switch(arenaslot)
595 case 0:
596 arenatype = ARENA_TYPE_2v2;
597 break;
598 case 1:
599 arenatype = ARENA_TYPE_3v3;
600 break;
601 case 2:
602 arenatype = ARENA_TYPE_5v5;
603 break;
604 default:
605 sLog.outError("Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot);
606 return;
609 //check existance
610 BattleGround* bg = NULL;
611 if (!(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)))
613 sLog.outError("Battleground: template bg (all arenas) not found");
614 return;
617 BattleGroundTypeId bgTypeId = bg->GetTypeID();
618 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype);
620 // check queueing conditions
621 if (!asGroup)
623 // check if already in queue
624 if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
625 //player is already in this queue
626 return;
627 // check if has free queue slots
628 if (!_player->HasFreeBattleGroundQueueId())
629 return;
631 else
633 grp = _player->GetGroup();
634 // no group found, error
635 if (!grp)
636 return;
637 uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot);
638 if (err != BG_JOIN_ERR_OK)
640 SendBattleGroundOrArenaJoinError(err);
641 return;
645 uint32 ateamId = 0;
647 if (isRated)
649 ateamId = _player->GetArenaTeamId(arenaslot);
650 // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
651 ArenaTeam * at = sObjectMgr.GetArenaTeamById(ateamId);
652 if (!at)
654 _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
655 return;
657 // get the team rating for queueing
658 arenaRating = at->GetRating();
659 // the arenateam id must match for everyone in the group
660 // get the personal ratings for queueing
661 uint32 avg_pers_rating = 0;
662 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
664 Player *member = itr->getSource();
666 // calc avg personal rating
667 avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaslot * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING);
670 if (arenatype)
671 avg_pers_rating /= arenatype;
673 // 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
674 if (avg_pers_rating + 150 < arenaRating)
675 arenaRating = avg_pers_rating;
678 BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
679 if (asGroup)
681 sLog.outDebug("Battleground: arena join as group start");
682 if (isRated)
683 sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype);
685 GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, arenatype, isRated, false, arenaRating, ateamId);
686 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel());
687 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
689 Player *member = itr->getSource();
690 if(!member) continue;
692 uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue
694 WorldPacket data;
695 // send status packet (in queue)
696 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
697 member->GetSession()->SendPacket(&data);
698 sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
699 member->GetSession()->SendPacket(&data);
700 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());
702 sLog.outDebug("Battleground: arena join as group end");
703 //announce to world ... removed
705 else
707 GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, arenatype, isRated, false, arenaRating, ateamId);
708 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel());
709 uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
711 WorldPacket data;
712 // send status packet (in queue)
713 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
714 SendPacket(&data);
715 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());
717 sBattleGroundMgr.ScheduleQueueUpdate(arenaRating, arenatype, bgQueueTypeId, bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
720 void WorldSession::HandleReportPvPAFK( WorldPacket & recv_data )
722 uint64 playerGuid;
723 recv_data >> playerGuid;
724 Player *reportedPlayer = sObjectMgr.GetPlayer(playerGuid);
726 if (!reportedPlayer)
728 sLog.outDebug("WorldSession::HandleReportPvPAFK: player not found");
729 return;
732 sLog.outDebug("WorldSession::HandleReportPvPAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName());
734 reportedPlayer->ReportedAfkBy(_player);
737 void WorldSession::SendBattleGroundOrArenaJoinError(uint8 err)
739 WorldPacket data;
740 int32 msg;
741 switch (err)
743 case BG_JOIN_ERR_OFFLINE_MEMBER:
744 msg = LANG_BG_GROUP_OFFLINE_MEMBER;
745 break;
746 case BG_JOIN_ERR_GROUP_TOO_MANY:
747 msg = LANG_BG_GROUP_TOO_LARGE;
748 break;
749 case BG_JOIN_ERR_MIXED_FACTION:
750 msg = LANG_BG_GROUP_MIXED_FACTION;
751 break;
752 case BG_JOIN_ERR_MIXED_LEVELS:
753 msg = LANG_BG_GROUP_MIXED_LEVELS;
754 break;
755 case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
756 msg = LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE;
757 break;
758 case BG_JOIN_ERR_GROUP_DESERTER:
759 msg = LANG_BG_GROUP_MEMBER_DESERTER;
760 break;
761 case BG_JOIN_ERR_ALL_QUEUES_USED:
762 msg = LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS;
763 break;
764 case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
765 case BG_JOIN_ERR_MIXED_ARENATEAM:
766 default:
767 return;
768 break;
770 ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(msg), NULL);
771 SendPacket(&data);
772 return;