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
20 #include "WorldPacket.h"
24 #include "ObjectMgr.h"
25 #include "WorldSession.h"
26 #include "ObjectAccessor.h"
29 #include "BattleGroundMgr.h"
30 #include "BattleGroundWS.h"
31 #include "BattleGround.h"
32 #include "ArenaTeam.h"
35 void WorldSession::HandleBattlemasterHelloOpcode( WorldPacket
& recv_data
)
37 CHECK_PACKET_SIZE(recv_data
, 8);
41 sLog
.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid
),GuidHigh2TypeId(GUID_HIPART(guid
)));
43 Creature
*unit
= GetPlayer()->GetMap()->GetCreature(guid
);
47 if(!unit
->isBattleMaster()) // it's not battlemaster
50 // Stop the npc if moving
53 BattleGroundTypeId bgTypeId
= sBattleGroundMgr
.GetBattleMasterBG(unit
->GetEntry());
55 if (!_player
->GetBGAccessByLevel(bgTypeId
))
57 // temp, must be gossip message...
58 SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR
);
62 SendBattlegGroundList(guid
, bgTypeId
);
65 void WorldSession::SendBattlegGroundList( uint64 guid
, BattleGroundTypeId bgTypeId
)
68 sBattleGroundMgr
.BuildBattleGroundListPacket(&data
, guid
, _player
, bgTypeId
);
72 void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket
& recv_data
)
74 CHECK_PACKET_SIZE(recv_data
, 8+4+4+1);
80 bool isPremade
= false;
83 recv_data
>> guid
; // battlemaster guid
84 recv_data
>> bgTypeId_
; // battleground type id (DBC id)
85 recv_data
>> instanceId
; // instance id, 0 if First Available selected
86 recv_data
>> joinAsGroup
; // join as group
88 if (!sBattlemasterListStore
.LookupEntry(bgTypeId_
))
90 sLog
.outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u",bgTypeId_
,_player
->GetGUIDLow());
94 BattleGroundTypeId bgTypeId
= BattleGroundTypeId(bgTypeId_
);
96 sLog
.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid
), GuidHigh2TypeId(GUID_HIPART(guid
)));
98 // can do this, since it's battleground, not arena
99 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(bgTypeId
, 0);
101 // ignore if player is already in BG
102 if (_player
->InBattleGround())
105 Creature
*unit
= GetPlayer()->GetMap()->GetCreature(guid
);
109 if(!unit
->isBattleMaster()) // it's not battlemaster
112 // get bg instance or bg template if instance not found
113 BattleGround
*bg
= NULL
;
115 bg
= sBattleGroundMgr
.GetBattleGroundThroughClientInstance(instanceId
, bgTypeId
);
117 if (!bg
&& !(bg
= sBattleGroundMgr
.GetBattleGroundTemplate(bgTypeId
)))
119 sLog
.outError("Battleground: no available bg / template found");
123 // check queueing conditions
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
);
134 // check if already in queue
135 if (_player
->GetBattleGroundQueueIndex(bgQueueTypeId
) < PLAYER_MAX_BATTLEGROUND_QUEUES
)
136 //player is already in this queue
138 // check if has free queue slots
139 if (!_player
->HasFreeBattleGroundQueueId())
144 grp
= _player
->GetGroup();
145 // no group found, error
148 uint32 err
= grp
->CanJoinBattleGroundQueue(bgTypeId
, bgQueueTypeId
, 0, bg
->GetMaxPlayersPerTeam(), false, 0);
149 isPremade
= (grp
->GetMembersCount() >= bg
->GetMinPlayersPerTeam());
150 if (err
!= BG_JOIN_ERR_OK
)
152 SendBattleGroundOrArenaJoinError(err
);
156 // if we're here, then the conditions to join a bg are met. We can proceed in joining.
158 // _player->GetGroup() was already checked, grp is already initialized
159 GroupQueueInfo
* ginfo
= sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].AddGroup(_player
, bgTypeId
, 0, false, isPremade
, 0);
160 uint32 avgTime
= sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].GetAverageQueueWaitTime(ginfo
, _player
->GetBattleGroundQueueIdFromLevel(bgTypeId
));
161 if (joinAsGroup
/* && _player->GetGroup()*/)
163 sLog
.outDebug("Battleground: the following players are joining as group:");
164 for(GroupReference
*itr
= grp
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
166 Player
*member
= itr
->getSource();
167 if(!member
) continue; // this should never happen
169 uint32 queueSlot
= member
->AddBattleGroundQueueId(bgQueueTypeId
); // add to queue
171 // store entry point coords (same as leader entry point)
172 member
->SetBattleGroundEntryPoint(_player
->GetMapId(),_player
->GetPositionX(),_player
->GetPositionY(),_player
->GetPositionZ(),_player
->GetOrientation());
175 // send status packet (in queue)
176 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, queueSlot
, STATUS_WAIT_QUEUE
, avgTime
, 0, ginfo
->ArenaType
);
177 member
->GetSession()->SendPacket(&data
);
178 sBattleGroundMgr
.BuildGroupJoinedBattlegroundPacket(&data
, bgTypeId
);
179 member
->GetSession()->SendPacket(&data
);
180 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].AddPlayer(member
, ginfo
);
181 sLog
.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId
,bgTypeId
,member
->GetGUIDLow(), member
->GetName());
183 sLog
.outDebug("Battleground: group end");
187 // already checked if queueSlot is valid, now just get it
188 uint32 queueSlot
= _player
->AddBattleGroundQueueId(bgQueueTypeId
);
189 // store entry point coords
190 _player
->SetBattleGroundEntryPoint(_player
->GetMapId(),_player
->GetPositionX(),_player
->GetPositionY(),_player
->GetPositionZ(),_player
->GetOrientation());
193 // send status packet (in queue)
194 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, queueSlot
, STATUS_WAIT_QUEUE
, avgTime
, 0, ginfo
->ArenaType
);
197 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].AddPlayer(_player
, ginfo
);
198 sLog
.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId
,bgTypeId
,_player
->GetGUIDLow(), _player
->GetName());
200 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].Update(bgTypeId
, _player
->GetBattleGroundQueueIdFromLevel(bgTypeId
));
201 if (!ginfo
->IsInvitedToBGInstanceGUID
)
202 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].AnnounceWorld(ginfo
, _player
->GetGUID(), true);
205 void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket
& /*recv_data*/ )
208 sLog
.outDebug("WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message");
210 BattleGround
*bg
= _player
->GetBattleGround();
211 if(!bg
) // can't be received if player not in battleground
214 switch( bg
->GetTypeID() )
216 case BATTLEGROUND_WS
:
218 uint32 count1
= 0; //always constant zero?
219 uint32 count2
= 0; //count of next fields
221 Player
*ali_plr
= objmgr
.GetPlayer(((BattleGroundWS
*)bg
)->GetAllianceFlagPickerGUID());
225 Player
*horde_plr
= objmgr
.GetPlayer(((BattleGroundWS
*)bg
)->GetHordeFlagPickerGUID());
229 WorldPacket
data(MSG_BATTLEGROUND_PLAYER_POSITIONS
, (4+4+16*count1
+16*count2
));
230 data
<< count1
; // alliance flag holders count - obsolete, now always 0
231 /*for(uint8 i = 0; i < count1; ++i)
233 data << uint64(0); // guid
234 data << (float)0; // x
235 data << (float)0; // y
237 data
<< count2
; // horde flag holders count - obsolete, now count of next fields
240 data
<< (uint64
)ali_plr
->GetGUID();
241 data
<< (float)ali_plr
->GetPositionX();
242 data
<< (float)ali_plr
->GetPositionY();
246 data
<< (uint64
)horde_plr
->GetGUID();
247 data
<< (float)horde_plr
->GetPositionX();
248 data
<< (float)horde_plr
->GetPositionY();
254 case BATTLEGROUND_EY
:
257 case BATTLEGROUND_AB
:
258 case BATTLEGROUND_AV
:
260 //for other BG types - send default
261 WorldPacket
data(MSG_BATTLEGROUND_PLAYER_POSITIONS
, (4+4));
268 //maybe it is sent also in arena - do nothing
273 void WorldSession::HandlePVPLogDataOpcode( WorldPacket
& /*recv_data*/ )
275 sLog
.outDebug( "WORLD: Recvd MSG_PVP_LOG_DATA Message");
277 BattleGround
*bg
= _player
->GetBattleGround();
282 sBattleGroundMgr
.BuildPvpLogDataPacket(&data
, bg
);
285 sLog
.outDebug( "WORLD: Sent MSG_PVP_LOG_DATA Message");
288 void WorldSession::HandleBattlefieldListOpcode( WorldPacket
&recv_data
)
290 CHECK_PACKET_SIZE(recv_data
, 4);
292 sLog
.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message");
295 recv_data
>> bgTypeId
; // id from DBC
297 BattlemasterListEntry
const* bl
= sBattlemasterListStore
.LookupEntry(bgTypeId
);
300 sLog
.outError("Battleground: invalid bgtype received.");
305 sBattleGroundMgr
.BuildBattleGroundListPacket(&data
, _player
->GetGUID(), _player
, BattleGroundTypeId(bgTypeId
));
309 void WorldSession::HandleBattleFieldPortOpcode( WorldPacket
&recv_data
)
311 CHECK_PACKET_SIZE(recv_data
, 1+1+4+2+1);
313 sLog
.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message");
315 uint8 type
; // arenatype if arena
316 uint8 unk2
; // unk, can be 0x0 (may be if was invited?) and 0x1
318 uint32 bgTypeId_
; // type id from dbc
319 uint16 unk
; // 0x1F90 constant?
320 uint8 action
; // enter battle 0x1, leave queue 0x0
322 recv_data
>> type
>> unk2
>> bgTypeId_
>> unk
>> action
;
324 if (!sBattlemasterListStore
.LookupEntry(bgTypeId_
))
326 sLog
.outError("Battleground: invalid bgtype (%u) received.", bgTypeId_
);
327 // update battleground slots for the player to fix his UI and sent data.
328 // this is a HACK, I don't know why the client starts sending invalid packets in the first place.
329 // it usually happens with extremely high latency (if debugging / stepping in the code for example)
330 if (_player
->InBattleGroundQueue())
332 // update all queues, send invitation info if player is invited, queue info if queued
333 for (uint32 i
= 0; i
< PLAYER_MAX_BATTLEGROUND_QUEUES
; ++i
)
335 BattleGroundQueueTypeId bgQueueTypeId
= _player
->GetBattleGroundQueueTypeId(i
);
338 BattleGroundTypeId bgTypeId
= BattleGroundMgr::BGTemplateId(bgQueueTypeId
);
339 BattleGroundQueue::QueuedPlayersMap
& qpMap
= sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].m_QueuedPlayers
;
340 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus
= qpMap
.find(_player
->GetGUID());
341 // if the player is not in queue, continue or no group information - this should never happen
342 if (itrPlayerStatus
== qpMap
.end() || !itrPlayerStatus
->second
.GroupInfo
)
345 BattleGround
* bg
= NULL
;
346 // get possibly needed data from groupinfo
347 uint8 arenatype
= itrPlayerStatus
->second
.GroupInfo
->ArenaType
;
350 if (!itrPlayerStatus
->second
.GroupInfo
->IsInvitedToBGInstanceGUID
)
352 // not invited to bg, get template
353 bg
= sBattleGroundMgr
.GetBattleGroundTemplate(bgTypeId
);
354 status
= STATUS_WAIT_QUEUE
;
358 // get the bg we're invited to
359 bg
= sBattleGroundMgr
.GetBattleGround(itrPlayerStatus
->second
.GroupInfo
->IsInvitedToBGInstanceGUID
, bgTypeId
);
360 status
= STATUS_WAIT_JOIN
;
363 // if bg not found, then continue, don't invite if already in the instance
364 if (!bg
|| (_player
->InBattleGround() && _player
->GetBattleGround() && _player
->GetBattleGround()->GetInstanceID() == bg
->GetInstanceID()))
367 // re - invite player with proper data
369 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, i
, status
, INVITE_ACCEPT_WAIT_TIME
, 0, arenatype
);
376 //get GroupQueueInfo from BattleGroundQueue
377 BattleGroundTypeId bgTypeId
= BattleGroundTypeId(bgTypeId_
);
378 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(bgTypeId
, type
);
379 BattleGroundQueue::QueuedPlayersMap
& qpMap
= sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].m_QueuedPlayers
;
380 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus
= qpMap
.find(_player
->GetGUID());
381 if (itrPlayerStatus
== qpMap
.end())
383 sLog
.outError("Battleground: itrplayerstatus not found.");
387 instanceId
= itrPlayerStatus
->second
.GroupInfo
->IsInvitedToBGInstanceGUID
;
388 // if action == 1, then instanceId is required
389 if (!instanceId
&& action
== 1)
391 sLog
.outError("Battleground: instance not found.");
395 BattleGround
*bg
= sBattleGroundMgr
.GetBattleGround(instanceId
, bgTypeId
);
397 // bg template might and must be used in case of leaving queue, when instance is not created yet
398 if (!bg
&& action
== 0)
399 bg
= sBattleGroundMgr
.GetBattleGroundTemplate(bgTypeId
);
402 sLog
.outError("Battleground: bg_template not found for type id %u.", bgTypeId
);
406 if (_player
->InBattleGroundQueue())
408 //we must use temporary variables, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function!
409 uint32 team
= itrPlayerStatus
->second
.GroupInfo
->Team
;
410 uint32 arenaType
= itrPlayerStatus
->second
.GroupInfo
->ArenaType
;
411 uint32 isRated
= itrPlayerStatus
->second
.GroupInfo
->IsRated
;
412 uint32 rating
= itrPlayerStatus
->second
.GroupInfo
->ArenaTeamRating
;
413 uint32 opponentsRating
= itrPlayerStatus
->second
.GroupInfo
->OpponentsTeamRating
;
415 //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
416 if (action
== 1 && arenaType
== 0)
418 //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
419 if (!_player
->CanJoinToBattleground())
421 //send bg command result to show nice message
422 WorldPacket
data2(SMSG_GROUP_JOINED_BATTLEGROUND
, 4);
423 data2
<< uint32(0xFFFFFFFE);
424 _player
->GetSession()->SendPacket(&data2
);
426 sLog
.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player
->GetName(), _player
->GetGUIDLow());
428 //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue
429 if (_player
->getLevel() > bg
->GetMaxLevel())
431 sLog
.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player
->GetName(), _player
->GetGUIDLow());
435 uint32 queueSlot
= _player
->GetBattleGroundQueueIndex(bgQueueTypeId
);
439 case 1: // port to battleground
440 if (!_player
->IsInvitedForBattleGroundQueueType(bgQueueTypeId
))
442 // resurrect the player
443 if (!_player
->isAlive())
445 _player
->ResurrectPlayer(1.0f
);
446 _player
->SpawnCorpseBones();
448 // stop taxi flight at port
449 if (_player
->isInFlight())
451 _player
->GetMotionMaster()->MovementExpired();
452 _player
->m_taxi
.ClearTaxiDestinations();
455 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, queueSlot
, STATUS_IN_PROGRESS
, 0, bg
->GetStartTime(), bg
->GetArenaType());
456 _player
->GetSession()->SendPacket(&data
);
457 // remove battleground queue status from BGmgr
458 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].RemovePlayer(_player
->GetGUID(), false);
459 // this is still needed here if battleground "jumping" shouldn't add deserter debuff
460 // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new
461 if (BattleGround
*currentBg
= _player
->GetBattleGround())
462 currentBg
->RemovePlayerAtLeave(_player
->GetGUID(), false, true);
464 // set the destination instance id
465 _player
->SetBattleGroundId(bg
->GetInstanceID(), bgTypeId
);
466 // set the destination team
467 _player
->SetBGTeam(team
);
468 // bg->HandleBeforeTeleportToBattleGround(_player);
469 sBattleGroundMgr
.SendToBattleGround(_player
, instanceId
, bgTypeId
);
470 // add only in HandleMoveWorldPortAck()
471 // bg->AddPlayer(_player,team);
472 sLog
.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player
->GetName(), _player
->GetGUIDLow(), bg
->GetInstanceID(), bg
->GetTypeID(), bgQueueTypeId
);
474 case 0: // leave queue
475 // if player leaves rated arena match before match start, it is counted as he played but he lost
478 ArenaTeam
* at
= objmgr
.GetArenaTeamById(team
);
481 sLog
.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player
->GetGUID()), opponentsRating
);
482 at
->MemberLost(_player
, opponentsRating
);
486 _player
->RemoveBattleGroundQueueId(bgQueueTypeId
); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
487 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, queueSlot
, STATUS_NONE
, 0, 0, 0);
488 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].RemovePlayer(_player
->GetGUID(), true);
489 // player left queue, we should update it - do not update Arena Queue
491 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].Update(bgTypeId
, _player
->GetBattleGroundQueueIdFromLevel(bgTypeId
), arenaType
, isRated
, rating
);
493 sLog
.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player
->GetName(), _player
->GetGUIDLow(), bg
->GetTypeID(), bgQueueTypeId
);
496 sLog
.outError("Battleground port: unknown action %u", action
);
502 void WorldSession::HandleLeaveBattlefieldOpcode( WorldPacket
& /*recv_data*/ )
504 //CHECK_PACKET_SIZE(recv_data, 1+1+4+2);
506 sLog
.outDebug( "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message");
509 //uint32 bgTypeId; // id from DBC
512 //recv_data >> unk1 >> unk2 >> bgTypeId >> unk3; - no used currently
514 //if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating? but not important in this case
517 // not allow leave battleground in combat
518 if (_player
->isInCombat())
519 if (BattleGround
* bg
= _player
->GetBattleGround())
520 if (bg
->GetStatus() != STATUS_WAIT_LEAVE
)
523 _player
->LeaveBattleground();
526 void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket
& /*recv_data*/ )
529 sLog
.outDebug( "WORLD: Battleground status" );
532 // we must update all queues here
533 BattleGround
*bg
= NULL
;
534 for (uint8 i
= 0; i
< PLAYER_MAX_BATTLEGROUND_QUEUES
; ++i
)
536 BattleGroundQueueTypeId bgQueueTypeId
= _player
->GetBattleGroundQueueTypeId(i
);
539 BattleGroundTypeId bgTypeId
= BattleGroundMgr::BGTemplateId(bgQueueTypeId
);
540 uint8 arenaType
= BattleGroundMgr::BGArenaType(bgQueueTypeId
);
541 if (bgTypeId
== _player
->GetBattleGroundTypeId())
543 bg
= _player
->GetBattleGround();
544 //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
545 //so i must use bg pointer to get that information
546 if (bg
&& bg
->GetArenaType() == arenaType
)
548 // this line is checked, i only don't know if GetStartTime is changing itself after bg end!
549 // send status in BattleGround
550 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, i
, STATUS_IN_PROGRESS
, bg
->GetEndTime(), bg
->GetStartTime(), arenaType
);
555 //we are sending update to player about queue - he can be invited there!
556 //get GroupQueueInfo for queue status
557 BattleGroundQueue::QueuedPlayersMap
& qpMap
= sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].m_QueuedPlayers
;
558 BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus
= qpMap
.find(_player
->GetGUID());
559 if (itrPlayerStatus
== qpMap
.end())
561 if (itrPlayerStatus
->second
.GroupInfo
->IsInvitedToBGInstanceGUID
)
563 bg
= sBattleGroundMgr
.GetBattleGround(itrPlayerStatus
->second
.GroupInfo
->IsInvitedToBGInstanceGUID
, bgTypeId
);
566 uint32 remainingTime
= getMSTimeDiff(getMSTime(), itrPlayerStatus
->second
.GroupInfo
->RemoveInviteTime
);
567 // send status invited to BattleGround
568 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, i
, STATUS_WAIT_JOIN
, remainingTime
, 0, arenaType
);
573 bg
= sBattleGroundMgr
.GetBattleGroundTemplate(bgTypeId
);
576 uint32 avgTime
= sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].GetAverageQueueWaitTime(itrPlayerStatus
->second
.GroupInfo
, _player
->GetBattleGroundQueueIdFromLevel(bgTypeId
));
577 // send status in BattleGround Queue
578 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, i
, STATUS_WAIT_QUEUE
, avgTime
, getMSTimeDiff(itrPlayerStatus
->second
.GroupInfo
->JoinTime
, getMSTime()), arenaType
);
584 void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket
& recv_data
)
586 sLog
.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY");
588 CHECK_PACKET_SIZE(recv_data
, 8);
590 BattleGround
*bg
= _player
->GetBattleGround();
597 Creature
*unit
= GetPlayer()->GetMap()->GetCreature(guid
);
601 if(!unit
->isSpiritService()) // it's not spirit service
604 sBattleGroundMgr
.SendAreaSpiritHealerQueryOpcode(_player
, bg
, guid
);
607 void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket
& recv_data
)
609 sLog
.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE");
611 CHECK_PACKET_SIZE(recv_data
, 8);
613 BattleGround
*bg
= _player
->GetBattleGround();
620 Creature
*unit
= GetPlayer()->GetMap()->GetCreature(guid
);
624 if(!unit
->isSpiritService()) // it's not spirit service
627 bg
->AddPlayerToResurrectQueue(guid
, _player
->GetGUID());
630 void WorldSession::HandleBattlemasterJoinArena( WorldPacket
& recv_data
)
632 CHECK_PACKET_SIZE(recv_data
, 8+1+1+1);
634 sLog
.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
637 // ignore if we already in BG or BG queue
638 if (_player
->InBattleGround())
641 uint64 guid
; // arena Battlemaster guid
642 uint8 arenaslot
; // 2v2, 3v3 or 5v5
643 uint8 asGroup
; // asGroup
644 uint8 isRated
; // isRated
647 recv_data
>> guid
>> arenaslot
>> asGroup
>> isRated
;
649 Creature
*unit
= GetPlayer()->GetMap()->GetCreature(guid
);
653 if(!unit
->isBattleMaster()) // it's not battle master
657 uint32 arenaRating
= 0;
662 arenatype
= ARENA_TYPE_2v2
;
665 arenatype
= ARENA_TYPE_3v3
;
668 arenatype
= ARENA_TYPE_5v5
;
671 sLog
.outError("Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot
);
676 BattleGround
* bg
= NULL
;
677 if (!(bg
= sBattleGroundMgr
.GetBattleGroundTemplate(BATTLEGROUND_AA
)))
679 sLog
.outError("Battleground: template bg (all arenas) not found");
683 BattleGroundTypeId bgTypeId
= bg
->GetTypeID();
684 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(bgTypeId
, arenatype
);
686 // check queueing conditions
689 // check if already in queue
690 if (_player
->GetBattleGroundQueueIndex(bgQueueTypeId
) < PLAYER_MAX_BATTLEGROUND_QUEUES
)
691 //player is already in this queue
693 // check if has free queue slots
694 if (!_player
->HasFreeBattleGroundQueueId())
699 grp
= _player
->GetGroup();
700 // no group found, error
703 uint32 err
= grp
->CanJoinBattleGroundQueue(bgTypeId
, bgQueueTypeId
, arenatype
, arenatype
, (bool)isRated
, arenaslot
);
704 if (err
!= BG_JOIN_ERR_OK
)
706 SendBattleGroundOrArenaJoinError(err
);
715 ateamId
= _player
->GetArenaTeamId(arenaslot
);
716 // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
717 ArenaTeam
* at
= objmgr
.GetArenaTeamById(ateamId
);
720 _player
->GetSession()->SendNotInArenaTeamPacket(arenatype
);
723 // get the team rating for queueing
724 arenaRating
= at
->GetRating();
725 // the arenateam id must match for everyone in the group
726 // get the personal ratings for queueing
727 uint32 avg_pers_rating
= 0;
728 for(GroupReference
*itr
= grp
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
730 Player
*member
= itr
->getSource();
732 // calc avg personal rating
733 avg_pers_rating
+= member
->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1
+ (arenaslot
*6) + 5);
737 avg_pers_rating
/= arenatype
;
739 // if avg personal rating is more than 150 points below the teams rating, the team will be queued against an opponent matching or similar to the average personal rating
740 if (avg_pers_rating
+ 150 < arenaRating
)
741 arenaRating
= avg_pers_rating
;
744 GroupQueueInfo
* ginfo
= sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].AddGroup(_player
, bgTypeId
, arenatype
, isRated
, false, arenaRating
, ateamId
);
745 uint32 avgTime
= sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].GetAverageQueueWaitTime(ginfo
, _player
->GetBattleGroundQueueIdFromLevel(bgTypeId
));
748 sLog
.outDebug("Battleground: arena join as group start");
750 sLog
.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player
->GetArenaTeamId(arenaslot
),_player
->GetName(),arenaRating
,arenatype
);
751 for(GroupReference
*itr
= grp
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
753 Player
*member
= itr
->getSource();
754 if(!member
) continue;
756 uint32 queueSlot
= member
->AddBattleGroundQueueId(bgQueueTypeId
);// add to queue
758 // store entry point coords (same as leader entry point)
759 member
->SetBattleGroundEntryPoint(_player
->GetMapId(),_player
->GetPositionX(),_player
->GetPositionY(),_player
->GetPositionZ(),_player
->GetOrientation());
762 // send status packet (in queue)
763 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, queueSlot
, STATUS_WAIT_QUEUE
, avgTime
, 0, arenatype
);
764 member
->GetSession()->SendPacket(&data
);
765 sBattleGroundMgr
.BuildGroupJoinedBattlegroundPacket(&data
, bgTypeId
);
766 member
->GetSession()->SendPacket(&data
);
767 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].AddPlayer(member
, ginfo
);
768 sLog
.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId
,bgTypeId
,member
->GetGUIDLow(), member
->GetName());
770 sLog
.outDebug("Battleground: arena join as group end");
772 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].AnnounceWorld(ginfo
, _player
->GetGUID(), true);
776 uint32 queueSlot
= _player
->AddBattleGroundQueueId(bgQueueTypeId
);
778 // store entry point coords
779 _player
->SetBattleGroundEntryPoint(_player
->GetMapId(),_player
->GetPositionX(),_player
->GetPositionY(),_player
->GetPositionZ(),_player
->GetOrientation());
782 // send status packet (in queue)
783 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, queueSlot
, STATUS_WAIT_QUEUE
, avgTime
, 0, arenatype
);
785 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].AddPlayer(_player
, ginfo
);
786 sLog
.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId
,bgTypeId
,_player
->GetGUIDLow(), _player
->GetName());
788 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].Update(bgTypeId
, _player
->GetBattleGroundQueueIdFromLevel(bgTypeId
), arenatype
, isRated
, arenaRating
);
791 void WorldSession::HandleReportPvPAFK( WorldPacket
& recv_data
)
793 CHECK_PACKET_SIZE(recv_data
, 8);
796 recv_data
>> playerGuid
;
797 Player
*reportedPlayer
= objmgr
.GetPlayer(playerGuid
);
801 sLog
.outDebug("WorldSession::HandleReportPvPAFK: player not found");
805 sLog
.outDebug("WorldSession::HandleReportPvPAFK: %s reported %s", _player
->GetName(), reportedPlayer
->GetName());
807 reportedPlayer
->ReportedAfkBy(_player
);
810 void WorldSession::SendBattleGroundOrArenaJoinError(uint8 err
)
816 case BG_JOIN_ERR_OFFLINE_MEMBER
:
817 msg
= LANG_BG_GROUP_OFFLINE_MEMBER
;
819 case BG_JOIN_ERR_GROUP_TOO_MANY
:
820 msg
= LANG_BG_GROUP_TOO_LARGE
;
822 case BG_JOIN_ERR_MIXED_FACTION
:
823 msg
= LANG_BG_GROUP_MIXED_FACTION
;
825 case BG_JOIN_ERR_MIXED_LEVELS
:
826 msg
= LANG_BG_GROUP_MIXED_LEVELS
;
828 case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE
:
829 msg
= LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE
;
831 case BG_JOIN_ERR_GROUP_DESERTER
:
832 msg
= LANG_BG_GROUP_MEMBER_DESERTER
;
834 case BG_JOIN_ERR_ALL_QUEUES_USED
:
835 msg
= LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS
;
837 case BG_JOIN_ERR_GROUP_NOT_ENOUGH
:
838 case BG_JOIN_ERR_MIXED_ARENATEAM
:
843 ChatHandler::FillMessageData(&data
, NULL
, CHAT_MSG_BG_SYSTEM_NEUTRAL
, LANG_UNIVERSAL
, NULL
, 0, GetMangosString(msg
), NULL
);