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 "ArenaScore.h"
20#include "BattlegroundMgr.h"
21#include "BattlegroundPackets.h"
22#include "BattlegroundScore.h"
23#include "ChatTextBuilder.h"
24#include "Creature.h"
25#include "CreatureTextMgr.h"
26#include "DatabaseEnv.h"
27#include "Formulas.h"
28#include "GameTime.h"
29#include "GridNotifiersImpl.h"
30#include "Group.h"
31#include "GroupMgr.h"
32#include "MiscPackets.h"
33#include "Object.h"
34#include "ObjectAccessor.h"
35#include "ObjectMgr.h"
36#include "Player.h"
37#include "ReputationMgr.h"
38#include "SpellAuras.h"
39#include "TemporarySummon.h"
40#include "Transport.h"
41#include "Util.h"
42#include "WorldPacket.h"
43#include "WorldStatePackets.h"
44#include <cstdarg>
45
47{
48 playerData.PlayerGUID = PlayerGuid;
49
50 playerData.Kills = KillingBlows;
52 {
54 .Deaths = Deaths,
55 .ContributionPoints = BonusHonor
56 };
57 playerData.DamageDone = DamageDone;
58 playerData.HealingDone = HealingDone;
59
60 BuildObjectivesBlock(playerData);
61}
62
63template<class Do>
65{
66 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
67 if (Player* player = _GetPlayer(itr, "BroadcastWorker"))
68 _do(player);
69}
70
72{
75 m_InstanceID = 0;
78 m_EndTime = 0;
83 m_ArenaType = 0;
84 m_IsArena = false;
86 m_StartTime = 0;
89 m_Events = 0;
91 m_IsRated = false;
92 m_BuffChange = false;
93 m_IsRandom = false;
94 m_LevelMin = 0;
95 m_LevelMax = 0;
96 m_InBGFreeSlotQueue = false;
97 m_SetDeleteThis = false;
98
100 m_MaxPlayers = 0;
102 m_MinPlayers = 0;
103
104 m_MapId = 0;
105 m_Map = nullptr;
106 m_StartMaxDist = 0.0f;
107 ScriptId = 0;
108
111
114
115 m_BgRaids[TEAM_ALLIANCE] = nullptr;
116 m_BgRaids[TEAM_HORDE] = nullptr;
117
120
123
124 m_PrematureCountDown = false;
126
128
133
138}
139
141{
142 // remove objects and creatures
143 // (this is done automatically in mapmanager update, when the instance is reset after the reset time)
144 uint32 size = uint32(BgCreatures.size());
145 for (uint32 i = 0; i < size; ++i)
146 DelCreature(i);
147
148 size = uint32(BgObjects.size());
149 for (uint32 i = 0; i < size; ++i)
150 DelObject(i);
151
152 // unload map
153 if (m_Map)
154 {
155 m_Map->SetUnload();
156 //unlink to prevent crash, always unlink all pointer reference before destruction
157 m_Map->SetBG(nullptr);
158 m_Map = nullptr;
159 }
160
161 // Clear Group::m_bgGroup, Group might later reference it in its own destructor
162 for (Group* bgRaid : m_BgRaids)
163 if (bgRaid)
164 bgRaid->SetBattlegroundGroup(nullptr);
165
166 // remove from bg free slot queue
168
169 for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr)
170 delete itr->second;
171}
172
174{
175 if (!PreUpdateImpl(diff))
176 return;
177
178 if (!GetPlayersSize())
179 {
180 //BG is empty
181 // if there are no players invited, delete BG
182 // this will delete arena or bg object, where any player entered
183 // [[ but if you use battleground object again (more battles possible to be played on 1 instance)
184 // then this condition should be removed and code:
185 // if (!GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
186 // AddToFreeBGObjectsQueue(); // not yet implemented
187 // should be used instead of current
188 // ]]
189 // Battleground Template instance cannot be updated, because it would be deleted
191 m_SetDeleteThis = true;
192 return;
193 }
194
195 switch (GetStatus())
196 {
197 case STATUS_WAIT_JOIN:
198 if (GetPlayersSize())
199 {
200 _ProcessJoin(diff);
202 }
203 break;
206 // after 47 minutes without one team losing, the arena closes with no winner and no rating change
207 if (isArena())
208 {
209 if (GetStartTime() >= 47 * MINUTE*IN_MILLISECONDS)
210 {
212 return;
213 }
214 }
215 else
216 {
217 _ProcessResurrect(diff);
219 _ProcessProgress(diff);
220 else if (m_PrematureCountDown)
221 m_PrematureCountDown = false;
222 }
223 break;
225 _ProcessLeave(diff);
226 break;
227 default:
228 break;
229 }
230
231 // Update start time and reset stats timer
232 m_StartTime += diff;
233 m_ResetStatTimer += diff;
234
235 PostUpdateImpl(diff);
236}
237
239{
240 float maxDist = GetStartMaxDist();
241 if (!maxDist)
242 return;
243
246 {
248
249 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
250 {
251 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
252 {
253 if (player->IsGameMaster())
254 continue;
255
256 Position pos = player->GetPosition();
257 Position const* startPos = GetTeamStartPosition(Battleground::GetTeamIndexByTeamId(player->GetBGTeam()));
258 if (pos.GetExactDistSq(startPos) > maxDist)
259 {
260 TC_LOG_DEBUG("bg.battleground", "BATTLEGROUND: Sending {} back to start location (map: {}) (possible exploit)", player->GetName(), GetMapId());
261 player->TeleportTo(GetMapId(), startPos->GetPositionX(), startPos->GetPositionY(), startPos->GetPositionZ(), startPos->GetOrientation());
262 }
263 }
264 }
265 }
266}
267
269{
270 // remove offline players from bg after 5 minutes
271 if (!m_OfflineQueue.empty())
272 {
273 BattlegroundPlayerMap::iterator itr = m_Players.find(*(m_OfflineQueue.begin()));
274 if (itr != m_Players.end())
275 {
276 if (itr->second.OfflineRemoveTime <= GameTime::GetGameTime())
277 {
280 {
282 stmt->setUInt32(0, itr->first.GetCounter());
284 CharacterDatabase.Execute(stmt);
285 }
286
287 RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
288 m_OfflineQueue.pop_front(); // remove from offline queue
289 //do not use itr for anything, because it is erased in RemovePlayerAtLeave()
290 }
291 }
292 }
293}
294
296{
297 // *********************************************************
298 // *** BATTLEGROUND RESURRECTION SYSTEM ***
299 // *********************************************************
300 // this should be handled by spell system
301 m_LastResurrectTime += diff;
303 {
304 if (GetReviveQueueSize())
305 {
306 for (std::map<ObjectGuid, GuidVector>::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
307 {
308 Creature* sh = nullptr;
309 for (GuidVector::const_iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
310 {
311 Player* player = ObjectAccessor::FindPlayer(*itr2);
312 if (!player)
313 continue;
314
315 if (!sh && player->IsInWorld())
316 {
317 sh = player->GetMap()->GetCreature(itr->first);
318 // only for visual effect
319 if (sh)
320 // Spirit Heal, effect 117
321 sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true);
322 }
323
324 // Resurrection visual
325 player->CastSpell(player, SPELL_RESURRECTION_VISUAL, true);
326 m_ResurrectQueue.push_back(*itr2);
327 }
328 (itr->second).clear();
329 }
330
331 m_ReviveQueue.clear();
333 }
334 else
335 // queue is clear and time passed, just update last resurrection time
337 }
338 else if (m_LastResurrectTime > 500) // Resurrect players only half a second later, to see spirit heal effect on NPC
339 {
340 for (GuidVector::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
341 {
342 Player* player = ObjectAccessor::FindPlayer(*itr);
343 if (!player)
344 continue;
345 player->ResurrectPlayer(1.0f);
346 player->CastSpell(player, 6962, true);
347 player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
348 player->SpawnCorpseBones(false);
349 }
350 m_ResurrectQueue.clear();
351 }
352}
353
355{
356 uint32 winner = 0;
358 winner = ALLIANCE;
360 winner = HORDE;
361
362 return winner;
363}
364
366{
367 // *********************************************************
368 // *** BATTLEGROUND BALLANCE SYSTEM ***
369 // *********************************************************
370 // if less then minimum players are in on one side, then start premature finish timer
372 {
374 m_PrematureCountDownTimer = sBattlegroundMgr->GetPrematureFinishTime();
375 }
376 else if (m_PrematureCountDownTimer < diff)
377 {
378 // time's up!
380 m_PrematureCountDown = false;
381 }
382 else if (!sBattlegroundMgr->isTesting())
383 {
384 uint32 newtime = m_PrematureCountDownTimer - diff;
385 // announce every minute
386 if (newtime > (MINUTE * IN_MILLISECONDS))
387 {
390 }
391 else
392 {
393 //announce every 15 seconds
394 if (newtime / (15 * IN_MILLISECONDS) != m_PrematureCountDownTimer / (15 * IN_MILLISECONDS))
396 }
398 }
399}
400
402{
403 // *********************************************************
404 // *** BATTLEGROUND STARTING SYSTEM ***
405 // *********************************************************
407
408 if (m_ResetStatTimer > 5000)
409 {
411 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
412 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
413 player->ResetAllPowers();
414 }
415
417 {
419
420 if (!FindBgMap())
421 {
422 TC_LOG_ERROR("bg.battleground", "Battleground::_ProcessJoin: map (map id: {}, instance id: {}) is not created!", m_MapId, m_InstanceID);
423 EndNow();
424 return;
425 }
426
427 // Setup here, only when at least one player has ported to the map
428 if (!SetupBattleground())
429 {
430 EndNow();
431 return;
432 }
433
436 // First start warning - 2 or 1 minute
439 }
440 // After 1 minute or 30 seconds, warning is signaled
442 {
446 }
447 // After 30 or 15 seconds, warning is signaled
449 {
453 }
454 // Delay expired (after 2 or 1 minute)
455 else if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4))
456 {
458
460
465
466 // Remove preparation
467 if (isArena())
468 {
470 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
471 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
472 {
473 // BG Status packet
476 BattlegroundMgr::BuildBattlegroundStatusActive(&battlefieldStatus, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), bgQueueTypeId);
477 player->SendDirectMessage(battlefieldStatus.Write());
478
479 player->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
480 player->ResetAllPowers();
481 if (!player->IsGameMaster())
482 {
483 // remove auras with duration lower than 30s
484 player->RemoveAppliedAuras([](AuraApplication const* aurApp)
485 {
486 Aura* aura = aurApp->GetBase();
487 return !aura->IsPermanent()
488 && aura->GetDuration() <= 30 * IN_MILLISECONDS
489 && aurApp->IsPositive()
492 });
493 }
494 }
495
497 }
498 else
499 {
501
502 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
503 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
504 {
505 player->RemoveAurasDueToSpell(SPELL_PREPARATION);
506 player->ResetAllPowers();
507 }
508 // Announce BG starting
511 }
512 }
513}
514
516{
517 // *********************************************************
518 // *** BATTLEGROUND ENDING SYSTEM ***
519 // *********************************************************
520 // remove all players from battleground after 2 minutes
521 m_EndTime -= diff;
522 if (m_EndTime <= 0)
523 {
524 m_EndTime = 0;
525 BattlegroundPlayerMap::iterator itr, next;
526 for (itr = m_Players.begin(); itr != m_Players.end(); itr = next)
527 {
528 next = itr;
529 ++next;
530 //itr is erased here!
531 RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
532 // do not change any battleground's private variables
533 }
534 }
535}
536
537Player* Battleground::_GetPlayer(ObjectGuid guid, bool offlineRemove, char const* context) const
538{
539 Player* player = nullptr;
540 if (!offlineRemove)
541 {
542 // should this be ObjectAccessor::FindConnectedPlayer() to return players teleporting ?
543 player = ObjectAccessor::FindPlayer(guid);
544 if (!player)
545 TC_LOG_ERROR("bg.battleground", "Battleground::{}: player ({}) not found for BG (map: {}, instance id: {})!",
546 context, guid.ToString(), m_MapId, m_InstanceID);
547 }
548 return player;
549}
550
551Player* Battleground::_GetPlayerForTeam(uint32 teamId, BattlegroundPlayerMap::const_iterator itr, char const* context) const
552{
553 Player* player = _GetPlayer(itr, context);
554 if (player)
555 {
556 uint32 team = itr->second.Team;
557 if (!team)
558 team = player->GetTeam();
559 if (team != teamId)
560 player = nullptr;
561 }
562 return player;
563}
564
566{
567 ASSERT(teamId < TEAM_NEUTRAL);
568 StartPosition[teamId] = pos;
569}
570
572{
573 ASSERT(teamId < TEAM_NEUTRAL);
574 return &StartPosition[teamId];
575}
576
578{
579 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
580 if (Player* player = _GetPlayer(itr, "SendPacketToAll"))
581 player->SendDirectMessage(packet);
582}
583
584void Battleground::SendPacketToTeam(uint32 TeamID, WorldPacket const* packet, Player* sender, bool self) const
585{
586 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
587 {
588 if (Player* player = _GetPlayerForTeam(TeamID, itr, "SendPacketToTeam"))
589 {
590 if (self || sender != player)
591 player->SendDirectMessage(packet);
592 }
593 }
594}
595
596void Battleground::SendChatMessage(Creature* source, uint8 textId, WorldObject* target /*= nullptr*/)
597{
598 sCreatureTextMgr->SendChat(source, textId, target);
599}
600
602{
603 if (!sObjectMgr->GetBroadcastText(id))
604 {
605 TC_LOG_ERROR("bg.battleground", "Battleground::SendBroadcastText: `broadcast_text` (ID: {}) was not found", id);
606 return;
607 }
608
609 Trinity::BroadcastTextBuilder builder(nullptr, msgType, id, GENDER_MALE, target);
611 BroadcastWorker(localizer);
612}
613
618
620{
621 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
622 {
623 if (Player* player = _GetPlayerForTeam(teamID, itr, "PlaySoundToTeam"))
624 player->SendDirectMessage(WorldPackets::Misc::PlaySound(soundID).Write());
625 }
626}
627
629{
630 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
631 if (Player* player = _GetPlayerForTeam(TeamID, itr, "CastSpellOnTeam"))
632 player->CastSpell(player, SpellID, true);
633}
634
636{
637 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
638 if (Player* player = _GetPlayerForTeam(TeamID, itr, "RemoveAuraOnTeam"))
639 player->RemoveAura(SpellID);
640}
641
643{
644 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
645 if (Player* player = _GetPlayerForTeam(TeamID, itr, "RewardHonorToTeam"))
646 UpdatePlayerScore(player, SCORE_BONUS_HONOR, Honor);
647}
648
649void Battleground::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
650{
651 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
652 if (!factionEntry)
653 return;
654
655 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
656 {
657 Player* player = _GetPlayerForTeam(TeamID, itr, "RewardReputationToTeam");
658 if (!player)
659 continue;
660
661 uint32 repGain = Reputation;
664 player->GetReputationMgr().ModifyReputation(factionEntry, repGain);
665 }
666}
667
669{
671 worldstate.VariableID = variable;
672 worldstate.Value = value;
673 SendPacketToAll(worldstate.Write());
674}
675
677{
679
680 if (winner == ALLIANCE)
681 {
682 if (isBattleground())
684
685 PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound
686
688 }
689 else if (winner == HORDE)
690 {
691 if (isBattleground())
693
694 PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
695
697 }
698 else
699 {
701 }
702
704 uint64 battlegroundId = 1;
706 {
707 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PVPSTATS_MAXID);
708 PreparedQueryResult result = CharacterDatabase.Query(stmt);
709
710 if (result)
711 {
712 Field* fields = result->Fetch();
713 battlegroundId = fields[0].GetUInt64() + 1;
714 }
715
716 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_BATTLEGROUND);
717 stmt->setUInt64(0, battlegroundId);
718 stmt->setUInt8(1, GetWinner());
719 stmt->setUInt8(2, GetUniqueBracketId());
720 stmt->setUInt8(3, GetTypeID(true));
721 CharacterDatabase.Execute(stmt);
722 }
723
725 //we must set it this way, because end time is sent in packet!
727
729 BuildPvPLogDataPacket(pvpMatchStatistics);
730 pvpMatchStatistics.Write();
731
733
734 for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
735 {
736 uint32 team = itr->second.Team;
737
738 Player* player = _GetPlayer(itr, "EndBattleground");
739 if (!player)
740 continue;
741
742 // should remove spirit of redemption
745
746 if (!player->IsAlive())
747 {
748 player->ResurrectPlayer(1.0f);
749 player->SpawnCorpseBones();
750 }
751 else
752 //needed cause else in av some creatures will kill the players at the end
753 player->CombatStop();
754
755 uint32 winner_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_FIRST);
756 uint32 loser_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_FIRST);
757 uint32 winner_arena = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_FIRST);
758
760 {
761 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_PLAYER);
762 BattlegroundScoreMap::const_iterator score = PlayerScores.find(player->GetGUID());
763
764 stmt->setUInt32(0, battlegroundId);
765 stmt->setUInt32(1, player->GetGUID().GetCounter());
766 stmt->setBool (2, team == winner);
767 stmt->setUInt32(3, score->second->GetKillingBlows());
768 stmt->setUInt32(4, score->second->GetDeaths());
769 stmt->setUInt32(5, score->second->GetHonorableKills());
770 stmt->setUInt32(6, score->second->GetBonusHonor());
771 stmt->setUInt32(7, score->second->GetDamageDone());
772 stmt->setUInt32(8, score->second->GetHealingDone());
773 stmt->setUInt32(9, score->second->GetAttr1());
774 stmt->setUInt32(10, score->second->GetAttr2());
775 stmt->setUInt32(11, score->second->GetAttr3());
776 stmt->setUInt32(12, score->second->GetAttr4());
777 stmt->setUInt32(13, score->second->GetAttr5());
778
779 CharacterDatabase.Execute(stmt);
780 }
781
782 // remove temporary currency bonus auras before rewarding player
785
786 // Reward winner team
787 if (team == winner)
788 {
790 {
793 player->ModifyArenaPoints(winner_arena);
794 if (!player->GetRandomWinner())
795 player->SetRandomWinner(true);
796 }
797
799 }
800 else
801 {
804 }
805
806 player->ResetAllPowers();
807 player->CombatStopWithPets(true);
808
809 BlockMovement(player);
810
811 player->SendDirectMessage(pvpMatchStatistics.GetRawPacket());
812
814 BattlegroundMgr::BuildBattlegroundStatusActive(&battlefieldStatus, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), bgQueueTypeId);
815 player->SendDirectMessage(battlefieldStatus.Write());
816
818 }
819}
820
822{
823 //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)
824 uint32 maxLevel = std::min<uint32>(GetMaxLevel(), 80U);
825 return Trinity::Honor::hk_honor_at_level(maxLevel, float(kills));
826}
827
829{
830 // 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()
831 player->SetClientControl(player, false);
832}
833
835{
836 uint32 team = GetPlayerTeam(guid);
837 bool participant = false;
838 // Remove from lists/maps
839 BattlegroundPlayerMap::iterator itr = m_Players.find(guid);
840 if (itr != m_Players.end())
841 {
842 UpdatePlayersCountByTeam(team, true); // -1 player
843 m_Players.erase(itr);
844 // check if the player was a participant of the match, or only entered through gm command (goname)
845 participant = true;
846 }
847
848 BattlegroundScoreMap::iterator itr2 = PlayerScores.find(guid);
849 if (itr2 != PlayerScores.end())
850 {
851 delete itr2->second; // delete player's score
852 PlayerScores.erase(itr2);
853 }
854
856
857 Player* player = ObjectAccessor::FindPlayer(guid);
858
859 if (player)
860 {
861 // should remove spirit of redemption
864
866
867 if (!player->IsAlive()) // resurrect on exit
868 {
869 player->ResurrectPlayer(1.0f);
870 player->SpawnCorpseBones();
871 }
872 }
873 else
874 {
875 CharacterDatabaseTransaction trans(nullptr);
876 Player::OfflineResurrect(guid, trans);
877 }
878
879 RemovePlayer(player, guid, team); // BG subclass specific code
880
881 if (participant) // if the player was a match participant, remove auras, calc rating, update queue
882 {
884 if (player)
885 {
886 player->ClearAfkReports();
887
888 // if arena, remove the specific arena auras
889 if (isArena())
890 {
891 bgQueueTypeId.BattlemasterListId = BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing)
892
893 // unsummon current and summon old pet if there was one and there isn't a current pet
894 player->RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT);
896 }
897
898 if (SendPacket)
899 {
901 BattlegroundMgr::BuildBattlegroundStatusNone(&battlefieldStatus, player->GetBattlegroundQueueIndex(bgQueueTypeId));
902 player->SendDirectMessage(battlefieldStatus.Write());
903 }
904
905 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
906 player->RemoveBattlegroundQueueId(bgQueueTypeId);
907 }
908
909 // remove from raid group if player is member
910 if (Group* group = GetBgRaid(team))
911 {
912 if (!group->RemoveMember(guid)) // group was disbanded
913 SetBgRaid(team, nullptr);
914 }
916 //we should update battleground queue, but only if bg isn't ending
918 {
919 // a player has left the battleground, so there are free slots -> add to queue
921 sBattlegroundMgr->ScheduleQueueUpdate(0, bgQueueTypeId);
922 }
923 // Let others know
925 playerLeft.Guid = guid;
926 SendPacketToTeam(team, playerLeft.Write(), player, false);
927 }
928
929 if (player)
930 {
931 // Do next only if found in battleground
932 player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG.
933 // reset destination bg team
934 player->SetBGTeam(0);
935
936 // remove all criterias on bg leave
938
939 if (Transport)
940 player->TeleportToBGEntryPoint();
941
942 TC_LOG_DEBUG("bg.battleground", "Removed player {} from Battleground.", player->GetName());
943 }
944
945 //battleground object will be deleted next Battleground::Update() call
946}
947
948// this method is called when no players remains in battleground
950{
953 SetStartTime(0);
954 SetEndTime(0);
956 m_Events = 0;
957
958 if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
959 TC_LOG_ERROR("bg.battleground", "Battleground::Reset: one of the counters is not 0 (alliance: {}, horde: {}) for BG (map: {}, instance id: {})!",
961
963 m_InvitedHorde = 0;
964 m_InBGFreeSlotQueue = false;
965
966 m_Players.clear();
967
968 for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr)
969 delete itr->second;
970 PlayerScores.clear();
971
972 for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i)
974
976}
977
979{
980 SetStartTime(0);
982 // add BG to free slot queue
984
985 // add bg to update list
986 // This must be done here, because we need to have already invited some players when first BG::Update() method is executed
987 // and it doesn't matter if we call StartBattleground() more times, because m_Battlegrounds is a map and instance id never changes
988 sBattlegroundMgr->AddBattleground(this);
989
990 if (m_IsRated)
991 TC_LOG_DEBUG("bg.arena", "Arena match type: {} for Team1Id: {} - Team2Id: {} started.", m_ArenaType, m_ArenaTeamIds[TEAM_ALLIANCE], m_ArenaTeamIds[TEAM_HORDE]);
992}
993
995{
996 // remove afk from player
998 player->ToggleAFK();
999
1000 // score struct must be created in inherited class
1001
1002 uint32 team = player->GetBGTeam();
1003
1005 bp.OfflineRemoveTime = 0;
1006 bp.Team = team;
1007
1008 bool const isInBattleground = IsPlayerInBattleground(player->GetGUID());
1009 // Add to list/maps
1010 m_Players[player->GetGUID()] = bp;
1011
1012 if (!isInBattleground)
1013 UpdatePlayersCountByTeam(team, false); // +1 player
1014
1016 playerJoined.Guid = player->GetGUID();
1017 SendPacketToTeam(team, playerJoined.Write(), player, false);
1018
1020
1021 // add arena specific auras
1022 if (isArena())
1023 {
1025 player->DestroyConjuredItems(true);
1026 player->UnsummonPetTemporaryIfAny();
1027
1028 if (GetStatus() == STATUS_WAIT_JOIN) // not started yet
1029 {
1030 player->CastSpell(player, SPELL_ARENA_PREPARATION, true);
1031 player->ResetAllPowers();
1032 }
1033 }
1034 else
1035 {
1036 if (GetStatus() == STATUS_WAIT_JOIN) // not started yet
1037 player->CastSpell(player, SPELL_PREPARATION, true); // reduces all mana cost of spells.
1038 }
1039
1040 // reset all map criterias on map enter
1041 if (!isInBattleground)
1043
1044 // setup BG group membership
1046 AddOrSetPlayerToCorrectBgGroup(player, team);
1047}
1048
1049// this method adds player to his team's bg group, or sets his correct group if player is already in bg group
1051{
1052 ObjectGuid playerGuid = player->GetGUID();
1053 Group* group = GetBgRaid(team);
1054 if (!group) // first player joined
1055 {
1056 group = new Group;
1057 SetBgRaid(team, group);
1058 group->Create(player);
1059 sGroupMgr->AddGroup(group);
1060 }
1061 else // raid already exist
1062 {
1063 if (group->IsMember(playerGuid))
1064 {
1065 uint8 subgroup = group->GetMemberGroup(playerGuid);
1066 player->SetBattlegroundOrBattlefieldRaid(group, subgroup);
1067 }
1068 else
1069 {
1070 group->AddMember(player);
1071 if (Group* originalGroup = player->GetOriginalGroup())
1072 if (originalGroup->IsLeader(playerGuid))
1073 {
1074 group->ChangeLeader(playerGuid);
1075 group->SendUpdate();
1076 }
1077 }
1078 }
1079}
1080
1081// This method should be called when player logs into running battleground
1083{
1084 ObjectGuid guid = player->GetGUID();
1085 // player is correct pointer
1086 for (auto itr = m_OfflineQueue.begin(); itr != m_OfflineQueue.end(); ++itr)
1087 {
1088 if (*itr == guid)
1089 {
1090 m_OfflineQueue.erase(itr);
1091 break;
1092 }
1093 }
1094 m_Players[guid].OfflineRemoveTime = 0;
1096 // if battleground is starting, then add preparation aura
1097 // we don't have to do that, because preparation aura isn't removed when player logs out
1098}
1099
1100// This method should be called when player logs out from running battleground
1102{
1103 ObjectGuid guid = player->GetGUID();
1104 if (!IsPlayerInBattleground(guid)) // Check if this player really is in battleground (might be a GM who teleported inside)
1105 return;
1106
1107 // player is correct pointer, it is checked in WorldSession::LogoutPlayer()
1108 m_OfflineQueue.push_back(player->GetGUID());
1109 m_Players[guid].OfflineRemoveTime = GameTime::GetGameTime() + MAX_OFFLINE_TIME;
1111 {
1112 // drop flag and handle other cleanups
1113 RemovePlayer(player, guid, GetPlayerTeam(guid));
1114
1115 // 1 player is logging out, if it is the last alive, then end arena!
1116 if (isArena() && player->IsAlive())
1119 }
1120}
1121
1122// This method should be called only once ... it adds pointer to queue
1124{
1126 {
1127 sBattlegroundMgr->AddToBGFreeSlotQueue(m_TypeID, this);
1128 m_InBGFreeSlotQueue = true;
1129 }
1130}
1131
1132// This method removes this battleground from free queue - it must be called when deleting battleground
1134{
1136 {
1137 sBattlegroundMgr->RemoveFromBGFreeSlotQueue(m_TypeID, m_InstanceID);
1138 m_InBGFreeSlotQueue = false;
1139 }
1140}
1141
1142// get the number of free slots for team
1143// returns the number how many players can join battleground to MaxPlayersPerTeam
1145{
1146 // if BG is starting and CONFIG_BATTLEGROUND_INVITATION_TYPE == BG_QUEUE_INVITATION_TYPE_NO_BALANCE, invite anyone
1149
1150 // 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
1151 uint32 otherTeamInvitedCount;
1152 uint32 thisTeamInvitedCount;
1153 uint32 otherTeamPlayersCount;
1154 uint32 thisTeamPlayersCount;
1155
1156 if (Team == ALLIANCE)
1157 {
1158 thisTeamInvitedCount = GetInvitedCount(ALLIANCE);
1159 otherTeamInvitedCount = GetInvitedCount(HORDE);
1160 thisTeamPlayersCount = GetPlayersCountByTeam(ALLIANCE);
1161 otherTeamPlayersCount = GetPlayersCountByTeam(HORDE);
1162 }
1163 else
1164 {
1165 thisTeamInvitedCount = GetInvitedCount(HORDE);
1166 otherTeamInvitedCount = GetInvitedCount(ALLIANCE);
1167 thisTeamPlayersCount = GetPlayersCountByTeam(HORDE);
1168 otherTeamPlayersCount = GetPlayersCountByTeam(ALLIANCE);
1169 }
1171 {
1172 // difference based on ppl invited (not necessarily entered battle)
1173 // default: allow 0
1174 uint32 diff = 0;
1175
1176 // allow join one person if the sides are equal (to fill up bg to minPlayerPerTeam)
1177 if (otherTeamInvitedCount == thisTeamInvitedCount)
1178 diff = 1;
1179 // allow join more ppl if the other side has more players
1180 else if (otherTeamInvitedCount > thisTeamInvitedCount)
1181 diff = otherTeamInvitedCount - thisTeamInvitedCount;
1182
1183 // difference based on max players per team (don't allow inviting more)
1184 uint32 diff2 = (thisTeamInvitedCount < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - thisTeamInvitedCount : 0;
1185
1186 // difference based on players who already entered
1187 // default: allow 0
1188 uint32 diff3 = 0;
1189 // allow join one person if the sides are equal (to fill up bg minPlayerPerTeam)
1190 if (otherTeamPlayersCount == thisTeamPlayersCount)
1191 diff3 = 1;
1192 // allow join more ppl if the other side has more players
1193 else if (otherTeamPlayersCount > thisTeamPlayersCount)
1194 diff3 = otherTeamPlayersCount - thisTeamPlayersCount;
1195 // or other side has less than minPlayersPerTeam
1196 else if (thisTeamInvitedCount <= GetMinPlayersPerTeam())
1197 diff3 = GetMinPlayersPerTeam() - thisTeamInvitedCount + 1;
1198
1199 // return the minimum of the 3 differences
1200
1201 // min of diff and diff 2
1202 diff = std::min(diff, diff2);
1203 // min of diff, diff2 and diff3
1204 return std::min(diff, diff3);
1205 }
1206 return 0;
1207}
1208
1210{
1211 return GetPlayersSize() < GetMaxPlayers();
1212}
1213
1215{
1216 if (isArena())
1217 {
1218 WorldPackets::Battleground::PVPLogData_Arena& arena = pvpLogData.Arena.emplace();
1219
1220 for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i)
1221 {
1222 ArenaTeamScore const& score = _arenaTeamScores[i];
1223
1224 uint32 ratingLost = std::abs(std::min(score.RatingChange, 0));
1225 uint32 ratingWon = std::max(score.RatingChange, 0);
1226
1227 // should be old rating, new rating, and client will calculate rating change itself
1228 arena.Ratings.Prematch[i] = ratingLost;
1229 arena.Ratings.Postmatch[i] = ratingWon;
1230 arena.Ratings.PrematchMMR[i] = score.MatchmakerRating;
1231
1232 arena.TeamName[i] = score.TeamName;
1233 }
1234 }
1235
1237 pvpLogData.Winner = GetWinner();
1238
1239 for (auto const& [_, score] : PlayerScores)
1240 score->AppendToPacket(pvpLogData.Players.emplace_back());
1241}
1242
1243bool Battleground::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
1244{
1245 BattlegroundScoreMap::const_iterator itr = PlayerScores.find(player->GetGUID());
1246 if (itr == PlayerScores.end()) // player not found...
1247 return false;
1248
1249 if (type == SCORE_BONUS_HONOR && doAddHonor && isBattleground())
1250 player->RewardHonor(nullptr, 1, value); // RewardHonor calls UpdatePlayerScore with doAddHonor = false
1251 else
1252 itr->second->UpdateScore(type, value);
1253
1254 return true;
1255}
1256
1258{
1259 m_ReviveQueue[npc_guid].push_back(player_guid);
1260
1261 Player* player = ObjectAccessor::FindPlayer(player_guid);
1262 if (!player)
1263 return;
1264
1265 player->CastSpell(player, SPELL_WAITING_FOR_RESURRECT, true);
1266}
1267
1269{
1270 for (std::map<ObjectGuid, GuidVector>::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
1271 {
1272 for (GuidVector::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2)
1273 {
1274 if (*itr2 == player_guid)
1275 {
1276 itr->second.erase(itr2);
1277 if (Player* player = ObjectAccessor::FindPlayer(player_guid))
1278 player->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
1279 return;
1280 }
1281 }
1282 }
1283}
1284
1286{
1287 // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard
1288 GuidVector& ghostList = m_ReviveQueue[guideGuid];
1289 if (!ghostList.empty())
1290 {
1291 WorldSafeLocsEntry const* closestGrave = nullptr;
1292 for (GuidVector::const_iterator itr = ghostList.begin(); itr != ghostList.end(); ++itr)
1293 {
1294 Player* player = ObjectAccessor::FindPlayer(*itr);
1295 if (!player)
1296 continue;
1297
1298 if (!closestGrave)
1299 closestGrave = GetClosestGraveyard(player);
1300
1301 if (closestGrave)
1302 player->TeleportTo(GetMapId(), closestGrave->Loc.X, closestGrave->Loc.Y, closestGrave->Loc.Z, player->GetOrientation());
1303 }
1304 ghostList.clear();
1305 }
1306}
1307
1308bool Battleground::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 /*respawnTime*/, GOState goState)
1309{
1310 // If the assert is called, means that BgObjects must be resized!
1311 ASSERT(type < BgObjects.size());
1312
1313 Map* map = FindBgMap();
1314 if (!map)
1315 return false;
1316
1317 QuaternionData rot(rotation0, rotation1, rotation2, rotation3);
1318 // Temporally add safety check for bad spawns and send log (object rotations need to be rechecked in sniff)
1319 if (!rotation0 && !rotation1 && !rotation2 && !rotation3)
1320 {
1321 TC_LOG_DEBUG("bg.battleground", "Battleground::AddObject: gameoobject [entry: {}, object type: {}] for BG (map: {}) has zeroed rotation fields, "
1322 "orientation used temporally, but please fix the spawn", entry, type, m_MapId);
1323
1324 rot = QuaternionData::fromEulerAnglesZYX(o, 0.f, 0.f);
1325 }
1326
1327 // Must be created this way, adding to godatamap would add it to the base map of the instance
1328 // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
1329 // So we must create it specific for this instance
1330 GameObject* go = new GameObject;
1331 if (!go->Create(GetBgMap()->GenerateLowGuid<HighGuid::GameObject>(), entry, GetBgMap(), PHASEMASK_NORMAL, Position(x, y, z, o), rot, 255, goState))
1332 {
1333 TC_LOG_ERROR("bg.battleground", "Battleground::AddObject: cannot create gameobject (entry: {}) for BG (map: {}, instance id: {})!",
1334 entry, m_MapId, m_InstanceID);
1335 delete go;
1336 return false;
1337 }
1338/*
1339 uint32 guid = go->GetGUID().GetCounter();
1340
1341 // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
1342 // iirc that was changed, so adding to go data map is no longer required if that was the only function using godata from GameObject without checking if it existed
1343 GameObjectData& data = sObjectMgr->NewGOData(guid);
1344
1345 data.id = entry;
1346 data.mapid = GetMapId();
1347 data.posX = x;
1348 data.posY = y;
1349 data.posZ = z;
1350 data.orientation = o;
1351 data.rotation0 = rotation0;
1352 data.rotation1 = rotation1;
1353 data.rotation2 = rotation2;
1354 data.rotation3 = rotation3;
1355 data.spawntimesecs = respawnTime;
1356 data.spawnMask = 1;
1357 data.animprogress = 100;
1358 data.go_state = 1;
1359*/
1360 // Add to world, so it can be later looked up from HashMapHolder
1361 if (!map->AddToMap(go))
1362 {
1363 delete go;
1364 return false;
1365 }
1366 BgObjects[type] = go->GetGUID();
1367 return true;
1368}
1369
1370bool Battleground::AddObject(uint32 type, uint32 entry, Position const& pos, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime /*= 0*/, GOState goState /*= GO_STATE_READY*/)
1371{
1372 return AddObject(type, entry, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), rotation0, rotation1, rotation2, rotation3, respawnTime, goState);
1373}
1374
1375// Some doors aren't despawned so we cannot handle their closing in gameobject::update()
1376// It would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
1378{
1379 if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]))
1380 {
1381 // If doors are open, close it
1382 if (obj->getLootState() == GO_ACTIVATED && obj->GetGoState() != GO_STATE_READY)
1383 {
1384 obj->SetLootState(GO_READY);
1385 obj->SetGoState(GO_STATE_READY);
1386 }
1387 }
1388 else
1389 TC_LOG_ERROR("bg.battleground", "Battleground::DoorClose: door gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
1390 type, BgObjects[type].ToString(), m_MapId, m_InstanceID);
1391}
1392
1394{
1395 if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]))
1396 {
1397 obj->SetLootState(GO_ACTIVATED);
1398 obj->SetGoState(GO_STATE_ACTIVE);
1399 }
1400 else
1401 TC_LOG_ERROR("bg.battleground", "Battleground::DoorOpen: door gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
1402 type, BgObjects[type].ToString(), m_MapId, m_InstanceID);
1403}
1404
1406{
1407 GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]);
1408 if (!obj)
1409 {
1410 if (logError)
1411 TC_LOG_ERROR("bg.battleground", "Battleground::GetBGObject: gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
1412 type, BgObjects[type].ToString(), m_MapId, m_InstanceID);
1413 else
1414 TC_LOG_INFO("bg.battleground", "Battleground::GetBGObject: gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
1415 type, BgObjects[type].ToString(), m_MapId, m_InstanceID);
1416 }
1417 return obj;
1418}
1419
1421{
1422 Creature* creature = GetBgMap()->GetCreature(BgCreatures[type]);
1423 if (!creature)
1424 {
1425 if (logError)
1426 TC_LOG_ERROR("bg.battleground", "Battleground::GetBGCreature: creature (type: {}, {}) not found for BG (map: {}, instance id: {})!",
1427 type, BgCreatures[type].ToString(), m_MapId, m_InstanceID);
1428 else
1429 TC_LOG_INFO("bg.battleground", "Battleground::GetBGCreature: creature (type: {}, {}) not found for BG (map: {}, instance id: {})!",
1430 type, BgCreatures[type].ToString(), m_MapId, m_InstanceID);
1431 }
1432 return creature;
1433}
1434
1436{
1437 if (Map* map = FindBgMap())
1438 if (GameObject* obj = map->GetGameObject(BgObjects[type]))
1439 {
1440 if (respawntime)
1441 {
1442 obj->SetLootState(GO_JUST_DEACTIVATED);
1443
1444 if (GameObjectOverride const* goOverride = obj->GetGameObjectOverride())
1445 if (goOverride->Flags & GO_FLAG_NODESPAWN)
1446 {
1447 // This function should be called in GameObject::Update() but in case of
1448 // GO_FLAG_NODESPAWN flag the function is never called, so we call it here
1449 obj->SendObjectDeSpawnAnim(obj->GetGUID());
1450 }
1451 }
1452 else if (obj->getLootState() == GO_JUST_DEACTIVATED)
1453 {
1454 // Change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
1455 obj->SetLootState(GO_READY);
1456 }
1457 obj->SetRespawnTime(respawntime);
1458 map->AddToMap(obj);
1459 }
1460}
1461
1462Creature* Battleground::AddCreature(uint32 entry, uint32 type, float x, float y, float z, float o, TeamId /*teamId = TEAM_NEUTRAL*/, uint32 respawntime /*= 0*/, Transport* transport)
1463{
1464 // If the assert is called, means that BgCreatures must be resized!
1465 ASSERT(type < BgCreatures.size());
1466
1467 Map* map = FindBgMap();
1468 if (!map)
1469 return nullptr;
1470
1471 if (transport)
1472 {
1473 if (Creature* creature = transport->SummonPassenger(entry, { x, y, z, o }, TEMPSUMMON_MANUAL_DESPAWN))
1474 {
1475 BgCreatures[type] = creature->GetGUID();
1476 return creature;
1477 }
1478
1479 return nullptr;
1480 }
1481
1482 Creature* creature = new Creature();
1483
1484 if (!creature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, PHASEMASK_NORMAL, entry, { x, y, z, o }))
1485 {
1486 TC_LOG_ERROR("bg.battleground", "Battleground::AddCreature: cannot create creature (entry: {}) for BG (map: {}, instance id: {})!",
1487 entry, m_MapId, m_InstanceID);
1488 delete creature;
1489 return nullptr;
1490 }
1491
1492 creature->SetHomePosition(x, y, z, o);
1493
1494 CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry);
1495 if (!cinfo)
1496 {
1497 TC_LOG_ERROR("bg.battleground", "Battleground::AddCreature: creature template (entry: {}) does not exist for BG (map: {}, instance id: {})!",
1498 entry, m_MapId, m_InstanceID);
1499 delete creature;
1500 return nullptr;
1501 }
1502
1503 if (!map->AddToMap(creature))
1504 {
1505 delete creature;
1506 return nullptr;
1507 }
1508
1509 BgCreatures[type] = creature->GetGUID();
1510
1511 if (respawntime)
1512 creature->SetRespawnDelay(respawntime);
1513
1514 return creature;
1515}
1516
1517Creature* Battleground::AddCreature(uint32 entry, uint32 type, Position const& pos, TeamId teamId /*= TEAM_NEUTRAL*/, uint32 respawntime /*= 0*/, Transport* transport)
1518{
1519 return AddCreature(entry, type, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teamId, respawntime, transport);
1520}
1521
1523{
1524 if (!BgCreatures[type])
1525 return true;
1526
1527 if (Creature* creature = GetBgMap()->GetCreature(BgCreatures[type]))
1528 {
1529 creature->AddObjectToRemoveList();
1530 BgCreatures[type].Clear();
1531 return true;
1532 }
1533
1534 TC_LOG_ERROR("bg.battleground", "Battleground::DelCreature: creature (type: {}, {}) not found for BG (map: {}, instance id: {})!",
1535 type, BgCreatures[type].ToString(), m_MapId, m_InstanceID);
1536 BgCreatures[type].Clear();
1537 return false;
1538}
1539
1541{
1542 if (!BgObjects[type])
1543 return true;
1544
1545 if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]))
1546 {
1547 obj->SetRespawnTime(0); // not save respawn time
1548 obj->Delete();
1549 BgObjects[type].Clear();
1550 return true;
1551 }
1552 TC_LOG_ERROR("bg.battleground", "Battleground::DelObject: gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
1553 type, BgObjects[type].ToString(), m_MapId, m_InstanceID);
1554 BgObjects[type].Clear();
1555 return false;
1556}
1557
1559{
1560 if (!BgObjects[type])
1561 return true;
1562
1563 if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]))
1564 {
1565 obj->RemoveFromWorld();
1566 BgObjects[type].Clear();
1567 return true;
1568 }
1569 TC_LOG_INFO("bg.battleground", "Battleground::RemoveObjectFromWorld: gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
1570 type, BgObjects[type].ToString(), m_MapId, m_InstanceID);
1571 return false;
1572}
1573
1574bool Battleground::AddSpiritGuide(uint32 type, float x, float y, float z, float o, TeamId teamId /*= TEAM_NEUTRAL*/)
1575{
1577
1578 if (Creature* creature = AddCreature(entry, type, x, y, z, o, teamId))
1579 {
1580 creature->SetChannelObjectGuid(creature->GetGUID());
1581 // aura
1583 // creature->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL);
1584 // casting visual effect
1585 creature->SetChannelSpellId(SPELL_SPIRIT_HEAL_CHANNEL);
1586 // correct cast speed
1587 creature->SetModCastingSpeed(1.0f);
1588 //creature->CastSpell(creature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1589 return true;
1590 }
1591 TC_LOG_ERROR("bg.battleground", "Battleground::AddSpiritGuide: cannot create spirit guide (type: {}, entry: {}) for BG (map: {}, instance id: {})!",
1592 type, entry, m_MapId, m_InstanceID);
1593 EndNow();
1594 return false;
1595}
1596
1597bool Battleground::AddSpiritGuide(uint32 type, Position const& pos, TeamId teamId /*= TEAM_NEUTRAL*/)
1598{
1599 return AddSpiritGuide(type, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teamId);
1600}
1601
1602void Battleground::SendMessageToAll(uint32 entry, ChatMsg msgType, Player const* source)
1603{
1604 if (!entry)
1605 return;
1606
1607 Trinity::TrinityStringChatBuilder builder(nullptr, msgType, entry, source);
1609 BroadcastWorker(localizer);
1610}
1611
1612void Battleground::PSendMessageToAll(uint32 entry, ChatMsg msgType, Player const* source, ...)
1613{
1614 if (!entry)
1615 return;
1616
1617 va_list ap;
1618 va_start(ap, source);
1619
1620 Trinity::TrinityStringChatBuilder builder(nullptr, msgType, entry, source, &ap);
1622 BroadcastWorker(localizer);
1623
1624 va_end(ap);
1625}
1626
1633
1634// IMPORTANT NOTICE:
1635// buffs aren't spawned/despawned when players captures anything
1636// buffs are in their positions when battleground starts
1638{
1639 if (!FindBgMap())
1640 {
1641 TC_LOG_ERROR("bg.battleground", "Battleground::HandleTriggerBuff called with null bg map, {}", go_guid.ToString());
1642 return;
1643 }
1644
1645 GameObject* obj = GetBgMap()->GetGameObject(go_guid);
1646 if (!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
1647 return;
1648
1649 // Change buff type, when buff is used:
1650 int32 index = BgObjects.size() - 1;
1651 while (index >= 0 && BgObjects[index] != go_guid)
1652 index--;
1653 if (index < 0)
1654 {
1655 TC_LOG_ERROR("bg.battleground", "Battleground::HandleTriggerBuff: cannot find buff gameobject ({}, entry: {}, type: {}) in internal data for BG (map: {}, instance id: {})!",
1656 go_guid.ToString(), obj->GetEntry(), obj->GetGoType(), m_MapId, m_InstanceID);
1657 return;
1658 }
1659
1660 // Randomly select new buff
1661 uint8 buff = urand(0, 2);
1662 uint32 entry = obj->GetEntry();
1663 if (m_BuffChange && entry != Buff_Entries[buff])
1664 {
1665 // Despawn current buff
1667 // Set index for new one
1668 for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex)
1669 if (entry == Buff_Entries[currBuffTypeIndex])
1670 {
1671 index -= currBuffTypeIndex;
1672 index += buff;
1673 }
1674 }
1675
1677}
1678
1680{
1681 // Keep in mind that for arena this will have to be changed a bit
1682
1683 // Add +1 deaths
1684 UpdatePlayerScore(victim, SCORE_DEATHS, 1);
1685 // Add +1 kills to group and +1 killing_blows to killer
1686 if (killer)
1687 {
1688 // Don't reward credit for killing ourselves, like fall damage of hellfire (warlock)
1689 if (killer == victim)
1690 return;
1691
1694
1695 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1696 {
1697 Player* creditedPlayer = ObjectAccessor::FindPlayer(itr->first);
1698 if (!creditedPlayer || creditedPlayer == killer)
1699 continue;
1700
1701 if (creditedPlayer->GetTeam() == killer->GetTeam() && creditedPlayer->IsAtGroupRewardDistance(victim))
1702 UpdatePlayerScore(creditedPlayer, SCORE_HONORABLE_KILLS, 1);
1703 }
1704 }
1705
1706 if (!isArena())
1707 {
1708 // To be able to remove insignia -- ONLY IN Battlegrounds
1710 RewardXPAtKill(killer, victim);
1711 }
1712}
1713
1714// Return the player's team based on battlegroundplayer info
1715// Used in same faction arena matches mainly
1717{
1718 BattlegroundPlayerMap::const_iterator itr = m_Players.find(guid);
1719 if (itr != m_Players.end())
1720 return itr->second.Team;
1721 return 0;
1722}
1723
1725{
1726 return teamId ? ((teamId == ALLIANCE) ? HORDE : ALLIANCE) : 0;
1727}
1728
1730{
1731 BattlegroundPlayerMap::const_iterator itr = m_Players.find(guid);
1732 if (itr != m_Players.end())
1733 return true;
1734 return false;
1735}
1736
1738{
1740 return;
1741
1743
1744 BlockMovement(player);
1745
1747 BuildPvPLogDataPacket(pvpMatchStatistics);
1748 player->SendDirectMessage(pvpMatchStatistics.Write());
1749
1751 BattlegroundMgr::BuildBattlegroundStatusActive(&battlefieldStatus, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), bgQueueTypeId);
1752 player->SendDirectMessage(battlefieldStatus.Write());
1753}
1754
1756{
1757 int count = 0;
1758 for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1759 {
1760 if (itr->second.Team == Team)
1761 {
1762 Player* player = ObjectAccessor::FindPlayer(itr->first);
1763 if (player && player->IsAlive() && player->GetShapeshiftForm() != FORM_SPIRITOFREDEMPTION)
1764 ++count;
1765 }
1766 }
1767 return count;
1768}
1769
1770void Battleground::SetHoliday(bool is_holiday)
1771{
1772 m_HonorMode = is_holiday ? BG_HOLIDAY : BG_NORMAL;
1773}
1774
1776{
1777 for (uint32 i = 0; i < BgObjects.size(); ++i)
1778 if (BgObjects[i] == guid)
1779 return i;
1780 TC_LOG_ERROR("bg.battleground", "Battleground::GetObjectType: player used gameobject ({}) which is not in internal data for BG (map: {}, instance id: {}), cheating?",
1781 guid.ToString(), m_MapId, m_InstanceID);
1782 return -1;
1783}
1784
1786{
1787 Group*& old_raid = TeamID == ALLIANCE ? m_BgRaids[TEAM_ALLIANCE] : m_BgRaids[TEAM_HORDE];
1788 if (old_raid)
1789 old_raid->SetBattlegroundGroup(nullptr);
1790 if (bg_raid)
1791 bg_raid->SetBattlegroundGroup(this);
1792 old_raid = bg_raid;
1793}
1794
1796{
1797 return sObjectMgr->GetClosestGraveyard(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), player->GetTeam(), player);
1798}
1799
1801{
1802 for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
1803 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
1804 player->StartTimedAchievement(type, entry);
1805}
1806
1808{
1809 m_BracketId = bracketEntry->GetBracketId();
1810 SetLevelRange(bracketEntry->MinLevel, bracketEntry->MaxLevel);
1811}
1812
1814{
1815 if (sWorld->getBoolConfig(CONFIG_BG_XP_FOR_KILL) && killer && victim)
1816 killer->RewardPlayerAndGroupAtKill(victim, true);
1817}
1818
1820{
1821 if (teamId == TEAM_ALLIANCE || teamId == TEAM_HORDE)
1822 return m_TeamScores[teamId];
1823
1824 TC_LOG_ERROR("bg.battleground", "GetTeamScore with wrong Team {} for BG {}", teamId, GetTypeID());
1825 return 0;
1826}
1827
1829{
1830 TC_LOG_DEBUG("bg.battleground", "Unhandled AreaTrigger {} in Battleground {}. Player coords (x: {}, y: {}, z: {})",
1831 trigger, player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
1832}
1833
1834bool Battleground::CheckAchievementCriteriaMeet(uint32 criteriaId, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/)
1835{
1836 TC_LOG_ERROR("bg.battleground", "Battleground::CheckAchievementCriteriaMeet: No implementation for criteria {}", criteriaId);
1837 return false;
1838}
1839
1841{
1842 return GetMinLevel() / 10;
1843}
#define sBattlegroundMgr
@ BG_QUEUE_INVITATION_TYPE_NO_BALANCE
@ SCORE_KILLING_BLOWS
@ SCORE_BONUS_HONOR
@ SCORE_DEATHS
@ SCORE_HONORABLE_KILLS
@ TIME_TO_AUTOREMOVE
@ RESURRECTION_INTERVAL
@ MAX_OFFLINE_TIME
@ BUFF_RESPAWN_TIME
@ RESPAWN_ONE_DAY
@ CHECK_PLAYER_POSITION_INVERVAL
const uint32 Buff_Entries[3]
@ BG_DESERTION_TYPE_OFFLINE
@ BG_STARTING_EVENT_3
@ BG_STARTING_EVENT_2
@ BG_STARTING_EVENT_1
@ BG_STARTING_EVENT_4
@ BG_CREATURE_ENTRY_H_SPIRITGUIDE
@ BG_CREATURE_ENTRY_A_SPIRITGUIDE
@ 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
@ BG_NORMAL
@ BG_HOLIDAY
@ SPELL_SPIRIT_HEAL
@ SPELL_SPIRIT_HEAL_CHANNEL
@ SPELL_ARENA_PREPARATION
@ SPELL_SPIRIT_HEAL_MANA
@ SPELL_HONORABLE_DEFENDER_25Y
@ SPELL_PREPARATION
@ SPELL_RESURRECTION_VISUAL
@ SPELL_WAITING_FOR_RESURRECT
@ 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
@ CHAR_INS_DESERTER_TRACK
@ IN_MILLISECONDS
Definition Common.h:35
@ MINUTE
Definition Common.h:29
#define sCreatureTextMgr
AchievementCriteriaTimedTypes
Definition DBCEnums.h:121
@ ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP
Definition DBCEnums.h:101
@ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND
Definition DBCEnums.h:144
@ ACHIEVEMENT_CRITERIA_TYPE_WIN_BG
Definition DBCEnums.h:135
@ BG_BRACKET_ID_FIRST
Definition DBCEnums.h:58
DBCStorage< FactionEntry > sFactionStore(FactionEntryfmt)
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint64_t uint64
Definition Define.h:132
uint32_t uint32
Definition Define.h:133
#define ASSERT
Definition Errors.h:68
@ GO_ACTIVATED
Definition GameObject.h:78
@ GO_READY
Definition GameObject.h:77
@ GO_JUST_DEACTIVATED
Definition GameObject.h:79
#define sGroupMgr
Definition GroupMgr.h:58
@ 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__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
@ PHASEMASK_NORMAL
@ TEMPSUMMON_MANUAL_DESPAWN
std::vector< ObjectGuid > GuidVector
Definition ObjectGuid.h:262
#define sObjectMgr
Definition ObjectMgr.h:1721
@ PET_SAVE_NOT_IN_SLOT
Definition PetDefines.h:45
@ PLAYER_FLAGS_AFK
Definition Player.h:345
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
@ GAMEOBJECT_TYPE_TRAP
@ GENDER_MALE
@ PVP_TEAM_NEUTRAL
@ PVP_TEAM_HORDE
@ PVP_TEAM_ALLIANCE
TeamId
@ TEAM_NEUTRAL
@ TEAM_ALLIANCE
@ TEAM_HORDE
uint8 constexpr PVP_TEAMS_COUNT
@ ALLIANCE
@ HORDE
@ SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY
ChatMsg
@ CHAT_MSG_SYSTEM
@ CHAT_MSG_BG_SYSTEM_NEUTRAL
@ BATTLEGROUND_AA
@ BATTLEGROUND_TYPE_NONE
@ GO_FLAG_NODESPAWN
GOState
@ GO_STATE_READY
@ GO_STATE_ACTIVE
@ 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
@ FORM_SPIRITOFREDEMPTION
@ UNIT_FLAG_SKINNABLE
@ PLAYER_FLAGS
T AddPct(T &base, U pct)
Definition Util.h:77
bool IsPositive() const
Definition SpellAuras.h:73
Aura * GetBase() const
Definition SpellAuras.h:67
int32 GetDuration() const
Definition SpellAuras.h:148
bool HasEffectType(AuraType type) const
SpellInfo const * GetSpellInfo() const
Definition SpellAuras.h:115
bool IsPermanent() const
Definition SpellAuras.h:153
void SetUnload()
Definition Map.cpp:4373
void SetBG(Battleground *bg)
Definition Map.h:929
static BattlegroundQueueTypeId BGQueueTypeId(BattlegroundTypeId bgTypeId, uint8 bracketId, uint8 arenaType)
static void BuildBattlegroundStatusNone(WorldPackets::Battleground::BattlefieldStatusNone *battlefieldStatus, uint32 queueSlot)
static bool IsBGWeekend(BattlegroundTypeId bgTypeId)
static void BuildBattlegroundStatusActive(WorldPackets::Battleground::BattlefieldStatusActive *battlefieldStatus, Battleground const *bg, Player const *player, uint32 queueSlot, BattlegroundQueueTypeId queueId)
Player * _GetPlayerForTeam(uint32 teamId, BattlegroundPlayerMap::const_iterator itr, char const *context) const
virtual void AddPlayer(Player *player)
uint32 m_InvitedAlliance
GuidVector m_ResurrectQueue
uint32 m_ArenaTeamMMR[PVP_TEAMS_COUNT]
uint32 GetAlivePlayersCountByTeam(uint32 Team) const
uint32 GetMapId() const
BattlegroundTypeId GetTypeID(bool GetRandom=false) const
virtual void EndBattleground(uint32 winner)
void HandleTriggerBuff(ObjectGuid go_guid)
void AddPlayerToResurrectQueue(ObjectGuid npc_guid, ObjectGuid player_guid)
virtual Creature * AddCreature(uint32 entry, uint32 type, float x, float y, float z, float o, TeamId teamId=TEAM_NEUTRAL, uint32 respawntime=0, Transport *transport=nullptr)
PvPTeamId _winnerTeamId
ArenaTeamScore _arenaTeamScores[PVP_TEAMS_COUNT]
void RelocateDeadPlayers(ObjectGuid guideGuid)
Relocate all players in ReviveQueue to the closest graveyard.
uint32 GetReviveQueueSize() const
void SendPacketToAll(WorldPacket const *packet) const
BGHonorMode m_HonorMode
uint32 GetMinLevel() const
void ModifyStartDelayTime(int diff)
Position const * GetTeamStartPosition(TeamId teamId) const
void BuildPvPLogDataPacket(WorldPackets::Battleground::PVPMatchStatistics &pvpLogData)
void CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
virtual void HandleKillPlayer(Player *player, Player *killer)
static TeamId GetTeamIndexByTeamId(uint32 Team)
uint32 m_ArenaTeamIds[PVP_TEAMS_COUNT]
virtual bool SetupBattleground()
void DoorOpen(uint32 type)
std::deque< ObjectGuid > m_OfflineQueue
uint32 GetMinPlayersPerTeam() const
void PlayerAddedToBGCheckIfBGIsRunning(Player *player)
bool DelCreature(uint32 type)
uint8 GetArenaType() const
BattlegroundPlayerMap m_Players
void SpawnBGObject(uint32 type, uint32 respawntime)
uint32 GetMaxPlayersPerTeam() const
virtual void Reset()
uint32 m_ValidStartPositionTimer
virtual bool AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime=0, GOState goState=GO_STATE_READY)
int32 m_StartDelayTime
void SetWinner(PvPTeamId winnerTeamId)
uint8 GetUniqueBracketId() const
void AddOrSetPlayerToCorrectBgGroup(Player *player, uint32 team)
uint32 m_ClientInstanceID
uint32 m_LevelMax
int32 GetObjectType(ObjectGuid guid)
void AddToBGFreeSlotQueue()
GuidVector BgObjects
uint32 GetPlayerTeam(ObjectGuid guid) const
BattlegroundTypeId m_TypeID
Group * GetBgRaid(uint32 TeamID) const
Creature * GetBGCreature(uint32 type, bool logError=true)
uint32 m_LastResurrectTime
bool CanAwardArenaPoints() const
uint32 GetOtherTeam(uint32 teamId) const
uint32 GetMaxPlayers() const
BattlegroundMap * GetBgMap() const
virtual void PostUpdateImpl(uint32)
Post-update hook.
BattlegroundTypeId m_RandomTypeID
void SetBracket(PvPDifficultyEntry const *bracketEntry)
void DecreaseInvitedCount(uint32 team)
std::string const & GetName() const
PvPTeamId GetWinner() const
virtual void RemovePlayer(Player *, ObjectGuid, uint32)
void _ProcessResurrect(uint32 diff)
BattlegroundMap * FindBgMap() const
void BlockMovement(Player *player)
void RemoveAuraOnTeam(uint32 SpellID, uint32 TeamID)
Player * _GetPlayer(ObjectGuid guid, bool offlineRemove, char const *context) const
void StartBattleground()
virtual bool AddSpiritGuide(uint32 type, float x, float y, float z, float o, TeamId teamId=TEAM_NEUTRAL)
virtual void ResetBGSubclass()
void DoorClose(uint32 type)
std::map< ObjectGuid, GuidVector > m_ReviveQueue
void Update(uint32 diff)
void SetBgRaid(uint32 TeamID, Group *bg_raid)
bool m_PrematureCountDown
uint32 m_PlayersCount[PVP_TEAMS_COUNT]
Group * m_BgRaids[PVP_TEAMS_COUNT]
uint32 m_PrematureCountDownTimer
void SetStartTime(uint32 Time)
void SetEndTime(uint32 Time)
void PlaySoundToTeam(uint32 soundID, uint32 teamID)
void SendPacketToTeam(uint32 TeamID, WorldPacket const *packet, Player *sender=nullptr, bool self=true) const
void SetLevelRange(uint32 min, uint32 max)
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)
GuidVector BgCreatures
virtual WorldSafeLocsEntry const * GetClosestGraveyard(Player *player)
uint32 m_MinPlayers
void SendChatMessage(Creature *source, uint8 textId, WorldObject *target=nullptr)
void RewardXPAtKill(Player *killer, Player *victim)
bool m_InBGFreeSlotQueue
void SetStatus(BattlegroundStatus Status)
virtual void StartingEventCloseDoors()
BattlegroundBracketId m_BracketId
void BroadcastWorker(Do &_do)
bool IsPlayerInBattleground(ObjectGuid guid) const
BattlegroundStartTimeIntervals StartDelayTimes[BG_STARTING_EVENT_COUNT]
bool isArena() const
void SendBroadcastText(uint32 id, ChatMsg msgType, WorldObject const *target=nullptr)
uint32 m_InstanceID
bool DelObject(uint32 type)
uint32 m_ResetStatTimer
uint32 GetStartTime() const
BattlegroundPlayerMap const & GetPlayers() const
int32 GetStartDelayTime() const
BattlegroundScoreMap PlayerScores
virtual void StartingEventOpenDoors()
float GetStartMaxDist() const
Position StartPosition[PVP_TEAMS_COUNT]
bool isBattleground() const
uint32 m_MinPlayersPerTeam
void SetLastResurrectTime(uint32 Time)
void RewardHonorToTeam(uint32 Honor, uint32 TeamID)
BattlegroundStatus GetStatus() const
bool HasFreeSlots() const
virtual bool UpdatePlayerScore(Player *player, uint32 type, uint32 value, bool doAddHonor=true)
bool IsRandom() const
virtual void HandleAreaTrigger(Player *, uint32)
void _ProcessOfflineQueue()
void RemoveFromBGFreeSlotQueue()
void _ProcessProgress(uint32 diff)
void SetHoliday(bool is_holiday)
uint32 GetPlayersCountByTeam(uint32 Team) const
virtual bool PreUpdateImpl(uint32)
Pre-update hook.
float m_StartMaxDist
void SetTeamStartPosition(TeamId teamId, Position const &pos)
virtual ~Battleground()
uint32 GetTeamScore(uint32 TeamID) const
void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry)
virtual bool CheckAchievementCriteriaMeet(uint32, Player const *, Unit const *=nullptr, uint32=0)
virtual void CheckWinConditions()
uint32 m_MaxPlayersPerTeam
void EventPlayerLoggedIn(Player *player)
void _CheckSafePositions(uint32 diff)
void _ProcessJoin(uint32 diff)
BattlegroundBracketId GetBracketId() const
uint32 m_InvitedHorde
void UpdateWorldState(uint32 variable, uint32 value)
void UpdatePlayersCountByTeam(uint32 Team, bool remove)
uint32 m_MaxPlayers
bool RemoveObjectFromWorld(uint32 type)
uint32 GetBonusHonorFromKill(uint32 kills) const
void RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
uint32 GetMaxLevel() const
uint32 GetPlayersSize() const
void RemovePlayerFromResurrectQueue(ObjectGuid player_guid)
uint32 m_LevelMin
uint32 m_StartTime
void SetStartDelayTime(int Time)
virtual void RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool SendPacket)
GameObject * GetBGObject(uint32 type, bool logError=true)
uint32 GetFreeSlotsForTeam(uint32 Team) const
BattlegroundMap * m_Map
void PlaySoundToAll(uint32 soundID)
uint32 GetInvitedCount(uint32 team) const
void _ProcessLeave(uint32 diff)
virtual uint32 GetPrematureWinner()
BattlegroundStatus m_Status
uint32 StartMessageIds[BG_STARTING_EVENT_COUNT]
void SetHomePosition(float x, float y, float z, float o)
Definition Creature.h:293
void SetRespawnDelay(uint32 delay)
Definition Creature.h:262
bool Create(ObjectGuid::LowType guidlow, Map *map, uint32 phaseMask, uint32 entry, Position const &pos, CreatureData const *data=nullptr, uint32 vehId=0, bool dynamic=false)
Class used to access individual fields of database query result.
Definition Field.h:92
uint64 GetUInt64() const
Definition Field.cpp:77
bool isSpawned() const
Definition GameObject.h:155
GameobjectTypes GetGoType() const
Definition GameObject.h:176
bool Create(ObjectGuid::LowType guidlow, uint32 name_id, Map *map, uint32 phaseMask, Position const &pos, QuaternionData const &rotation, uint32 animprogress, GOState go_state, uint32 artKit=0, bool dynamic=false, ObjectGuid::LowType spawnid=0)
Definition Group.h:165
uint8 GetMemberGroup(ObjectGuid guid) const
Definition Group.cpp:2552
bool AddMember(Player *player)
Definition Group.cpp:395
void SendUpdate()
Definition Group.cpp:1697
void ChangeLeader(ObjectGuid guid)
Definition Group.cpp:704
void SetBattlegroundGroup(Battleground *bg)
Definition Group.cpp:2560
bool IsMember(ObjectGuid guid) const
Definition Group.cpp:2505
bool Create(Player *leader)
Definition Group.cpp:151
Definition Map.h:281
bool AddToMap(T *)
Definition Map.cpp:630
ObjectGuid::LowType GenerateLowGuid()
Definition Map.h:587
GameObject * GetGameObject(ObjectGuid const &guid)
Definition Map.cpp:4430
Creature * GetCreature(ObjectGuid const &guid)
Definition Map.cpp:4397
LowType GetCounter() const
Definition ObjectGuid.h:156
std::string ToString() const
bool IsInWorld() const
Definition Object.h:73
uint32 GetEntry() const
Definition Object.h:81
bool HasFlag(uint16 index, uint32 flag) const
Definition Object.cpp:799
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
uint32 GetTeam() const
Definition Player.h:1832
void SetClientControl(Unit *target, bool allowMove)
Definition Player.cpp:23743
void SetBGTeam(uint32 team)
Definition Player.cpp:21944
uint32 GetBGTeam() const
Definition Player.cpp:21950
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6161
void ClearAfkReports()
Definition Player.h:2012
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1=0, uint32 miscValue2=0, WorldObject *ref=nullptr)
Definition Player.cpp:24940
static void OfflineResurrect(ObjectGuid const &guid, CharacterDatabaseTransaction trans)
Definition Player.cpp:4465
void SpawnCorpseBones(bool triggerSave=true)
Definition Player.cpp:4536
Group * GetOriginalGroup() const
Definition Player.h:2186
bool IsAtGroupRewardDistance(WorldObject const *pRewardSource) const
Definition Player.cpp:23664
void DestroyConjuredItems(bool update)
Definition Player.cpp:12433
void UnsummonPetTemporaryIfAny()
Definition Player.cpp:25197
void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val)
Definition Player.cpp:23120
bool GetRandomWinner() const
Definition Player.h:2019
void RewardPlayerAndGroupAtKill(Unit *victim, bool isBattleGround)
Definition Player.cpp:23631
void RemovePet(Pet *pet, PetSaveMode mode, bool returnreagent=false)
Definition Player.cpp:20310
bool TeleportToBGEntryPoint()
Definition Player.cpp:1766
void ResetAchievementCriteria(AchievementCriteriaCondition condition, uint32 value, bool evenIfCriteriaComplete=false)
Definition Player.cpp:24935
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options=0)
Definition Player.cpp:1524
void ToggleAFK()
Definition Player.cpp:1494
uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const
Definition Player.cpp:23071
void ModifyArenaPoints(int32 value, CharacterDatabaseTransaction trans=CharacterDatabaseTransaction(nullptr))
If trans is specified, honor save query will be added to trans.
Definition Player.cpp:6695
void ResetAllPowers()
Definition Player.cpp:2054
bool RewardHonor(Unit *victim, uint32 groupsize, int32 honor=-1, bool pvptoken=false)
Definition Player.cpp:6524
void ResummonPetTemporaryUnSummonedIfAny()
Definition Player.cpp:25212
void SetBattlegroundId(uint32 val, BattlegroundTypeId bgTypeId)
Definition Player.cpp:23092
void SetBattlegroundOrBattlefieldRaid(Group *group, int8 subgroup=-1)
Definition Player.cpp:23990
ReputationMgr & GetReputationMgr()
Definition Player.h:1848
void RemoveArenaEnchantments(EnchantmentSlot slot)
Definition Player.cpp:13355
void SetRandomWinner(bool isWinner)
Definition Player.cpp:26125
void ResurrectPlayer(float restore_percent, bool applySickness=false)
Definition Player.cpp:4346
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 HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:375
TempSummon * SummonPassenger(uint32 entry, Position const &pos, TempSummonType summonType, SummonPropertiesEntry const *properties=nullptr, uint32 duration=0, Unit *summoner=nullptr, uint32 spellId=0, uint32 vehId=0)
Temporarily summons a creature as passenger on this transport.
Definition Unit.h:769
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3765
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3638
ShapeshiftForm GetShapeshiftForm() const
Definition Unit.h:1490
bool IsAlive() const
Definition Unit.h:1234
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4542
int32 GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:4792
int32 GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:4852
void CombatStop(bool includingCast=false, bool mutualPvP=true)
Definition Unit.cpp:5691
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:954
void CombatStopWithPets(bool includingCast=false)
Definition Unit.cpp:5710
uint32 GetMapId() const
Definition Position.h:193
Map * GetMap() const
Definition Object.h:449
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2832
std::string const & GetName() const
Definition Object.h:382
void SendObjectDeSpawnAnim(ObjectGuid guid)
Definition Object.cpp:1801
WorldPacket const * Write() override
WorldPacket const * GetRawPacket() const
Definition Packet.h:38
#define sWorld
Definition World.h:900
@ CONFIG_BG_REWARD_LOSER_HONOR_LAST
Definition World.h:380
@ CONFIG_BATTLEGROUND_INVITATION_TYPE
Definition World.h:313
@ CONFIG_BG_REWARD_WINNER_ARENA_FIRST
Definition World.h:376
@ CONFIG_BG_REWARD_WINNER_ARENA_LAST
Definition World.h:378
@ CONFIG_BG_REWARD_WINNER_HONOR_FIRST
Definition World.h:375
@ CONFIG_BG_REWARD_LOSER_HONOR_FIRST
Definition World.h:379
@ CONFIG_BG_REWARD_WINNER_HONOR_LAST
Definition World.h:377
@ CONFIG_BG_XP_FOR_KILL
Definition World.h:129
@ CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE
Definition World.h:127
@ CONFIG_BATTLEGROUND_TRACK_DESERTERS
Definition World.h:128
@ CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE
Definition World.h:125
time_t GetGameTime()
Definition GameTime.cpp:42
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
uint32 hk_honor_at_level(uint8 level, float multiplier=1.0f)
Definition Formulas.h:41
uint32 MatchmakerRating
Definition ArenaScore.h:68
int32 RatingChange
Definition ArenaScore.h:67
std::string TeamName
Definition ArenaScore.h:69
virtual void BuildObjectivesBlock(WorldPackets::Battleground::PVPLogData_Player &playerData)=0
virtual void AppendToPacket(WorldPackets::Battleground::PVPLogData_Player &playerData)
float GetPositionZ() const
Definition Position.h:81
float GetOrientation() const
Definition Position.h:82
float GetPositionX() const
Definition Position.h:79
void GetPosition(float &x, float &y) const
Definition Position.h:84
float GetPositionY() const
Definition Position.h:80
float GetExactDistSq(float x, float y, float z) const
Definition Position.h:113
BattlegroundBracketId GetBracketId() const
static QuaternionData fromEulerAnglesZYX(float Z, float Y, float X)
std::array< std::string_view, 2 > TeamName
std::variant< PVPLogData_Honor, uint8 > HonorOrFaction
DBCPosition3D Loc