TrinityCore
Loading...
Searching...
No Matches
Battlefield.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 "Battlefield.h"
19#include "BattlefieldMgr.h"
20#include "Battleground.h"
21#include "BattlegroundPackets.h"
22#include "CellImpl.h"
23#include "CreatureTextMgr.h"
24#include "DBCStores.h"
25#include "GameTime.h"
26#include "GridNotifiers.h"
27#include "GridNotifiersImpl.h"
28#include "Group.h"
29#include "GroupMgr.h"
30#include "Log.h"
31#include "Map.h"
32#include "MapManager.h"
33#include "MiscPackets.h"
34#include "ObjectAccessor.h"
35#include "ObjectMgr.h"
36#include "WorldPacket.h"
37#include "WorldStatePackets.h"
38#include <G3D/g3dmath.h>
39
41{
42 m_Timer = 0;
43 m_IsEnabled = true;
44 m_isActive = false;
46
47 m_TypeId = 0;
48 m_BattleId = 0;
49 m_ZoneId = 0;
50 m_Map = nullptr;
51 m_MapId = 0;
52 m_MaxPlayer = 0;
53 m_MinPlayer = 0;
54 m_MinLevel = 0;
55 m_BattleTime = 0;
60
62
65 m_StartGrouping = false;
66}
67
69{
70 for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
71 delete itr->second;
72
73 for (GraveyardVect::const_iterator itr = m_GraveyardList.begin(); itr != m_GraveyardList.end(); ++itr)
74 delete *itr;
75}
76
77// Called when a player enters the zone
79{
80 // If battle is started,
81 // If not full of players > invite player to join the war
82 // If full of players > announce to player that BF is full and kick him after a few second if he desn't leave
83 if (IsWarTime())
84 {
85 if (m_PlayersInWar[player->GetTeamId()].size() + m_InvitedPlayers[player->GetTeamId()].size() < m_MaxPlayer) // Vacant spaces
86 InvitePlayerToWar(player);
87 else // No more vacant places
88 {
90 m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = GameTime::GetGameTime() + 10;
91 InvitePlayerToQueue(player);
92 }
93 }
94 else
95 {
96 // If time left is < 15 minutes invite player to join queue
98 InvitePlayerToQueue(player);
99 }
100
101 // Add player in the list of player in zone
102 m_players[player->GetTeamId()].insert(player->GetGUID());
103 OnPlayerEnterZone(player);
104}
105
106// Called when a player leave the zone
108{
109 if (IsWarTime())
110 {
111 // If the player is participating to the battle
112 if (m_PlayersInWar[player->GetTeamId()].find(player->GetGUID()) != m_PlayersInWar[player->GetTeamId()].end())
113 {
114 m_PlayersInWar[player->GetTeamId()].erase(player->GetGUID());
116 if (Group* group = player->GetGroup()) // Remove the player from the raid group
117 group->RemoveMember(player->GetGUID());
118
119 OnPlayerLeaveWar(player);
120 }
121 }
122
123 for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
124 itr->second->HandlePlayerLeave(player);
125
126 m_InvitedPlayers[player->GetTeamId()].erase(player->GetGUID());
127 m_PlayersWillBeKick[player->GetTeamId()].erase(player->GetGUID());
128 m_players[player->GetTeamId()].erase(player->GetGUID());
129 SendRemoveWorldStates(player);
131 OnPlayerLeaveZone(player);
132}
133
135{
136 if (m_Timer <= diff)
137 {
138 // Battlefield ends on time
139 if (IsWarTime())
140 EndBattle(true);
141 else // Time to start a new battle!
142 StartBattle();
143 }
144 else
145 m_Timer -= diff;
146
147 // Invite players a few minutes before the battle's beginning
149 {
150 m_StartGrouping = true;
153 }
154
155 bool objective_changed = false;
156 if (IsWarTime())
157 {
158 if (m_uiKickAfkPlayersTimer <= diff)
159 {
162 }
163 else
165
166 // Kick players who chose not to accept invitation to the battle
167 if (m_uiKickDontAcceptTimer <= diff)
168 {
169 time_t now = GameTime::GetGameTime();
170 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
171 for (PlayerTimerMap::iterator itr = m_InvitedPlayers[team].begin(); itr != m_InvitedPlayers[team].end(); ++itr)
172 if (itr->second <= now)
173 KickPlayerFromBattlefield(itr->first);
174
176 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
177 for (PlayerTimerMap::iterator itr = m_PlayersWillBeKick[team].begin(); itr != m_PlayersWillBeKick[team].end(); ++itr)
178 if (itr->second <= now)
179 KickPlayerFromBattlefield(itr->first);
180
182 }
183 else
185
186 for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
187 if (itr->second->Update(diff))
188 objective_changed = true;
189 }
190
191 if (m_LastResurrectTimer <= diff)
192 {
193 for (uint8 i = 0; i < m_GraveyardList.size(); i++)
194 if (GetGraveyardById(i))
197 }
198 else
199 m_LastResurrectTimer -= diff;
200
201 return objective_changed;
202}
203
205{
206 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
207 for (auto itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
208 if (Player* player = ObjectAccessor::FindPlayer(*itr))
209 InvitePlayerToQueue(player);
210}
211
213{
214 if (m_PlayersInQueue[player->GetTeamId()].count(player->GetGUID()))
215 return;
216
217 if (m_PlayersInQueue[player->GetTeamId()].size() <= m_MinPlayer || m_PlayersInQueue[GetOtherTeam(player->GetTeamId())].size() >= m_MinPlayer)
219}
220
222{
223 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
224 {
225 for (auto itr = m_PlayersInQueue[team].begin(); itr != m_PlayersInQueue[team].end(); ++itr)
226 {
227 if (Player* player = ObjectAccessor::FindPlayer(*itr))
228 {
229 if (m_PlayersInWar[player->GetTeamId()].size() + m_InvitedPlayers[player->GetTeamId()].size() < m_MaxPlayer)
230 InvitePlayerToWar(player);
231 else
232 {
233 //Full
234 }
235 }
236 }
237 m_PlayersInQueue[team].clear();
238 }
239}
240
242{
243 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
244 {
245 for (auto itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
246 {
247 if (Player* player = ObjectAccessor::FindPlayer(*itr))
248 {
249 if (m_PlayersInWar[player->GetTeamId()].count(player->GetGUID()) || m_InvitedPlayers[player->GetTeamId()].count(player->GetGUID()))
250 continue;
251 if (m_PlayersInWar[player->GetTeamId()].size() + m_InvitedPlayers[player->GetTeamId()].size() < m_MaxPlayer)
252 InvitePlayerToWar(player);
253 else // Battlefield is full of players
254 m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = GameTime::GetGameTime() + 10;
255 }
256 }
257 }
258}
259
261{
262 if (!player)
263 return;
264
266 if (player->IsInFlight())
267 return;
268
269 if (player->GetBattleground())
270 return;
271
272 // If the player does not match minimal level requirements for the battlefield, kick him
273 if (player->GetLevel() < m_MinLevel)
274 {
275 if (m_PlayersWillBeKick[player->GetTeamId()].count(player->GetGUID()) == 0)
276 m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = GameTime::GetGameTime() + 10;
277 return;
278 }
279
280 // Check if player is not already in war
281 if (m_PlayersInWar[player->GetTeamId()].count(player->GetGUID()) || m_InvitedPlayers[player->GetTeamId()].count(player->GetGUID()))
282 return;
283
284 m_PlayersWillBeKick[player->GetTeamId()].erase(player->GetGUID());
287}
288
290{
291 if (Creature* creature = SpawnCreature(entry, pos))
292 StalkerGuid = creature->GetGUID();
293 else
294 TC_LOG_ERROR("bg.battlefield", "Battlefield::InitStalker: Could not spawn Stalker (Creature entry {}), zone messages will be unavailable!", entry);
295}
296
298{
299 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
300 for (auto itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
301 if (Player* player = ObjectAccessor::FindPlayer(*itr))
302 if (player->isAFK())
304}
305
307{
308 if (Player* player = ObjectAccessor::FindPlayer(guid))
309 if (player->GetZoneId() == GetZoneId())
310 player->TeleportTo(KickPosition);
311}
312
314{
315 if (m_isActive)
316 return;
317
318 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
319 {
320 m_PlayersInWar[team].clear();
321 m_Groups[team].clear();
322 }
323
325 m_isActive = true;
326
329
331}
332
333void Battlefield::EndBattle(bool endByTimer)
334{
335 if (!m_isActive)
336 return;
337
338 m_isActive = false;
339
340 m_StartGrouping = false;
341
342 if (!endByTimer)
344
345 OnBattleEnd(endByTimer);
346
347 // Reset battlefield timer
350}
351
356
358{
359 return m_players[player->GetTeamId()].find(player->GetGUID()) != m_players[player->GetTeamId()].end();
360}
361
362// Called in WorldSession::HandleBfQueueInviteResponse
364{
365 // Add player in queue
366 m_PlayersInQueue[player->GetTeamId()].insert(player->GetGUID());
367 // Send notification
369}
370
371// Called in WorldSession::HandleBfQueueExitRequest
373{
374 // Remove player from queue
375 m_PlayersInQueue[player->GetTeamId()].erase(player->GetGUID());
376}
377
378// Called in WorldSession::HandleHearthAndResurrect
380{
381 // Player leaving Wintergrasp, teleport to Dalaran.
382 // ToDo: confirm teleport destination.
383 player->TeleportTo(571, 5804.1499f, 624.7710f, 647.7670f, 1.6400f);
384}
385
386// Called in WorldSession::HandleBfEntryInviteResponse
388{
389 if (!IsWarTime())
390 return;
391
393 {
395 m_PlayersInWar[player->GetTeamId()].insert(player->GetGUID());
396 m_InvitedPlayers[player->GetTeamId()].erase(player->GetGUID());
397
398 if (player->isAFK())
399 player->ToggleAFK();
400
401 OnPlayerJoinWar(player); //for scripting
402 }
403}
404
406{
407 if (spellId > 0)
408 {
409 for (auto itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
410 if (Player* player = ObjectAccessor::FindPlayer(*itr))
411 player->CastSpell(player, uint32(spellId), true);
412 }
413 else
414 {
415 for (auto itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
416 if (Player* player = ObjectAccessor::FindPlayer(*itr))
417 player->RemoveAuraFromStack(uint32(-spellId));
418 }
419}
420
422{
423 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
424 for (auto itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
425 if (Player* player = ObjectAccessor::FindPlayer(*itr))
426 player->SendDirectMessage(data);
427}
428
430{
431 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
432 for (auto itr = m_PlayersInQueue[team].begin(); itr != m_PlayersInQueue[team].end(); ++itr)
434 player->SendDirectMessage(data);
435}
436
438{
439 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
440 for (auto itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
441 if (Player* player = ObjectAccessor::FindPlayer(*itr))
442 player->SendDirectMessage(data);
443}
444
445void Battlefield::SendWarning(uint8 id, WorldObject const* target /*= nullptr*/)
446{
447 if (Creature* stalker = GetCreature(StalkerGuid))
448 sCreatureTextMgr->SendChat(stalker, id, target);
449}
450
452{
454 packet.MapID = m_MapId;
455 packet.AreaID = m_ZoneId;
456 packet.SubareaID = player->GetAreaId();
458
459 player->SendDirectMessage(packet.Write());
460}
461
463{
465 worldstate.VariableID = variable;
466 worldstate.Value = value;
467 BroadcastPacketToZone(worldstate.Write());
468}
469
471{
472 sBattlefieldMgr->AddZone(zoneId, this);
473}
474
476{
477 creature->CombatStop();
478 creature->SetReactState(REACT_PASSIVE);
480 creature->SetPhaseMask(2, true);
481 creature->DisappearAndDie();
482 creature->SetVisible(false);
483}
484
485void Battlefield::ShowNpc(Creature* creature, bool aggressive)
486{
487 creature->SetPhaseMask(1, true);
488 creature->SetVisible(true);
490 if (!creature->IsAlive())
491 creature->Respawn(true);
492 if (aggressive)
494 else
495 {
497 creature->SetReactState(REACT_PASSIVE);
498 }
499}
500
501// ****************************************************
502// ******************* Group System *******************
503// ****************************************************
505{
506 for (auto itr = m_Groups[TeamId].begin(); itr != m_Groups[TeamId].end(); ++itr)
507 if (Group* group = sGroupMgr->GetGroupByGUID(*itr))
508 if (!group->IsFull())
509 return group;
510
511 return nullptr;
512}
513
515{
516 for (auto itr = m_Groups[TeamId].begin(); itr != m_Groups[TeamId].end(); ++itr)
517 if (Group* group = sGroupMgr->GetGroupByGUID(*itr))
518 if (group->IsMember(guid))
519 return group;
520
521 return nullptr;
522}
523
525{
526 if (!player->IsInWorld())
527 return false;
528
529 if (Group* group = player->GetGroup())
530 group->RemoveMember(player->GetGUID());
531
532 Group* group = GetFreeBfRaid(player->GetTeamId());
533 if (!group)
534 {
535 group = new Group;
536 group->SetBattlefieldGroup(this);
537 group->Create(player);
538 sGroupMgr->AddGroup(group);
539 m_Groups[player->GetTeamId()].insert(group->GetGUID());
540 }
541 else if (group->IsMember(player->GetGUID()))
542 {
543 uint8 subgroup = group->GetMemberGroup(player->GetGUID());
544 player->SetBattlegroundOrBattlefieldRaid(group, subgroup);
545 }
546 else
547 group->AddMember(player);
548
549 return true;
550}
551
552//***************End of Group System*******************
553
554//*****************************************************
555//***************Spirit Guide System*******************
556//*****************************************************
557
558//--------------------
559//-Battlefield Method-
560//--------------------
562{
563 if (id < m_GraveyardList.size())
564 {
565 if (BfGraveyard* graveyard = m_GraveyardList.at(id))
566 return graveyard;
567 else
568 TC_LOG_ERROR("bg.battlefield", "Battlefield::GetGraveyardById Id:{} does not exist.", id);
569 }
570 else
571 TC_LOG_ERROR("bg.battlefield", "Battlefield::GetGraveyardById Id:{} could not be found.", id);
572
573 return nullptr;
574}
575
577{
578 BfGraveyard* closestGY = nullptr;
579 float maxdist = -1;
580 for (uint8 i = 0; i < m_GraveyardList.size(); i++)
581 {
582 if (m_GraveyardList[i])
583 {
584 if (m_GraveyardList[i]->GetControlTeamId() != player->GetTeamId())
585 continue;
586
587 float dist = m_GraveyardList[i]->GetDistance(player);
588 if (dist < maxdist || maxdist < 0)
589 {
590 closestGY = m_GraveyardList[i];
591 maxdist = dist;
592 }
593 }
594 }
595
596 if (closestGY)
597 return sWorldSafeLocsStore.LookupEntry(closestGY->GetGraveyardId());
598
599 return nullptr;
600}
601
603{
604 for (uint8 i = 0; i < m_GraveyardList.size(); i++)
605 {
606 if (!m_GraveyardList[i])
607 continue;
608
609 if (m_GraveyardList[i]->HasNpc(npcGuid))
610 {
611 m_GraveyardList[i]->AddPlayer(playerGuid);
612 break;
613 }
614 }
615}
616
618{
619 for (uint8 i = 0; i < m_GraveyardList.size(); i++)
620 {
621 if (!m_GraveyardList[i])
622 continue;
623
624 if (m_GraveyardList[i]->HasPlayer(playerGuid))
625 {
626 m_GraveyardList[i]->RemovePlayer(playerGuid);
627 break;
628 }
629 }
630}
631
633{
635 areaSpiritHealerTime.HealerGuid = guid;
636 areaSpiritHealerTime.TimeLeft = m_LastResurrectTimer;
637 player->SendDirectMessage(areaSpiritHealerTime.Write());
638}
639
640// ----------------------
641// - BfGraveyard Method -
642// ----------------------
649
650BfGraveyard::~BfGraveyard() = default;
651
652void BfGraveyard::Initialize(TeamId startControl, uint32 graveyardId)
653{
654 m_ControlTeam = startControl;
655 m_GraveyardId = graveyardId;
656}
657
659{
660 if (!spirit)
661 {
662 TC_LOG_ERROR("bg.battlefield", "BfGraveyard::SetSpirit: Invalid Spirit.");
663 return;
664 }
665
666 m_SpiritGuide[team] = spirit->GetGUID();
668}
669
671{
672 WorldSafeLocsEntry const* safeLoc = sWorldSafeLocsStore.LookupEntry(m_GraveyardId);
673 return player->GetDistance2d(safeLoc->Loc.X, safeLoc->Loc.Y);
674}
675
677{
678 if (!m_ResurrectQueue.count(playerGuid))
679 {
680 m_ResurrectQueue.insert(playerGuid);
681
682 if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
683 player->CastSpell(player, SPELL_WAITING_FOR_RESURRECT, true);
684 }
685}
686
688{
689 m_ResurrectQueue.erase(m_ResurrectQueue.find(playerGuid));
690
691 if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
692 player->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
693}
694
696{
697 if (m_ResurrectQueue.empty())
698 return;
699
700 for (GuidSet::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
701 {
702 // Get player object from his guid
703 Player* player = ObjectAccessor::FindPlayer(*itr);
704 if (!player)
705 continue;
706
707 // Check if the player is in world and on the good graveyard
708 if (player->IsInWorld())
710 spirit->CastSpell(spirit, SPELL_SPIRIT_HEAL, true);
711
712 // Resurrect player
713 player->CastSpell(player, SPELL_RESURRECTION_VISUAL, true);
714 player->ResurrectPlayer(1.0f);
715 player->CastSpell(player, 6962, true);
716 player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
717
718 player->SpawnCorpseBones(false);
719 }
720
721 m_ResurrectQueue.clear();
722}
723
724// For changing graveyard control
726{
727 // Guide switching
728 // Note: Visiblity changes are made by phasing
729 /*if (m_SpiritGuide[1 - team])
730 m_SpiritGuide[1 - team]->SetVisible(false);
731 if (m_SpiritGuide[team])
732 m_SpiritGuide[team]->SetVisible(true);*/
733
734 m_ControlTeam = team;
735 // Teleport to other graveyard, player witch were on this graveyard
737}
738
740{
741 WorldSafeLocsEntry const* closestGrave = nullptr;
742 for (GuidSet::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
743 {
744 Player* player = ObjectAccessor::FindPlayer(*itr);
745 if (!player)
746 continue;
747
748 if (closestGrave)
749 player->TeleportTo(player->GetMapId(), closestGrave->Loc.X, closestGrave->Loc.Y, closestGrave->Loc.Z, player->GetOrientation());
750 else
751 {
752 closestGrave = m_Bf->GetClosestGraveyard(player);
753 if (closestGrave)
754 player->TeleportTo(player->GetMapId(), closestGrave->Loc.X, closestGrave->Loc.Y, closestGrave->Loc.Z, player->GetOrientation());
755 }
756 }
757}
758
760{
762 return false;
763
766 return false;
767
768 return (m_SpiritGuide[TEAM_ALLIANCE] == guid || m_SpiritGuide[TEAM_HORDE] == guid);
769}
770
771// *******************************************************
772// *************** End Spirit Guide system ***************
773// *******************************************************
774// ********************** Misc ***************************
775// *******************************************************
776
778{
779 //Get map object
780 Map* map = sMapMgr->CreateBaseMap(m_MapId);
781 if (!map)
782 {
783 TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: Can't create creature entry: {}, map not found.", entry);
784 return nullptr;
785 }
786
787 Creature* creature = new Creature();
788 if (!creature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, PHASEMASK_NORMAL, entry, pos))
789 {
790 TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: Can't create creature entry: {}", entry);
791 delete creature;
792 return nullptr;
793 }
794
795 creature->SetHomePosition(pos);
796
797 // Set creature in world
798 map->AddToMap(creature);
799 creature->setActive(true);
800 creature->SetFarVisible(true);
801
802 return creature;
803}
804
805// Method for spawning gameobject on map
807{
808 // Get map object
809 Map* map = sMapMgr->CreateBaseMap(m_MapId);
810 if (!map)
811 return nullptr;
812
813 // Create gameobject
814 GameObject* go = new GameObject;
815 if (!go->Create(map->GenerateLowGuid<HighGuid::GameObject>(), entry, map, PHASEMASK_NORMAL, pos, rot, 255, GO_STATE_READY))
816 {
817 TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Gameobject template {} could not be found in the database! Battlefield has not been created!", entry);
818 TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Could not create gameobject template {}! Battlefield has not been created!", entry);
819 delete go;
820 return nullptr;
821 }
822
823 // Add to world
824 map->AddToMap(go);
825 go->setActive(true);
826 go->SetFarVisible(true);
827
828 return go;
829}
830
832{
833 if (!m_Map)
834 return nullptr;
835 return m_Map->GetCreature(guid);
836}
837
839{
840 if (!m_Map)
841 return nullptr;
842 return m_Map->GetGameObject(guid);
843}
844
845// *******************************************************
846// ******************* CapturePoint **********************
847// *******************************************************
848
861
863
865{
867 {
868 if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
869 {
870 player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 1);
871 player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate2, uint32(ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f)));
872 player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate3, m_neutralValuePct);
873 }
874 }
875
876 return m_activePlayers[player->GetTeamId()].insert(player->GetGUID()).second;
877}
878
880{
882 if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
883 player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 0);
884
885 GuidSet::iterator current = m_activePlayers[player->GetTeamId()].find(player->GetGUID());
886
887 if (current == m_activePlayers[player->GetTeamId()].end())
888 return current; // return end()
889
890 m_activePlayers[player->GetTeamId()].erase(current++);
891 return current;
892}
893
895{
897 return;
898
899 if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
900 {
901 // send this too, sometimes the slider disappears, dunno why :(
902 SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 1);
903 // send these updates to only the ones in this objective
904 SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate2, (uint32) std::ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f));
905 // send this too, sometimes it resets :S
906 SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate3, m_neutralValuePct);
907 }
908}
909
911{
912 ASSERT(capturePoint);
913
914 TC_LOG_DEBUG("bg.battlefield", "Creating capture point {}", capturePoint->GetEntry());
915
916 m_capturePointGUID = capturePoint->GetGUID();
917
918 // check info existence
919 GameObjectTemplate const* goinfo = capturePoint->GetGOInfo();
920 if (goinfo->type != GAMEOBJECT_TYPE_CAPTURE_POINT)
921 {
922 TC_LOG_ERROR("misc", "OutdoorPvP: GO {} is not a capture point!", capturePoint->GetEntry());
923 return false;
924 }
925
926 // get the needed values from goinfo
928 m_maxSpeed = m_maxValue / (goinfo->capturePoint.minTime ? goinfo->capturePoint.minTime : 60);
931 m_capturePointEntry = capturePoint->GetEntry();
932 if (m_team == TEAM_ALLIANCE)
933 {
936 }
937 else
938 {
941 }
942
943 return true;
944}
945
950
952{
954 {
955 if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
956 {
957 capturePoint->SetRespawnTime(0); // not save respawn time
958 capturePoint->Delete();
959 capturePoint = nullptr;
960 }
962 }
963
964 return true;
965}
966
968{
970 return false;
971
972 if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
973 {
974 float radius = capturePoint->GetGOInfo()->capturePoint.radius;
975
976 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
977 {
978 for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end();)
979 {
980 if (Player* player = ObjectAccessor::FindPlayer(*itr))
981 {
982 if (!capturePoint->IsWithinDistInMap(player, radius) || !player->IsOutdoorPvPActive())
983 itr = HandlePlayerLeave(player);
984 else
985 ++itr;
986 }
987 else
988 ++itr;
989 }
990 }
991
992 std::list<Player*> players;
993 Trinity::AnyPlayerInObjectRangeCheck checker(capturePoint, radius);
994 Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(capturePoint, players, checker);
995 Cell::VisitWorldObjects(capturePoint, searcher, radius);
996
997 for (std::list<Player*>::iterator itr = players.begin(); itr != players.end(); ++itr)
998 if ((*itr)->IsOutdoorPvPActive())
999 if (m_activePlayers[(*itr)->GetTeamId()].insert((*itr)->GetGUID()).second)
1000 HandlePlayerEnter(*itr);
1001 }
1002
1003 // get the difference of numbers
1004 float fact_diff = ((float) m_activePlayers[TEAM_ALLIANCE].size() - (float) m_activePlayers[TEAM_HORDE].size()) * diff / float(BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL);
1005 if (G3D::fuzzyEq(fact_diff, 0.0f))
1006 return false;
1007
1008 uint32 Challenger = 0;
1009 float maxDiff = m_maxSpeed * diff;
1010
1011 if (fact_diff < 0)
1012 {
1013 // horde is in majority, but it's already horde-controlled -> no change
1015 return false;
1016
1017 if (fact_diff < -maxDiff)
1018 fact_diff = -maxDiff;
1019
1020 Challenger = HORDE;
1021 }
1022 else
1023 {
1024 // ally is in majority, but it's already ally-controlled -> no change
1026 return false;
1027
1028 if (fact_diff > maxDiff)
1029 fact_diff = maxDiff;
1030
1031 Challenger = ALLIANCE;
1032 }
1033
1034 float oldValue = m_value;
1035 TeamId oldTeam = m_team;
1036
1038
1039 m_value += fact_diff;
1040
1041 if (m_value < -m_minValue) // red
1042 {
1043 if (m_value < -m_maxValue)
1047 }
1048 else if (m_value > m_minValue) // blue
1049 {
1050 if (m_value > m_maxValue)
1054 }
1055 else if (oldValue * m_value <= 0) // grey, go through mid point
1056 {
1057 // if challenger is ally, then n->a challenge
1058 if (Challenger == ALLIANCE)
1060 // if challenger is horde, then n->h challenge
1061 else if (Challenger == HORDE)
1064 }
1065 else // grey, did not go through mid point
1066 {
1067 // old phase and current are on the same side, so one team challenges the other
1073 }
1074
1075 if (G3D::fuzzyNe(m_value, oldValue))
1077
1078 if (m_OldState != m_State)
1079 {
1080 //TC_LOG_ERROR("bg.battlefield", "{}->{}", m_OldState, m_State);
1081 if (oldTeam != m_team)
1082 ChangeTeam(oldTeam);
1083 return true;
1084 }
1085
1086 return false;
1087}
1088
1090{
1091 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
1092 for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) // send to all players present in the area
1093 if (Player* player = ObjectAccessor::FindPlayer(*itr))
1094 player->SendUpdateWorldState(field, value);
1095}
1096
1098{
1099 uint8 team;
1100 switch (m_State)
1101 {
1103 team = TEAM_ALLIANCE;
1104 break;
1106 team = TEAM_HORDE;
1107 break;
1108 default:
1109 return;
1110 }
1111
1112 // send to all players present in the area
1113 for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr)
1114 if (Player* player = ObjectAccessor::FindPlayer(*itr))
1115 player->KilledMonsterCredit(id, guid);
1116}
1117
1119{
1120 return m_activePlayers[player->GetTeamId()].find(player->GetGUID()) != m_activePlayers[player->GetTeamId()].end();
1121}
#define sBattlefieldMgr
@ BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL
Definition Battlefield.h:57
@ BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE
Definition Battlefield.h:43
@ BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE
Definition Battlefield.h:42
@ BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE
Definition Battlefield.h:41
@ BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE
Definition Battlefield.h:44
@ BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE
Definition Battlefield.h:40
@ BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE
Definition Battlefield.h:45
@ BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL
Definition Battlefield.h:39
@ RESURRECTION_INTERVAL
@ SPELL_SPIRIT_HEAL
@ SPELL_SPIRIT_HEAL_MANA
@ SPELL_RESURRECTION_VISUAL
@ SPELL_WAITING_FOR_RESURRECT
@ IN_MILLISECONDS
Definition Common.h:35
#define sCreatureTextMgr
DBCStorage< WorldSafeLocsEntry > sWorldSafeLocsStore(WorldSafeLocsEntryfmt)
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
#define ASSERT
Definition Errors.h:68
#define sGroupMgr
Definition GroupMgr.h:58
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define sMapMgr
Definition MapManager.h:211
@ PHASEMASK_NORMAL
@ GAMEOBJECT_TYPE_CAPTURE_POINT
TeamId
@ TEAM_NEUTRAL
@ TEAM_ALLIANCE
@ TEAM_HORDE
uint8 constexpr PVP_TEAMS_COUNT
@ ALLIANCE
@ HORDE
@ GO_STATE_READY
@ REACT_PASSIVE
@ REACT_AGGRESSIVE
@ UNIT_FLAG_NON_ATTACKABLE
@ UNIT_FLAG_UNINTERACTIBLE
void Resurrect(Creature *target)
uint32 m_Timer
uint32 m_MapId
GameObject * SpawnGameObject(uint32 entry, Position const &pos, QuaternionData const &rot)
GraveyardVect m_GraveyardList
GameObject * GetGameObject(ObjectGuid guid)
void BroadcastPacketToWar(WorldPacket const *data) const
void DoPlaySoundToAll(uint32 soundID)
void ShowNpc(Creature *creature, bool aggressive)
Creature * GetCreature(ObjectGuid guid)
uint32 m_MaxPlayer
ObjectGuid StalkerGuid
Creature * SpawnCreature(uint32 entry, Position const &pos)
void BroadcastPacketToZone(WorldPacket const *data) const
uint32 m_NoWarBattleTime
virtual ~Battlefield()
Destructor.
virtual void SendInitWorldStatesToAll()=0
Send all worldstate data to all player in zone.
void EndBattle(bool endByTimer)
virtual void OnBattleEnd(bool)
Called at the end of battle.
uint32 m_BattleTime
uint32 GetZoneId() const
bool IsWarTime() const
Return true if battle is start, false if battle is not started.
uint32 m_ZoneId
void InitStalker(uint32 entry, Position const &pos)
uint32 m_TypeId
uint32 m_BattleId
void InvitePlayersInQueueToWar()
Invite all players in queue to join battle on battle start.
virtual void SendRemoveWorldStates(Player *)
uint32 m_StartGroupingTimer
virtual void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates &)=0
virtual bool Update(uint32 diff)
Called every time for update bf data and time.
void InvitePlayersInZoneToQueue()
Invite all players in zone to join the queue, called x minutes before battle start in Update()
void KickPlayerFromBattlefield(ObjectGuid guid)
Kick player from battlefield and teleport him to kick-point location.
void InvitePlayerToQueue(Player *player)
void RegisterZone(uint32 zoneid)
void SetDefenderTeam(TeamId team)
TeamId m_DefenderTeam
void InvitePlayerToWar(Player *player)
uint32 m_uiKickAfkPlayersTimer
void PlayerAcceptInviteToWar(Player *player)
void BroadcastPacketToQueue(WorldPacket const *data) const
void SendWarning(uint8 id, WorldObject const *target=nullptr)
Group * GetFreeBfRaid(TeamId TeamId)
Find a not full battlefield group, if there is no, create one.
void SendAreaSpiritHealerQueryOpcode(Player *player, ObjectGuid guid)
void StartBattle()
virtual void OnPlayerJoinWar(Player *)
Called when a player accept to join the battle.
uint32 m_TimeForAcceptInvite
BfGraveyard * GetGraveyardById(uint32 id) const
virtual void OnBattleStart()
Called on start.
GuidUnorderedSet m_PlayersInWar[PVP_TEAMS_COUNT]
void InvitePlayersInZoneToWar()
Invite all players in zone to join battle on battle start.
void HideNpc(Creature *creature)
PlayerTimerMap m_PlayersWillBeKick[PVP_TEAMS_COUNT]
uint32 m_RestartAfterCrash
void SendUpdateWorldState(uint32 variable, uint32 value)
Update data of a worldstate to all players present in zone.
virtual void AddPlayerToResurrectQueue(ObjectGuid npc_guid, ObjectGuid player_guid)
TeamId GetAttackerTeam() const
uint32 m_MinLevel
void SendInitWorldStatesTo(Player *player)
GuidUnorderedSet m_PlayersInQueue[PVP_TEAMS_COUNT]
bool AddOrSetPlayerToCorrectBfGroup(Player *player)
Force player to join a battlefield group.
void KickAfkPlayers()
void PlayerAskToLeave(Player *player)
void TeamCastSpell(TeamId team, int32 spellId)
uint32 m_MinPlayer
uint32 m_LastResurrectTimer
virtual void OnPlayerLeaveZone(Player *)
Called when a player leave battlefield zone.
void PlayerAcceptInviteToQueue(Player *player)
void RemovePlayerFromResurrectQueue(ObjectGuid player_guid)
BfCapturePointMap m_capturePoints
Group * GetGroupPlayer(ObjectGuid guid, TeamId TeamId)
Return battlefield group where player is.
uint32 m_uiKickDontAcceptTimer
GuidUnorderedSet m_Groups[PVP_TEAMS_COUNT]
virtual void OnStartGrouping()
Called x minutes before battle start when player in zone are invite to join queue.
bool m_StartGrouping
WorldLocation KickPosition
virtual void OnPlayerLeaveWar(Player *)
Called when a player leave the battle.
PlayerTimerMap m_InvitedPlayers[PVP_TEAMS_COUNT]
bool HasPlayer(Player *player) const
void AskToLeaveQueue(Player *player)
TeamId GetOtherTeam(TeamId team) const
WorldSafeLocsEntry const * GetClosestGraveyard(Player *player)
void HandlePlayerLeaveZone(Player *player, uint32 zone)
Called when player (player) leave the zone.
virtual void OnPlayerEnterZone(Player *)
Called when a player enter in battlefield zone.
Battlefield()
Constructor.
GuidUnorderedSet m_players[PVP_TEAMS_COUNT]
void HandlePlayerEnterZone(Player *player, uint32 zone)
Called when player (player) enter in zone.
virtual GuidSet::iterator HandlePlayerLeave(Player *player)
virtual bool HandlePlayerEnter(Player *player)
BfCapturePoint(Battlefield *bf)
Battlefield * m_Bf
virtual bool Update(uint32 diff)
BattlefieldObjectiveStates m_OldState
bool SetCapturePointData(GameObject *capturePoint)
virtual void ChangeTeam(TeamId)
bool IsInsideObjective(Player *player) const
GameObject * GetCapturePointGo()
virtual void SendChangePhase()
void SendUpdateWorldState(uint32 field, uint32 value)
uint32 m_capturePointEntry
ObjectGuid m_capturePointGUID
uint32 m_neutralValuePct
void SendObjectiveComplete(uint32 id, ObjectGuid guid)
GuidSet m_activePlayers[PVP_TEAMS_COUNT]
BattlefieldObjectiveStates m_State
virtual ~BfCapturePoint()
ObjectGuid m_SpiritGuide[PVP_TEAMS_COUNT]
GuidSet m_ResurrectQueue
BfGraveyard(Battlefield *bf)
virtual ~BfGraveyard()
bool HasNpc(ObjectGuid guid)
uint32 m_GraveyardId
void GiveControlTo(TeamId team)
Battlefield * m_Bf
TeamId m_ControlTeam
void SetSpirit(Creature *spirit, TeamId team)
uint32 GetGraveyardId() const
void Initialize(TeamId startcontrol, uint32 gy)
void AddPlayer(ObjectGuid player_guid)
void RelocateDeadPlayers()
float GetDistance(Player *player)
void RemovePlayer(ObjectGuid player_guid)
void SetPhaseMask(uint32 newPhaseMask, bool update) override
Definition Creature.cpp:652
void SetHomePosition(float x, float y, float z, float o)
Definition Creature.h:293
void Respawn(bool force=false)
void SetReactState(ReactStates st)
Definition Creature.h:119
bool Create(ObjectGuid::LowType guidlow, Map *map, uint32 phaseMask, uint32 entry, Position const &pos, CreatureData const *data=nullptr, uint32 vehId=0, bool dynamic=false)
void DisappearAndDie()
Definition Creature.h:73
GameObjectTemplate const * GetGOInfo() const
Definition GameObject.h:102
void SetRespawnTime(int32 respawn)
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
void SetBattlefieldGroup(Battlefield *bf)
Definition Group.cpp:2565
bool AddMember(Player *player)
Definition Group.cpp:395
ObjectGuid GetGUID() const
Definition Group.cpp:2473
bool IsMember(ObjectGuid guid) const
Definition Group.cpp:2505
bool RemoveMember(ObjectGuid guid, RemoveMethod const &method=GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker=ObjectGuid::Empty, char const *reason=nullptr)
Definition Group.cpp:538
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
bool IsEmpty() const
Definition ObjectGuid.h:172
void Clear()
Definition ObjectGuid.h:150
bool IsInWorld() const
Definition Object.h:73
uint32 GetEntry() const
Definition Object.h:81
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
void SendUpdateWorldState(uint32 variable, uint32 value) const
Definition Player.cpp:8493
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6161
void SpawnCorpseBones(bool triggerSave=true)
Definition Player.cpp:4536
WorldSession * GetSession() const
Definition Player.h:1719
TeamId GetTeamId() const
Definition Player.h:1833
Battleground * GetBattleground() const
Definition Player.cpp:23049
Group * GetGroup()
Definition Player.h:2171
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
bool isAFK() const
Definition Player.h:975
void SetBattlegroundOrBattlefieldRaid(Group *group, int8 subgroup=-1)
Definition Player.cpp:23990
void ResurrectPlayer(float restore_percent, bool applySickness=false)
Definition Player.cpp:4346
void SetVisible(bool x)
Definition Unit.cpp:8513
bool IsAlive() const
Definition Unit.h:1234
bool IsInFlight() const
Definition Unit.h:1119
void CombatStop(bool includingCast=false, bool mutualPvP=true)
Definition Unit.cpp:5691
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:954
uint8 GetLevel() const
Definition Unit.h:889
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:955
uint32 GetMapId() const
Definition Position.h:193
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2832
void setActive(bool isActiveObject)
Definition Object.cpp:991
float GetDistance2d(WorldObject const *obj) const
Definition Object.cpp:1141
void SetFarVisible(bool on)
Definition Object.cpp:1014
uint32 GetAreaId() const
Definition Object.h:374
void SendBfLeaveMessage(uint32 battleId, BFLeaveReason reason=BF_LEAVE_REASON_EXITED)
This is call when player leave battlefield zone.
void SendBfQueueInviteResponse(uint32 battleId, uint32 zoneId, bool canQueue=true, bool full=false)
This send packet for inform player that he join queue.
void SendBfInvitePlayerToWar(uint32 battleId, uint32 zoneId, uint32 time)
This send to player windows for invite player to join the war.
void SendBfInvitePlayerToQueue(uint32 battleId)
This send invitation to player to join the queue.
void SendBfEntered(uint32 battleId)
This is call when player accept to join war.
time_t GetGameTime()
Definition GameTime.cpp:42
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:180
struct GameObjectTemplate::@191::@216 capturePoint
float GetOrientation() const
Definition Position.h:82
DBCPosition3D Loc