TrinityCore
Loading...
Searching...
No Matches
BattlegroundMgr.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 "ArenaTeamMgr.h"
19#include "BattlegroundMgr.h"
20#include "BattlegroundAV.h"
21#include "BattlegroundAB.h"
22#include "BattlegroundEY.h"
23#include "BattlegroundWS.h"
24#include "BattlegroundNA.h"
25#include "BattlegroundBE.h"
26#include "BattlegroundRL.h"
27#include "BattlegroundSA.h"
28#include "BattlegroundDS.h"
29#include "BattlegroundRV.h"
30#include "BattlegroundIC.h"
31#include "BattlegroundPackets.h"
32#include "Common.h"
33#include "Containers.h"
34#include "Chat.h"
35#include "DatabaseEnv.h"
36#include "DisableMgr.h"
37#include "Formulas.h"
38#include "GameEventMgr.h"
39#include "GameTime.h"
40#include "Language.h"
41#include "Map.h"
42#include "MapManager.h"
43#include "MiscPackets.h"
44#include "SharedDefines.h"
45#include "ObjectMgr.h"
46#include "Opcodes.h"
47#include "Player.h"
48#include "World.h"
49#include "WorldPacket.h"
50
55
56/*********************************************************/
57/*** BATTLEGROUND MANAGER ***/
58/*********************************************************/
59
61 m_NextRatedArenaUpdate(sWorld->getIntConfig(CONFIG_ARENA_RATED_UPDATE_TIMER)),
62 m_NextAutoDistributionTime(0),
63 m_AutoDistributionTimeChecker(0), m_UpdateTimer(0), m_ArenaTesting(false), m_Testing(false)
64{ }
65
70
72{
73 for (auto& [_, data] : bgDataStore)
74 for (Battleground* battleground : data.BGFreeSlotQueue)
75 battleground->RemoveFromBGFreeSlotQueueOnShutdown();
76
77 bgDataStore.clear();
78}
79
85
86// used to update running battlegrounds, and delete finished ones
88{
89 m_UpdateTimer += diff;
91 {
92 for (BattlegroundDataContainer::iterator itr1 = bgDataStore.begin(); itr1 != bgDataStore.end(); ++itr1)
93 {
94 BattlegroundContainer& bgs = itr1->second.m_Battlegrounds;
95 BattlegroundContainer::iterator itrDelete = bgs.begin();
96 // first one is template and should not be deleted
97 for (BattlegroundContainer::iterator itr = ++itrDelete; itr != bgs.end();)
98 {
99 itrDelete = itr++;
100 Battleground* bg = itrDelete->second.get();
101
103 if (bg->ToBeDeleted())
104 {
105 BattlegroundClientIdsContainer& clients = itr1->second.m_ClientBattlegroundIds[bg->GetBracketId()];
106 if (!clients.empty())
107 clients.erase(bg->GetClientInstanceID());
108
109 // move out unique_ptr to delete after erasing
110 Trinity::unique_trackable_ptr<Battleground> bgPtr = std::move(itrDelete->second);
111
112 bgs.erase(itrDelete);
113 }
114 }
115 }
116
117 m_UpdateTimer = 0;
118 }
119
120 // update events timer
121 for (std::pair<BattlegroundQueueTypeId const, BattlegroundQueue>& pair : m_BattlegroundQueues)
122 pair.second.UpdateEvents(diff);
123
124 // update scheduled queues
125 if (!m_QueueUpdateScheduler.empty())
126 {
127 std::vector<ScheduledQueueUpdate> scheduled;
128 std::swap(scheduled, m_QueueUpdateScheduler);
129
130 for (auto& [arenaMMRating, bgQueueTypeId] : scheduled)
131 GetBattlegroundQueue(bgQueueTypeId).BattlegroundQueueUpdate(diff, arenaMMRating > 0, arenaMMRating);
132 }
133
134 // if rating difference counts, maybe force-update queues
136 {
137 // it's time to force update
138 if (m_NextRatedArenaUpdate < diff)
139 {
140 // forced update for rated arenas (scan all, but skipped non rated)
141 TC_LOG_TRACE("bg.arena", "BattlegroundMgr: UPDATING ARENA QUEUES");
143 {
144 for (int bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
145 {
146 BattlegroundQueueTypeId ratedArenaQueueId = BGQueueTypeId(BATTLEGROUND_AA, bracket, teamSize);
148 arenaQueue->BattlegroundQueueUpdate(diff, true, 0);
149 }
150 }
151
153 }
154 else
156 }
157
159 {
161 {
163 {
164 sArenaTeamMgr->DistributeArenaPoints();
165
166 time_t arenaDistributionTime = sWorld->getWorldState(WS_ARENA_DISTRIBUTION_TIME) == 0 ? m_NextAutoDistributionTime : time_t(sWorld->getWorldState(WS_ARENA_DISTRIBUTION_TIME));
169 }
170 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
171 }
172 else
174 }
175}
176
178{
179 header->QueueSlot = queueSlot;
180 header->QueueID = queueId.GetPacked();
181 header->RangeMin = bg->GetMinLevel();
182 header->RangeMax = bg->GetMaxLevel();
183 header->InstanceID = bg->GetClientInstanceID();
184 header->RegisteredMatch = bg->isRated();
185}
186
188{
189 battlefieldStatus->QueueSlot = queueSlot;
190}
191
193{
194 BuildBattlegroundStatusHeader(&battlefieldStatus->Hdr, bg, queueSlot, queueId);
195 battlefieldStatus->Mapid = bg->GetMapId();
196 battlefieldStatus->Timeout = timeout;
197}
198
200{
201 BuildBattlegroundStatusHeader(&battlefieldStatus->Hdr, bg, queueSlot, queueId);
202 battlefieldStatus->ShutdownTimer = bg->GetEndTime();
203 battlefieldStatus->ArenaFaction = player->GetBGTeam() == HORDE ? PVP_TEAM_HORDE : PVP_TEAM_ALLIANCE;
204 battlefieldStatus->StartTimer = bg->GetStartTime();
205 battlefieldStatus->Mapid = bg->GetMapId();
206 if (bg->IsRandom())
207 {
208 BattlegroundTemplate const* realTemplate = sBattlegroundMgr->GetBattlegroundTemplateByTypeId(bg->GetTypeID(true));
209 if (PvPDifficultyEntry const* realBracket = GetBattlegroundBracketByLevel(realTemplate->MapIDs.front(), DEFAULT_MAX_LEVEL))
210 battlefieldStatus->RandomQueueID = BattlegroundQueueTypeId{
211 .BattlemasterListId = uint16(realTemplate->Id),
212 .BracketId = uint8(realBracket->GetBracketId()),
213 .TeamSize = 0
214 }.GetPacked();
215 }
216}
217
219{
220 BuildBattlegroundStatusHeader(&battlefieldStatus->Hdr, bg, queueSlot, queueId);
221 battlefieldStatus->AverageWaitTime = avgWaitTime;
222 battlefieldStatus->WaitTime = GetMSTimeDiffToNow(joinTime);
223}
224
226{
227 battlefieldStatus->Reason = result;
228 if (errorGuid && (result == ERR_BATTLEGROUND_NOT_IN_BATTLEGROUND || result == ERR_BATTLEGROUND_JOIN_TIMED_OUT))
229 battlefieldStatus->ClientID = *errorGuid;
230}
231
233{
234 groupJoinedBattleground->Reason = bgTypeId;
235}
236
238{
239 //cause at HandleBattlegroundJoinOpcode the clients sends the instanceid he gets from
240 //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
242 if (!bg)
243 return nullptr;
244
245 if (bg->isArena())
246 return GetBattleground(instanceId, bgTypeId);
247
248 BattlegroundDataContainer::const_iterator it = bgDataStore.find(bgTypeId);
249 if (it == bgDataStore.end())
250 return nullptr;
251
252 for (BattlegroundContainer::const_iterator itr = it->second.m_Battlegrounds.begin(); itr != it->second.m_Battlegrounds.end(); ++itr)
253 {
254 if (itr->second->GetClientInstanceID() == instanceId)
255 return itr->second.get();
256 }
257
258 return nullptr;
259}
260
262{
263 if (!instanceId)
264 return nullptr;
265
266 BattlegroundDataContainer::const_iterator begin, end;
267
268 if (bgTypeId == BATTLEGROUND_TYPE_NONE)
269 {
270 begin = bgDataStore.begin();
271 end = bgDataStore.end();
272 }
273 else
274 {
275 end = bgDataStore.find(bgTypeId);
276 if (end == bgDataStore.end())
277 return nullptr;
278 begin = end++;
279 }
280
281 for (BattlegroundDataContainer::const_iterator it = begin; it != end; ++it)
282 {
283 BattlegroundContainer const& bgs = it->second.m_Battlegrounds;
284 BattlegroundContainer::const_iterator itr = bgs.find(instanceId);
285 if (itr != bgs.end())
286 return itr->second.get();
287 }
288
289 return nullptr;
290}
291
293{
294 BattlegroundDataContainer::const_iterator itr = bgDataStore.find(bgTypeId);
295 if (itr == bgDataStore.end())
296 return nullptr;
297
298 BattlegroundContainer const& bgs = itr->second.m_Battlegrounds;
299 //map is sorted and we can be sure that lowest instance id has only BG template
300 return bgs.empty() ? nullptr : bgs.begin()->second.get();
301}
302
304{
305 if (IsArenaType(bgTypeId))
306 return 0; //arenas don't have client-instanceids
307
308 // we create here an instanceid, which is just for
309 // displaying this to the client and without any other use..
310 // the client-instanceIds are unique for each battleground-type
311 // the instance-id just needs to be as low as possible, beginning with 1
312 // the following works, because std::set is default ordered with "<"
313 // the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
314
315 BattlegroundClientIdsContainer& clientIds = bgDataStore[bgTypeId].m_ClientBattlegroundIds[bracket_id];
316 uint32 lastId = 0;
317 for (BattlegroundClientIdsContainer::const_iterator itr = clientIds.begin(); itr != clientIds.end();)
318 {
319 if ((++lastId) != *itr) //if there is a gap between the ids, we will break..
320 break;
321 lastId = *itr;
322 }
323
324 clientIds.insert(++lastId);
325 return lastId;
326}
327
328// create a new battleground that will really be used to play
329Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId originalBgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated)
330{
331 BattlegroundTypeId bgTypeId = GetRandomBG(originalBgTypeId);
332
333 // get the template BG
334 Battleground* bg_template = GetBattlegroundTemplate(bgTypeId);
335
336 if (!bg_template)
337 {
338 TC_LOG_ERROR("bg.battleground", "Battleground: CreateNewBattleground - bg template not found for {}", bgTypeId);
339 return nullptr;
340 }
341
342 Battleground* bg = nullptr;
343 // create a copy of the BG template
344 switch (bgTypeId)
345 {
346 case BATTLEGROUND_AV:
347 bg = new BattlegroundAV(*(BattlegroundAV*)bg_template);
348 break;
349 case BATTLEGROUND_WS:
350 bg = new BattlegroundWS(*(BattlegroundWS*)bg_template);
351 break;
352 case BATTLEGROUND_AB:
353 bg = new BattlegroundAB(*(BattlegroundAB*)bg_template);
354 break;
355 case BATTLEGROUND_NA:
356 bg = new BattlegroundNA(*(BattlegroundNA*)bg_template);
357 break;
358 case BATTLEGROUND_BE:
359 bg = new BattlegroundBE(*(BattlegroundBE*)bg_template);
360 break;
361 case BATTLEGROUND_EY:
362 bg = new BattlegroundEY(*(BattlegroundEY*)bg_template);
363 break;
364 case BATTLEGROUND_RL:
365 bg = new BattlegroundRL(*(BattlegroundRL*)bg_template);
366 break;
367 case BATTLEGROUND_SA:
368 bg = new BattlegroundSA(*(BattlegroundSA*)bg_template);
369 break;
370 case BATTLEGROUND_DS:
371 bg = new BattlegroundDS(*(BattlegroundDS*)bg_template);
372 break;
373 case BATTLEGROUND_RV:
374 bg = new BattlegroundRV(*(BattlegroundRV*)bg_template);
375 break;
376 case BATTLEGROUND_IC:
377 bg = new BattlegroundIC(*(BattlegroundIC*)bg_template);
378 break;
379 case BATTLEGROUND_RB:
380 case BATTLEGROUND_AA:
381 default:
382 return nullptr;
383 }
384
385 bool isRandom = bgTypeId != originalBgTypeId && !bg->isArena();
386
387 bg->SetBracket(bracketEntry);
388 bg->SetInstanceID(sMapMgr->GenerateInstanceId());
389 bg->SetClientInstanceID(CreateClientVisibleInstanceId(originalBgTypeId, bracketEntry->GetBracketId()));
390 bg->Reset(); // reset the new bg (set status to status_wait_queue from status_none)
391 bg->SetStatus(STATUS_WAIT_JOIN); // start the joining of the bg
392 bg->SetArenaType(arenaType);
393 bg->SetTypeID(originalBgTypeId);
394 bg->SetRandomTypeID(bgTypeId);
395 bg->SetRated(isRated);
396 bg->SetRandom(isRandom);
397
398 // Set up correct min/max player counts for scoreboards
399 if (bg->isArena())
400 {
401 uint32 maxPlayersPerTeam = 0;
402 switch (arenaType)
403 {
404 case ARENA_TYPE_2v2:
405 maxPlayersPerTeam = 2;
406 break;
407 case ARENA_TYPE_3v3:
408 maxPlayersPerTeam = 3;
409 break;
410 case ARENA_TYPE_5v5:
411 maxPlayersPerTeam = 5;
412 break;
413 }
414
415 bg->SetMaxPlayersPerTeam(maxPlayersPerTeam);
416 bg->SetMaxPlayers(maxPlayersPerTeam * 2);
417 }
418
419 return bg;
420}
421
422// used to create the BG templates
424{
425 Battleground* bg = GetBattlegroundTemplate(bgTemplate->Id);
426 if (!bg)
427 {
428 // Create the BG
429 switch (bgTemplate->Id)
430 {
431 case BATTLEGROUND_AV:
432 bg = new BattlegroundAV();
433 break;
434 case BATTLEGROUND_WS:
435 bg = new BattlegroundWS();
436 break;
437 case BATTLEGROUND_AB:
438 bg = new BattlegroundAB();
439 break;
440 case BATTLEGROUND_NA:
441 bg = new BattlegroundNA();
442 break;
443 case BATTLEGROUND_BE:
444 bg = new BattlegroundBE();
445 break;
446 case BATTLEGROUND_EY:
447 bg = new BattlegroundEY();
448 break;
449 case BATTLEGROUND_RL:
450 bg = new BattlegroundRL();
451 break;
452 case BATTLEGROUND_SA:
453 bg = new BattlegroundSA();
454 break;
455 case BATTLEGROUND_DS:
456 bg = new BattlegroundDS();
457 break;
458 case BATTLEGROUND_RV:
459 bg = new BattlegroundRV();
460 break;
461 case BATTLEGROUND_IC:
462 bg = new BattlegroundIC();
463 break;
464 case BATTLEGROUND_AA:
465 bg = new Battleground();
466 break;
467 case BATTLEGROUND_RB:
468 bg = new Battleground();
469 bg->SetRandom(true);
470 break;
471 default:
472 return false;
473 }
474
475 bg->SetTypeID(bgTemplate->Id);
476 bg->SetInstanceID(0);
477 AddBattleground(bg);
478 }
479
480 bg->SetMapId(!bgTemplate->MapIDs.empty() ? bgTemplate->MapIDs.front() : -1);
481 bg->SetName(bgTemplate->BattlemasterEntry->Name[sWorld->GetDefaultDbcLocale()]);
482 bg->SetArenaorBGType(bgTemplate->IsArena());
485 bg->SetMinPlayers(bgTemplate->MinPlayersPerTeam * 2);
486 bg->SetMaxPlayers(bgTemplate->MaxPlayersPerTeam * 2);
489 bg->SetStartMaxDist(bgTemplate->MaxStartDistSq);
490 bg->SetLevelRange(bgTemplate->MinLevel, bgTemplate->MaxLevel);
491 bg->SetScriptId(bgTemplate->ScriptId);
492
493 return true;
494}
495
497{
498 uint32 oldMSTime = getMSTime();
499
502
503 // 0 1 2 3 4 5 6 7 8 9 10 11
504 QueryResult result = WorldDatabase.Query("SELECT ID, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, AllianceStartLoc, AllianceStartO, HordeStartLoc, HordeStartO, StartMaxDist, Weight, ScriptName FROM battleground_template");
505 if (!result)
506 {
507 TC_LOG_INFO("server.loading", ">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
508 return;
509 }
510
511 uint32 count = 0;
512
513 do
514 {
515 Field* fields = result->Fetch();
516
517 BattlegroundTypeId bgTypeId = BattlegroundTypeId(fields[0].GetUInt32());
518
520 continue;
521
522 // can be overwrite by values from DB
523 BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
524 if (!bl)
525 {
526 TC_LOG_ERROR("bg.battleground", "Battleground ID {} could not be found in BattlemasterList.dbc. The battleground was not created.", bgTypeId);
527 continue;
528 }
529
530 BattlegroundTemplate bgTemplate;
531 bgTemplate.Id = bgTypeId;
532 bgTemplate.MinPlayersPerTeam = fields[1].GetUInt16();
533 bgTemplate.MaxPlayersPerTeam = fields[2].GetUInt16();
534 bgTemplate.MinLevel = fields[3].GetUInt8();
535 bgTemplate.MaxLevel = fields[4].GetUInt8();
536 float dist = fields[9].GetFloat();
537 bgTemplate.MaxStartDistSq = dist * dist;
538 bgTemplate.Weight = fields[10].GetUInt8();
539 bgTemplate.ScriptId = sObjectMgr->GetScriptId(fields[11].GetString());
540 bgTemplate.BattlemasterEntry = bl;
541 for (int32 mapId : bl->MapID)
542 if (sMapStore.LookupEntry(mapId))
543 bgTemplate.MapIDs.push_back(mapId);
544
545 if (bgTemplate.MaxPlayersPerTeam == 0 || bgTemplate.MinPlayersPerTeam > bgTemplate.MaxPlayersPerTeam)
546 {
547 TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains bad values for MinPlayersPerTeam ({}) and MaxPlayersPerTeam({}).",
548 bgTemplate.Id, bgTemplate.MinPlayersPerTeam, bgTemplate.MaxPlayersPerTeam);
549 continue;
550 }
551
552 if (bgTemplate.MinLevel == 0 || bgTemplate.MaxLevel == 0 || bgTemplate.MinLevel > bgTemplate.MaxLevel)
553 {
554 TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains bad values for MinLevel ({}) and MaxLevel ({}).",
555 bgTemplate.Id, bgTemplate.MinLevel, bgTemplate.MaxLevel);
556 continue;
557 }
558
559 if (bgTemplate.Id != BATTLEGROUND_AA && bgTemplate.Id != BATTLEGROUND_RB)
560 {
561 uint32 startId = fields[5].GetUInt32();
562 if (WorldSafeLocsEntry const* start = sWorldSafeLocsStore.LookupEntry(startId))
563 {
564 bgTemplate.StartLocation[TEAM_ALLIANCE].Relocate(start->Loc.X, start->Loc.Y, start->Loc.Z, fields[6].GetFloat());
565 }
566 else
567 {
568 TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains a non-existing WorldSafeLocs.dbc id {} in field `AllianceStartLoc`. BG not created.", bgTemplate.Id, startId);
569 continue;
570 }
571
572 startId = fields[7].GetUInt32();
573 if (WorldSafeLocsEntry const* start = sWorldSafeLocsStore.LookupEntry(startId))
574 {
575 bgTemplate.StartLocation[TEAM_HORDE].Relocate(start->Loc.X, start->Loc.Y, start->Loc.Z, fields[8].GetFloat());
576 }
577 else
578 {
579 TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains a non-existing WorldSafeLocs.dbc id {} in field `HordeStartLoc`. BG not created.", bgTemplate.Id, startId);
580 continue;
581 }
582 }
583
584 if (!CreateBattleground(&bgTemplate))
585 continue;
586
587 _battlegroundTemplates[bgTypeId] = bgTemplate;
588
589 if (bgTemplate.MapIDs.size() == 1)
590 _battlegroundMapTemplates[bgTemplate.MapIDs[0]] = &_battlegroundTemplates[bgTypeId];
591
592 ++count;
593 }
594 while (result->NextRow());
595
596 TC_LOG_INFO("server.loading", ">> Loaded {} battlegrounds in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
597}
598
600{
602 return;
603
604 time_t wstime = time_t(sWorld->getWorldState(WS_ARENA_DISTRIBUTION_TIME));
605 time_t curtime = GameTime::GetGameTime();
606 TC_LOG_DEBUG("bg.battleground", "Initializing Automatic Arena Point Distribution");
607 if (wstime < curtime)
608 {
609 m_NextAutoDistributionTime = curtime; // reset will be called in the next update
610 TC_LOG_DEBUG("bg.battleground", "Battleground: Next arena point distribution time in the past, reseting it now.");
611 }
612 else
614 TC_LOG_DEBUG("bg.battleground", "Automatic Arena Point Distribution initialized.");
615}
616
618{
619 if (!player)
620 return;
621
622 uint32 winner_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_FIRST);
623 uint32 winner_arena = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_FIRST);
624 uint32 loser_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_FIRST);
625
626 winner_kills = Trinity::Honor::hk_honor_at_level(player->GetLevel(), float(winner_kills));
627 loser_kills = Trinity::Honor::hk_honor_at_level(player->GetLevel(), float(loser_kills));
628
630 battlefieldList.BattlemasterGuid = guid;
631 battlefieldList.PvpAnywhere = guid.IsEmpty();
632 battlefieldList.BattlemasterListID = bgTypeId;
633 battlefieldList.MinLevel = 0;
634 battlefieldList.MaxLevel = 0;
635
636 battlefieldList.HasHolidayWinToday = player->GetRandomWinner();
637 battlefieldList.HolidayWinHonorCurrencyBonus = winner_kills;
638 battlefieldList.HolidayFirstWinArenaCurrencyBonus = winner_arena;
639 battlefieldList.HolidayLossHonorCurrencyBonus = loser_kills;
640
641 battlefieldList.HasRandomWinToday = player->GetRandomWinner();
642 battlefieldList.RandomWinHonorCurrencyBonus = winner_kills;
643 battlefieldList.RandomFirstWinArenaCurrencyBonus = winner_arena;
644 battlefieldList.RandomLossHonorCurrencyBonus = loser_kills;
645
646 if (bgTypeId != BATTLEGROUND_AA)
647 {
648 if (BattlegroundData const* battlegrounds = Trinity::Containers::MapGetValuePtr(bgDataStore, bgTypeId))
649 {
650 // expected bracket entry
651 if (PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(battlegrounds->m_Battlegrounds.begin()->second->GetMapId(), player->GetLevel()))
652 battlefieldList.Battlefields = &battlegrounds->m_ClientBattlegroundIds[bracketEntry->GetBracketId()];
653 }
654 }
655
656 player->SendDirectMessage(battlefieldList.Write());
657}
658
660{
661 if (Battleground* bg = GetBattleground(instanceId, bgTypeId))
662 {
663 uint32 mapid = bg->GetMapId();
664 uint32 team = player->GetBGTeam();
665 if (team == 0)
666 team = player->GetTeam();
667
668 Position const* pos = bg->GetTeamStartPosition(Battleground::GetTeamIndexByTeamId(team));
669 TC_LOG_DEBUG("bg.battleground", "BattlegroundMgr::SendToBattleground: Sending {} to map {}, {} (bgType {})", player->GetName(), mapid, pos->ToString(), bgTypeId);
670 player->TeleportTo(mapid, pos->GetPositionX(), pos->GetPositionY(), pos->GetPositionZ(), pos->GetOrientation());
671 }
672 else
673 TC_LOG_ERROR("bg.battleground", "BattlegroundMgr::SendToBattleground: Instance {} (bgType {}) not found while trying to teleport player {}", instanceId, bgTypeId, player->GetName());
674}
675
677{
679 areaSpiritHealerTime.HealerGuid = guid;
680 areaSpiritHealerTime.TimeLeft = std::max(30000 - int32(bg->GetLastResurrectTime()), 0);
681 player->SendDirectMessage(areaSpiritHealerTime.Write());
682}
683
685{
686 return bgTypeId == BATTLEGROUND_AA
687 || bgTypeId == BATTLEGROUND_BE
688 || bgTypeId == BATTLEGROUND_NA
689 || bgTypeId == BATTLEGROUND_DS
690 || bgTypeId == BATTLEGROUND_RV
691 || bgTypeId == BATTLEGROUND_RL;
692}
693
695{
696 return battlemasterListId == BATTLEGROUND_RB;
697}
698
700{
701 return { .BattlemasterListId = uint16(bgTypeId), .BracketId = bracketId, .TeamSize = arenaType };
702}
703
709
715
717{
720 bg->SetHoliday(false);
721}
722
724{
726 bg->SetHoliday(true);
727}
728
730{
732 if (!battlemasterList)
733 return false;
734
735 switch (battlemasterList->BattlemasterEntry->InstanceType)
736 {
737 case MAP_BATTLEGROUND:
738 if (bgQueueTypeId.TeamSize)
739 return false;
740 break;
741 case MAP_ARENA:
742 if (!bgQueueTypeId.TeamSize)
743 return false;
744 break;
745 default:
746 break;
747 }
748
749 if (battlemasterList->MapIDs.empty())
750 return false;
751
752 if (!GetBattlegroundBracketById(battlemasterList->MapIDs[0], BattlegroundBracketId(bgQueueTypeId.BracketId)))
753 return false;
754
755 return true;
756}
757
759{
760 //This method must be atomic, @todo add mutex
761 //we will use only 1 number created of bgTypeId and bracket_id
762 ScheduledQueueUpdate scheduleId{ arenaMatchmakerRating, bgQueueTypeId };
763 if (std::find(m_QueueUpdateScheduler.begin(), m_QueueUpdateScheduler.end(), scheduleId) == m_QueueUpdateScheduler.end())
764 m_QueueUpdateScheduler.push_back(scheduleId);
765}
766
768{
769 // this is for stupid people who can't use brain and set max rating difference to 0
771 if (diff == 0)
772 diff = 5000;
773 return diff;
774}
775
780
785
787{
788 uint32 oldMSTime = getMSTime();
789
790 mBattleMastersMap.clear(); // need for reload case
791
792 QueryResult result = WorldDatabase.Query("SELECT entry, bg_template FROM battlemaster_entry");
793
794 if (!result)
795 {
796 TC_LOG_INFO("server.loading", ">> Loaded 0 battlemaster entries. DB table `battlemaster_entry` is empty!");
797 return;
798 }
799
800 uint32 count = 0;
801
802 do
803 {
804 ++count;
805
806 Field* fields = result->Fetch();
807
808 uint32 entry = fields[0].GetUInt32();
809 if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(entry))
810 {
811 if ((cInfo->npcflag & UNIT_NPC_FLAG_BATTLEMASTER) == 0)
812 TC_LOG_ERROR("sql.sql", "Creature (Entry: {}) listed in `battlemaster_entry` is not a battlemaster.", entry);
813 }
814 else
815 {
816 TC_LOG_ERROR("sql.sql", "Creature (Entry: {}) listed in `battlemaster_entry` does not exist.", entry);
817 continue;
818 }
819
820 uint32 bgTypeId = fields[1].GetUInt32();
821 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
822 {
823 TC_LOG_ERROR("sql.sql", "Table `battlemaster_entry` contains entry {} for a non-existing battleground type {}, ignored.", entry, bgTypeId);
824 continue;
825 }
826
827 mBattleMastersMap[entry] = BattlegroundTypeId(bgTypeId);
828 }
829 while (result->NextRow());
830
832
833 TC_LOG_INFO("server.loading", ">> Loaded {} battlemaster entries in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
834}
835
837{
838 CreatureTemplateContainer const& ctc = sObjectMgr->GetCreatureTemplates();
839 for (auto const& creatureTemplatePair : ctc)
840 {
841 if ((creatureTemplatePair.second.npcflag & UNIT_NPC_FLAG_BATTLEMASTER) && !mBattleMastersMap.count(creatureTemplatePair.first))
842 {
843 TC_LOG_ERROR("sql.sql", "Creature_Template Entry: {} has UNIT_NPC_FLAG_BATTLEMASTER, but no data in the `battlemaster_entry` table. Removing flag.", creatureTemplatePair.first);
844 const_cast<CreatureTemplate&>(creatureTemplatePair.second).npcflag &= ~UNIT_NPC_FLAG_BATTLEMASTER;
845 }
846 }
847}
848
862
876
881
883{
884 if (BattlegroundTemplate const* bgTemplate = GetBattlegroundTemplateByTypeId(bgTypeId))
885 {
886 std::vector<BattlegroundTemplate const*> ids;
887 ids.reserve(bgTemplate->MapIDs.size());
888 for (int32 mapId : bgTemplate->MapIDs)
890 ids.push_back(bg);
891
892 if (!ids.empty())
893 return (*Trinity::Containers::SelectRandomWeightedContainerElement(ids, [](BattlegroundTemplate const* bg) { return bg->Weight; }))->Id;
894 }
895
897}
898
903
905{
906 bgDataStore[bgTypeId].BGFreeSlotQueue.push_front(bg);
907}
908
910{
911 if (BattlegroundData* battlegroundData = Trinity::Containers::MapGetValuePtr(bgDataStore, bgTypeId))
912 {
913 auto itr = std::ranges::find(battlegroundData->BGFreeSlotQueue, instanceId, [](Battleground const* bg) { return bg->GetInstanceID(); });
914 if (itr != battlegroundData->BGFreeSlotQueue.end())
915 battlegroundData->BGFreeSlotQueue.erase(itr);
916 }
917}
918
920{
921 if (bg)
922 {
924 ptr.reset(bg);
925 bg->SetWeakPtr(ptr);
926 }
927}
#define sArenaTeamMgr
@ BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY
@ BATTLEGROUND_OBJECTIVE_UPDATE_INTERVAL
std::set< uint32 > BattlegroundClientIdsContainer
std::map< uint32, Trinity::unique_trackable_ptr< Battleground > > BattlegroundContainer
#define sBattlegroundMgr
std::list< Battleground * > BGFreeSlotQueueContainer
@ ARENA_TYPE_5v5
@ ARENA_TYPE_3v3
@ ARENA_TYPE_2v2
@ STATUS_WAIT_JOIN
@ MAP_BATTLEGROUND
Definition DBCEnums.h:338
@ MAP_ARENA
Definition DBCEnums.h:339
#define MAX_BATTLEGROUND_BRACKETS
Definition DBCEnums.h:63
BattlegroundBracketId
Definition DBCEnums.h:57
@ BG_BRACKET_ID_FIRST
Definition DBCEnums.h:58
@ DEFAULT_MAX_LEVEL
Definition DBCEnums.h:45
DBCStorage< WorldSafeLocsEntry > sWorldSafeLocsStore(WorldSafeLocsEntryfmt)
DBCStorage< BattlemasterListEntry > sBattlemasterListStore(BattlemasterListEntryfmt)
PvPDifficultyEntry const * GetBattlegroundBracketByLevel(uint32 mapid, uint32 level)
PvPDifficultyEntry const * GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id)
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint64_t uint64
Definition Define.h:132
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
@ DISABLE_TYPE_BATTLEGROUND
Definition DisableMgr.h:30
bool IsHolidayActive(HolidayIds id)
@ LANG_DEBUG_BG_OFF
Definition Language.h:733
@ LANG_DEBUG_ARENA_OFF
Definition Language.h:731
@ LANG_DEBUG_BG_ON
Definition Language.h:732
@ LANG_DEBUG_ARENA_ON
Definition Language.h:730
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_TRACE(filterType__,...)
Definition Log.h:153
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
#define sMapMgr
Definition MapManager.h:211
#define sObjectMgr
Definition ObjectMgr.h:1721
std::unordered_map< uint32, CreatureTemplate > CreatureTemplateContainer
Definition ObjectMgr.h:535
GroupJoinBattlegroundResult
@ ERR_BATTLEGROUND_JOIN_TIMED_OUT
@ ERR_BATTLEGROUND_NOT_IN_BATTLEGROUND
@ PVP_TEAM_HORDE
@ PVP_TEAM_ALLIANCE
@ TEAM_ALLIANCE
@ TEAM_HORDE
@ HORDE
BattlegroundTypeId
@ BATTLEGROUND_IC
@ BATTLEGROUND_AA
@ BATTLEGROUND_WS
@ BATTLEGROUND_EY
@ BATTLEGROUND_AV
@ BATTLEGROUND_BE
@ BATTLEGROUND_RV
@ BATTLEGROUND_TYPE_NONE
@ BATTLEGROUND_NA
@ BATTLEGROUND_DS
@ BATTLEGROUND_SA
@ BATTLEGROUND_AB
@ BATTLEGROUND_RL
@ BATTLEGROUND_RB
HolidayIds
@ HOLIDAY_NONE
@ HOLIDAY_CALL_TO_ARMS_AB
@ HOLIDAY_CALL_TO_ARMS_EY
@ HOLIDAY_CALL_TO_ARMS_SA
@ HOLIDAY_CALL_TO_ARMS_IC
@ HOLIDAY_CALL_TO_ARMS_AV
@ HOLIDAY_CALL_TO_ARMS_WS
#define MAX_BATTLEGROUND_TYPE_ID
@ WS_ARENA_DISTRIBUTION_TIME
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
@ UNIT_NPC_FLAG_BATTLEMASTER
Battleground * GetBattlegroundThroughClientInstance(uint32 instanceId, BattlegroundTypeId bgTypeId)
BattlegroundMapTemplateContainer _battlegroundMapTemplates
static void BuildBattlegroundStatusHeader(WorldPackets::Battleground::BattlefieldStatusHeader *header, Battleground const *bg, uint32 queueSlot, BattlegroundQueueTypeId queueId)
std::map< BattlegroundQueueTypeId, BattlegroundQueue > m_BattlegroundQueues
BattlegroundTemplate const * GetBattlegroundTemplateByMapId(uint32 mapId)
void AddToBGFreeSlotQueue(BattlegroundTypeId bgTypeId, Battleground *bg)
std::vector< ScheduledQueueUpdate > m_QueueUpdateScheduler
static void BuildGroupJoinedBattlegroundPacket(WorldPackets::Battleground::GroupJoinedBattleground *groupJoinedBattleground, BattlegroundTypeId bgTypeId)
Battleground * GetBattleground(uint32 InstanceID, BattlegroundTypeId bgTypeId)
static void BuildBattlegroundStatusNeedConfirmation(WorldPackets::Battleground::BattlefieldStatusNeedConfirmation *battlefieldStatus, Battleground const *bg, uint32 queueSlot, uint32 timeout, BattlegroundQueueTypeId queueId)
static BattlegroundQueueTypeId BGQueueTypeId(BattlegroundTypeId bgTypeId, uint8 bracketId, uint8 arenaType)
BattlegroundTemplateMap _battlegroundTemplates
uint32 GetMaxRatingDifference() const
void SetHolidayActive(uint32 battlegroundId)
static BattlegroundMgr * instance()
uint32 m_AutoDistributionTimeChecker
bool IsValidQueueId(BattlegroundQueueTypeId bgQueueTypeId)
static void BuildBattlegroundStatusQueued(WorldPackets::Battleground::BattlefieldStatusQueued *battlefieldStatus, Battleground const *bg, uint32 queueSlot, uint32 joinTime, BattlegroundQueueTypeId queueId, uint32 avgWaitTime)
BattlegroundTypeId GetRandomBG(BattlegroundTypeId id)
bool CreateBattleground(BattlegroundTemplate const *bgTemplate)
static bool IsArenaType(BattlegroundTypeId bgTypeId)
BGFreeSlotQueueContainer & GetBGFreeSlotQueueStore(BattlegroundTypeId bgTypeId)
BattlegroundQueue & GetBattlegroundQueue(BattlegroundQueueTypeId bgQueueTypeId)
void AddBattleground(Battleground *bg)
time_t m_NextAutoDistributionTime
void RemoveFromBGFreeSlotQueue(BattlegroundTypeId bgTypeId, uint32 instanceId)
void ScheduleQueueUpdate(uint32 arenaMatchmakerRating, BattlegroundQueueTypeId bgQueueTypeId)
BattleMastersMap mBattleMastersMap
static bool IsRandomBattleground(uint32 battlemasterListId)
void SendBattlegroundList(Player *player, ObjectGuid const &guid, BattlegroundTypeId bgTypeId)
BattlegroundTemplate const * GetBattlegroundTemplateByTypeId(BattlegroundTypeId id)
Battleground * CreateNewBattleground(BattlegroundTypeId bgTypeId, PvPDifficultyEntry const *bracketEntry, uint8 arenaType, bool isRated)
void SendToBattleground(Player *player, uint32 InstanceID, BattlegroundTypeId bgTypeId)
void InitAutomaticArenaPointDistribution()
uint32 GetRatingDiscardTimer() const
static void BuildBattlegroundStatusFailed(WorldPackets::Battleground::BattlefieldStatusFailed *battlefieldStatus, GroupJoinBattlegroundResult result, ObjectGuid const *errorGuid=nullptr)
static BattlegroundTypeId WeekendHolidayIdToBGType(HolidayIds holiday)
static HolidayIds BGTypeToWeekendHolidayId(BattlegroundTypeId bgTypeId)
Battleground * GetBattlegroundTemplate(BattlegroundTypeId bgTypeId)
uint32 GetPrematureFinishTime() const
void SendAreaSpiritHealerQueryOpcode(Player *player, Battleground *bg, ObjectGuid guid)
uint32 CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
static void BuildBattlegroundStatusNone(WorldPackets::Battleground::BattlefieldStatusNone *battlefieldStatus, uint32 queueSlot)
void Update(uint32 diff)
uint32 m_NextRatedArenaUpdate
static bool IsBGWeekend(BattlegroundTypeId bgTypeId)
BattlegroundDataContainer bgDataStore
static void BuildBattlegroundStatusActive(WorldPackets::Battleground::BattlefieldStatusActive *battlefieldStatus, Battleground const *bg, Player const *player, uint32 queueSlot, BattlegroundQueueTypeId queueId)
void BattlegroundQueueUpdate(uint32 diff, bool isRated=false, uint32 minRating=0)
Class for manage Strand of Ancient battleground.
void SetMapId(uint32 MapID)
void SetInstanceID(uint32 InstanceID)
uint32 GetMapId() const
BattlegroundTypeId GetTypeID(bool GetRandom=false) const
bool ToBeDeleted() const
uint32 GetMinLevel() const
void SetRandom(bool isRandom)
void SetMaxPlayers(uint32 MaxPlayers)
static TeamId GetTeamIndexByTeamId(uint32 Team)
virtual void Reset()
void SetName(std::string const &name)
uint32 GetEndTime() const
void SetScriptId(uint32 scriptId)
bool isRated() const
void SetBracket(PvPDifficultyEntry const *bracketEntry)
void SetMinPlayersPerTeam(uint32 MinPlayers)
void SetRated(bool state)
void SetStartMaxDist(float startMaxDist)
void Update(uint32 diff)
uint32 GetInstanceID() const
void SetLevelRange(uint32 min, uint32 max)
uint32 GetClientInstanceID() const
void SetClientInstanceID(uint32 InstanceID)
void SetStatus(BattlegroundStatus Status)
bool isArena() const
void SetArenaType(uint8 type)
void SetRandomTypeID(BattlegroundTypeId TypeID)
uint32 GetStartTime() const
void SetArenaorBGType(bool _isArena)
bool IsRandom() const
uint32 GetLastResurrectTime() const
void SetTeamStartPosition(TeamId teamId, Position const &pos)
BattlegroundBracketId GetBracketId() const
uint32 GetMaxLevel() const
void SetMinPlayers(uint32 MinPlayers)
void SetMaxPlayersPerTeam(uint32 MaxPlayers)
void SetWeakPtr(Trinity::unique_weak_ptr< Battleground > weakRef)
void SetTypeID(BattlegroundTypeId TypeID)
Class used to access individual fields of database query result.
Definition Field.h:92
uint8 GetUInt8() const
Definition Field.cpp:29
uint16 GetUInt16() const
Definition Field.cpp:45
float GetFloat() const
Definition Field.cpp:93
uint32 GetUInt32() const
Definition Field.cpp:61
bool IsEmpty() const
Definition ObjectGuid.h:172
uint32 GetTeam() const
Definition Player.h:1832
uint32 GetBGTeam() const
Definition Player.cpp:21950
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6161
bool GetRandomWinner() const
Definition Player.h:2019
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options=0)
Definition Player.cpp:1524
Specialized variant of std::shared_ptr that enforces unique ownership and/or std::unique_ptr with std...
uint8 GetLevel() const
Definition Unit.h:889
std::string const & GetName() const
Definition Object.h:382
#define sWorld
Definition World.h:900
@ CONFIG_ARENA_MAX_RATING_DIFFERENCE
Definition World.h:317
@ CONFIG_BG_REWARD_LOSER_HONOR_LAST
Definition World.h:380
@ CONFIG_ARENA_RATED_UPDATE_TIMER
Definition World.h:320
@ CONFIG_BG_REWARD_WINNER_ARENA_FIRST
Definition World.h:376
@ CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS
Definition World.h:321
@ CONFIG_BG_REWARD_WINNER_ARENA_LAST
Definition World.h:378
@ CONFIG_BG_REWARD_WINNER_HONOR_FIRST
Definition World.h:375
@ CONFIG_BG_REWARD_LOSER_HONOR_FIRST
Definition World.h:379
@ CONFIG_ARENA_RATING_DISCARD_TIMER
Definition World.h:318
@ CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER
Definition World.h:314
@ CONFIG_BG_REWARD_WINNER_HONOR_LAST
Definition World.h:377
@ CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS
Definition World.h:130
@ CONFIG_ARENA_SEASON_IN_PROGRESS
Definition World.h:132
bool IsDisabledFor(DisableType type, uint32 entry, WorldObject const *ref, uint8 flags)
time_t GetGameTime()
Definition GameTime.cpp:42
auto SelectRandomWeightedContainerElement(C const &container, std::vector< double > weights) -> decltype(std::begin(container))
Definition Containers.h:125
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:29
uint32 hk_honor_at_level(uint8 level, float multiplier=1.0f)
Definition Formulas.h:41
constexpr uint64 GetPacked() const
BattlegroundTypeId Id
BattlemasterListEntry const * BattlemasterEntry
Position StartLocation[PVP_TEAMS_COUNT]
std::vector< int32 > MapIDs
char const * Name[16]
std::string ToString() const
Definition Position.cpp:149
float GetPositionZ() const
Definition Position.h:81
float GetOrientation() const
Definition Position.h:82
float GetPositionX() const
Definition Position.h:79
float GetPositionY() const
Definition Position.h:80
void Relocate(float x, float y)
Definition Position.h:66
BattlegroundBracketId GetBracketId() const