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 "GroupMgr.h"
34#include "Guild.h"
35#include "GuildMgr.h"
36#include "KillRewarder.h"
37#include "Language.h"
38#include "Log.h"
39#include "Map.h"
40#include "MapUtils.h"
41#include "MiscPackets.h"
42#include "ObjectAccessor.h"
43#include "ObjectMgr.h"
44#include "Player.h"
45#include "ReputationMgr.h"
46#include "SpellAuras.h"
47#include "TemporarySummon.h"
48#include "Transport.h"
49#include "Util.h"
50#include "WorldStateMgr.h"
51#include <cstdarg>
52
53template<class Do>
55{
56 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
57 if (Player* player = _GetPlayer(itr, "BroadcastWorker"))
58 _do(player);
59}
60
61Battleground::Battleground(BattlegroundTemplate const* battlegroundTemplate) : _battlegroundTemplate(battlegroundTemplate), _pvpDifficultyEntry(nullptr), _pvpStatIds(nullptr), _preparationStartTime(0)
62{
63 ASSERT(_battlegroundTemplate, "Nonexisting Battleground Template passed to battleground ctor!");
64
65 m_InstanceID = 0;
68 m_EndTime = 0;
71 m_ArenaType = 0;
73 m_StartTime = 0;
76 m_Events = 0;
78 m_IsRated = false;
79 m_InBGFreeSlotQueue = false;
80 m_SetDeleteThis = false;
81
82 m_Map = nullptr;
83
86
87 m_BgRaids[TEAM_ALLIANCE] = nullptr;
88 m_BgRaids[TEAM_HORDE] = nullptr;
89
92
95
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
126 // Clear Group::m_bgGroup, Group might later reference it in its own destructor
127 for (Group* bgRaid : m_BgRaids)
128 if (bgRaid)
129 bgRaid->SetBattlegroundGroup(nullptr);
130
131 // remove from bg free slot queue
133
134 for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr)
135 delete itr->second;
136
137 _playerPositions.clear();
138}
139
141{
142 if (!PreUpdateImpl(diff))
143 return;
144
145 if (!GetPlayersSize())
146 {
147 //BG is empty
148 // if there are no players invited, delete BG
149 // this will delete arena or bg object, where any player entered
150 // [[ but if you use battleground object again (more battles possible to be played on 1 instance)
151 // then this condition should be removed and code:
152 // if (!GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
153 // AddToFreeBGObjectsQueue(); // not yet implemented
154 // should be used instead of current
155 // ]]
156 // Battleground Template instance cannot be updated, because it would be deleted
158 m_SetDeleteThis = true;
159 return;
160 }
161
162 switch (GetStatus())
163 {
164 case STATUS_WAIT_JOIN:
165 if (GetPlayersSize())
166 {
167 _ProcessJoin(diff);
169 }
170 break;
174 // after 47 minutes without one team losing, the arena closes with no winner and no rating change
175 if (isArena())
176 {
178 {
180 return;
181 }
182 }
183 else
184 {
185 _ProcessProgress(diff);
186 }
187 break;
189 _ProcessLeave(diff);
190 break;
191 default:
192 break;
193 }
194
195 // Update start time and reset stats timer
198 m_ResetStatTimer += diff;
199
200 PostUpdateImpl(diff);
201}
202
204{
205 float maxDist = GetStartMaxDist();
206 if (!maxDist)
207 return;
208
211 {
213
214 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
215 {
216 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
217 {
218 if (player->IsGameMaster())
219 continue;
220
221 Position pos = player->GetPosition();
222 WorldSafeLocsEntry const* startPos = GetTeamStartPosition(Battleground::GetTeamIndexByTeamId(player->GetBGTeam()));
223 if (pos.GetExactDistSq(startPos->Loc) > maxDist)
224 {
225 TC_LOG_DEBUG("bg.battleground", "BATTLEGROUND: Sending {} back to start location (map: {}) (possible exploit)", player->GetName(), GetMapId());
226 player->TeleportTo(startPos->Loc);
227 }
228 }
229 }
230 }
231}
232
234{
237 {
239
241
243 {
244 // Update position data if we found player.
245 if (Player* player = ObjectAccessor::GetPlayer(GetBgMap(), playerPosition.Guid))
246 playerPosition.Pos = player->GetPosition();
247
248 playerPositions.FlagCarriers.push_back(playerPosition);
249 }
250
251 SendPacketToAll(playerPositions.Write());
252 }
253}
254
256{
257 // remove offline players from bg after 5 minutes
258 if (!m_OfflineQueue.empty())
259 {
260 BattlegroundPlayerMap::iterator itr = m_Players.find(*(m_OfflineQueue.begin()));
261 if (itr != m_Players.end())
262 {
263 if (itr->second.OfflineRemoveTime <= GameTime::GetGameTime())
264 {
265 RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
266 m_OfflineQueue.pop_front(); // remove from offline queue
267 //do not use itr for anything, because it is erased in RemovePlayerAtLeave()
268 }
269 }
270 }
271}
272
274{
275 Team winner = TEAM_OTHER;
277 winner = ALLIANCE;
279 winner = HORDE;
280
281 return winner;
282}
283
285{
286 // *********************************************************
287 // *** BATTLEGROUND BALLANCE SYSTEM ***
288 // *********************************************************
289 // if less then minimum players are in on one side, then start premature finish timer
290 bool broadcastStatusUpdate = false;
292 {
294 {
296 SetRemainingTime(sBattlegroundMgr->GetPrematureFinishTime());
297 broadcastStatusUpdate = true;
298 }
299 else if ((m_EndTime -= int32(diff)) < 0)
300 {
301 // time's up!
303 m_PrematureCountDown = false;
304 }
305 }
306 else if (m_PrematureCountDown)
307 {
308 m_PrematureCountDown = false;
310 broadcastStatusUpdate = true;
311 }
312
313 if (broadcastStatusUpdate)
314 {
315 for (auto const& [guid, playerData] : m_Players)
316 {
317 if (Player* player = _GetPlayer(guid, false, "_ProcessProgress"))
318 {
320 BattlegroundMgr::BuildBattlegroundStatusActive(&battlefieldStatus, this, player,
321 player->GetBattlegroundQueueIndex(playerData.queueTypeId),
322 player->GetBattlegroundQueueJoinTime(playerData.queueTypeId), playerData.queueTypeId);
323 player->SendDirectMessage(battlefieldStatus.Write());
324 }
325 }
326 }
327}
328
330{
331 // *********************************************************
332 // *** BATTLEGROUND STARTING SYSTEM ***
333 // *********************************************************
335
336 if (m_ResetStatTimer > 5000)
337 {
339 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
340 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
341 player->ResetAllPowers();
342 }
343
345 {
347
348 if (!FindBgMap())
349 {
350 TC_LOG_ERROR("bg.battleground", "Battleground::_ProcessJoin: map (map id: {}, instance id: {}) is not created!", GetMapId(), m_InstanceID);
351 EndNow();
352 return;
353 }
354
356 for (Group* group : m_BgRaids)
357 if (group)
359
362 // First start warning - 2 or 1 minute
365 }
366 // After 1 minute or 30 seconds, warning is signaled
368 {
373 }
374 // After 30 or 15 seconds, warning is signaled
376 {
381 }
382 // Delay expired (after 2 or 1 minute)
383 else if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4))
384 {
386
388
393
395
396 for (auto const& [guid, _] : GetPlayers())
397 {
398 if (Player* player = ObjectAccessor::GetPlayer(GetBgMap(), guid))
399 {
400 player->StartCriteria(CriteriaStartEvent::StartBattleground, GetBgMap()->GetId());
401 player->AtStartOfEncounter(EncounterType::Battleground);
402 }
403 }
404
405 // Remove preparation
406 if (isArena())
407 {
409 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
410 {
411 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
412 {
413 // Correctly display EnemyUnitFrame
414 player->SetArenaFaction(player->GetBGTeam());
415
416 player->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
417 player->ResetAllPowers();
418 if (!player->IsGameMaster())
419 {
420 // remove auras with duration lower than 30s
421 player->RemoveAppliedAuras([](AuraApplication const* aurApp)
422 {
423 Aura* aura = aurApp->GetBase();
424 return !aura->IsPermanent()
425 && aura->GetDuration() <= 30 * IN_MILLISECONDS
426 && aurApp->IsPositive()
429 });
430 }
431 }
432 }
433
435 }
436 else
437 {
439
440 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
441 {
442 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
443 {
444 player->RemoveAurasDueToSpell(SPELL_PREPARATION);
445 player->ResetAllPowers();
446 }
447 }
448 // Announce BG starting
451 }
452 }
453}
454
456{
457 // *********************************************************
458 // *** BATTLEGROUND ENDING SYSTEM ***
459 // *********************************************************
460 // remove all players from battleground after 2 minutes
462 if (GetRemainingTime() <= 0)
463 {
465 BattlegroundPlayerMap::iterator itr, next;
466 for (itr = m_Players.begin(); itr != m_Players.end(); itr = next)
467 {
468 next = itr;
469 ++next;
470 //itr is erased here!
471 RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
472 // do not change any battleground's private variables
473 }
474 }
475}
476
477Player* Battleground::_GetPlayer(ObjectGuid guid, bool offlineRemove, char const* context) const
478{
479 Player* player = nullptr;
480 if (!offlineRemove)
481 {
482 // should this be ObjectAccessor::FindConnectedPlayer() to return players teleporting ?
483 player = ObjectAccessor::FindPlayer(guid);
484 if (!player)
485 TC_LOG_ERROR("bg.battleground", "Battleground::{}: player ({}) not found for BG (map: {}, instance id: {})!",
486 context, guid.ToString(), GetMapId(), m_InstanceID);
487 }
488 return player;
489}
490
491Player* Battleground::_GetPlayerForTeam(Team team, BattlegroundPlayerMap::const_iterator itr, char const* context) const
492{
493 Player* player = _GetPlayer(itr, context);
494 if (player)
495 {
496 Team playerTeam = itr->second.Team;
497 if (!playerTeam)
498 playerTeam = player->GetEffectiveTeam();
499 if (playerTeam != team)
500 player = nullptr;
501 }
502 return player;
503}
504
506{
507 ASSERT(m_Map);
508 return m_Map;
509}
510
516
521
523{
524 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
525 if (Player* player = _GetPlayer(itr, "SendPacketToAll"))
526 player->SendDirectMessage(packet);
527}
528
529void Battleground::SendPacketToTeam(Team team, WorldPacket const* packet, Player* except /*= nullptr*/) const
530{
531 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
532 {
533 if (Player* player = _GetPlayerForTeam(team, itr, "SendPacketToTeam"))
534 if (player != except)
535 player->SendDirectMessage(packet);
536 }
537}
538
539void Battleground::SendChatMessage(Creature* source, uint8 textId, WorldObject* target /*= nullptr*/)
540{
541 sCreatureTextMgr->SendChat(source, textId, target);
542}
543
545{
546 if (!sBroadcastTextStore.LookupEntry(id))
547 {
548 TC_LOG_ERROR("bg.battleground", "Battleground::SendBroadcastText: `broadcast_text` (ID: {}) was not found", id);
549 return;
550 }
551
552 Trinity::BroadcastTextBuilder builder(nullptr, msgType, id, GENDER_MALE, target);
554 BroadcastWorker(localizer);
555}
556
561
566
568{
569 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
570 if (Player* player = _GetPlayerForTeam(team, itr, "CastSpellOnTeam"))
571 player->CastSpell(player, SpellID, true);
572}
573
575{
576 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
577 if (Player* player = _GetPlayerForTeam(team, itr, "RemoveAuraOnTeam"))
578 player->RemoveAura(SpellID);
579}
580
582{
583 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
584 if (Player* player = _GetPlayerForTeam(team, itr, "RewardHonorToTeam"))
586}
587
588void Battleground::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, Team team)
589{
590 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
591 if (!factionEntry)
592 return;
593
594 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
595 {
596 Player* player = _GetPlayerForTeam(team, itr, "RewardReputationToTeam");
597 if (!player)
598 continue;
599
601 continue;
602
603 uint32 repGain = Reputation;
606 player->GetReputationMgr().ModifyReputation(factionEntry, repGain);
607 }
608}
609
610void Battleground::UpdateWorldState(int32 worldStateId, int32 value, bool hidden /*= false*/)
611{
612 WorldStateMgr::SetValue(worldStateId, value, hidden, GetBgMap());
613}
614
616{
618
619 bool guildAwarded = false;
620
621 if (winner == ALLIANCE)
622 {
623 if (isBattleground())
625
626 PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound
627
629 }
630 else if (winner == HORDE)
631 {
632 if (isBattleground())
634
635 PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
636
638 }
639 else
640 {
642 }
643
645 uint64 battlegroundId = 1;
647 {
648 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PVPSTATS_MAXID);
649 PreparedQueryResult result = CharacterDatabase.Query(stmt);
650
651 if (result)
652 {
653 Field* fields = result->Fetch();
654 battlegroundId = fields[0].GetUInt64() + 1;
655 }
656
657 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_BATTLEGROUND);
658 stmt->setUInt64(0, battlegroundId);
659 stmt->setUInt8(1, GetWinner());
660 stmt->setUInt8(2, GetUniqueBracketId());
661 stmt->setUInt32(3, GetTypeID());
662 CharacterDatabase.Execute(stmt);
663 }
664
666 //we must set it this way, because end time is sent in packet!
668
670 pvpMatchComplete.Winner = GetWinner();
671 pvpMatchComplete.Duration = std::chrono::duration_cast<Seconds>(Milliseconds(std::max<int32>(0, (GetElapsedTime() - BG_START_DELAY_2M))));
672 BuildPvPLogDataPacket(pvpMatchComplete.LogData.emplace());
673 pvpMatchComplete.Write();
674
675 for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
676 {
677 Team team = itr->second.Team;
678
679 Player* player = _GetPlayer(itr, "EndBattleground");
680 if (!player)
681 continue;
682
683 // should remove spirit of redemption
686
687 if (!player->IsAlive())
688 {
689 player->ResurrectPlayer(1.0f);
690 player->SpawnCorpseBones();
691 }
692 else
693 //needed cause else in av some creatures will kill the players at the end
694 player->CombatStop();
695
696 // remove temporary currency bonus auras before rewarding player
699
700 uint32 winnerKills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_FIRST);
701 uint32 loserKills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_FIRST);
702
704 {
705 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_PLAYER);
706 BattlegroundScoreMap::const_iterator score = PlayerScores.find(player->GetGUID());
707
708 stmt->setUInt32(0, battlegroundId);
709 stmt->setUInt64(1, player->GetGUID().GetCounter());
710 stmt->setBool (2, team == winner);
711 stmt->setUInt32(3, score->second->GetKillingBlows());
712 stmt->setUInt32(4, score->second->GetDeaths());
713 stmt->setUInt32(5, score->second->GetHonorableKills());
714 stmt->setUInt32(6, score->second->GetBonusHonor());
715 stmt->setUInt32(7, score->second->GetDamageDone());
716 stmt->setUInt32(8, score->second->GetHealingDone());
717 stmt->setUInt32(9, score->second->GetAttr(0));
718 stmt->setUInt32(10, score->second->GetAttr(1));
719 stmt->setUInt32(11, score->second->GetAttr(2));
720 stmt->setUInt32(12, score->second->GetAttr(3));
721 stmt->setUInt32(13, score->second->GetAttr(4));
722
723 CharacterDatabase.Execute(stmt);
724 }
725
726 // Reward winner team
727 if (team == winner)
728 {
729 if (BattlegroundPlayer const* bgPlayer = GetBattlegroundPlayerData(player->GetGUID()))
730 {
731 if (BattlegroundMgr::IsRandomBattleground(bgPlayer->queueTypeId.BattlemasterListId)
732 || BattlegroundMgr::IsBGWeekend(BattlegroundTypeId(bgPlayer->queueTypeId.BattlemasterListId)))
733 {
735 if (!player->GetRandomWinner())
737
738 UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(winnerKills), true, source);
739 if (!player->GetRandomWinner())
740 {
741 player->SetRandomWinner(true);
742 // TODO: win honor xp
743 }
744 }
745 else
746 {
747 // TODO: loss honor xp
748 }
749 }
750
752 if (!guildAwarded)
753 {
754 guildAwarded = true;
755 if (ObjectGuid::LowType guildId = GetBgMap()->GetOwnerGuildId(player->GetBGTeam()))
756 {
757 if (Guild* guild = sGuildMgr->GetGuildById(guildId))
758 guild->UpdateCriteria(CriteriaType::WinBattleground, player->GetMapId(), 0, 0, nullptr, player);
759 }
760 }
761 }
762 else
763 {
764 if (BattlegroundPlayer const* bgPlayer = GetBattlegroundPlayerData(player->GetGUID()))
765 {
766 if (BattlegroundMgr::IsRandomBattleground(bgPlayer->queueTypeId.BattlemasterListId)
767 || BattlegroundMgr::IsBGWeekend(BattlegroundTypeId(bgPlayer->queueTypeId.BattlemasterListId)))
769 }
770 }
771
772 player->ResetAllPowers();
773 player->CombatStopWithPets(true);
774
775 BlockMovement(player);
776
777 player->SendDirectMessage(pvpMatchComplete.GetRawPacket());
778
780
782 }
783}
784
789
791{
792 //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)
793 uint32 maxLevel = std::min<uint32>(GetMaxLevel(), 80U);
794 return Trinity::Honor::hk_honor_at_level(maxLevel, float(kills));
795}
796
798{
799 // 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()
800 player->SetClientControl(player, false);
801}
802
804{
805 Team team = GetPlayerTeam(guid);
806 bool participant = false;
807 // Remove from lists/maps
808 BattlegroundPlayerMap::iterator itr = m_Players.find(guid);
810 if (itr != m_Players.end())
811 {
812 bgQueueTypeId = itr->second.queueTypeId;
813 UpdatePlayersCountByTeam(team, true); // -1 player
814 m_Players.erase(itr);
815 // check if the player was a participant of the match, or only entered through gm command (goname)
816 participant = true;
817 }
818
819 BattlegroundScoreMap::iterator itr2 = PlayerScores.find(guid);
820 if (itr2 != PlayerScores.end())
821 {
822 delete itr2->second; // delete player's score
823 PlayerScores.erase(itr2);
824 }
825
826 Player* player = ObjectAccessor::FindPlayer(guid);
827
828 if (player)
829 {
830 // should remove spirit of redemption
833
841
843
845
846 if (!player->IsAlive()) // resurrect on exit
847 {
848 player->ResurrectPlayer(1.0f);
849 player->SpawnCorpseBones();
850 }
851 }
852 else
853 {
854 CharacterDatabaseTransaction trans(nullptr);
855 Player::OfflineResurrect(guid, trans);
856 }
857
858 RemovePlayer(player, guid, team); // BG subclass specific code
859
860 if (participant) // if the player was a match participant, remove auras, calc rating, update queue
861 {
862 if (player)
863 {
864 player->ClearAfkReports();
865
866 // if arena, remove the specific arena auras
867 if (isArena())
868 {
869 // unsummon current and summon old pet if there was one and there isn't a current pet
870 player->RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT);
872 }
873
874 if (SendPacket && bgQueueTypeId)
875 {
877 BattlegroundMgr::BuildBattlegroundStatusNone(&battlefieldStatus, player, player->GetBattlegroundQueueIndex(*bgQueueTypeId), player->GetBattlegroundQueueJoinTime(*bgQueueTypeId));
878 player->SendDirectMessage(battlefieldStatus.Write());
879 }
880
881 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
882 if (bgQueueTypeId)
883 player->RemoveBattlegroundQueueId(*bgQueueTypeId);
884 }
885
886 // remove from raid group if player is member
887 if (Group* group = GetBgRaid(team))
888 {
889 if (!group->RemoveMember(guid)) // group was disbanded
890 SetBgRaid(team, nullptr);
891 }
893 //we should update battleground queue, but only if bg isn't ending
894 if (isBattleground() && GetStatus() < STATUS_WAIT_LEAVE && bgQueueTypeId)
895 {
896 // a player has left the battleground, so there are free slots -> add to queue
898 sBattlegroundMgr->ScheduleQueueUpdate(0, *bgQueueTypeId, GetBracketId());
899 }
900
901 // Let others know
903 playerLeft.Guid = guid;
904 SendPacketToTeam(team, playerLeft.Write(), player);
905 }
906
907 if (player)
908 {
909 // Do next only if found in battleground
911 // reset destination bg team
912 player->SetBGTeam(TEAM_OTHER);
913
914 // remove all criterias on bg leave
916
917 if (Transport)
918 player->TeleportToBGEntryPoint();
919
920 TC_LOG_DEBUG("bg.battleground", "Removed player {} from Battleground.", player->GetName());
921 }
922
923 //battleground object will be deleted next Battleground::Update() call
924}
925
926// this method is called when no players remains in battleground
928{
933 m_Events = 0;
934
935 if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
936 TC_LOG_ERROR("bg.battleground", "Battleground::Reset: one of the counters is not 0 (alliance: {}, horde: {}) for BG (map: {}, instance id: {})!",
938
940 m_InvitedHorde = 0;
941 m_InBGFreeSlotQueue = false;
942
943 m_Players.clear();
944
945 for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr)
946 delete itr->second;
947 PlayerScores.clear();
948
949 _playerPositions.clear();
950}
951
953{
955 // add BG to free slot queue
957
958 // add bg to update list
959 // This must be done here, because we need to have already invited some players when first BG::Update() method is executed
960 // and it doesn't matter if we call StartBattleground() more times, because m_Battlegrounds is a map and instance id never changes
961 sBattlegroundMgr->AddBattleground(this);
962
963 if (m_IsRated)
964 TC_LOG_DEBUG("bg.arena", "Arena match type: {} started.", m_ArenaType);
965}
966
968{
969 if (WorldSafeLocsEntry const* loc = GetExploitTeleportLocation(Team(player->GetBGTeam())))
970 player->TeleportTo(loc->Loc);
971}
972
974{
975 // remove afk from player
976 if (player->isAFK())
977 player->ToggleAFK();
978
979 // score struct must be created in inherited class
980
981 Team team = player->GetBGTeam();
982
984 bp.OfflineRemoveTime = 0;
985 bp.Team = team;
987 bp.queueTypeId = queueId;
988
989 bool const isInBattleground = IsPlayerInBattleground(player->GetGUID());
990 // Add to list/maps
991 m_Players[player->GetGUID()] = bp;
992
993 if (!isInBattleground)
994 {
995 UpdatePlayersCountByTeam(team, false); // +1 player
996 PlayerScores[player->GetGUID()] = new BattlegroundScore(player->GetGUID(), player->GetBGTeam(), _pvpStatIds);
997 }
998
1000 playerJoined.Guid = player->GetGUID();
1001 SendPacketToTeam(team, playerJoined.Write(), player);
1002
1004 pvpMatchInitialize.MapID = GetMapId();
1005 switch (GetStatus())
1006 {
1007 case STATUS_NONE:
1008 case STATUS_WAIT_QUEUE:
1010 break;
1011 case STATUS_WAIT_JOIN:
1013 break;
1014 case STATUS_IN_PROGRESS:
1016 break;
1017 case STATUS_WAIT_LEAVE:
1019 break;
1020 default:
1021 break;
1022 }
1023
1025 {
1027 pvpMatchInitialize.Duration = std::chrono::duration_cast<Seconds>(duration);
1028 pvpMatchInitialize.StartTime = GameTime::GetSystemTime() - duration;
1029 }
1030
1031 pvpMatchInitialize.ArenaFaction = player->GetBGTeam() == HORDE ? PVP_TEAM_HORDE : PVP_TEAM_ALLIANCE;
1032 pvpMatchInitialize.BattlemasterListID = queueId.BattlemasterListId;
1033 pvpMatchInitialize.Registered = false;
1034 pvpMatchInitialize.AffectsRating = isRated();
1035
1036 player->SendDirectMessage(pvpMatchInitialize.Write());
1037
1039
1040 // add arena specific auras
1041 if (isArena())
1042 {
1044 player->DestroyConjuredItems(true);
1045 player->UnsummonPetTemporaryIfAny();
1046
1047 if (GetStatus() == STATUS_WAIT_JOIN) // not started yet
1048 {
1049 player->CastSpell(player, SPELL_ARENA_PREPARATION, true);
1050 player->ResetAllPowers();
1051 }
1052 }
1053 else
1054 {
1055 if (GetStatus() == STATUS_WAIT_JOIN) // not started yet
1056 player->CastSpell(player, SPELL_PREPARATION, true); // reduces all mana cost of spells.
1057
1058 if (bp.Mercenary)
1059 {
1060 if (bp.Team == HORDE)
1061 {
1062 player->CastSpell(player, SPELL_MERCENARY_HORDE_1);
1064 }
1065 else if (bp.Team == ALLIANCE)
1066 {
1067 player->CastSpell(player, SPELL_MERCENARY_ALLIANCE_1);
1069 }
1070 player->CastSpell(player, SPELL_MERCENARY_SHAPESHIFT);
1072 }
1073 }
1074
1075 // setup BG group membership
1077 AddOrSetPlayerToCorrectBgGroup(player, team);
1078
1079 GetBgMap()->GetBattlegroundScript()->OnPlayerJoined(player, isInBattleground);
1080}
1081
1082// this method adds player to his team's bg group, or sets his correct group if player is already in bg group
1084{
1085 ObjectGuid playerGuid = player->GetGUID();
1086 Group* group = GetBgRaid(team);
1087 if (!group) // first player joined
1088 {
1089 group = new Group;
1090 SetBgRaid(team, group);
1091 group->Create(player);
1092 sGroupMgr->AddGroup(group);
1093 Seconds countdownMaxForBGType = Seconds(StartDelayTimes[BG_STARTING_EVENT_FIRST] / 1000);
1095 group->StartCountdown(CountdownTimerType::Pvp, countdownMaxForBGType, _preparationStartTime);
1096 else
1097 group->StartCountdown(CountdownTimerType::Pvp, countdownMaxForBGType);
1098 }
1099 else // raid already exist
1100 {
1101 if (group->IsMember(playerGuid))
1102 {
1103 uint8 subgroup = group->GetMemberGroup(playerGuid);
1104 player->SetBattlegroundOrBattlefieldRaid(group, subgroup);
1105 }
1106 else
1107 {
1108 group->AddMember(player);
1109 if (Group* originalGroup = player->GetOriginalGroup())
1110 if (originalGroup->IsLeader(playerGuid))
1111 {
1112 group->ChangeLeader(playerGuid);
1113 group->SendUpdate();
1114 }
1115 }
1116 }
1117}
1118
1119// This method should be called when player logs into running battleground
1121{
1122 ObjectGuid guid = player->GetGUID();
1123 // player is correct pointer
1124 for (auto itr = m_OfflineQueue.begin(); itr != m_OfflineQueue.end(); ++itr)
1125 {
1126 if (*itr == guid)
1127 {
1128 m_OfflineQueue.erase(itr);
1129 break;
1130 }
1131 }
1132 m_Players[guid].OfflineRemoveTime = 0;
1134 // if battleground is starting, then add preparation aura
1135 // we don't have to do that, because preparation aura isn't removed when player logs out
1136}
1137
1138// This method should be called when player logs out from running battleground
1140{
1141 ObjectGuid guid = player->GetGUID();
1142 if (!IsPlayerInBattleground(guid)) // Check if this player really is in battleground (might be a GM who teleported inside)
1143 return;
1144
1145 // player is correct pointer, it is checked in WorldSession::LogoutPlayer()
1146 m_OfflineQueue.push_back(player->GetGUID());
1147 m_Players[guid].OfflineRemoveTime = GameTime::GetGameTime() + MAX_OFFLINE_TIME;
1149 {
1150 // drop flag and handle other cleanups
1151 RemovePlayer(player, guid, GetPlayerTeam(guid));
1152
1153 // 1 player is logging out, if it is the last alive, then end arena!
1154 if (isArena() && player->IsAlive())
1157 }
1158}
1159
1160// This method should be called only once ... it adds pointer to queue
1162{
1164 {
1165 sBattlegroundMgr->AddToBGFreeSlotQueue(this);
1166 m_InBGFreeSlotQueue = true;
1167 }
1168}
1169
1170// This method removes this battleground from free queue - it must be called when deleting battleground
1172{
1174 {
1175 sBattlegroundMgr->RemoveFromBGFreeSlotQueue(GetMapId(), m_InstanceID);
1176 m_InBGFreeSlotQueue = false;
1177 }
1178}
1179
1180// get the number of free slots for team
1181// returns the number how many players can join battleground to MaxPlayersPerTeam
1183{
1184 // if BG is starting and CONFIG_BATTLEGROUND_INVITATION_TYPE == BG_QUEUE_INVITATION_TYPE_NO_BALANCE, invite anyone
1187
1188 // 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
1189 uint32 otherTeamInvitedCount;
1190 uint32 thisTeamInvitedCount;
1191 uint32 otherTeamPlayersCount;
1192 uint32 thisTeamPlayersCount;
1193
1194 if (team == ALLIANCE)
1195 {
1196 thisTeamInvitedCount = GetInvitedCount(ALLIANCE);
1197 otherTeamInvitedCount = GetInvitedCount(HORDE);
1198 thisTeamPlayersCount = GetPlayersCountByTeam(ALLIANCE);
1199 otherTeamPlayersCount = GetPlayersCountByTeam(HORDE);
1200 }
1201 else
1202 {
1203 thisTeamInvitedCount = GetInvitedCount(HORDE);
1204 otherTeamInvitedCount = GetInvitedCount(ALLIANCE);
1205 thisTeamPlayersCount = GetPlayersCountByTeam(HORDE);
1206 otherTeamPlayersCount = GetPlayersCountByTeam(ALLIANCE);
1207 }
1209 {
1210 // difference based on ppl invited (not necessarily entered battle)
1211 // default: allow 0
1212 uint32 diff = 0;
1213
1214 // allow join one person if the sides are equal (to fill up bg to minPlayerPerTeam)
1215 if (otherTeamInvitedCount == thisTeamInvitedCount)
1216 diff = 1;
1217 // allow join more ppl if the other side has more players
1218 else if (otherTeamInvitedCount > thisTeamInvitedCount)
1219 diff = otherTeamInvitedCount - thisTeamInvitedCount;
1220
1221 // difference based on max players per team (don't allow inviting more)
1222 uint32 diff2 = (thisTeamInvitedCount < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - thisTeamInvitedCount : 0;
1223
1224 // difference based on players who already entered
1225 // default: allow 0
1226 uint32 diff3 = 0;
1227 // allow join one person if the sides are equal (to fill up bg minPlayerPerTeam)
1228 if (otherTeamPlayersCount == thisTeamPlayersCount)
1229 diff3 = 1;
1230 // allow join more ppl if the other side has more players
1231 else if (otherTeamPlayersCount > thisTeamPlayersCount)
1232 diff3 = otherTeamPlayersCount - thisTeamPlayersCount;
1233 // or other side has less than minPlayersPerTeam
1234 else if (thisTeamInvitedCount <= GetMinPlayersPerTeam())
1235 diff3 = GetMinPlayersPerTeam() - thisTeamInvitedCount + 1;
1236
1237 // return the minimum of the 3 differences
1238
1239 // min of diff and diff 2
1240 diff = std::min(diff, diff2);
1241 // min of diff, diff2 and diff3
1242 return std::min(diff, diff3);
1243 }
1244 return 0;
1245}
1246
1248{
1250}
1251
1253{
1254 return !isArena();
1255}
1256
1258{
1259 return GetPlayersSize() < GetMaxPlayers();
1260}
1261
1263{
1264 pvpLogData.Statistics.reserve(GetPlayerScoresSize());
1265 for (auto const& score : PlayerScores)
1266 {
1267 if (Player* player = ObjectAccessor::GetPlayer(GetBgMap(), score.first))
1268 {
1270 score.second->BuildPvPLogPlayerDataPacket(playerData);
1271
1272 playerData.IsInWorld = true;
1273 playerData.PrimaryTalentTree = AsUnderlyingType(player->GetPrimarySpecialization());
1274 playerData.Sex = player->GetGender();
1275 playerData.Race = player->GetRace();
1276 playerData.Class = player->GetClass();
1277 playerData.HonorLevel = player->GetHonorLevel();
1278
1279 pvpLogData.Statistics.push_back(playerData);
1280 }
1281 }
1282
1285}
1286
1291
1292bool Battleground::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor, Optional<HonorGainSource> source)
1293{
1294 BattlegroundScoreMap::const_iterator itr = PlayerScores.find(player->GetGUID());
1295 if (itr == PlayerScores.end()) // player not found...
1296 return false;
1297
1298 if (type == SCORE_BONUS_HONOR && doAddHonor && isBattleground())
1299 player->RewardHonor(nullptr, 1, value, source.value_or(HonorGainSource::Kill)); // RewardHonor calls UpdatePlayerScore with doAddHonor = false
1300 else
1301 itr->second->UpdateScore(type, value);
1302
1303 return true;
1304}
1305
1306void Battleground::UpdatePvpStat(Player* player, uint32 pvpStatId, uint32 value)
1307{
1309 score->UpdatePvpStat(pvpStatId, value);
1310}
1311
1313{
1314 return _battlegroundTemplate->MapIDs.front();
1315}
1316
1318{
1319 m_Map = map;
1320 if (map)
1321 _pvpStatIds = sDB2Manager.GetPVPStatIDsForMap(map->GetId());
1322 else
1323 _pvpStatIds = nullptr;
1324}
1325
1326void Battleground::SendMessageToAll(uint32 entry, ChatMsg msgType, Player const* source)
1327{
1328 if (!entry)
1329 return;
1330
1331 Trinity::TrinityStringChatBuilder builder(nullptr, msgType, entry, source);
1333 BroadcastWorker(localizer);
1334}
1335
1340
1342{
1344 _playerPositions.erase(itr.begin(), itr.end());
1345}
1346
1353
1355{
1356 // Keep in mind that for arena this will have to be changed a bit
1357
1358 // Add +1 deaths
1359 UpdatePlayerScore(victim, SCORE_DEATHS, 1);
1360 // Add +1 kills to group and +1 killing_blows to killer
1361 if (killer)
1362 {
1363 // Don't reward credit for killing ourselves, like fall damage of hellfire (warlock)
1364 if (killer == victim)
1365 return;
1366
1367 Team killerTeam = GetPlayerTeam(killer->GetGUID());
1368
1371 killer->UpdateCriteria(CriteriaType::KillPlayer, 1, 0, 0, victim);
1372
1373 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1374 {
1375 Player* creditedPlayer = ObjectAccessor::FindPlayer(itr->first);
1376 if (!creditedPlayer || creditedPlayer == killer)
1377 continue;
1378
1379 if (itr->second.Team == killerTeam && creditedPlayer->IsAtGroupRewardDistance(victim))
1380 {
1381 UpdatePlayerScore(creditedPlayer, SCORE_HONORABLE_KILLS, 1);
1382 creditedPlayer->UpdateCriteria(CriteriaType::KillPlayer, 1, 0, 0, victim);
1383 }
1384 }
1385 }
1386
1387 if (!isArena())
1388 {
1389 // To be able to remove insignia -- ONLY IN Battlegrounds
1391 RewardXPAtKill(killer, victim);
1392 }
1393
1394 if (BattlegroundScript* script = GetBgMap()->GetBattlegroundScript())
1395 script->OnPlayerKilled(victim, killer);
1396}
1397
1399{
1400 if (BattlegroundScript* script = GetBgMap()->GetBattlegroundScript())
1401 script->OnUnitKilled(victim, killer);
1402}
1403
1404// Return the player's team based on battlegroundplayer info
1405// Used in same faction arena matches mainly
1407{
1408 BattlegroundPlayerMap::const_iterator itr = m_Players.find(guid);
1409 if (itr != m_Players.end())
1410 return itr->second.Team;
1411 return TEAM_OTHER;
1412}
1413
1415{
1416 BattlegroundPlayerMap::const_iterator itr = m_Players.find(guid);
1417 if (itr != m_Players.end())
1418 return true;
1419 return false;
1420}
1421
1423{
1424 auto itr = m_Players.find(guid);
1425 if (itr != m_Players.end())
1426 return itr->second.Mercenary;
1427 return false;
1428}
1429
1431{
1433 return;
1434
1435 BlockMovement(player);
1436
1438 BuildPvPLogDataPacket(pvpMatchStatistics.Data);
1439 player->SendDirectMessage(pvpMatchStatistics.Write());
1440}
1441
1443{
1444 int count = 0;
1445 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1446 {
1447 if (itr->second.Team == team)
1448 {
1449 Player* player = ObjectAccessor::FindPlayer(itr->first);
1450 if (player && player->IsAlive())
1451 ++count;
1452 }
1453 }
1454 return count;
1455}
1456
1458{
1459 Group*& old_raid = team == ALLIANCE ? m_BgRaids[TEAM_ALLIANCE] : m_BgRaids[TEAM_HORDE];
1460 if (old_raid)
1461 old_raid->SetBattlegroundGroup(nullptr);
1462 if (bg_raid)
1463 bg_raid->SetBattlegroundGroup(this);
1464 old_raid = bg_raid;
1465}
1466
1468{
1469 _pvpDifficultyEntry = bracketEntry;
1470}
1471
1473{
1474 if (sWorld->getBoolConfig(CONFIG_BG_XP_FOR_KILL) && killer && victim)
1475 {
1476 Player* killers[] = { killer };
1477 KillRewarder(Trinity::IteratorPair(std::begin(killers), std::end(killers)), victim, true).Reward();
1478 }
1479}
1480
1482{
1483 if (teamId == TEAM_ALLIANCE || teamId == TEAM_HORDE)
1484 return m_TeamScores[teamId];
1485
1486 TC_LOG_ERROR("bg.battleground", "GetTeamScore with wrong Team {} for BG {}", teamId, GetTypeID());
1487 return 0;
1488}
1489
1490char const* Battleground::GetName() const
1491{
1492 return _battlegroundTemplate->BattlemasterEntry->Name[sWorld->GetDefaultDbcLocale()];
1493}
1494
1499
1504
1506{
1507 return uint8(GetMinLevel() / 5) - 1; // 10 - 1, 15 - 2, 20 - 3, etc.
1508}
1509
1511{
1512 return GetMaxPlayersPerTeam() * 2;
1513}
1514
1516{
1517 return GetMinPlayersPerTeam() * 2;
1518}
1519
1527
1535
1537{
1538 if (isArena())
1539 {
1540 switch (GetArenaType())
1541 {
1542 case ARENA_TYPE_2v2:
1543 return 2;
1544 case ARENA_TYPE_3v3:
1545 return 3;
1546 case ARENA_TYPE_5v5: // removed
1547 return 5;
1548 default:
1549 break;
1550 }
1551 }
1552
1554}
1555
#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:579
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:72
#define sGroupMgr
Definition GroupMgr.h:66
#define sGuildMgr
Definition GuildMgr.h:76
@ TEMP_ENCHANTMENT_SLOT
@ LANG_BG_STARTED_ANNOUNCE_WORLD
Definition Language.h:710
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:173
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
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:378
@ PLAYER_FLAGS_EX_MERCENARY_MODE
Definition Player.h:551
@ 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_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:3533
void SetBG(Battleground *bg)
Definition Map.h:943
BattlegroundScript * GetBattlegroundScript()
Definition Map.h:947
static void BuildBattlegroundStatusActive(WorldPackets::Battleground::BattlefieldStatusActive *battlefieldStatus, Battleground const *bg, Player const *player, uint32 ticketId, uint32 joinTime, BattlegroundQueueTypeId queueId)
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]
void RemoveAuraOnTeam(uint32 SpellID, Team team)
virtual WorldSafeLocsEntry const * GetExploitTeleportLocation(Team)
int32 m_TeamScores[PVP_TEAMS_COUNT]
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:209
uint8 GetMemberGroup(ObjectGuid guid) const
Definition Group.cpp:1703
void SendUpdate() const
Definition Group.cpp:809
bool AddMember(Player *player)
Definition Group.cpp:424
void ChangeLeader(ObjectGuid guid)
Definition Group.cpp:663
void SetBattlegroundGroup(Battleground *bg)
Definition Group.cpp:1711
bool IsMember(ObjectGuid guid) const
Definition Group.cpp:1655
bool Create(Player *leader)
Definition Group.cpp:141
void StartCountdown(CountdownTimerType timerType, Seconds duration, Optional< time_t > startTime={ })
Definition Group.cpp:1386
Definition Guild.h:329
void UnloadAll()
Definition Map.cpp:1662
uint32 GetId() const
Definition Map.cpp:3288
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:6673
void SetClientControl(Unit *target, bool allowMove)
Definition Player.cpp:26441
void SetBGTeam(Team team)
Definition Player.cpp:24271
void SetPlayerFlagEx(PlayerFlagsEx flags)
Definition Player.h:2901
bool HasPlayerFlagEx(PlayerFlagsEx flags) const
Definition Player.h:2900
void SetBattlegroundId(uint32 val, BattlegroundTypeId bgTypeId, BattlegroundQueueTypeId queueId)
Definition Player.cpp:25704
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6193
void ClearAfkReports()
Definition Player.h:2603
static void OfflineResurrect(ObjectGuid const &guid, CharacterDatabaseTransaction trans)
Definition Player.cpp:4387
void RemovePlayerFlagEx(PlayerFlagsEx flags)
Definition Player.h:2902
void SpawnCorpseBones(bool triggerSave=true)
Definition Player.cpp:4453
Group * GetOriginalGroup() const
Definition Player.h:2800
uint32 GetBattlegroundQueueJoinTime(BattlegroundQueueTypeId bgQueueTypeId) const
Definition Player.cpp:25658
bool IsMercenaryForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
Definition Player.cpp:25772
bool IsAtGroupRewardDistance(WorldObject const *pRewardSource) const
Definition Player.cpp:26375
void DestroyConjuredItems(bool update)
Definition Player.cpp:12364
void UnsummonPetTemporaryIfAny()
Definition Player.cpp:27929
void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val)
Definition Player.cpp:25735
bool GetRandomWinner() const
Definition Player.h:2610
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition Player.cpp:27532
void RemovePet(Pet *pet, PetSaveMode mode, bool returnreagent=false)
Definition Player.cpp:22031
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:1181
bool TeleportToBGEntryPoint()
Definition Player.cpp:1436
void ToggleAFK()
Definition Player.cpp:1143
uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const
Definition Player.cpp:25683
void ResetAllPowers()
Definition Player.cpp:1770
bool isAFK() const
Definition Player.h:1267
Team GetEffectiveTeam() const
Definition Player.h:2410
void FailCriteria(CriteriaFailEvent condition, int32 failAsset)
Definition Player.cpp:27526
void ResummonPetTemporaryUnSummonedIfAny()
Definition Player.cpp:27944
Team GetBGTeam() const
Definition Player.cpp:24277
void SetBattlegroundOrBattlefieldRaid(Group *group, int8 subgroup=-1)
Definition Player.cpp:26689
ReputationMgr & GetReputationMgr()
Definition Player.h:2422
void RemoveArenaEnchantments(EnchantmentSlot slot)
Definition Player.cpp:13335
void SetRandomWinner(bool isWinner)
Definition Player.cpp:29956
void ResurrectPlayer(float restore_percent, bool applySickness=false)
Definition Player.cpp:4269
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:647
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3973
void CombatStop(bool includingCast=false, bool mutualPvP=true, bool(*unitFilter)(Unit const *otherUnit)=nullptr)
Definition Unit.cpp:6031
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3846
void AtEndOfEncounter(EncounterType type)
Definition Unit.cpp:573
bool IsAlive() const
Definition Unit.h:1205
float GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:5087
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4832
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition Unit.cpp:4259
float GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:5147
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:861
void CombatStopWithPets(bool includingCast=false)
Definition Unit.cpp:6059
constexpr uint32 GetMapId() const
Definition Position.h:216
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2222
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:919
@ CONFIG_BG_REWARD_LOSER_HONOR_LAST
Definition World.h:402
@ CONFIG_BATTLEGROUND_INVITATION_TYPE
Definition World.h:337
@ CONFIG_BG_REWARD_WINNER_HONOR_FIRST
Definition World.h:399
@ CONFIG_BG_REWARD_LOSER_HONOR_FIRST
Definition World.h:401
@ CONFIG_BG_REWARD_WINNER_HONOR_LAST
Definition World.h:400
@ 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:835