[9143] Typos
[getmangos.git] / src / game / BattleGroundHandler.cpp
blob6ec38302163a4819719ea4a806b9c245c2614636
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 //uint8 unk1, unk2;
459 //uint32 bgTypeId; // id from DBC
460 //uint16 unk3;
462 //recv_data >> unk1 >> unk2 >> bgTypeId >> unk3; - no used currently
464 //if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating? but not important in this case
465 // return;
467 // not allow leave battleground in combat
468 if (_player->isInCombat())
469 if (BattleGround* bg = _player->GetBattleGround())
470 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
471 return;
473 _player->LeaveBattleground();
476 void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
478 // empty opcode
479 sLog.outDebug( "WORLD: Battleground status" );
481 WorldPacket data;
482 // we must update all queues here
483 BattleGround *bg = NULL;
484 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
486 BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
487 if (!bgQueueTypeId)
488 continue;
489 BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
490 uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId);
491 if (bgTypeId == _player->GetBattleGroundTypeId())
493 bg = _player->GetBattleGround();
494 //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
495 //so i must use bg pointer to get that information
496 if (bg && bg->GetArenaType() == arenaType)
498 // this line is checked, i only don't know if GetStartTime is changing itself after bg end!
499 // send status in BattleGround
500 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType);
501 SendPacket(&data);
502 continue;
505 //we are sending update to player about queue - he can be invited there!
506 //get GroupQueueInfo for queue status
507 BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
508 GroupQueueInfo ginfo;
509 if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo))
510 continue;
511 if (ginfo.IsInvitedToBGInstanceGUID)
513 bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
514 if (!bg)
515 continue;
516 uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime);
517 // send status invited to BattleGround
518 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType);
519 SendPacket(&data);
521 else
523 bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
524 if (!bg)
525 continue;
527 // expected bracket entry
528 PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel());
529 if (!bracketEntry)
530 continue;
532 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId());
533 // send status in BattleGround Queue
534 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType);
535 SendPacket(&data);
540 void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
542 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY");
544 BattleGround *bg = _player->GetBattleGround();
545 if (!bg)
546 return;
548 uint64 guid;
549 recv_data >> guid;
551 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
552 if (!unit)
553 return;
555 if(!unit->isSpiritService()) // it's not spirit service
556 return;
558 unit->SendAreaSpiritHealerQueryOpcode(GetPlayer());
561 void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data )
563 sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE");
565 BattleGround *bg = _player->GetBattleGround();
566 if (!bg)
567 return;
569 uint64 guid;
570 recv_data >> guid;
572 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
573 if (!unit)
574 return;
576 if(!unit->isSpiritService()) // it's not spirit service
577 return;
579 Script->GossipHello(GetPlayer(), unit);
582 void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data )
584 sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
585 //recv_data.hexlike();
587 uint64 guid; // arena Battlemaster guid
588 uint8 arenaslot; // 2v2, 3v3 or 5v5
589 uint8 asGroup; // asGroup
590 uint8 isRated; // isRated
591 Group * grp;
593 recv_data >> guid >> arenaslot >> asGroup >> isRated;
595 // ignore if we already in BG or BG queue
596 if (_player->InBattleGround())
597 return;
599 Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
600 if (!unit)
601 return;
603 if(!unit->isBattleMaster()) // it's not battle master
604 return;
606 uint8 arenatype = 0;
607 uint32 arenaRating = 0;
609 switch(arenaslot)
611 case 0:
612 arenatype = ARENA_TYPE_2v2;
613 break;
614 case 1:
615 arenatype = ARENA_TYPE_3v3;
616 break;
617 case 2:
618 arenatype = ARENA_TYPE_5v5;
619 break;
620 default:
621 sLog.outError("Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot);
622 return;
625 //check existance
626 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA);
627 if (!bg)
629 sLog.outError("Battleground: template bg (all arenas) not found");
630 return;
633 BattleGroundTypeId bgTypeId = bg->GetTypeID();
634 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype);
635 PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel());
636 if (!bracketEntry)
637 return;
639 // check queueing conditions
640 if (!asGroup)
642 // check if already in queue
643 if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
644 //player is already in this queue
645 return;
646 // check if has free queue slots
647 if (!_player->HasFreeBattleGroundQueueId())
648 return;
650 else
652 grp = _player->GetGroup();
653 // no group found, error
654 if (!grp)
655 return;
656 uint32 err = grp->CanJoinBattleGroundQueue(bg, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot);
657 if (err != BG_JOIN_ERR_OK)
659 SendBattleGroundOrArenaJoinError(err);
660 return;
664 uint32 ateamId = 0;
666 if (isRated)
668 ateamId = _player->GetArenaTeamId(arenaslot);
669 // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
670 ArenaTeam * at = sObjectMgr.GetArenaTeamById(ateamId);
671 if (!at)
673 _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
674 return;
676 // get the team rating for queueing
677 arenaRating = at->GetRating();
678 // the arenateam id must match for everyone in the group
679 // get the personal ratings for queueing
680 uint32 avg_pers_rating = 0;
681 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
683 Player *member = itr->getSource();
685 // calc avg personal rating
686 avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaslot * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING);
689 if (arenatype)
690 avg_pers_rating /= arenatype;
692 // 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
693 if (avg_pers_rating + 150 < arenaRating)
694 arenaRating = avg_pers_rating;
697 BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
698 if (asGroup)
700 sLog.outDebug("Battleground: arena join as group start");
701 if (isRated)
702 sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype);
704 GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, ateamId);
705 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
706 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
708 Player *member = itr->getSource();
709 if(!member) continue;
711 uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue
713 WorldPacket data;
714 // send status packet (in queue)
715 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
716 member->GetSession()->SendPacket(&data);
717 sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
718 member->GetSession()->SendPacket(&data);
719 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());
721 sLog.outDebug("Battleground: arena join as group end");
722 //announce to world ... removed
724 else
726 GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, ateamId);
727 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
728 uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
730 WorldPacket data;
731 // send status packet (in queue)
732 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
733 SendPacket(&data);
734 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());
736 sBattleGroundMgr.ScheduleQueueUpdate(arenaRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
739 void WorldSession::HandleReportPvPAFK( WorldPacket & recv_data )
741 uint64 playerGuid;
742 recv_data >> playerGuid;
743 Player *reportedPlayer = sObjectMgr.GetPlayer(playerGuid);
745 if (!reportedPlayer)
747 sLog.outDebug("WorldSession::HandleReportPvPAFK: player not found");
748 return;
751 sLog.outDebug("WorldSession::HandleReportPvPAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName());
753 reportedPlayer->ReportedAfkBy(_player);
756 void WorldSession::SendBattleGroundOrArenaJoinError(uint8 err)
758 WorldPacket data;
759 int32 msg;
760 switch (err)
762 case BG_JOIN_ERR_OFFLINE_MEMBER:
763 msg = LANG_BG_GROUP_OFFLINE_MEMBER;
764 break;
765 case BG_JOIN_ERR_GROUP_TOO_MANY:
766 msg = LANG_BG_GROUP_TOO_LARGE;
767 break;
768 case BG_JOIN_ERR_MIXED_FACTION:
769 msg = LANG_BG_GROUP_MIXED_FACTION;
770 break;
771 case BG_JOIN_ERR_MIXED_LEVELS:
772 msg = LANG_BG_GROUP_MIXED_LEVELS;
773 break;
774 case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
775 msg = LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE;
776 break;
777 case BG_JOIN_ERR_GROUP_DESERTER:
778 msg = LANG_BG_GROUP_MEMBER_DESERTER;
779 break;
780 case BG_JOIN_ERR_ALL_QUEUES_USED:
781 msg = LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS;
782 break;
783 case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
784 case BG_JOIN_ERR_MIXED_ARENATEAM:
785 default:
786 return;
787 break;
789 ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(msg), NULL);
790 SendPacket(&data);
791 return;