TrinityCore
BattleGroundHandler.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "WorldSession.h"
19#include "ArenaTeam.h"
20#include "ArenaTeamMgr.h"
21#include "Battlefield.h"
22#include "BattlefieldMgr.h"
23#include "Battleground.h"
24#include "BattlegroundMgr.h"
25#include "BattlegroundPackets.h"
26#include "Chat.h"
27#include "Common.h"
28#include "Creature.h"
29#include "DB2Stores.h"
30#include "DisableMgr.h"
31#include "Group.h"
32#include "Language.h"
33#include "Log.h"
34#include "NPCPackets.h"
35#include "Object.h"
36#include "ObjectAccessor.h"
37#include "Player.h"
38#include "SpellAuras.h"
39#include "SpellMgr.h"
40#include "SpellInfo.h"
41#include "World.h"
42
44{
46 if (!unit)
47 return;
48
49 // Stop the npc if moving
51 unit->PauseMovement(pause);
52 unit->SetHomePosition(unit->GetPosition());
53
54 BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(unit->GetEntry());
55
56 if (!_player->GetBGAccessByLevel(bgTypeId))
57 {
58 // temp, must be gossip message...
60 return;
61 }
62
63 sBattlegroundMgr->SendBattlegroundList(_player, hello.Unit, bgTypeId);
64}
65
67{
68 bool isPremade = false;
69 if (battlemasterJoin.QueueIDs.empty())
70 {
71 TC_LOG_ERROR("network", "Battleground: no bgtype received. possible cheater? {}", _player->GetGUID().ToString());
72 return;
73 }
74
75 BattlegroundQueueTypeId bgQueueTypeId = BattlegroundQueueTypeId::FromPacked(battlemasterJoin.QueueIDs[0]);
76 if (!BattlegroundMgr::IsValidQueueId(bgQueueTypeId))
77 {
78 TC_LOG_ERROR("network", "Battleground: invalid bg queue {{ BattlemasterListId: {}, Type: {}, Rated: {}, TeamSize: {} }} received. possible cheater? {}",
79 bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.Type), bgQueueTypeId.Rated ? "true" : "false", uint32(bgQueueTypeId.TeamSize),
81 return;
82 }
83
84 BattlemasterListEntry const* battlemasterListEntry = sBattlemasterListStore.AssertEntry(bgQueueTypeId.BattlemasterListId);
85
86 if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgQueueTypeId.BattlemasterListId, nullptr) || battlemasterListEntry->GetFlags().HasFlag(BattlemasterListFlags::InternalOnly))
87 {
89 return;
90 }
91
93
94 // ignore if player is already in BG
96 return;
97
98 BattlegroundTemplate const* bgTemplate = sBattlegroundMgr->GetBattlegroundTemplateByTypeId(bgTypeId);
99 if (!bgTemplate)
100 return;
101
102 // expected bracket entry
104 if (!bracketEntry)
105 return;
106
108
109 Group const* grp = _player->GetGroup();
110
111 auto getQueueTeam = [&]() -> Team
112 {
113 // mercenary applies only to unrated battlegrounds
114 if (!bgQueueTypeId.Rated && !bgTemplate->IsArena())
115 {
117 return HORDE;
118
120 return ALLIANCE;
121 }
122
123 return Team(_player->GetTeam());
124 };
125
126 // check queue conditions
127 if (!grp)
128 {
129 if (GetPlayer()->isUsingLfg())
130 {
132 sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bgQueueTypeId, _player, 0, ERR_LFG_CANT_USE_BATTLEGROUND);
133 SendPacket(battlefieldStatus.Write());
134 return;
135 }
136
137 // check RBAC permissions
138 if (!_player->CanJoinToBattleground(bgTemplate))
139 {
141 sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bgQueueTypeId, _player, 0, ERR_BATTLEGROUND_JOIN_TIMED_OUT);
142 SendPacket(battlefieldStatus.Write());
143 return;
144 }
145
146 // check Deserter debuff
147 if (_player->IsDeserter())
148 {
150 sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bgQueueTypeId, _player, 0, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS);
151 SendPacket(battlefieldStatus.Write());
152 return;
153 }
154
157 if (!BattlegroundMgr::IsRandomBattleground(bgTypeId) && isInRandomBgQueue)
158 {
159 // player is already in random queue
161 sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bgQueueTypeId, _player, 0, ERR_IN_RANDOM_BG);
162 SendPacket(battlefieldStatus.Write());
163 return;
164 }
165
166 if (_player->InBattlegroundQueue(true) && !isInRandomBgQueue && BattlegroundMgr::IsRandomBattleground(bgTypeId))
167 {
168 // player is already in queue, can't start random queue
170 sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bgQueueTypeId, _player, 0, ERR_IN_NON_RANDOM_BG);
171 SendPacket(battlefieldStatus.Write());
172 return;
173 }
174
175 // check if already in queue
177 // player is already in this queue
178 return;
179
180 // check if has free queue slots
182 {
184 sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bgQueueTypeId, _player, 0, ERR_BATTLEGROUND_TOO_MANY_QUEUES);
185 SendPacket(battlefieldStatus.Write());
186 return;
187 }
188
189 // check Freeze debuff
190 if (_player->HasAura(9454))
191 return;
192
193 BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
194 GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, getQueueTeam(), bracketEntry, false, isPremade, 0, 0);
195 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
196 uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId);
197
199 sBattlegroundMgr->BuildBattlegroundStatusQueued(&battlefieldStatus, _player, queueSlot, ginfo->JoinTime, bgQueueTypeId, avgTime, false);
200 SendPacket(battlefieldStatus.Write());
201
202 TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue {{ BattlemasterListId: {}, Type: {}, Rated: {}, TeamSize: {} }}, {}, NAME {}",
203 bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.Type), bgQueueTypeId.Rated ? "true" : "false", uint32(bgQueueTypeId.TeamSize),
205 }
206 else
207 {
208 if (grp->GetLeaderGUID() != _player->GetGUID())
209 return;
210
211 ObjectGuid errorGuid;
212 err = grp->CanJoinBattlegroundQueue(bgTemplate, bgQueueTypeId, 0, bgTemplate->GetMaxPlayersPerTeam(), false, 0, errorGuid);
213 isPremade = (grp->GetMembersCount() >= bgTemplate->GetMinPlayersPerTeam());
214
215 BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
216 GroupQueueInfo* ginfo = nullptr;
217 uint32 avgTime = 0;
218
219 if (!err)
220 {
221 TC_LOG_DEBUG("bg.battleground", "Battleground: the following players are joining as group:");
222 ginfo = bgQueue.AddGroup(_player, grp, getQueueTeam(), bracketEntry, false, isPremade, 0, 0);
223 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
224 }
225
226 for (GroupReference const* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
227 {
228 Player* member = itr->GetSource();
229 if (!member)
230 continue; // this should never happen
231
232 if (err)
233 {
235 sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bgQueueTypeId, _player, 0, err, &errorGuid);
236 member->SendDirectMessage(battlefieldStatus.Write());
237 continue;
238 }
239
240 // add to queue
241 uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId);
242
244 sBattlegroundMgr->BuildBattlegroundStatusQueued(&battlefieldStatus, member, queueSlot, ginfo->JoinTime, bgQueueTypeId, avgTime, true);
245 member->SendDirectMessage(battlefieldStatus.Write());
246 TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue {{ BattlemasterListId: {}, Type: {}, Rated: {}, TeamSize: {} }}, {}, NAME {}",
247 bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.Type), bgQueueTypeId.Rated ? "true" : "false", uint32(bgQueueTypeId.TeamSize),
248 member->GetGUID().ToString(), member->GetName());
249 }
250 TC_LOG_DEBUG("bg.battleground", "Battleground: group end");
251 }
252
253 sBattlegroundMgr->ScheduleQueueUpdate(0, bgQueueTypeId, bracketEntry->GetBracketId());
254}
255
257{
259 if (!bg)
260 return;
261
262 // Prevent players from sending BuildPvpLogDataPacket in an arena except for when sent in BattleGround::EndBattleGround.
263 if (bg->isArena())
264 return;
265
267 bg->BuildPvPLogDataPacket(pvpMatchStatistics.Data);
268 SendPacket(pvpMatchStatistics.Write());
269}
270
272{
273 BattlemasterListEntry const* battlemasterListEntry = sBattlemasterListStore.LookupEntry(battlefieldList.ListID);
274 if (!battlemasterListEntry)
275 {
276 TC_LOG_DEBUG("bg.battleground", "BattlegroundHandler: invalid bgtype ({}) with player (Name: {}, {}) received.", battlefieldList.ListID, _player->GetName(), _player->GetGUID().ToString());
277 return;
278 }
279
280 sBattlegroundMgr->SendBattlegroundList(_player, ObjectGuid::Empty, BattlegroundTypeId(battlefieldList.ListID));
281}
282
284{
286 {
287 TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} Slot: {}, Unk: {}, Time: {}, AcceptedInvite: {}. Player not in queue!",
288 GetPlayerInfo(), battlefieldPort.Ticket.Id, uint32(battlefieldPort.Ticket.Type), battlefieldPort.Ticket.Time.AsUnderlyingType(), uint32(battlefieldPort.AcceptedInvite));
289 return;
290 }
291
292 BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(battlefieldPort.Ticket.Id);
293 if (bgQueueTypeId == BATTLEGROUND_QUEUE_NONE)
294 {
295 TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} Slot: {}, Unk: {}, Time: {}, AcceptedInvite: {}. Invalid queueSlot!",
296 GetPlayerInfo(), battlefieldPort.Ticket.Id, uint32(battlefieldPort.Ticket.Type), battlefieldPort.Ticket.Time.AsUnderlyingType(), uint32(battlefieldPort.AcceptedInvite));
297 return;
298 }
299
300 BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
301
302 //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue::RemovePlayer() function
303 GroupQueueInfo ginfo;
304 if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo))
305 {
306 TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} Slot: {}, Unk: {}, Time: {}, AcceptedInvite: {}. Player not in queue (No player Group Info)!",
307 GetPlayerInfo(), battlefieldPort.Ticket.Id, uint32(battlefieldPort.Ticket.Type), battlefieldPort.Ticket.Time.AsUnderlyingType(), uint32(battlefieldPort.AcceptedInvite));
308 return;
309 }
310 // if action == 1, then player must have been invited to join
311 if (!ginfo.IsInvitedToBGInstanceGUID && battlefieldPort.AcceptedInvite)
312 {
313 TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} Slot: {}, Unk: {}, Time: {}, AcceptedInvite: {}. Player is not invited to any bg!",
314 GetPlayerInfo(), battlefieldPort.Ticket.Id, uint32(battlefieldPort.Ticket.Type), battlefieldPort.Ticket.Time.AsUnderlyingType(), uint32(battlefieldPort.AcceptedInvite));
315 return;
316 }
317
319 BattlegroundTemplate const* bgTemplate = sBattlegroundMgr->GetBattlegroundTemplateByTypeId(bgTypeId);
320 if (!bgTemplate)
321 {
322 TC_LOG_ERROR("network", "BattlegroundHandle: BattlegroundTemplate not found for type id {}.", bgTypeId);
323 return;
324 }
325
326 uint32 mapId = bgTemplate->BattlemasterEntry->MapID[0];
327
328 // BGTemplateId returns BATTLEGROUND_AA when it is arena queue.
329 // Do instance id search as there is no AA bg instances.
330 Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId == BATTLEGROUND_AA ? BATTLEGROUND_TYPE_NONE : bgTypeId);
331 if (!bg && battlefieldPort.AcceptedInvite)
332 {
333 TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} Slot: {}, Unk: {}, Time: {}, AcceptedInvite: {}. Cant find BG with id {}!",
334 GetPlayerInfo(), battlefieldPort.Ticket.Id, uint32(battlefieldPort.Ticket.Type), battlefieldPort.Ticket.Time.AsUnderlyingType(), uint32(battlefieldPort.AcceptedInvite), ginfo.IsInvitedToBGInstanceGUID);
335 return;
336 }
337 else if (bg)
338 mapId = bg->GetMapId();
339
340 TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} Slot: {}, Unk: {}, Time: {}, AcceptedInvite: {}.",
341 GetPlayerInfo(), battlefieldPort.Ticket.Id, uint32(battlefieldPort.Ticket.Type), battlefieldPort.Ticket.Time.AsUnderlyingType(), uint32(battlefieldPort.AcceptedInvite));
342
343 // expected bracket entry
345 if (!bracketEntry)
346 return;
347
348 //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
349 if (battlefieldPort.AcceptedInvite && bgQueue.GetQueueId().TeamSize == 0)
350 {
351 //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
352 if (_player->IsDeserter())
353 {
354 //send bg command result to show nice message
356 sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bgQueueTypeId, _player, battlefieldPort.Ticket.Id, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS);
357 SendPacket(battlefieldStatus.Write());
358 battlefieldPort.AcceptedInvite = false;
359 TC_LOG_DEBUG("bg.battleground", "Player {} {} has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUID().ToString());
360 }
361 //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
362 if (_player->GetLevel() > bg->GetMaxLevel())
363 {
364 TC_LOG_ERROR("network", "Player {} {} has level ({}) higher than maxlevel ({}) of battleground ({})! Do not port him to battleground!",
366 battlefieldPort.AcceptedInvite = false;
367 }
368 }
369
370 if (battlefieldPort.AcceptedInvite)
371 {
372 // check Freeze debuff
373 if (_player->HasAura(9454))
374 return;
375
376 if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId))
377 return; // cheating?
378
379 if (!_player->InBattleground())
381
382 // resurrect the player
383 if (!_player->IsAlive())
384 {
387 }
388 // stop taxi flight at port
390
392 sBattlegroundMgr->BuildBattlegroundStatusActive(&battlefieldStatus, bg, _player, battlefieldPort.Ticket.Id, _player->GetBattlegroundQueueJoinTime(bgQueueTypeId), bgQueueTypeId);
393 SendPacket(battlefieldStatus.Write());
394
395 // remove battleground queue status from BGmgr
396 bgQueue.RemovePlayer(_player->GetGUID(), false);
397 // this is still needed here if battleground "jumping" shouldn't add deserter debuff
398 // also this is required to prevent stuck at old battleground after SetBattlegroundId set to new
399 if (Battleground* currentBg = _player->GetBattleground())
400 currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
401
402 // set the destination instance id
403 _player->SetBattlegroundId(bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId);
404 // set the destination team
405 _player->SetBGTeam(ginfo.Team);
406
407 // bg->HandleBeforeTeleportToBattleground(_player);
408 sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
409 // add only in HandleMoveWorldPortAck()
410 // bg->AddPlayer(_player, team);
411 TC_LOG_DEBUG("bg.battleground", "Battleground: player {} ({}) joined battle for bg {}, bgtype {}, queue {{ BattlemasterListId: {}, Type: {}, Rated: {}, TeamSize: {} }}.",
413 bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.Type), bgQueueTypeId.Rated ? "true" : "false", uint32(bgQueueTypeId.TeamSize));
414 }
415 else // leave queue
416 {
417 // if player leaves rated arena match before match start, it is counted as he played but he lost
418 if (bgQueue.GetQueueId().Rated && ginfo.IsInvitedToBGInstanceGUID)
419 {
420 ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ginfo.Team);
421 if (at)
422 {
423 TC_LOG_DEBUG("bg.battleground", "UPDATING memberLost's personal arena rating for {} by opponents rating: {}, because he has left queue!", _player->GetGUID().ToString(), ginfo.OpponentsTeamRating);
425 at->SaveToDB();
426 }
427 }
428
430 battlefieldStatus.Ticket = battlefieldPort.Ticket;
431 SendPacket(battlefieldStatus.Write());
432
433 _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
434 bgQueue.RemovePlayer(_player->GetGUID(), true);
435 // player left queue, we should update it - do not update Arena Queue
436 if (!bgQueue.GetQueueId().TeamSize)
437 sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, bgQueueTypeId, bracketEntry->GetBracketId());
438
439 TC_LOG_DEBUG("bg.battleground", "Battleground: player {} ({}) left queue for bgtype {}, queue {{ BattlemasterListId: {}, Type: {}, Rated: {}, TeamSize: {} }}.",
441 bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.Type), bgQueueTypeId.Rated ? "true" : "false", uint32(bgQueueTypeId.TeamSize));
442 }
443}
444
446{
447 // not allow leave battleground in combat
448 if (_player->IsInCombat())
450 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
451 return;
452
454}
455
457{
458 // we must update all queues here
459 Battleground* bg = nullptr;
460 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
461 {
463 if (bgQueueTypeId == BATTLEGROUND_QUEUE_NONE)
464 continue;
466 bg = _player->GetBattleground();
467 if (bg)
468 {
470 if (bgPlayer && bgPlayer->queueTypeId == bgQueueTypeId)
471 {
472 //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
473 //so i must use bg pointer to get that information
475 sBattlegroundMgr->BuildBattlegroundStatusActive(&battlefieldStatus, bg, _player, i, _player->GetBattlegroundQueueJoinTime(bgQueueTypeId), bgQueueTypeId);
476 SendPacket(battlefieldStatus.Write());
477 continue;
478 }
479 }
480
481 //we are sending update to player about queue - he can be invited there!
482 //get GroupQueueInfo for queue status
483 BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
484 GroupQueueInfo ginfo;
485 if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo))
486 continue;
488 {
489 bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
490 if (!bg)
491 continue;
492
494 sBattlegroundMgr->BuildBattlegroundStatusNeedConfirmation(&battlefieldStatus, bg, _player, i, _player->GetBattlegroundQueueJoinTime(bgQueueTypeId), getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime), bgQueueTypeId);
495 SendPacket(battlefieldStatus.Write());
496 }
497 else
498 {
499 BattlegroundTemplate const* bgTemplate = sBattlegroundMgr->GetBattlegroundTemplateByTypeId(bgTypeId);
500 if (!bgTemplate)
501 continue;
502
503 // expected bracket entry
505 if (!bracketEntry)
506 continue;
507
508 uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId());
510 sBattlegroundMgr->BuildBattlegroundStatusQueued(&battlefieldStatus, _player, i, _player->GetBattlegroundQueueJoinTime(bgQueueTypeId), bgQueueTypeId, avgTime, ginfo.Players.size() > 1);
511 SendPacket(battlefieldStatus.Write());
512 }
513 }
514}
515
517{
518 // ignore if we already in BG or BG queue
519 if (_player->InBattleground())
520 return;
521
522 uint8 arenatype = ArenaTeam::GetTypeBySlot(packet.TeamSizeIndex);
523
524 //check existence
525 BattlegroundTemplate const* bgTemplate = sBattlegroundMgr->GetBattlegroundTemplateByTypeId(BATTLEGROUND_AA);
526 if (!bgTemplate)
527 {
528 TC_LOG_ERROR("network", "Battleground: template bg (all arenas) not found");
529 return;
530 }
531
533 {
535 return;
536 }
537
538 BattlegroundTypeId bgTypeId = bgTemplate->Id;
541 if (!bracketEntry)
542 return;
543
544 Group* grp = _player->GetGroup();
545 // no group found, error
546 if (!grp)
547 return;
548 if (grp->GetLeaderGUID() != _player->GetGUID())
549 return;
550
551 uint32 ateamId = _player->GetArenaTeamId(packet.TeamSizeIndex);
552 // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
553 ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ateamId);
554 if (!at)
555 return;
556
557 // get the team rating for queuing
558 uint32 arenaRating = at->GetRating();
559 uint32 matchmakerRating = at->GetAverageMMR(grp);
560 // the arenateam id must match for everyone in the group
561
562 if (arenaRating <= 0)
563 arenaRating = 1;
564
565 BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
566
567 uint32 avgTime = 0;
568 GroupQueueInfo* ginfo = nullptr;
569
570 ObjectGuid errorGuid;
571 GroupJoinBattlegroundResult err = grp->CanJoinBattlegroundQueue(bgTemplate, bgQueueTypeId, arenatype, arenatype, true, packet.TeamSizeIndex, errorGuid);
572 if (!err)
573 {
574 TC_LOG_DEBUG("bg.battleground", "Battleground: arena team id {}, leader {} queued with matchmaker rating {} for type {}", _player->GetArenaTeamId(packet.TeamSizeIndex), _player->GetName(), matchmakerRating, arenatype);
575
576 ginfo = bgQueue.AddGroup(_player, grp, Team(_player->GetTeam()), bracketEntry, false, arenaRating, matchmakerRating, ateamId);
577 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId());
578 }
579
580 for (GroupReference* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
581 {
582 Player* member = itr->GetSource();
583 if (!member)
584 continue;
585
586 if (err)
587 {
589 sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bgQueueTypeId, _player, 0, err, &errorGuid);
590 member->SendDirectMessage(battlefieldStatus.Write());
591 continue;
592 }
593
594 if (!_player->CanJoinToBattleground(bgTemplate))
595 {
597 sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bgQueueTypeId, _player, 0, ERR_BATTLEGROUND_JOIN_FAILED, &errorGuid);
598 member->SendDirectMessage(battlefieldStatus.Write());
599 return;
600 }
601
602 // add to queue
603 uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId);
604
606 sBattlegroundMgr->BuildBattlegroundStatusQueued(&battlefieldStatus, member, queueSlot, ginfo->JoinTime, bgQueueTypeId, avgTime, true);
607 member->SendDirectMessage(battlefieldStatus.Write());
608
609 TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for arena as group bg queue {{ BattlemasterListId: {}, Type: {}, Rated: {}, TeamSize: {} }}, {}, NAME {}",
610 bgQueueTypeId.BattlemasterListId, uint32(bgQueueTypeId.Type), bgQueueTypeId.Rated ? "true" : "false", uint32(bgQueueTypeId.TeamSize),
611 member->GetGUID().ToString(), member->GetName());
612 }
613
614 sBattlegroundMgr->ScheduleQueueUpdate(matchmakerRating, bgQueueTypeId, bracketEntry->GetBracketId());
615}
616
618{
619 Player* reportedPlayer = ObjectAccessor::FindPlayer(reportPvPPlayerAFK.Offender);
620 if (!reportedPlayer)
621 {
622 TC_LOG_INFO("bg.reportpvpafk", "WorldSession::HandleReportPvPAFK: {} [IP: {}] reported {}", _player->GetName(), _player->GetSession()->GetRemoteAddress(), reportPvPPlayerAFK.Offender.ToString());
623 return;
624 }
625
626 TC_LOG_DEBUG("bg.battleground", "WorldSession::HandleReportPvPAFK: {} reported {}", _player->GetName(), reportedPlayer->GetName());
627
628 reportedPlayer->ReportedAfkBy(_player);
629}
630
632{
634 SendPacket(ratedPvpInfo.Write());
635}
636
638{
640 pvpOptionsEnabled.RatedBattlegrounds = false;
641 pvpOptionsEnabled.PugBattlegrounds = true;
642 pvpOptionsEnabled.WargameBattlegrounds = false;
643 pvpOptionsEnabled.WargameArenas = false;
644 pvpOptionsEnabled.RatedArenas = false;
645 pvpOptionsEnabled.ArenaSkirmish = false;
646 pvpOptionsEnabled.SoloShuffle = false;
647 pvpOptionsEnabled.RatedSoloShuffle = false;
648 pvpOptionsEnabled.BattlegroundBlitz = false;
649 pvpOptionsEnabled.RatedBattlegroundBlitz = false;
650 SendPacket(pvpOptionsEnabled.Write());
651}
652
654{
656}
657
659{
660 Player* player = GetPlayer();
661 Creature* spiritHealer = ObjectAccessor::GetCreature(*player, areaSpiritHealerQuery.HealerGuid);
662 if (!spiritHealer)
663 return;
664
665 if (!spiritHealer->IsAreaSpiritHealer())
666 return;
667
669 return;
670
671 if (spiritHealer->IsAreaSpiritHealerIndividual())
672 {
673 if (Aura* aura = player->GetAura(SPELL_SPIRIT_HEAL_PLAYER_AURA))
674 {
675 player->SendAreaSpiritHealerTime(spiritHealer->GetGUID(), aura->GetDuration());
676 }
677 else if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_SPIRIT_HEAL_PLAYER_AURA, DIFFICULTY_NONE))
678 {
679 spiritHealer->CastSpell(player, SPELL_SPIRIT_HEAL_PLAYER_AURA);
680 player->SendAreaSpiritHealerTime(spiritHealer->GetGUID(), spellInfo->GetDuration());
681 spiritHealer->CastSpell(nullptr, SPELL_SPIRIT_HEAL_CHANNEL_SELF);
682 }
683 }
684 else
685 _player->SendAreaSpiritHealerTime(spiritHealer);
686}
687
689{
690 Creature* spiritHealer = ObjectAccessor::GetCreature(*GetPlayer(), areaSpiritHealerQueue.HealerGuid);
691 if (!spiritHealer)
692 return;
693
694 if (!spiritHealer->IsAreaSpiritHealer())
695 return;
696
698 return;
699
700 _player->SetAreaSpiritHealer(spiritHealer);
701}
702
704{
705 if (_player->IsInFlight())
706 return;
707
708 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetMap(), _player->GetZoneId()))
709 {
710 bf->PlayerAskToLeave(_player);
711 return;
712 }
713
714 AreaTableEntry const* atEntry = sAreaTableStore.LookupEntry(_player->GetAreaId());
715 if (!atEntry || !(atEntry->GetFlags().HasFlag(AreaFlags::AllowHearthAndRessurectFromArea)))
716 return;
717
721}
#define sArenaTeamMgr
Definition: ArenaTeamMgr.h:53
#define sBattlefieldMgr
#define sBattlegroundMgr
@ SPELL_SPIRIT_HEAL_PLAYER_AURA
Definition: Battleground.h:102
@ SPELL_MERCENARY_CONTRACT_ALLIANCE
Definition: Battleground.h:118
@ SPELL_MERCENARY_CONTRACT_HORDE
Definition: Battleground.h:117
@ SPELL_SPIRIT_HEAL_CHANNEL_SELF
Definition: Battleground.h:103
@ STATUS_WAIT_LEAVE
Definition: Battleground.h:168
DB2Storage< BattlemasterListEntry > sBattlemasterListStore("BattlemasterList.db2", &BattlemasterListLoadInfo::Instance)
DB2Storage< AreaTableEntry > sAreaTableStore("AreaTable.db2", &AreaTableLoadInfo::Instance)
@ DIFFICULTY_NONE
Definition: DBCEnums.h:874
@ AllowHearthAndRessurectFromArea
uint8_t uint8
Definition: Define.h:144
uint32_t uint32
Definition: Define.h:142
@ DISABLE_TYPE_BATTLEGROUND
Definition: DisableMgr.h:30
@ LANG_ARENA_DISABLED
Definition: Language.h:738
@ LANG_YOUR_BG_LEVEL_REQ_ERROR
Definition: Language.h:705
@ LANG_BG_DISABLED
Definition: Language.h:737
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
float constexpr MAX_AREA_SPIRIT_HEALER_RANGE
Definition: Player.h:1097
GroupJoinBattlegroundResult
@ ERR_BATTLEGROUND_NONE
constexpr BattlegroundQueueTypeId BATTLEGROUND_QUEUE_NONE
static constexpr uint8 PLAYER_MAX_BATTLEGROUND_QUEUES
@ ERR_IN_RANDOM_BG
@ ERR_IN_NON_RANDOM_BG
@ ERR_BATTLEGROUND_JOIN_TIMED_OUT
@ ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS
@ ERR_LFG_CANT_USE_BATTLEGROUND
@ ERR_BATTLEGROUND_JOIN_FAILED
@ ERR_BATTLEGROUND_TOO_MANY_QUEUES
Team
@ ALLIANCE
@ HORDE
BattlegroundTypeId
@ BATTLEGROUND_AA
@ BATTLEGROUND_TYPE_NONE
@ BATTLEGROUND_RANDOM_EPIC
@ BATTLEGROUND_RB
#define sSpellMgr
Definition: SpellMgr.h:849
uint32 getMSTime()
Definition: Timer.h:33
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
Definition: Timer.h:40
@ UNIT_NPC_FLAG_BATTLEMASTER
Definition: UnitDefines.h:317
@ UNIT_NPC_FLAG_2_NONE
Definition: UnitDefines.h:336
void SaveToDB(bool forceMemberSave=false)
Definition: ArenaTeam.cpp:734
uint32 GetRating() const
Definition: ArenaTeam.h:132
void MemberLost(Player *player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange=-12)
Definition: ArenaTeam.cpp:659
uint32 GetAverageMMR(Group *group) const
Definition: ArenaTeam.cpp:504
static uint8 GetTypeBySlot(uint8 slot)
Definition: ArenaTeam.cpp:481
static BattlegroundQueueTypeId BGQueueTypeId(uint16 battlemasterListId, BattlegroundQueueIdType type, bool rated, uint8 teamSize)
static bool IsValidQueueId(BattlegroundQueueTypeId bgQueueTypeId)
static bool IsRandomBattleground(uint32 battlemasterListId)
GroupQueueInfo * AddGroup(Player const *leader, Group const *group, Team team, PVPDifficultyEntry const *bracketEntry, bool isPremade, uint32 ArenaRating, uint32 MatchmakerRating, uint32 ArenaTeamId=0)
uint32 GetAverageQueueWaitTime(GroupQueueInfo *ginfo, BattlegroundBracketId bracket_id) const
BattlegroundQueueTypeId const GetQueueId() const
bool GetPlayerGroupInfoData(ObjectGuid guid, GroupQueueInfo *ginfo)
void RemovePlayer(ObjectGuid guid, bool decreaseInvitedCount)
uint32 GetMapId() const
BattlegroundTypeId GetTypeID() const
uint32 GetInstanceID() const
Definition: Battleground.h:283
BattlegroundPlayer const * GetBattlegroundPlayerData(ObjectGuid const &playerGuid) const
Definition: Battleground.h:489
bool isArena() const
uint32 GetMaxLevel() const
virtual void BuildPvPLogDataPacket(WorldPackets::Battleground::PVPMatchStatistics &pvpLogData) const
void PSendSysMessage(const char *fmt, Args &&... args)
Definition: Chat.h:57
void SetHomePosition(float x, float y, float z, float o)
Definition: Creature.h:371
CreatureMovementData const & GetMovementTemplate() const
Definition: Creature.cpp:2939
static PVPDifficultyEntry const * GetBattlegroundBracketByLevel(uint32 mapid, uint32 level)
Definition: DB2Stores.cpp:2768
GroupReference * next()
Definition: Group.h:197
uint32 GetMembersCount() const
Definition: Group.h:327
GroupReference * GetFirstMember()
Definition: Group.h:325
ObjectGuid GetLeaderGUID() const
Definition: Group.cpp:1658
GroupJoinBattlegroundResult CanJoinBattlegroundQueue(BattlegroundTemplate const *bgOrTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot, ObjectGuid &errorGuid) const
Definition: Group.cpp:1198
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
std::string ToString() const
Definition: ObjectGuid.cpp:554
uint32 GetEntry() const
Definition: Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
bool InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
Definition: Player.cpp:25025
void SetBGTeam(Team team)
Definition: Player.cpp:23603
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition: Player.cpp:1947
void SetBattlegroundId(uint32 val, BattlegroundTypeId bgTypeId, BattlegroundQueueTypeId queueId)
Definition: Player.cpp:25030
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6324
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={})
Definition: Player.cpp:1250
bool IsInvitedForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
Definition: Player.cpp:25017
void SetBattlegroundEntryPoint()
Definition: Player.cpp:23560
bool InBattleground() const
Definition: Player.h:2394
void SpawnCorpseBones(bool triggerSave=true)
Definition: Player.cpp:4598
void LeaveBattleground(bool teleportToEntryPoint=true)
Definition: Player.cpp:23614
uint32 GetBattlegroundQueueJoinTime(BattlegroundQueueTypeId bgQueueTypeId) const
Definition: Player.cpp:24984
WorldLocation m_homebind
Definition: Player.h:2503
bool IsDeserter() const
Definition: Player.h:2402
bool InBattlegroundQueue(bool ignoreArena=false) const
Definition: Player.cpp:24992
WorldSession * GetSession() const
Definition: Player.h:2101
void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val)
Definition: Player.cpp:25061
void SendAreaSpiritHealerTime(Unit *spiritHealer) const
Definition: Player.cpp:30146
void SendPvpRewards() const
Send conquest currency points and their cap week/arena.
Definition: Player.cpp:7088
bool CanJoinToBattleground(BattlegroundTemplate const *bg) const
Definition: Player.cpp:23638
bool HasFreeBattlegroundQueueId() const
Definition: Player.cpp:25053
void FinishTaxiFlight()
Definition: Player.cpp:22706
Battleground * GetBattleground() const
Definition: Player.cpp:24976
uint32 AddBattlegroundQueueId(BattlegroundQueueTypeId val)
Definition: Player.cpp:25037
uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const
Definition: Player.cpp:25009
void SetAreaSpiritHealer(Creature *creature)
Definition: Player.cpp:30130
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
void BuildPlayerRepop()
Definition: Player.cpp:4350
void ReportedAfkBy(Player *reporter)
This player has been blamed to be inactive in a battleground.
Definition: Player.cpp:23659
uint32 GetArenaTeamId(uint8) const
Definition: Player.h:2004
BattlegroundQueueTypeId GetBattlegroundQueueTypeId(uint32 index) const
Definition: Player.cpp:25001
Team GetTeam() const
Definition: Player.h:2235
bool GetBGAccessByLevel(BattlegroundTypeId bgTypeId) const
Definition: Player.cpp:25115
void ResurrectPlayer(float restore_percent, bool applySickness=false)
Definition: Player.cpp:4408
bool IsAreaSpiritHealer() const
Definition: Unit.h:1002
bool IsAreaSpiritHealerIndividual() const
Definition: Unit.h:1009
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition: Unit.cpp:10064
bool IsAlive() const
Definition: Unit.h:1164
bool IsInFlight() const
Definition: Unit.h:1012
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4560
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4664
uint8 GetLevel() const
Definition: Unit.h:746
bool IsInCombat() const
Definition: Unit.h:1043
Map * GetMap() const
Definition: Object.h:624
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
std::string const & GetName() const
Definition: Object.h:555
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1147
uint32 GetAreaId() const
Definition: Object.h:546
uint32 GetZoneId() const
Definition: Object.h:545
Underlying AsUnderlyingType() const
void HandleHearthAndResurrect(WorldPackets::Battleground::HearthAndResurrect &hearthAndResurrect)
void HandleBattlefieldLeaveOpcode(WorldPackets::Battleground::BattlefieldLeave &battlefieldLeave)
void HandleRequestBattlefieldStatusOpcode(WorldPackets::Battleground::RequestBattlefieldStatus &requestBattlefieldStatus)
void SendNotification(char const *format,...) ATTR_PRINTF(2
std::string GetPlayerInfo() const
void HandleGetPVPOptionsEnabled(WorldPackets::Battleground::GetPVPOptionsEnabled &getPvPOptionsEnabled)
Player * GetPlayer() const
void HandleRequestRatedPvpInfo(WorldPackets::Battleground::RequestRatedPvpInfo &packet)
void HandleBattleFieldPortOpcode(WorldPackets::Battleground::BattlefieldPort &battlefieldPort)
void HandleAreaSpiritHealerQueueOpcode(WorldPackets::Battleground::AreaSpiritHealerQueue &areaSpiritHealerQueue)
std::string const & GetRemoteAddress() const
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
Player * _player
void HandleBattlemasterJoinArena(WorldPackets::Battleground::BattlemasterJoinArena &packet)
void HandleBattlemasterJoinOpcode(WorldPackets::Battleground::BattlemasterJoin &battlemasterJoin)
void HandleRequestPvpReward(WorldPackets::Battleground::RequestPVPRewards &packet)
void HandleAreaSpiritHealerQueryOpcode(WorldPackets::Battleground::AreaSpiritHealerQuery &areaSpiritHealerQuery)
void HandlePVPLogDataOpcode(WorldPackets::Battleground::PVPLogDataRequest &pvpLogDataRequest)
void HandleReportPvPAFK(WorldPackets::Battleground::ReportPvPPlayerAFK &reportPvPPlayerAFK)
void HandleBattlefieldListOpcode(WorldPackets::Battleground::BattlefieldListRequest &battlefieldList)
void HandleBattlemasterHelloOpcode(WorldPackets::NPC::Hello &hello)
bool IsDisabledFor(DisableType type, uint32 entry, WorldObject const *ref, uint8 flags)
Definition: DisableMgr.cpp:285
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
EnumFlag< AreaFlags > GetFlags() const
Definition: DB2Structure.h:153
BattlegroundQueueTypeId queueTypeId
Definition: Battleground.h:176
static constexpr BattlegroundQueueTypeId FromPacked(uint64 packedQueueId)
BattlegroundTypeId Id
BattlemasterListEntry const * BattlemasterEntry
uint16 GetMaxPlayersPerTeam() const
uint16 GetMinPlayersPerTeam() const
EnumFlag< BattlemasterListFlags > GetFlags() const
Definition: DB2Structure.h:519
std::array< int16, 16 > MapID
Definition: DB2Structure.h:517
uint32 GetInteractionPauseTimer() const
Definition: CreatureData.h:407
uint32 IsInvitedToBGInstanceGUID
std::map< ObjectGuid, PlayerQueueInfo * > Players
uint32 OpponentsMatchmakerRating
uint32 OpponentsTeamRating
uint32 ArenaMatchmakerRating
BattlegroundBracketId GetBracketId() const
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81