[9184] Fixed unread packet tail spam for CMSG_LEAVE_BATTLEFIELD
[getmangos.git] / src / game / BattleGroundHandler.cpp
blobda6c943fcdff65065de0eafd67b15a8951197c07
1 /*
2 * Copyright (C) 2005-2010 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 // expected bracket entry
119 PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel());
120 if (!bracketEntry)
121 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(bg, 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 BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
160 if (joinAsGroup /* && _player->GetGroup()*/)
162 sLog.outDebug("Battleground: the following players are joining as group:");
163 GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0);
164 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
165 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
167 Player *member = itr->getSource();
168 if(!member) continue; // this should never happen
170 uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue
172 WorldPacket data;
173 // send status packet (in queue)
174 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
175 member->GetSession()->SendPacket(&data);
176 sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
177 member->GetSession()->SendPacket(&data);
178 sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
180 sLog.outDebug("Battleground: group end");
182 else
184 GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0);
185 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
186 // already checked if queueSlot is valid, now just get it
187 uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
189 WorldPacket data;
190 // send status packet (in queue)
191 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
192 SendPacket(&data);
193 sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
195 sBattleGroundMgr.ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
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 = sObjectMgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID());
215 if (ali_plr)
216 ++count2;
218 Player *horde_plr = sObjectMgr.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 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message");
285 uint32 bgTypeId;
286 recv_data >> bgTypeId; // id from DBC
288 uint8 fromWhere;
289 recv_data >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo)
291 uint8 unk1;
292 recv_data >> unk1; // unknown 3.2.2
294 BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
295 if (!bl)
297 sLog.outError("Battleground: invalid bgtype received.");
298 return;
301 WorldPacket data;
302 sBattleGroundMgr.BuildBattleGroundListPacket(&data, 0, _player, BattleGroundTypeId(bgTypeId), fromWhere);
303 SendPacket( &data );
306 void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data )
308 sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message");
310 uint8 type; // arenatype if arena
311 uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
312 uint32 bgTypeId_; // type id from dbc
313 uint16 unk; // 0x1F90 constant?
314 uint8 action; // enter battle 0x1, leave queue 0x0
316 recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action;
318 if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
320 sLog.outError("BattlegroundHandler: invalid bgtype (%u) received.", bgTypeId_);
321 return;
323 if (!_player->InBattleGroundQueue())
325 sLog.outError("BattlegroundHandler: Invalid CMSG_BATTLEFIELD_PORT received from player (%u), he is not in bg_queue.", _player->GetGUIDLow());
326 return;
329 //get GroupQueueInfo from BattleGroundQueue
330 BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
331 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type);
332 BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
333 //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function
334 GroupQueueInfo ginfo;
335 if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo))
337 sLog.outError("BattlegroundHandler: itrplayerstatus not found.");
338 return;
340 // if action == 1, then instanceId is required
341 if (!ginfo.IsInvitedToBGInstanceGUID && action == 1)
343 sLog.outError("BattlegroundHandler: instance not found.");
344 return;
347 BattleGround *bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
349 // bg template might and must be used in case of leaving queue, when instance is not created yet
350 if (!bg && action == 0)
351 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
352 if (!bg)
354 sLog.outError("BattlegroundHandler: bg_template not found for type id %u.", bgTypeId);
355 return;
358 // expected bracket entry
359 PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel());
360 if (!bracketEntry)
361 return;
363 //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
364 if (action == 1 && ginfo.ArenaType == 0)
366 //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
367 if (!_player->CanJoinToBattleground())
369 //send bg command result to show nice message
370 WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
371 data2 << uint32(0xFFFFFFFE);
372 _player->GetSession()->SendPacket(&data2);
373 action = 0;
374 sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
376 //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
377 if (_player->getLevel() > bg->GetMaxLevel())
379 sLog.outError("Battleground: Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!",
380 _player->GetName(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID());
381 action = 0;
384 uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
385 WorldPacket data;
386 switch( action )
388 case 1: // port to battleground
389 if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
390 return; // cheating?
392 if (!_player->InBattleGround())
393 _player->SetBattleGroundEntryPoint();
395 // resurrect the player
396 if (!_player->isAlive())
398 _player->ResurrectPlayer(1.0f);
399 _player->SpawnCorpseBones();
401 // stop taxi flight at port
402 if (_player->isInFlight())
404 _player->GetMotionMaster()->MovementExpired();
405 _player->m_taxi.ClearTaxiDestinations();
408 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType());
409 _player->GetSession()->SendPacket(&data);
410 // remove battleground queue status from BGmgr
411 bgQueue.RemovePlayer(_player->GetGUID(), false);
412 // this is still needed here if battleground "jumping" shouldn't add deserter debuff
413 // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new
414 if (BattleGround *currentBg = _player->GetBattleGround())
415 currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
417 // set the destination instance id
418 _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId);
419 // set the destination team
420 _player->SetBGTeam(ginfo.Team);
421 // bg->HandleBeforeTeleportToBattleGround(_player);
422 sBattleGroundMgr.SendToBattleGround(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
423 // add only in HandleMoveWorldPortAck()
424 // bg->AddPlayer(_player,team);
425 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);
426 break;
427 case 0: // leave queue
428 // if player leaves rated arena match before match start, it is counted as he played but he lost
429 if (ginfo.IsRated)
431 ArenaTeam * at = sObjectMgr.GetArenaTeamById(ginfo.Team);
432 if (at)
434 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);
435 at->MemberLost(_player, ginfo.OpponentsTeamRating);
436 at->SaveToDB();
439 _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
440 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
441 bgQueue.RemovePlayer(_player->GetGUID(), true);
442 // player left queue, we should update it - do not update Arena Queue
443 if (!ginfo.ArenaType)
444 sBattleGroundMgr.ScheduleQueueUpdate(ginfo.ArenaTeamRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
445 SendPacket(&data);
446 sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId);
447 break;
448 default:
449 sLog.outError("Battleground port: unknown action %u", action);
450 break;
454 void WorldSession::HandleLeaveBattlefieldOpcode( WorldPacket& recv_data )
456 sLog.outDebug( "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message");
458 recv_data.read_skip<uint8>(); // unk1
459 recv_data.read_skip<uint8>(); // unk2
460 recv_data.read_skip<uint32>(); // BattleGroundTypeId
461 recv_data.read_skip<uint16>(); // unk3
463 //if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating? but not important in this case
464 // return;
466 // not allow leave battleground in combat
467 if (_player->isInCombat())
468 if (BattleGround* bg = _player->GetBattleGround())
469 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
470 return;
472 _player->LeaveBattleground();
475 void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
477 // empty opcode
478 sLog.outDebug( "WORLD: Battleground status" );
480 WorldPacket data;
481 // we must update all queues here
482 BattleGround *bg = NULL;
483 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
485 BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
486 if (!bgQueueTypeId)
487 continue;
488 BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
489 uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId);
490 if (bgTypeId == _player->GetBattleGroundTypeId())
492 bg = _player->GetBattleGround();
493 //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
494 //so i must use bg pointer to get that information
495 if (bg && bg->GetArenaType() == arenaType)
497 // this line is checked, i only don't know if GetStartTime is changing itself after bg end!
498 // send status in BattleGround
499 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType);
500 SendPacket(&data);
501 continue;
504 //we are sending update to player about queue - he can be invited there!
505 //get GroupQueueInfo for queue status
506 BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
507 GroupQueueInfo ginfo;
508 if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo))
509 continue;
510 if (ginfo.IsInvitedToBGInstanceGUID)
512 bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
513 if (!bg)
514 continue;
515 uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime);
516 // send status invited to BattleGround
517 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType);
518 SendPacket(&data);
520 else
522 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
523 if (!bg)
524 continue;
526 // expected bracket entry
527 PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel());
528 if (!bracketEntry)
529 continue;
531 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId());
532 // send status in BattleGround Queue
533 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType);
534 SendPacket(&data);
539 void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
541 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY");
543 BattleGround *bg = _player->GetBattleGround();
544 if (!bg)
545 return;
547 uint64 guid;
548 recv_data >> guid;
550 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
551 if (!unit)
552 return;
554 if(!unit->isSpiritService()) // it's not spirit service
555 return;
557 unit->SendAreaSpiritHealerQueryOpcode(GetPlayer());
560 void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data )
562 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE");
564 BattleGround *bg = _player->GetBattleGround();
565 if (!bg)
566 return;
568 uint64 guid;
569 recv_data >> guid;
571 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
572 if (!unit)
573 return;
575 if(!unit->isSpiritService()) // it's not spirit service
576 return;
578 Script->GossipHello(GetPlayer(), unit);
581 void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data )
583 sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
584 //recv_data.hexlike();
586 uint64 guid; // arena Battlemaster guid
587 uint8 arenaslot; // 2v2, 3v3 or 5v5
588 uint8 asGroup; // asGroup
589 uint8 isRated; // isRated
590 Group * grp;
592 recv_data >> guid >> arenaslot >> asGroup >> isRated;
594 // ignore if we already in BG or BG queue
595 if (_player->InBattleGround())
596 return;
598 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
599 if (!unit)
600 return;
602 if(!unit->isBattleMaster()) // it's not battle master
603 return;
605 uint8 arenatype = 0;
606 uint32 arenaRating = 0;
608 switch(arenaslot)
610 case 0:
611 arenatype = ARENA_TYPE_2v2;
612 break;
613 case 1:
614 arenatype = ARENA_TYPE_3v3;
615 break;
616 case 2:
617 arenatype = ARENA_TYPE_5v5;
618 break;
619 default:
620 sLog.outError("Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot);
621 return;
624 //check existance
625 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA);
626 if (!bg)
628 sLog.outError("Battleground: template bg (all arenas) not found");
629 return;
632 BattleGroundTypeId bgTypeId = bg->GetTypeID();
633 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype);
634 PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel());
635 if (!bracketEntry)
636 return;
638 // check queueing conditions
639 if (!asGroup)
641 // check if already in queue
642 if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
643 //player is already in this queue
644 return;
645 // check if has free queue slots
646 if (!_player->HasFreeBattleGroundQueueId())
647 return;
649 else
651 grp = _player->GetGroup();
652 // no group found, error
653 if (!grp)
654 return;
655 uint32 err = grp->CanJoinBattleGroundQueue(bg, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot);
656 if (err != BG_JOIN_ERR_OK)
658 SendBattleGroundOrArenaJoinError(err);
659 return;
663 uint32 ateamId = 0;
665 if (isRated)
667 ateamId = _player->GetArenaTeamId(arenaslot);
668 // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
669 ArenaTeam * at = sObjectMgr.GetArenaTeamById(ateamId);
670 if (!at)
672 _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
673 return;
675 // get the team rating for queueing
676 arenaRating = at->GetRating();
677 // the arenateam id must match for everyone in the group
678 // get the personal ratings for queueing
679 uint32 avg_pers_rating = 0;
680 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
682 Player *member = itr->getSource();
684 // calc avg personal rating
685 avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaslot * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING);
688 if (arenatype)
689 avg_pers_rating /= arenatype;
691 // 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
692 if (avg_pers_rating + 150 < arenaRating)
693 arenaRating = avg_pers_rating;
696 BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
697 if (asGroup)
699 sLog.outDebug("Battleground: arena join as group start");
700 if (isRated)
701 sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype);
703 GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, ateamId);
704 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
705 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
707 Player *member = itr->getSource();
708 if(!member) continue;
710 uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue
712 WorldPacket data;
713 // send status packet (in queue)
714 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
715 member->GetSession()->SendPacket(&data);
716 sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
717 member->GetSession()->SendPacket(&data);
718 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());
720 sLog.outDebug("Battleground: arena join as group end");
721 //announce to world ... removed
723 else
725 GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, ateamId);
726 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
727 uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
729 WorldPacket data;
730 // send status packet (in queue)
731 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
732 SendPacket(&data);
733 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());
735 sBattleGroundMgr.ScheduleQueueUpdate(arenaRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
738 void WorldSession::HandleReportPvPAFK( WorldPacket & recv_data )
740 uint64 playerGuid;
741 recv_data >> playerGuid;
742 Player *reportedPlayer = sObjectMgr.GetPlayer(playerGuid);
744 if (!reportedPlayer)
746 sLog.outDebug("WorldSession::HandleReportPvPAFK: player not found");
747 return;
750 sLog.outDebug("WorldSession::HandleReportPvPAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName());
752 reportedPlayer->ReportedAfkBy(_player);
755 void WorldSession::SendBattleGroundOrArenaJoinError(uint8 err)
757 WorldPacket data;
758 int32 msg;
759 switch (err)
761 case BG_JOIN_ERR_OFFLINE_MEMBER:
762 msg = LANG_BG_GROUP_OFFLINE_MEMBER;
763 break;
764 case BG_JOIN_ERR_GROUP_TOO_MANY:
765 msg = LANG_BG_GROUP_TOO_LARGE;
766 break;
767 case BG_JOIN_ERR_MIXED_FACTION:
768 msg = LANG_BG_GROUP_MIXED_FACTION;
769 break;
770 case BG_JOIN_ERR_MIXED_LEVELS:
771 msg = LANG_BG_GROUP_MIXED_LEVELS;
772 break;
773 case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
774 msg = LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE;
775 break;
776 case BG_JOIN_ERR_GROUP_DESERTER:
777 msg = LANG_BG_GROUP_MEMBER_DESERTER;
778 break;
779 case BG_JOIN_ERR_ALL_QUEUES_USED:
780 msg = LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS;
781 break;
782 case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
783 case BG_JOIN_ERR_MIXED_ARENATEAM:
784 default:
785 return;
786 break;
788 ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(msg), NULL);
789 SendPacket(&data);
790 return;