TrinityCore
Loading...
Searching...
No Matches
Battleground.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 "Battleground.h"
19#include "BattlegroundMgr.h"
20#include "BattlegroundPackets.h"
21#include "BattlegroundScore.h"
22#include "BattlegroundScript.h"
23#include "ChatTextBuilder.h"
24#include "Creature.h"
25#include "CreatureTextMgr.h"
26#include "DatabaseEnv.h"
27#include "DB2Stores.h"
28#include "Formulas.h"
29#include "GameEventSender.h"
30#include "GameTime.h"
31#include "GridNotifiersImpl.h"
32#include "Group.h"
33#include "Guild.h"
34#include "GuildMgr.h"
35#include "KillRewarder.h"
36#include "Language.h"
37#include "Log.h"
38#include "Map.h"
39#include "MapUtils.h"
40#include "MiscPackets.h"
41#include "ObjectAccessor.h"
42#include "ObjectMgr.h"
43#include "Player.h"
44#include "ReputationMgr.h"
45#include "SpellAuras.h"
46#include "TemporarySummon.h"
47#include "Transport.h"
48#include "Util.h"
49#include "WorldStateMgr.h"
50#include <cstdarg>
51
52template<class Do>
54{
55 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
56 if (Player* player = _GetPlayer(itr, "BroadcastWorker"))
57 _do(player);
58}
59
60Battleground::Battleground(BattlegroundTemplate const* battlegroundTemplate) : _battlegroundTemplate(battlegroundTemplate), _pvpDifficultyEntry(nullptr), _pvpStatIds(nullptr), _preparationStartTime(0)
61{
62 ASSERT(_battlegroundTemplate, "Nonexisting Battleground Template passed to battleground ctor!");
63
64 m_InstanceID = 0;
67 m_EndTime = 0;
70 m_ArenaType = 0;
72 m_StartTime = 0;
75 m_Events = 0;
77 m_IsRated = false;
78 m_InBGFreeSlotQueue = false;
79 m_SetDeleteThis = false;
80
81 m_Map = nullptr;
82
85
86 m_BgRaids[TEAM_ALLIANCE] = nullptr;
87 m_BgRaids[TEAM_HORDE] = nullptr;
88
91
94
97
99
104
109}
110
112
114{
115 // unload map
116 if (m_Map)
117 {
118 m_Map->UnloadAll(); // unload all objects (they may hold a reference to bg in their ZoneScript pointer)
119 m_Map->SetUnload(); // mark for deletion by MapManager
120
121 //unlink to prevent crash, always unlink all pointer reference before destruction
122 m_Map->SetBG(nullptr);
123 m_Map = nullptr;
124 }
125 // remove from bg free slot queue
127
128 for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr)
129 delete itr->second;
130
131 _playerPositions.clear();
132}
133
135{
136 if (!PreUpdateImpl(diff))
137 return;
138
139 if (!GetPlayersSize())
140 {
141 //BG is empty
142 // if there are no players invited, delete BG
143 // this will delete arena or bg object, where any player entered
144 // [[ but if you use battleground object again (more battles possible to be played on 1 instance)
145 // then this condition should be removed and code:
146 // if (!GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
147 // AddToFreeBGObjectsQueue(); // not yet implemented
148 // should be used instead of current
149 // ]]
150 // Battleground Template instance cannot be updated, because it would be deleted
152 m_SetDeleteThis = true;
153 return;
154 }
155
156 switch (GetStatus())
157 {
158 case STATUS_WAIT_JOIN:
159 if (GetPlayersSize())
160 {
161 _ProcessJoin(diff);
163 }
164 break;
168 // after 47 minutes without one team losing, the arena closes with no winner and no rating change
169 if (isArena())
170 {
172 {
174 return;
175 }
176 }
177 else
178 {
180 _ProcessProgress(diff);
181 else if (m_PrematureCountDown)
182 m_PrematureCountDown = false;
183 }
184 break;
186 _ProcessLeave(diff);
187 break;
188 default:
189 break;
190 }
191
192 // Update start time and reset stats timer
195 m_ResetStatTimer += diff;
196
197 PostUpdateImpl(diff);
198}
199
201{
202 float maxDist = GetStartMaxDist();
203 if (!maxDist)
204 return;
205
208 {
210
211 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
212 {
213 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
214 {
215 if (player->IsGameMaster())
216 continue;
217
218 Position pos = player->GetPosition();
219 WorldSafeLocsEntry const* startPos = GetTeamStartPosition(Battleground::GetTeamIndexByTeamId(player->GetBGTeam()));
220 if (pos.GetExactDistSq(startPos->Loc) > maxDist)
221 {
222 TC_LOG_DEBUG("bg.battleground", "BATTLEGROUND: Sending {} back to start location (map: {}) (possible exploit)", player->GetName(), GetMapId());
223 player->TeleportTo(startPos->Loc);
224 }
225 }
226 }
227 }
228}
229
231{
234 {
236
238
240 {
241 // Update position data if we found player.
242 if (Player* player = ObjectAccessor::GetPlayer(GetBgMap(), playerPosition.Guid))
243 playerPosition.Pos = player->GetPosition();
244
245 playerPositions.FlagCarriers.push_back(playerPosition);
246 }
247
248 SendPacketToAll(playerPositions.Write());
249 }
250}
251
253{
254 // remove offline players from bg after 5 minutes
255 if (!m_OfflineQueue.empty())
256 {
257 BattlegroundPlayerMap::iterator itr = m_Players.find(*(m_OfflineQueue.begin()));
258 if (itr != m_Players.end())
259 {
260 if (itr->second.OfflineRemoveTime <= GameTime::GetGameTime())
261 {
262 RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
263 m_OfflineQueue.pop_front(); // remove from offline queue
264 //do not use itr for anything, because it is erased in RemovePlayerAtLeave()
265 }
266 }
267 }
268}
269
271{
272 Team winner = TEAM_OTHER;
274 winner = ALLIANCE;
276 winner = HORDE;
277
278 return winner;
279}
280
282{
283 // *********************************************************
284 // *** BATTLEGROUND BALLANCE SYSTEM ***
285 // *********************************************************
286 // if less then minimum players are in on one side, then start premature finish timer
288 {
290 m_PrematureCountDownTimer = sBattlegroundMgr->GetPrematureFinishTime();
291 }
292 else if (m_PrematureCountDownTimer < diff)
293 {
294 // time's up!
296 m_PrematureCountDown = false;
297 }
298 else if (!sBattlegroundMgr->isTesting())
299 {
300 uint32 newtime = m_PrematureCountDownTimer - diff;
301 // announce every minute
302 if (newtime > (MINUTE * IN_MILLISECONDS))
303 {
306 }
307 else
308 {
309 //announce every 15 seconds
310 if (newtime / (15 * IN_MILLISECONDS) != m_PrematureCountDownTimer / (15 * IN_MILLISECONDS))
312 }
314 }
315}
316
318{
319 // *********************************************************
320 // *** BATTLEGROUND STARTING SYSTEM ***
321 // *********************************************************
323
324 if (!isArena())
325 SetRemainingTime(300000);
326
327 if (m_ResetStatTimer > 5000)
328 {
330 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
331 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
332 player->ResetAllPowers();
333 }
334
336 {
338
339 if (!FindBgMap())
340 {
341 TC_LOG_ERROR("bg.battleground", "Battleground::_ProcessJoin: map (map id: {}, instance id: {}) is not created!", GetMapId(), m_InstanceID);
342 EndNow();
343 return;
344 }
345
347 for (Group* group : m_BgRaids)
348 if (group)
350
353 // First start warning - 2 or 1 minute
356 }
357 // After 1 minute or 30 seconds, warning is signaled
359 {
364 }
365 // After 30 or 15 seconds, warning is signaled
367 {
372 }
373 // Delay expired (after 2 or 1 minute)
374 else if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4))
375 {
377
379
384
386
387 for (auto const& [guid, _] : GetPlayers())
388 {
389 if (Player* player = ObjectAccessor::GetPlayer(GetBgMap(), guid))
390 {
391 player->StartCriteria(CriteriaStartEvent::StartBattleground, GetBgMap()->GetId());
392 player->AtStartOfEncounter(EncounterType::Battleground);
393 }
394 }
395
396 // Remove preparation
397 if (isArena())
398 {
400 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
401 {
402 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
403 {
404 // Correctly display EnemyUnitFrame
405 player->SetArenaFaction(player->GetBGTeam());
406
407 player->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
408 player->ResetAllPowers();
409 if (!player->IsGameMaster())
410 {
411 // remove auras with duration lower than 30s
412 player->RemoveAppliedAuras([](AuraApplication const* aurApp)
413 {
414 Aura* aura = aurApp->GetBase();
415 return !aura->IsPermanent()
416 && aura->GetDuration() <= 30 * IN_MILLISECONDS
417 && aurApp->IsPositive()
420 });
421 }
422 }
423 }
424
426 }
427 else
428 {
430
431 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
432 {
433 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
434 {
435 player->RemoveAurasDueToSpell(SPELL_PREPARATION);
436 player->ResetAllPowers();
437 }
438 }
439 // Announce BG starting
442 }
443 }
444
445 if (GetRemainingTime() > 0 && (m_EndTime -= diff) > 0)
447}
448
450{
451 // *********************************************************
452 // *** BATTLEGROUND ENDING SYSTEM ***
453 // *********************************************************
454 // remove all players from battleground after 2 minutes
456 if (GetRemainingTime() <= 0)
457 {
459 BattlegroundPlayerMap::iterator itr, next;
460 for (itr = m_Players.begin(); itr != m_Players.end(); itr = next)
461 {
462 next = itr;
463 ++next;
464 //itr is erased here!
465 RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
466 // do not change any battleground's private variables
467 }
468 }
469}
470
471Player* Battleground::_GetPlayer(ObjectGuid guid, bool offlineRemove, char const* context) const
472{
473 Player* player = nullptr;
474 if (!offlineRemove)
475 {
476 // should this be ObjectAccessor::FindConnectedPlayer() to return players teleporting ?
477 player = ObjectAccessor::FindPlayer(guid);
478 if (!player)
479 TC_LOG_ERROR("bg.battleground", "Battleground::{}: player ({}) not found for BG (map: {}, instance id: {})!",
480 context, guid.ToString(), GetMapId(), m_InstanceID);
481 }
482 return player;
483}
484
485Player* Battleground::_GetPlayerForTeam(Team team, BattlegroundPlayerMap::const_iterator itr, char const* context) const
486{
487 Player* player = _GetPlayer(itr, context);
488 if (player)
489 {
490 Team playerTeam = itr->second.Team;
491 if (!playerTeam)
492 playerTeam = player->GetEffectiveTeam();
493 if (playerTeam != team)
494 player = nullptr;
495 }
496 return player;
497}
498
500{
501 ASSERT(m_Map);
502 return m_Map;
503}
504
510
515
517{
518 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
519 if (Player* player = _GetPlayer(itr, "SendPacketToAll"))
520 player->SendDirectMessage(packet);
521}
522
523void Battleground::SendPacketToTeam(Team team, WorldPacket const* packet, Player* except /*= nullptr*/) const
524{
525 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
526 {
527 if (Player* player = _GetPlayerForTeam(team, itr, "SendPacketToTeam"))
528 if (player != except)
529 player->SendDirectMessage(packet);
530 }
531}
532
533void Battleground::SendChatMessage(Creature* source, uint8 textId, WorldObject* target /*= nullptr*/)
534{
535 sCreatureTextMgr->SendChat(source, textId, target);
536}
537
539{
540 if (!sBroadcastTextStore.LookupEntry(id))
541 {
542 TC_LOG_ERROR("bg.battleground", "Battleground::SendBroadcastText: `broadcast_text` (ID: {}) was not found", id);
543 return;
544 }
545
546 Trinity::BroadcastTextBuilder builder(nullptr, msgType, id, GENDER_MALE, target);
548 BroadcastWorker(localizer);
549}
550
555
560
562{
563 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
564 if (Player* player = _GetPlayerForTeam(team, itr, "CastSpellOnTeam"))
565 player->CastSpell(player, SpellID, true);
566}
567
569{
570 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
571 if (Player* player = _GetPlayerForTeam(team, itr, "RemoveAuraOnTeam"))
572 player->RemoveAura(SpellID);
573}
574
576{
577 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
578 if (Player* player = _GetPlayerForTeam(team, itr, "RewardHonorToTeam"))
580}
581
582void Battleground::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, Team team)
583{
584 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
585 if (!factionEntry)
586 return;
587
588 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
589 {
590 Player* player = _GetPlayerForTeam(team, itr, "RewardReputationToTeam");
591 if (!player)
592 continue;
593
595 continue;
596
597 uint32 repGain = Reputation;
600 player->GetReputationMgr().ModifyReputation(factionEntry, repGain);
601 }
602}
603
604void Battleground::UpdateWorldState(int32 worldStateId, int32 value, bool hidden /*= false*/)
605{
606 WorldStateMgr::SetValue(worldStateId, value, hidden, GetBgMap());
607}
608
610{
612
613 bool guildAwarded = false;
614
615 if (winner == ALLIANCE)
616 {
617 if (isBattleground())
619
620 PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound
621
623 }
624 else if (winner == HORDE)
625 {
626 if (isBattleground())
628
629 PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
630
632 }
633 else
634 {
636 }
637
639 uint64 battlegroundId = 1;
641 {
642 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PVPSTATS_MAXID);
643 PreparedQueryResult result = CharacterDatabase.Query(stmt);
644
645 if (result)
646 {
647 Field* fields = result->Fetch();
648 battlegroundId = fields[0].GetUInt64() + 1;
649 }
650
651 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_BATTLEGROUND);
652 stmt->setUInt64(0, battlegroundId);
653 stmt->setUInt8(1, GetWinner());
654 stmt->setUInt8(2, GetUniqueBracketId());
655 stmt->setUInt32(3, GetTypeID());
656 CharacterDatabase.Execute(stmt);
657 }
658
660 //we must set it this way, because end time is sent in packet!
662
664 pvpMatchComplete.Winner = GetWinner();
665 pvpMatchComplete.Duration = std::chrono::duration_cast<Seconds>(Milliseconds(std::max<int32>(0, (GetElapsedTime() - BG_START_DELAY_2M))));
666 pvpMatchComplete.LogData.emplace();
667 BuildPvPLogDataPacket(*pvpMatchComplete.LogData);
668 pvpMatchComplete.Write();
669
670 for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
671 {
672 Team team = itr->second.Team;
673
674 Player* player = _GetPlayer(itr, "EndBattleground");
675 if (!player)
676 continue;
677
678 // should remove spirit of redemption
681
682 if (!player->IsAlive())
683 {
684 player->ResurrectPlayer(1.0f);
685 player->SpawnCorpseBones();
686 }
687 else
688 //needed cause else in av some creatures will kill the players at the end
689 player->CombatStop();
690
691 // remove temporary currency bonus auras before rewarding player
694
695 uint32 winnerKills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_FIRST);
696 uint32 loserKills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_FIRST);
697
699 {
700 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_PLAYER);
701 BattlegroundScoreMap::const_iterator score = PlayerScores.find(player->GetGUID());
702
703 stmt->setUInt32(0, battlegroundId);
704 stmt->setUInt64(1, player->GetGUID().GetCounter());
705 stmt->setBool (2, team == winner);
706 stmt->setUInt32(3, score->second->GetKillingBlows());
707 stmt->setUInt32(4, score->second->GetDeaths());
708 stmt->setUInt32(5, score->second->GetHonorableKills());
709 stmt->setUInt32(6, score->second->GetBonusHonor());
710 stmt->setUInt32(7, score->second->GetDamageDone());
711 stmt->setUInt32(8, score->second->GetHealingDone());
712 stmt->setUInt32(9, score->second->GetAttr(0));
713 stmt->setUInt32(10, score->second->GetAttr(1));
714 stmt->setUInt32(11, score->second->GetAttr(2));
715 stmt->setUInt32(12, score->second->GetAttr(3));
716 stmt->setUInt32(13, score->second->GetAttr(4));
717
718 CharacterDatabase.Execute(stmt);
719 }
720
721 // Reward winner team
722 if (team == winner)
723 {
724 if (BattlegroundPlayer const* bgPlayer = GetBattlegroundPlayerData(player->GetGUID()))
725 {
726 if (BattlegroundMgr::IsRandomBattleground(bgPlayer->queueTypeId.BattlemasterListId)
727 || BattlegroundMgr::IsBGWeekend(BattlegroundTypeId(bgPlayer->queueTypeId.BattlemasterListId)))
728 {
730 if (!player->GetRandomWinner())
732
733 UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(winnerKills), true, source);
734 if (!player->GetRandomWinner())
735 {
736 player->SetRandomWinner(true);
737 // TODO: win honor xp
738 }
739 }
740 else
741 {
742 // TODO: loss honor xp
743 }
744 }
745
747 if (!guildAwarded)
748 {
749 guildAwarded = true;
750 if (ObjectGuid::LowType guildId = GetBgMap()->GetOwnerGuildId(player->GetBGTeam()))
751 {
752 if (Guild* guild = sGuildMgr->GetGuildById(guildId))
753 guild->UpdateCriteria(CriteriaType::WinBattleground, player->GetMapId(), 0, 0, nullptr, player);
754 }
755 }
756 }
757 else
758 {
759 if (BattlegroundPlayer const* bgPlayer = GetBattlegroundPlayerData(player->GetGUID()))
760 {
761 if (BattlegroundMgr::IsRandomBattleground(bgPlayer->queueTypeId.BattlemasterListId)
762 || BattlegroundMgr::IsBGWeekend(BattlegroundTypeId(bgPlayer->queueTypeId.BattlemasterListId)))
764 }
765 }
766
767 player->ResetAllPowers();
768 player->CombatStopWithPets(true);
769
770 BlockMovement(player);
771
772 player->SendDirectMessage(pvpMatchComplete.GetRawPacket());
773
775
777 }
778}
779
784
786{
787 //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)
788 uint32 maxLevel = std::min<uint32>(GetMaxLevel(), 80U);
789 return Trinity::Honor::hk_honor_at_level(maxLevel, float(kills));
790}
791
793{
794 // movement disabled NOTE: the effect will be automatically removed by client when the player is teleported from the battleground, so no need to send with uint8(1) in RemovePlayerAtLeave()
795 player->SetClientControl(player, false);
796}
797
799{
800 Team team = GetPlayerTeam(guid);
801 bool participant = false;
802 // Remove from lists/maps
803 BattlegroundPlayerMap::iterator itr = m_Players.find(guid);
805 if (itr != m_Players.end())
806 {
807 bgQueueTypeId = itr->second.queueTypeId;
808 UpdatePlayersCountByTeam(team, true); // -1 player
809 m_Players.erase(itr);
810 // check if the player was a participant of the match, or only entered through gm command (goname)
811 participant = true;
812 }
813
814 BattlegroundScoreMap::iterator itr2 = PlayerScores.find(guid);
815 if (itr2 != PlayerScores.end())
816 {
817 delete itr2->second; // delete player's score
818 PlayerScores.erase(itr2);
819 }
820
821 Player* player = ObjectAccessor::FindPlayer(guid);
822
823 if (player)
824 {
825 // should remove spirit of redemption
828
836
838
840
841 if (!player->IsAlive()) // resurrect on exit
842 {
843 player->ResurrectPlayer(1.0f);
844 player->SpawnCorpseBones();
845 }
846 }
847 else
848 {
849 CharacterDatabaseTransaction trans(nullptr);
850 Player::OfflineResurrect(guid, trans);
851 }
852
853 RemovePlayer(player, guid, team); // BG subclass specific code
854
855 if (participant) // if the player was a match participant, remove auras, calc rating, update queue
856 {
857 if (player)
858 {
859 player->ClearAfkReports();
860
861 // if arena, remove the specific arena auras
862 if (isArena())
863 {
864 // unsummon current and summon old pet if there was one and there isn't a current pet
865 player->RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT);
867 }
868
869 if (SendPacket && bgQueueTypeId)
870 {
872 BattlegroundMgr::BuildBattlegroundStatusNone(&battlefieldStatus, player, player->GetBattlegroundQueueIndex(*bgQueueTypeId), player->GetBattlegroundQueueJoinTime(*bgQueueTypeId));
873 player->SendDirectMessage(battlefieldStatus.Write());
874 }
875
876 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
877 if (bgQueueTypeId)
878 player->RemoveBattlegroundQueueId(*bgQueueTypeId);
879 }
880
881 // remove from raid group if player is member
882 if (Group* group = GetBgRaid(team))
883 {
884 if (!group->RemoveMember(guid)) // group was disbanded
885 SetBgRaid(team, nullptr);
886 }
888 //we should update battleground queue, but only if bg isn't ending
889 if (isBattleground() && GetStatus() < STATUS_WAIT_LEAVE && bgQueueTypeId)
890 {
891 // a player has left the battleground, so there are free slots -> add to queue
893 sBattlegroundMgr->ScheduleQueueUpdate(0, *bgQueueTypeId, GetBracketId());
894 }
895
896 // Let others know
898 playerLeft.Guid = guid;
899 SendPacketToTeam(team, playerLeft.Write(), player);
900 }
901
902 if (player)
903 {
904 // Do next only if found in battleground
906 // reset destination bg team
907 player->SetBGTeam(TEAM_OTHER);
908
909 // remove all criterias on bg leave
911
912 if (Transport)
913 player->TeleportToBGEntryPoint();
914
915 TC_LOG_DEBUG("bg.battleground", "Removed player {} from Battleground.", player->GetName());
916 }
917
918 //battleground object will be deleted next Battleground::Update() call
919}
920
921// this method is called when no players remains in battleground
923{
928 m_Events = 0;
929
930 if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
931 TC_LOG_ERROR("bg.battleground", "Battleground::Reset: one of the counters is not 0 (alliance: {}, horde: {}) for BG (map: {}, instance id: {})!",
933
935 m_InvitedHorde = 0;
936 m_InBGFreeSlotQueue = false;
937
938 m_Players.clear();
939
940 for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr)
941 delete itr->second;
942 PlayerScores.clear();
943
944 _playerPositions.clear();
945}
946
948{
950 // add BG to free slot queue
952
953 // add bg to update list
954 // This must be done here, because we need to have already invited some players when first BG::Update() method is executed
955 // and it doesn't matter if we call StartBattleground() more times, because m_Battlegrounds is a map and instance id never changes
956 sBattlegroundMgr->AddBattleground(this);
957
958 if (m_IsRated)
959 TC_LOG_DEBUG("bg.arena", "Arena match type: {} started.", m_ArenaType);
960}
961
963{
964 if (WorldSafeLocsEntry const* loc = GetExploitTeleportLocation(Team(player->GetBGTeam())))
965 player->TeleportTo(loc->Loc);
966}
967
969{
970 // remove afk from player
971 if (player->isAFK())
972 player->ToggleAFK();
973
974 // score struct must be created in inherited class
975
976 Team team = player->GetBGTeam();
977
979 bp.OfflineRemoveTime = 0;
980 bp.Team = team;
982 bp.queueTypeId = queueId;
983
984 bool const isInBattleground = IsPlayerInBattleground(player->GetGUID());
985 // Add to list/maps
986 m_Players[player->GetGUID()] = bp;
987
988 if (!isInBattleground)
989 {
990 UpdatePlayersCountByTeam(team, false); // +1 player
991 PlayerScores[player->GetGUID()] = new BattlegroundScore(player->GetGUID(), player->GetBGTeam(), _pvpStatIds);
992 }
993
995 playerJoined.Guid = player->GetGUID();
996 SendPacketToTeam(team, playerJoined.Write(), player);
997
999 pvpMatchInitialize.MapID = GetMapId();
1000 switch (GetStatus())
1001 {
1002 case STATUS_NONE:
1003 case STATUS_WAIT_QUEUE:
1005 break;
1006 case STATUS_WAIT_JOIN:
1008 break;
1009 case STATUS_IN_PROGRESS:
1011 break;
1012 case STATUS_WAIT_LEAVE:
1014 break;
1015 default:
1016 break;
1017 }
1018
1020 {
1022 pvpMatchInitialize.Duration = std::chrono::duration_cast<Seconds>(duration);
1023 pvpMatchInitialize.StartTime = GameTime::GetSystemTime() - duration;
1024 }
1025
1026 pvpMatchInitialize.ArenaFaction = player->GetBGTeam() == HORDE ? PVP_TEAM_HORDE : PVP_TEAM_ALLIANCE;
1027 pvpMatchInitialize.BattlemasterListID = queueId.BattlemasterListId;
1028 pvpMatchInitialize.Registered = false;
1029 pvpMatchInitialize.AffectsRating = isRated();
1030
1031 player->SendDirectMessage(pvpMatchInitialize.Write());
1032
1034
1035 // add arena specific auras
1036 if (isArena())
1037 {
1039 player->DestroyConjuredItems(true);
1040 player->UnsummonPetTemporaryIfAny();
1041
1042 if (GetStatus() == STATUS_WAIT_JOIN) // not started yet
1043 {
1044 player->CastSpell(player, SPELL_ARENA_PREPARATION, true);
1045 player->ResetAllPowers();
1046 }
1047 }
1048 else
1049 {
1050 if (GetStatus() == STATUS_WAIT_JOIN) // not started yet
1051 player->CastSpell(player, SPELL_PREPARATION, true); // reduces all mana cost of spells.
1052
1053 if (bp.Mercenary)
1054 {
1055 if (bp.Team == HORDE)
1056 {
1057 player->CastSpell(player, SPELL_MERCENARY_HORDE_1);
1059 }
1060 else if (bp.Team == ALLIANCE)
1061 {
1062 player->CastSpell(player, SPELL_MERCENARY_ALLIANCE_1);
1064 }
1065 player->CastSpell(player, SPELL_MERCENARY_SHAPESHIFT);
1067 }
1068 }
1069
1070 // setup BG group membership
1072 AddOrSetPlayerToCorrectBgGroup(player, team);
1073
1074 GetBgMap()->GetBattlegroundScript()->OnPlayerJoined(player, isInBattleground);
1075}
1076
1077// this method adds player to his team's bg group, or sets his correct group if player is already in bg group
1079{
1080 ObjectGuid playerGuid = player->GetGUID();
1081 Group* group = GetBgRaid(team);
1082 if (!group) // first player joined
1083 {
1084 group = new Group;
1085 SetBgRaid(team, group);
1086 group->Create(player);
1087 Seconds countdownMaxForBGType = Seconds(StartDelayTimes[BG_STARTING_EVENT_FIRST] / 1000);
1089 group->StartCountdown(CountdownTimerType::Pvp, countdownMaxForBGType, _preparationStartTime);
1090 else
1091 group->StartCountdown(CountdownTimerType::Pvp, countdownMaxForBGType);
1092 }
1093 else // raid already exist
1094 {
1095 if (group->IsMember(playerGuid))
1096 {
1097 uint8 subgroup = group->GetMemberGroup(playerGuid);
1098 player->SetBattlegroundOrBattlefieldRaid(group, subgroup);
1099 }
1100 else
1101 {
1102 group->AddMember(player);
1103 if (Group* originalGroup = player->GetOriginalGroup())
1104 if (originalGroup->IsLeader(playerGuid))
1105 {
1106 group->ChangeLeader(playerGuid);
1107 group->SendUpdate();
1108 }
1109 }
1110 }
1111}
1112
1113// This method should be called when player logs into running battleground
1115{
1116 ObjectGuid guid = player->GetGUID();
1117 // player is correct pointer
1118 for (auto itr = m_OfflineQueue.begin(); itr != m_OfflineQueue.end(); ++itr)
1119 {
1120 if (*itr == guid)
1121 {
1122 m_OfflineQueue.erase(itr);
1123 break;
1124 }
1125 }
1126 m_Players[guid].OfflineRemoveTime = 0;
1128 // if battleground is starting, then add preparation aura
1129 // we don't have to do that, because preparation aura isn't removed when player logs out
1130}
1131
1132// This method should be called when player logs out from running battleground
1134{
1135 ObjectGuid guid = player->GetGUID();
1136 if (!IsPlayerInBattleground(guid)) // Check if this player really is in battleground (might be a GM who teleported inside)
1137 return;
1138
1139 // player is correct pointer, it is checked in WorldSession::LogoutPlayer()
1140 m_OfflineQueue.push_back(player->GetGUID());
1141 m_Players[guid].OfflineRemoveTime = GameTime::GetGameTime() + MAX_OFFLINE_TIME;
1143 {
1144 // drop flag and handle other cleanups
1145 RemovePlayer(player, guid, GetPlayerTeam(guid));
1146
1147 // 1 player is logging out, if it is the last alive, then end arena!
1148 if (isArena() && player->IsAlive())
1151 }
1152}
1153
1154// This method should be called only once ... it adds pointer to queue
1156{
1158 {
1159 sBattlegroundMgr->AddToBGFreeSlotQueue(this);
1160 m_InBGFreeSlotQueue = true;
1161 }
1162}
1163
1164// This method removes this battleground from free queue - it must be called when deleting battleground
1166{
1168 {
1169 sBattlegroundMgr->RemoveFromBGFreeSlotQueue(GetMapId(), m_InstanceID);
1170 m_InBGFreeSlotQueue = false;
1171 }
1172}
1173
1174// get the number of free slots for team
1175// returns the number how many players can join battleground to MaxPlayersPerTeam
1177{
1178 // if BG is starting and CONFIG_BATTLEGROUND_INVITATION_TYPE == BG_QUEUE_INVITATION_TYPE_NO_BALANCE, invite anyone
1181
1182 // if BG is already started or CONFIG_BATTLEGROUND_INVITATION_TYPE != BG_QUEUE_INVITATION_TYPE_NO_BALANCE, do not allow to join too much players of one faction
1183 uint32 otherTeamInvitedCount;
1184 uint32 thisTeamInvitedCount;
1185 uint32 otherTeamPlayersCount;
1186 uint32 thisTeamPlayersCount;
1187
1188 if (team == ALLIANCE)
1189 {
1190 thisTeamInvitedCount = GetInvitedCount(ALLIANCE);
1191 otherTeamInvitedCount = GetInvitedCount(HORDE);
1192 thisTeamPlayersCount = GetPlayersCountByTeam(ALLIANCE);
1193 otherTeamPlayersCount = GetPlayersCountByTeam(HORDE);
1194 }
1195 else
1196 {
1197 thisTeamInvitedCount = GetInvitedCount(HORDE);
1198 otherTeamInvitedCount = GetInvitedCount(ALLIANCE);
1199 thisTeamPlayersCount = GetPlayersCountByTeam(HORDE);
1200 otherTeamPlayersCount = GetPlayersCountByTeam(ALLIANCE);
1201 }
1203 {
1204 // difference based on ppl invited (not necessarily entered battle)
1205 // default: allow 0
1206 uint32 diff = 0;
1207
1208 // allow join one person if the sides are equal (to fill up bg to minPlayerPerTeam)
1209 if (otherTeamInvitedCount == thisTeamInvitedCount)
1210 diff = 1;
1211 // allow join more ppl if the other side has more players
1212 else if (otherTeamInvitedCount > thisTeamInvitedCount)
1213 diff = otherTeamInvitedCount - thisTeamInvitedCount;
1214
1215 // difference based on max players per team (don't allow inviting more)
1216 uint32 diff2 = (thisTeamInvitedCount < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - thisTeamInvitedCount : 0;
1217
1218 // difference based on players who already entered
1219 // default: allow 0
1220 uint32 diff3 = 0;
1221 // allow join one person if the sides are equal (to fill up bg minPlayerPerTeam)
1222 if (otherTeamPlayersCount == thisTeamPlayersCount)
1223 diff3 = 1;
1224 // allow join more ppl if the other side has more players
1225 else if (otherTeamPlayersCount > thisTeamPlayersCount)
1226 diff3 = otherTeamPlayersCount - thisTeamPlayersCount;
1227 // or other side has less than minPlayersPerTeam
1228 else if (thisTeamInvitedCount <= GetMinPlayersPerTeam())
1229 diff3 = GetMinPlayersPerTeam() - thisTeamInvitedCount + 1;
1230
1231 // return the minimum of the 3 differences
1232
1233 // min of diff and diff 2
1234 diff = std::min(diff, diff2);
1235 // min of diff, diff2 and diff3
1236 return std::min(diff, diff3);
1237 }
1238 return 0;
1239}
1240
1242{
1244}
1245
1247{
1248 return !isArena();
1249}
1250
1252{
1253 return GetPlayersSize() < GetMaxPlayers();
1254}
1255
1257{
1258 pvpLogData.Statistics.reserve(GetPlayerScoresSize());
1259 for (auto const& score : PlayerScores)
1260 {
1261 if (Player* player = ObjectAccessor::GetPlayer(GetBgMap(), score.first))
1262 {
1264 score.second->BuildPvPLogPlayerDataPacket(playerData);
1265
1266 playerData.IsInWorld = true;
1267 playerData.PrimaryTalentTree = AsUnderlyingType(player->GetPrimarySpecialization());
1268 playerData.Sex = player->GetGender();
1269 playerData.Race = player->GetRace();
1270 playerData.Class = player->GetClass();
1271 playerData.HonorLevel = player->GetHonorLevel();
1272
1273 pvpLogData.Statistics.push_back(playerData);
1274 }
1275 }
1276
1279}
1280
1285
1286bool Battleground::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor, Optional<HonorGainSource> source)
1287{
1288 BattlegroundScoreMap::const_iterator itr = PlayerScores.find(player->GetGUID());
1289 if (itr == PlayerScores.end()) // player not found...
1290 return false;
1291
1292 if (type == SCORE_BONUS_HONOR && doAddHonor && isBattleground())
1293 player->RewardHonor(nullptr, 1, value, source.value_or(HonorGainSource::Kill)); // RewardHonor calls UpdatePlayerScore with doAddHonor = false
1294 else
1295 itr->second->UpdateScore(type, value);
1296
1297 return true;
1298}
1299
1300void Battleground::UpdatePvpStat(Player* player, uint32 pvpStatId, uint32 value)
1301{
1303 score->UpdatePvpStat(pvpStatId, value);
1304}
1305
1307{
1308 return _battlegroundTemplate->MapIDs.front();
1309}
1310
1312{
1313 m_Map = map;
1314 if (map)
1315 _pvpStatIds = sDB2Manager.GetPVPStatIDsForMap(map->GetId());
1316 else
1317 _pvpStatIds = nullptr;
1318}
1319
1320void Battleground::SendMessageToAll(uint32 entry, ChatMsg msgType, Player const* source)
1321{
1322 if (!entry)
1323 return;
1324
1325 Trinity::TrinityStringChatBuilder builder(nullptr, msgType, entry, source);
1327 BroadcastWorker(localizer);
1328}
1329
1330void Battleground::PSendMessageToAll(uint32 entry, ChatMsg msgType, Player const* source, ...)
1331{
1332 if (!entry)
1333 return;
1334
1335 va_list ap;
1336 va_start(ap, source);
1337
1338 Trinity::TrinityStringChatBuilder builder(nullptr, msgType, entry, source, &ap);
1340 BroadcastWorker(localizer);
1341
1342 va_end(ap);
1343}
1344
1349
1351{
1352 auto itr = std::remove_if(_playerPositions.begin(), _playerPositions.end(), [guid](WorldPackets::Battleground::BattlegroundPlayerPosition const& playerPosition)
1353 {
1354 return playerPosition.Guid == guid;
1355 });
1356
1357 _playerPositions.erase(itr, _playerPositions.end());
1358}
1359
1366
1368{
1369 // Keep in mind that for arena this will have to be changed a bit
1370
1371 // Add +1 deaths
1372 UpdatePlayerScore(victim, SCORE_DEATHS, 1);
1373 // Add +1 kills to group and +1 killing_blows to killer
1374 if (killer)
1375 {
1376 // Don't reward credit for killing ourselves, like fall damage of hellfire (warlock)
1377 if (killer == victim)
1378 return;
1379
1380 Team killerTeam = GetPlayerTeam(killer->GetGUID());
1381
1384 killer->UpdateCriteria(CriteriaType::KillPlayer, 1, 0, 0, victim);
1385
1386 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1387 {
1388 Player* creditedPlayer = ObjectAccessor::FindPlayer(itr->first);
1389 if (!creditedPlayer || creditedPlayer == killer)
1390 continue;
1391
1392 if (itr->second.Team == killerTeam && creditedPlayer->IsAtGroupRewardDistance(victim))
1393 {
1394 UpdatePlayerScore(creditedPlayer, SCORE_HONORABLE_KILLS, 1);
1395 creditedPlayer->UpdateCriteria(CriteriaType::KillPlayer, 1, 0, 0, victim);
1396 }
1397 }
1398 }
1399
1400 if (!isArena())
1401 {
1402 // To be able to remove insignia -- ONLY IN Battlegrounds
1404 RewardXPAtKill(killer, victim);
1405 }
1406
1407 if (BattlegroundScript* script = GetBgMap()->GetBattlegroundScript())
1408 script->OnPlayerKilled(victim, killer);
1409}
1410
1412{
1413 if (BattlegroundScript* script = GetBgMap()->GetBattlegroundScript())
1414 script->OnUnitKilled(victim, killer);
1415}
1416
1417// Return the player's team based on battlegroundplayer info
1418// Used in same faction arena matches mainly
1420{
1421 BattlegroundPlayerMap::const_iterator itr = m_Players.find(guid);
1422 if (itr != m_Players.end())
1423 return itr->second.Team;
1424 return TEAM_OTHER;
1425}
1426
1428{
1429 BattlegroundPlayerMap::const_iterator itr = m_Players.find(guid);
1430 if (itr != m_Players.end())
1431 return true;
1432 return false;
1433}
1434
1436{
1437 auto itr = m_Players.find(guid);
1438 if (itr != m_Players.end())
1439 return itr->second.Mercenary;
1440 return false;
1441}
1442
1444{
1446 return;
1447
1448 BlockMovement(player);
1449
1451 BuildPvPLogDataPacket(pvpMatchStatistics.Data);
1452 player->SendDirectMessage(pvpMatchStatistics.Write());
1453}
1454
1456{
1457 int count = 0;
1458 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1459 {
1460 if (itr->second.Team == team)
1461 {
1462 Player* player = ObjectAccessor::FindPlayer(itr->first);
1463 if (player && player->IsAlive())
1464 ++count;
1465 }
1466 }
1467 return count;
1468}
1469
1471{
1472 Group*& old_raid = team == ALLIANCE ? m_BgRaids[TEAM_ALLIANCE] : m_BgRaids[TEAM_HORDE];
1473 if (old_raid)
1474 old_raid->SetBattlegroundGroup(nullptr);
1475 if (bg_raid)
1476 bg_raid->SetBattlegroundGroup(this);
1477 old_raid = bg_raid;
1478}
1479
1481{
1482 _pvpDifficultyEntry = bracketEntry;
1483}
1484
1486{
1487 if (sWorld->getBoolConfig(CONFIG_BG_XP_FOR_KILL) && killer && victim)
1488 {
1489 Player* killers[] = { killer };
1490 KillRewarder(Trinity::IteratorPair(std::begin(killers), std::end(killers)), victim, true).Reward();
1491 }
1492}
1493
1495{
1496 if (teamId == TEAM_ALLIANCE || teamId == TEAM_HORDE)
1497 return m_TeamScores[teamId];
1498
1499 TC_LOG_ERROR("bg.battleground", "GetTeamScore with wrong Team {} for BG {}", teamId, GetTypeID());
1500 return 0;
1501}
1502
1503char const* Battleground::GetName() const
1504{
1505 return _battlegroundTemplate->BattlemasterEntry->Name[sWorld->GetDefaultDbcLocale()];
1506}
1507
1512
1517
1519{
1520 return uint8(GetMinLevel() / 5) - 1; // 10 - 1, 15 - 2, 20 - 3, etc.
1521}
1522
1524{
1525 return GetMaxPlayersPerTeam() * 2;
1526}
1527
1529{
1530 return GetMinPlayersPerTeam() * 2;
1531}
1532
1540
1548
1550{
1551 if (isArena())
1552 {
1553 switch (GetArenaType())
1554 {
1555 case ARENA_TYPE_2v2:
1556 return 2;
1557 case ARENA_TYPE_3v3:
1558 return 3;
1559 case ARENA_TYPE_5v5: // removed
1560 return 5;
1561 default:
1562 break;
1563 }
1564 }
1565
1567}
1568
#define sBattlegroundMgr
@ BG_QUEUE_INVITATION_TYPE_NO_BALANCE
@ SCORE_KILLING_BLOWS
@ SCORE_BONUS_HONOR
@ SCORE_DEATHS
@ SCORE_HONORABLE_KILLS
@ PLAYER_POSITION_UPDATE_INTERVAL
@ MAX_OFFLINE_TIME
@ TIME_AUTOCLOSE_BATTLEGROUND
@ CHECK_PLAYER_POSITION_INVERVAL
@ ARENA_TYPE_5v5
@ ARENA_TYPE_3v3
@ ARENA_TYPE_2v2
@ BG_STARTING_EVENT_3
@ BG_STARTING_EVENT_2
@ BG_STARTING_EVENT_1
@ BG_STARTING_EVENT_4
@ BG_TEXT_START_TWO_MINUTES
@ BG_TEXT_BATTLE_HAS_BEGUN
@ BG_TEXT_ALLIANCE_WINS
@ BG_TEXT_HORDE_WINS
@ BG_TEXT_START_ONE_MINUTE
@ BG_TEXT_START_HALF_MINUTE
@ SPELL_MERCENARY_SHAPESHIFT
@ SPELL_MERCENARY_ALLIANCE_REACTIONS
@ SPELL_MERCENARY_HORDE_REACTIONS
@ SPELL_MERCENARY_HORDE_1
@ SPELL_ARENA_PREPARATION
@ SPELL_HONORABLE_DEFENDER_25Y
@ SPELL_PREPARATION
@ SPELL_MERCENARY_ALLIANCE_1
@ SPELL_HONORABLE_DEFENDER_60Y
@ BG_START_DELAY_1M
@ BG_START_DELAY_30S
@ BG_START_DELAY_2M
@ BG_START_DELAY_NONE
@ STATUS_WAIT_QUEUE
@ STATUS_NONE
@ STATUS_WAIT_LEAVE
@ STATUS_WAIT_JOIN
@ STATUS_IN_PROGRESS
@ SOUND_BG_START
@ SOUND_ALLIANCE_WINS
@ SOUND_HORDE_WINS
@ BG_STARTING_EVENT_THIRD
@ BG_STARTING_EVENT_SECOND
@ BG_STARTING_EVENT_FIRST
@ BG_STARTING_EVENT_FOURTH
@ CHAR_SEL_PVPSTATS_MAXID
@ CHAR_INS_PVPSTATS_PLAYER
@ CHAR_INS_PVPSTATS_BATTLEGROUND
@ IN_MILLISECONDS
Definition Common.h:38
@ MINUTE
Definition Common.h:32
#define sCreatureTextMgr
DB2Storage< BroadcastTextEntry > sBroadcastTextStore("BroadcastText.db2", &BroadcastTextLoadInfo::Instance)
DB2Storage< FactionEntry > sFactionStore("Faction.db2", &FactionLoadInfo::Instance)
#define sDB2Manager
Definition DB2Stores.h:569
BattlegroundBracketId
Definition DBCEnums.h:53
@ ParticipateInBattleground
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:156
int8_t int8
Definition Define.h:152
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
uint32_t uint32
Definition Define.h:154
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:28
#define ASSERT
Definition Errors.h:80
#define sGuildMgr
Definition GuildMgr.h:76
@ TEMP_ENCHANTMENT_SLOT
@ LANG_BG_STARTED_ANNOUNCE_WORLD
Definition Language.h:710
@ LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING
Definition Language.h:743
@ LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS
Definition Language.h:744
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ PET_SAVE_NOT_IN_SLOT
Definition PetDefines.h:48
HonorGainSource
Definition Player.h:381
@ PLAYER_FLAGS_EX_MERCENARY_MODE
Definition Player.h:559
@ GENDER_MALE
constexpr BattlegroundQueueTypeId BATTLEGROUND_QUEUE_NONE
@ TEAM_NEUTRAL
@ TEAM_ALLIANCE
@ TEAM_HORDE
constexpr TeamId GetOtherTeam(TeamId team)
@ TEAM_OTHER
@ ALLIANCE
@ HORDE
@ SPELL_ATTR0_NO_IMMUNITIES
BattlegroundTypeId
@ BATTLEGROUND_TYPE_NONE
@ PVP_TEAM_NEUTRAL
@ PVP_TEAM_HORDE
@ PVP_TEAM_ALLIANCE
ChatMsg
@ CHAT_MSG_SYSTEM
@ CHAT_MSG_BG_SYSTEM_NEUTRAL
@ SPELL_AURA_MOD_SHAPESHIFT
@ SPELL_AURA_SPIRIT_OF_REDEMPTION
@ SPELL_AURA_MOD_INVISIBILITY
@ SPELL_AURA_MOD_REPUTATION_GAIN
@ SPELL_AURA_MOUNTED
@ SPELL_AURA_MOD_FACTION_REPUTATION_GAIN
@ UNIT_FLAG_SKINNABLE
T AddPct(T &base, U pct)
Definition Util.h:85
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
bool IsPositive() const
Definition SpellAuras.h:88
Aura * GetBase() const
Definition SpellAuras.h:82
int32 GetDuration() const
Definition SpellAuras.h:222
bool HasEffectType(AuraType type) const
SpellInfo const * GetSpellInfo() const
Definition SpellAuras.h:182
bool IsPermanent() const
Definition SpellAuras.h:227
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
void SetUnload()
Definition Map.cpp:3497
void SetBG(Battleground *bg)
Definition Map.h:938
BattlegroundScript * GetBattlegroundScript()
Definition Map.h:942
static void BuildBattlegroundStatusNone(WorldPackets::Battleground::BattlefieldStatusNone *battlefieldStatus, Player const *player, uint32 ticketId, uint32 joinTime)
static bool IsRandomBattleground(uint32 battlemasterListId)
static bool IsBGWeekend(BattlegroundTypeId bgTypeId)
virtual void OnPrepareStage1()
virtual void OnEnd(Team winner)
virtual void OnPrepareStage2()
virtual void OnPrepareStage3()
virtual void OnPlayerJoined(Player *player, bool inBattleground)
uint32 m_InvitedAlliance
void UpdatePlayersCountByTeam(Team team, bool remove)
void SetRemainingTime(uint32 Time)
uint32 m_ArenaTeamMMR[PVP_TEAMS_COUNT]
WorldSafeLocsEntry const * GetTeamStartPosition(TeamId teamId) const
uint32 GetMapId() const
Team GetPrematureWinner()
PvPTeamId _winnerTeamId
void SendPacketToTeam(Team team, WorldPacket const *packet, Player *except=nullptr) const
char const * GetName() const
PVPDifficultyEntry const * _pvpDifficultyEntry
void SendPacketToAll(WorldPacket const *packet) const
void RemovePlayerPosition(ObjectGuid guid)
uint32 GetMinLevel() const
void ModifyStartDelayTime(int diff)
void SetElapsedTime(uint32 Time)
virtual void HandleKillPlayer(Player *player, Player *killer)
void _ProcessPlayerPositionBroadcast(uint32 diff)
void AddOrSetPlayerToCorrectBgGroup(Player *player, Team team)
std::deque< ObjectGuid > m_OfflineQueue
uint32 GetMinPlayersPerTeam() const
void PlayerAddedToBGCheckIfBGIsRunning(Player *player)
uint8 GetArenaType() const
BattlegroundPlayerMap m_Players
Player * _GetPlayerForTeam(Team team, BattlegroundPlayerMap::const_iterator itr, char const *context) const
uint32 GetMaxPlayersPerTeam() const
time_t _preparationStartTime
uint32 m_ValidStartPositionTimer
int32 m_StartDelayTime
Group * GetBgRaid(Team team) const
BattlegroundTemplate const * _battlegroundTemplate
uint32 GetInvitedCount(Team team) const
void SetWinner(PvPTeamId winnerTeamId)
uint8 GetUniqueBracketId() const
void PlaySoundToAll(uint32 SoundID)
uint32 m_ClientInstanceID
void AddToBGFreeSlotQueue()
uint32 GetTeamScore(TeamId teamId) const
uint32 GetPlayerScoresSize() const
void DecreaseInvitedCount(Team team)
bool isRated() const
void RewardHonorToTeam(uint32 Honor, Team team)
void SetBgMap(BattlegroundMap *map)
virtual void HandleKillUnit(Creature *, Unit *)
uint32 GetMaxPlayers() const
BattlegroundMap * GetBgMap() const
virtual void PostUpdateImpl(uint32)
Post-update hook.
PvPTeamId GetWinner() const
Battleground(BattlegroundTemplate const *battlegroundTemplate)
virtual void RemovePlayer(Player *, ObjectGuid, uint32)
BattlegroundMap * FindBgMap() const
void BlockMovement(Player *player)
uint32 GetRemainingTime() const
Player * _GetPlayer(ObjectGuid guid, bool offlineRemove, char const *context) const
void StartBattleground()
BattlegroundTypeId GetTypeID() const
void Update(uint32 diff)
bool m_PrematureCountDown
uint32 m_PlayersCount[PVP_TEAMS_COUNT]
Group * m_BgRaids[PVP_TEAMS_COUNT]
uint32 m_PrematureCountDownTimer
void RemoveAuraOnTeam(uint32 SpellID, Team team)
virtual WorldSafeLocsEntry const * GetExploitTeleportLocation(Team)
int32 m_TeamScores[PVP_TEAMS_COUNT]
void PSendMessageToAll(uint32 entry, ChatMsg type, Player const *source,...)
void SendMessageToAll(uint32 entry, ChatMsg type, Player const *source=nullptr)
void EventPlayerLoggedOut(Player *player)
void SendChatMessage(Creature *source, uint8 textId, WorldObject *target=nullptr)
BattlegroundPlayer const * GetBattlegroundPlayerData(ObjectGuid const &playerGuid) const
void RewardXPAtKill(Player *killer, Player *victim)
bool m_InBGFreeSlotQueue
static TeamId GetTeamIndexByTeamId(Team team)
void UpdateWorldState(int32 worldStateId, int32 value, bool hidden=false)
void SetStatus(BattlegroundStatus Status)
bool IsPlayerMercenaryInBattleground(ObjectGuid guid) const
void BroadcastWorker(Do &_do)
virtual void EndBattleground(Team winner)
bool IsPlayerInBattleground(ObjectGuid guid) const
BattlegroundStartTimeIntervals StartDelayTimes[BG_STARTING_EVENT_COUNT]
bool isArena() const
uint32 m_LastPlayerPositionBroadcast
void SendBroadcastText(uint32 id, ChatMsg msgType, WorldObject const *target=nullptr)
BattlegroundScore const * GetBattlegroundScore(Player *player) const
uint32 m_InstanceID
void AddPlayerPosition(WorldPackets::Battleground::BattlegroundPlayerPosition const &position)
void PlaySoundToTeam(uint32 SoundID, Team team)
uint32 m_ResetStatTimer
void RewardReputationToTeam(uint32 faction_id, uint32 Reputation, Team team)
BattlegroundPlayerMap const & GetPlayers() const
int32 GetStartDelayTime() const
BattlegroundScoreMap PlayerScores
float GetStartMaxDist() const
bool isBattleground() const
bool UpdatePlayerScore(Player *player, uint32 type, uint32 value, bool doAddHonor=true, Optional< HonorGainSource > source={})
std::vector< WorldPackets::Battleground::BattlegroundPlayerPosition > _playerPositions
virtual void AddPlayer(Player *player, BattlegroundQueueTypeId queueId)
BattlegroundStatus GetStatus() const
bool HasFreeSlots() const
uint32 GetPlayersCountByTeam(Team team) const
void _ProcessOfflineQueue()
uint32 GetAlivePlayersCountByTeam(Team team) const
void RemoveFromBGFreeSlotQueue()
void TeleportPlayerToExploitLocation(Player *player)
void _ProcessProgress(uint32 diff)
uint32 GetFreeSlotsForTeam(Team team) const
virtual bool PreUpdateImpl(uint32)
Pre-update hook.
uint32 GetScriptId() const
virtual ~Battleground()
virtual void CheckWinConditions()
void EventPlayerLoggedIn(Player *player)
void _CheckSafePositions(uint32 diff)
void _ProcessJoin(uint32 diff)
BattlegroundBracketId GetBracketId() const
std::unordered_set< uint32 > const * _pvpStatIds
Team GetPlayerTeam(ObjectGuid guid) const
uint32 m_InvitedHorde
uint32 GetBonusHonorFromKill(uint32 kills) const
void UpdatePvpStat(Player *player, uint32 pvpStatId, uint32 value)
uint32 GetMaxLevel() const
uint32 GetElapsedTime() const
void CastSpellOnTeam(uint32 SpellID, Team team)
void SetBracket(PVPDifficultyEntry const *bracketEntry)
uint32 GetPlayersSize() const
uint32 m_StartTime
void SetBgRaid(Team team, Group *bg_raid)
void SetStartDelayTime(int Time)
virtual void BuildPvPLogDataPacket(WorldPackets::Battleground::PVPMatchStatistics &pvpLogData) const
virtual void RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool SendPacket)
BattlegroundMap * m_Map
uint32 GetMinPlayers() const
void _ProcessLeave(uint32 diff)
BattlegroundStatus m_Status
uint32 StartMessageIds[BG_STARTING_EVENT_COUNT]
Class used to access individual fields of database query result.
Definition Field.h:94
uint64 GetUInt64() const noexcept
Definition Field.cpp:71
Definition Group.h:205
uint8 GetMemberGroup(ObjectGuid guid) const
Definition Group.cpp:1733
void SendUpdate() const
Definition Group.cpp:828
bool AddMember(Player *player)
Definition Group.cpp:424
void ChangeLeader(ObjectGuid guid)
Definition Group.cpp:682
void SetBattlegroundGroup(Battleground *bg)
Definition Group.cpp:1741
bool IsMember(ObjectGuid guid) const
Definition Group.cpp:1685
bool Create(Player *leader)
Definition Group.cpp:141
void StartCountdown(CountdownTimerType timerType, Seconds duration, Optional< time_t > startTime={ })
Definition Group.cpp:1416
Definition Guild.h:329
void UnloadAll()
Definition Map.cpp:1652
uint32 GetId() const
Definition Map.cpp:3257
LowType GetCounter() const
Definition ObjectGuid.h:336
static ObjectGuid const Empty
Definition ObjectGuid.h:314
std::string ToString() const
uint64 LowType
Definition ObjectGuid.h:321
bool RewardHonor(Unit *victim, uint32 groupsize, int32 honor=-1, HonorGainSource source=HonorGainSource::Kill)
Definition Player.cpp:6763
void SetClientControl(Unit *target, bool allowMove)
Definition Player.cpp:26500
void SetBGTeam(Team team)
Definition Player.cpp:24352
void SetPlayerFlagEx(PlayerFlagsEx flags)
Definition Player.h:2916
bool HasPlayerFlagEx(PlayerFlagsEx flags) const
Definition Player.h:2915
void SetBattlegroundId(uint32 val, BattlegroundTypeId bgTypeId, BattlegroundQueueTypeId queueId)
Definition Player.cpp:25773
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6283
void ClearAfkReports()
Definition Player.h:2617
static void OfflineResurrect(ObjectGuid const &guid, CharacterDatabaseTransaction trans)
Definition Player.cpp:4494
void RemovePlayerFlagEx(PlayerFlagsEx flags)
Definition Player.h:2917
void SpawnCorpseBones(bool triggerSave=true)
Definition Player.cpp:4554
Group * GetOriginalGroup() const
Definition Player.h:2815
uint32 GetBattlegroundQueueJoinTime(BattlegroundQueueTypeId bgQueueTypeId) const
Definition Player.cpp:25727
bool IsMercenaryForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
Definition Player.cpp:25841
bool IsAtGroupRewardDistance(WorldObject const *pRewardSource) const
Definition Player.cpp:26434
void DestroyConjuredItems(bool update)
Definition Player.cpp:12446
void UnsummonPetTemporaryIfAny()
Definition Player.cpp:27985
void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val)
Definition Player.cpp:25804
bool GetRandomWinner() const
Definition Player.h:2624
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition Player.cpp:27588
void RemovePet(Pet *pet, PetSaveMode mode, bool returnreagent=false)
Definition Player.cpp:22084
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={}, uint32 teleportSpellId=0)
Definition Player.cpp:1226
bool TeleportToBGEntryPoint()
Definition Player.cpp:1478
void ToggleAFK()
Definition Player.cpp:1188
uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const
Definition Player.cpp:25752
void ResetAllPowers()
Definition Player.cpp:1859
bool isAFK() const
Definition Player.h:1283
Team GetEffectiveTeam() const
Definition Player.h:2427
void FailCriteria(CriteriaFailEvent condition, int32 failAsset)
Definition Player.cpp:27582
void ResummonPetTemporaryUnSummonedIfAny()
Definition Player.cpp:28000
Team GetBGTeam() const
Definition Player.cpp:24358
void SetBattlegroundOrBattlefieldRaid(Group *group, int8 subgroup=-1)
Definition Player.cpp:26748
ReputationMgr & GetReputationMgr()
Definition Player.h:2439
void RemoveArenaEnchantments(EnchantmentSlot slot)
Definition Player.cpp:13378
void SetRandomWinner(bool isWinner)
Definition Player.cpp:30012
void ResurrectPlayer(float restore_percent, bool applySickness=false)
Definition Player.cpp:4379
void setUInt32(uint8 index, uint32 value)
void setBool(uint8 index, bool value)
void setUInt64(uint8 index, uint64 value)
void setUInt8(uint8 index, uint8 value)
bool ModifyReputation(FactionEntry const *factionEntry, int32 standing, bool spillOverOnly=false, bool noSpillover=false)
bool HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:456
Utility class to enable range for loop syntax for multimap.equal_range uses.
Definition Unit.h:635
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3955
void CombatStop(bool includingCast=false, bool mutualPvP=true, bool(*unitFilter)(Unit const *otherUnit)=nullptr)
Definition Unit.cpp:6012
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3828
void AtEndOfEncounter(EncounterType type)
Definition Unit.cpp:568
bool IsAlive() const
Definition Unit.h:1185
float GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:5069
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4814
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition Unit.cpp:4241
float GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:5129
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:846
void CombatStopWithPets(bool includingCast=false)
Definition Unit.cpp:6040
constexpr uint32 GetMapId() const
Definition Position.h:216
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
std::string const & GetName() const
Definition Object.h:342
std::vector< BattlegroundPlayerPosition > FlagCarriers
WorldPackets::Duration< Seconds > Duration
WorldPacket const * GetRawPacket() const
Definition Packet.h:38
#define sWorld
Definition World.h:916
@ CONFIG_BG_REWARD_LOSER_HONOR_LAST
Definition World.h:401
@ CONFIG_BATTLEGROUND_INVITATION_TYPE
Definition World.h:337
@ CONFIG_BG_REWARD_WINNER_HONOR_FIRST
Definition World.h:398
@ CONFIG_BG_REWARD_LOSER_HONOR_FIRST
Definition World.h:400
@ CONFIG_BG_REWARD_WINNER_HONOR_LAST
Definition World.h:399
@ CONFIG_BG_XP_FOR_KILL
Definition World.h:141
@ CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE
Definition World.h:140
@ CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE
Definition World.h:138
SystemTimePoint GetSystemTime()
Current chrono system_clock time point.
Definition GameTime.cpp:62
time_t GetGameTime()
Definition GameTime.cpp:52
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:37
uint32 hk_honor_at_level(uint8 level, float multiplier=1.0f)
Definition Formulas.h:62
TC_GAME_API void SetValue(int32 worldStateId, int32 value, bool hidden, Map *map)
BattlegroundQueueTypeId queueTypeId
BattlegroundTypeId Id
BattlemasterListEntry const * BattlemasterEntry
uint16 GetMaxPlayersPerTeam() const
std::vector< int32 > MapIDs
WorldSafeLocsEntry const * StartLocation[PVP_TEAMS_COUNT]
uint16 GetMinPlayersPerTeam() const
LocalizedString Name
BattlegroundBracketId GetBracketId() const
constexpr void GetPosition(float &x, float &y) const
Definition Position.h:92
constexpr float GetExactDistSq(float x, float y, float z) const
Definition Position.h:121
std::vector< PVPMatchPlayerStatistics > Statistics
WorldLocation Loc
Definition ObjectMgr.h:836