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))
195 m_GraveyardList[i]->Resurrect();
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 Battlefield::BfCapturePointMap::iterator i = m_capturePoints.find(cp->GetCapturePointEntry());
473 if (i != m_capturePoints.end())
474 {
475 TC_LOG_ERROR("bg.battlefield", "Battlefield::AddCapturePoint: CapturePoint {} already exists!", cp->GetCapturePointEntry());
476 delete i->second;
477 }
479}
480
482{
483 Battlefield::BfCapturePointMap::const_iterator itr = m_capturePoints.find(entry);
484 if (itr != m_capturePoints.end())
485 return itr->second;
486 return nullptr;
487}
488
490{
491 sBattlefieldMgr->AddZone(zoneId, this);
492}
493
495{
496 creature->CombatStop();
497 creature->SetReactState(REACT_PASSIVE);
499 creature->SetPhaseMask(2, true);
500 creature->DisappearAndDie();
501 creature->SetVisible(false);
502}
503
504void Battlefield::ShowNpc(Creature* creature, bool aggressive)
505{
506 creature->SetPhaseMask(1, true);
507 creature->SetVisible(true);
509 if (!creature->IsAlive())
510 creature->Respawn(true);
511 if (aggressive)
513 else
514 {
516 creature->SetReactState(REACT_PASSIVE);
517 }
518}
519
520// ****************************************************
521// ******************* Group System *******************
522// ****************************************************
524{
525 for (auto itr = m_Groups[TeamId].begin(); itr != m_Groups[TeamId].end(); ++itr)
526 if (Group* group = sGroupMgr->GetGroupByGUID(*itr))
527 if (!group->IsFull())
528 return group;
529
530 return nullptr;
531}
532
534{
535 for (auto itr = m_Groups[TeamId].begin(); itr != m_Groups[TeamId].end(); ++itr)
536 if (Group* group = sGroupMgr->GetGroupByGUID(*itr))
537 if (group->IsMember(guid))
538 return group;
539
540 return nullptr;
541}
542
544{
545 if (!player->IsInWorld())
546 return false;
547
548 if (Group* group = player->GetGroup())
549 group->RemoveMember(player->GetGUID());
550
551 Group* group = GetFreeBfRaid(player->GetTeamId());
552 if (!group)
553 {
554 group = new Group;
555 group->SetBattlefieldGroup(this);
556 group->Create(player);
557 sGroupMgr->AddGroup(group);
558 m_Groups[player->GetTeamId()].insert(group->GetGUID());
559 }
560 else if (group->IsMember(player->GetGUID()))
561 {
562 uint8 subgroup = group->GetMemberGroup(player->GetGUID());
563 player->SetBattlegroundOrBattlefieldRaid(group, subgroup);
564 }
565 else
566 group->AddMember(player);
567
568 return true;
569}
570
571//***************End of Group System*******************
572
573//*****************************************************
574//***************Spirit Guide System*******************
575//*****************************************************
576
577//--------------------
578//-Battlefield Method-
579//--------------------
581{
582 if (id < m_GraveyardList.size())
583 {
584 if (BfGraveyard* graveyard = m_GraveyardList.at(id))
585 return graveyard;
586 else
587 TC_LOG_ERROR("bg.battlefield", "Battlefield::GetGraveyardById Id:{} does not exist.", id);
588 }
589 else
590 TC_LOG_ERROR("bg.battlefield", "Battlefield::GetGraveyardById Id:{} could not be found.", id);
591
592 return nullptr;
593}
594
596{
597 BfGraveyard* closestGY = nullptr;
598 float maxdist = -1;
599 for (uint8 i = 0; i < m_GraveyardList.size(); i++)
600 {
601 if (m_GraveyardList[i])
602 {
603 if (m_GraveyardList[i]->GetControlTeamId() != player->GetTeamId())
604 continue;
605
606 float dist = m_GraveyardList[i]->GetDistance(player);
607 if (dist < maxdist || maxdist < 0)
608 {
609 closestGY = m_GraveyardList[i];
610 maxdist = dist;
611 }
612 }
613 }
614
615 if (closestGY)
616 return sWorldSafeLocsStore.LookupEntry(closestGY->GetGraveyardId());
617
618 return nullptr;
619}
620
622{
623 for (uint8 i = 0; i < m_GraveyardList.size(); i++)
624 {
625 if (!m_GraveyardList[i])
626 continue;
627
628 if (m_GraveyardList[i]->HasNpc(npcGuid))
629 {
630 m_GraveyardList[i]->AddPlayer(playerGuid);
631 break;
632 }
633 }
634}
635
637{
638 for (uint8 i = 0; i < m_GraveyardList.size(); i++)
639 {
640 if (!m_GraveyardList[i])
641 continue;
642
643 if (m_GraveyardList[i]->HasPlayer(playerGuid))
644 {
645 m_GraveyardList[i]->RemovePlayer(playerGuid);
646 break;
647 }
648 }
649}
650
652{
654 areaSpiritHealerTime.HealerGuid = guid;
655 areaSpiritHealerTime.TimeLeft = m_LastResurrectTimer;
656 player->SendDirectMessage(areaSpiritHealerTime.Write());
657}
658
659// ----------------------
660// - BfGraveyard Method -
661// ----------------------
668
669BfGraveyard::~BfGraveyard() = default;
670
671void BfGraveyard::Initialize(TeamId startControl, uint32 graveyardId)
672{
673 m_ControlTeam = startControl;
674 m_GraveyardId = graveyardId;
675}
676
678{
679 if (!spirit)
680 {
681 TC_LOG_ERROR("bg.battlefield", "BfGraveyard::SetSpirit: Invalid Spirit.");
682 return;
683 }
684
685 m_SpiritGuide[team] = spirit->GetGUID();
687}
688
690{
691 WorldSafeLocsEntry const* safeLoc = sWorldSafeLocsStore.LookupEntry(m_GraveyardId);
692 return player->GetDistance2d(safeLoc->Loc.X, safeLoc->Loc.Y);
693}
694
696{
697 if (!m_ResurrectQueue.count(playerGuid))
698 {
699 m_ResurrectQueue.insert(playerGuid);
700
701 if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
702 player->CastSpell(player, SPELL_WAITING_FOR_RESURRECT, true);
703 }
704}
705
707{
708 m_ResurrectQueue.erase(m_ResurrectQueue.find(playerGuid));
709
710 if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
711 player->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
712}
713
715{
716 if (m_ResurrectQueue.empty())
717 return;
718
719 for (GuidSet::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
720 {
721 // Get player object from his guid
722 Player* player = ObjectAccessor::FindPlayer(*itr);
723 if (!player)
724 continue;
725
726 // Check if the player is in world and on the good graveyard
727 if (player->IsInWorld())
729 spirit->CastSpell(spirit, SPELL_SPIRIT_HEAL, true);
730
731 // Resurrect player
732 player->CastSpell(player, SPELL_RESURRECTION_VISUAL, true);
733 player->ResurrectPlayer(1.0f);
734 player->CastSpell(player, 6962, true);
735 player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
736
737 player->SpawnCorpseBones(false);
738 }
739
740 m_ResurrectQueue.clear();
741}
742
743// For changing graveyard control
745{
746 // Guide switching
747 // Note: Visiblity changes are made by phasing
748 /*if (m_SpiritGuide[1 - team])
749 m_SpiritGuide[1 - team]->SetVisible(false);
750 if (m_SpiritGuide[team])
751 m_SpiritGuide[team]->SetVisible(true);*/
752
753 m_ControlTeam = team;
754 // Teleport to other graveyard, player witch were on this graveyard
756}
757
759{
760 WorldSafeLocsEntry const* closestGrave = nullptr;
761 for (GuidSet::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
762 {
763 Player* player = ObjectAccessor::FindPlayer(*itr);
764 if (!player)
765 continue;
766
767 if (closestGrave)
768 player->TeleportTo(player->GetMapId(), closestGrave->Loc.X, closestGrave->Loc.Y, closestGrave->Loc.Z, player->GetOrientation());
769 else
770 {
771 closestGrave = m_Bf->GetClosestGraveyard(player);
772 if (closestGrave)
773 player->TeleportTo(player->GetMapId(), closestGrave->Loc.X, closestGrave->Loc.Y, closestGrave->Loc.Z, player->GetOrientation());
774 }
775 }
776}
777
779{
781 return false;
782
785 return false;
786
787 return (m_SpiritGuide[TEAM_ALLIANCE] == guid || m_SpiritGuide[TEAM_HORDE] == guid);
788}
789
790// *******************************************************
791// *************** End Spirit Guide system ***************
792// *******************************************************
793// ********************** Misc ***************************
794// *******************************************************
795
797{
798 //Get map object
799 Map* map = sMapMgr->CreateBaseMap(m_MapId);
800 if (!map)
801 {
802 TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: Can't create creature entry: {}, map not found.", entry);
803 return nullptr;
804 }
805
806 Creature* creature = new Creature();
807 if (!creature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, PHASEMASK_NORMAL, entry, pos))
808 {
809 TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: Can't create creature entry: {}", entry);
810 delete creature;
811 return nullptr;
812 }
813
814 creature->SetHomePosition(pos);
815
816 // Set creature in world
817 map->AddToMap(creature);
818 creature->setActive(true);
819 creature->SetFarVisible(true);
820
821 return creature;
822}
823
824// Method for spawning gameobject on map
826{
827 // Get map object
828 Map* map = sMapMgr->CreateBaseMap(m_MapId);
829 if (!map)
830 return nullptr;
831
832 // Create gameobject
833 GameObject* go = new GameObject;
834 if (!go->Create(map->GenerateLowGuid<HighGuid::GameObject>(), entry, map, PHASEMASK_NORMAL, pos, rot, 255, GO_STATE_READY))
835 {
836 TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Gameobject template {} could not be found in the database! Battlefield has not been created!", entry);
837 delete go;
838 return nullptr;
839 }
840
841 // Add to world
842 map->AddToMap(go);
843 go->setActive(true);
844 go->SetFarVisible(true);
845
846 return go;
847}
848
850{
851 if (!m_Map)
852 return nullptr;
853 return m_Map->GetCreature(guid);
854}
855
857{
858 if (!m_Map)
859 return nullptr;
860 return m_Map->GetGameObject(guid);
861}
862
863// *******************************************************
864// ******************* CapturePoint **********************
865// *******************************************************
866
879
881
883{
885 {
886 if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
887 {
888 player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 1);
889 player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate2, uint32(ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f)));
890 player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate3, m_neutralValuePct);
891 }
892 }
893
894 return m_activePlayers[player->GetTeamId()].insert(player->GetGUID()).second;
895}
896
898{
900 if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
901 player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 0);
902
903 GuidSet::iterator current = m_activePlayers[player->GetTeamId()].find(player->GetGUID());
904
905 if (current == m_activePlayers[player->GetTeamId()].end())
906 return current; // return end()
907
908 m_activePlayers[player->GetTeamId()].erase(current++);
909 return current;
910}
911
913{
915 return;
916
917 if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
918 {
919 // send this too, sometimes the slider disappears, dunno why :(
920 SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 1);
921 // send these updates to only the ones in this objective
922 SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate2, (uint32) std::ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f));
923 // send this too, sometimes it resets :S
924 SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate3, m_neutralValuePct);
925 }
926}
927
929{
930 ASSERT(capturePoint);
931
932 TC_LOG_DEBUG("bg.battlefield", "Creating capture point {}", capturePoint->GetEntry());
933
934 m_capturePointGUID = capturePoint->GetGUID();
935 m_capturePointEntry = capturePoint->GetEntry();
936
937 // check info existence
938 GameObjectTemplate const* goinfo = capturePoint->GetGOInfo();
939 if (goinfo->type != GAMEOBJECT_TYPE_CAPTURE_POINT)
940 {
941 TC_LOG_ERROR("misc", "OutdoorPvP: GO {} is not a capture point!", capturePoint->GetEntry());
942 return false;
943 }
944
945 // get the needed values from goinfo
947 m_maxSpeed = m_maxValue / (goinfo->capturePoint.minTime ? goinfo->capturePoint.minTime : 60);
950
951 if (m_team == TEAM_ALLIANCE)
952 {
955 }
956 else
957 {
960 }
961
962 return true;
963}
964
969
971{
973 {
974 if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
975 {
976 capturePoint->SetRespawnTime(0); // not save respawn time
977 capturePoint->Delete();
978 capturePoint = nullptr;
979 }
981 }
982
983 return true;
984}
985
987{
989 return false;
990
991 if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
992 {
993 float radius = capturePoint->GetGOInfo()->capturePoint.radius;
994
995 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
996 {
997 for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end();)
998 {
999 if (Player* player = ObjectAccessor::FindPlayer(*itr))
1000 {
1001 if (!capturePoint->IsWithinDistInMap(player, radius) || !player->IsOutdoorPvPActive())
1002 itr = HandlePlayerLeave(player);
1003 else
1004 ++itr;
1005 }
1006 else
1007 ++itr;
1008 }
1009 }
1010
1011 std::list<Player*> players;
1012 Trinity::AnyPlayerInObjectRangeCheck checker(capturePoint, radius);
1013 Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(capturePoint, players, checker);
1014 Cell::VisitWorldObjects(capturePoint, searcher, radius);
1015
1016 for (std::list<Player*>::iterator itr = players.begin(); itr != players.end(); ++itr)
1017 if ((*itr)->IsOutdoorPvPActive())
1018 if (m_activePlayers[(*itr)->GetTeamId()].insert((*itr)->GetGUID()).second)
1019 HandlePlayerEnter(*itr);
1020 }
1021
1022 // get the difference of numbers
1023 float fact_diff = ((float) m_activePlayers[TEAM_ALLIANCE].size() - (float) m_activePlayers[TEAM_HORDE].size()) * diff / float(BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL);
1024 if (G3D::fuzzyEq(fact_diff, 0.0f))
1025 return false;
1026
1027 uint32 Challenger = 0;
1028 float maxDiff = m_maxSpeed * diff;
1029
1030 if (fact_diff < 0)
1031 {
1032 // horde is in majority, but it's already horde-controlled -> no change
1034 return false;
1035
1036 if (fact_diff < -maxDiff)
1037 fact_diff = -maxDiff;
1038
1039 Challenger = HORDE;
1040 }
1041 else
1042 {
1043 // ally is in majority, but it's already ally-controlled -> no change
1045 return false;
1046
1047 if (fact_diff > maxDiff)
1048 fact_diff = maxDiff;
1049
1050 Challenger = ALLIANCE;
1051 }
1052
1053 float oldValue = m_value;
1054 TeamId oldTeam = m_team;
1055
1057
1058 m_value += fact_diff;
1059
1060 if (m_value < -m_minValue) // red
1061 {
1062 if (m_value < -m_maxValue)
1066 }
1067 else if (m_value > m_minValue) // blue
1068 {
1069 if (m_value > m_maxValue)
1073 }
1074 else if (oldValue * m_value <= 0) // grey, go through mid point
1075 {
1076 // if challenger is ally, then n->a challenge
1077 if (Challenger == ALLIANCE)
1079 // if challenger is horde, then n->h challenge
1080 else if (Challenger == HORDE)
1083 }
1084 else // grey, did not go through mid point
1085 {
1086 // old phase and current are on the same side, so one team challenges the other
1092 }
1093
1094 if (G3D::fuzzyNe(m_value, oldValue))
1096
1097 if (m_OldState != m_State)
1098 {
1099 //TC_LOG_ERROR("bg.battlefield", "{}->{}", m_OldState, m_State);
1100 if (oldTeam != m_team)
1101 ChangeTeam(oldTeam);
1102 return true;
1103 }
1104
1105 return false;
1106}
1107
1109{
1110 for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
1111 for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) // send to all players present in the area
1112 if (Player* player = ObjectAccessor::FindPlayer(*itr))
1113 player->SendUpdateWorldState(field, value);
1114}
1115
1117{
1118 uint8 team;
1119 switch (m_State)
1120 {
1122 team = TEAM_ALLIANCE;
1123 break;
1125 team = TEAM_HORDE;
1126 break;
1127 default:
1128 return;
1129 }
1130
1131 // send to all players present in the area
1132 for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr)
1133 if (Player* player = ObjectAccessor::FindPlayer(*itr))
1134 player->KilledMonsterCredit(id, guid);
1135}
1136
1138{
1139 return m_activePlayers[player->GetTeamId()].find(player->GetGUID()) != m_activePlayers[player->GetTeamId()].end();
1140}
#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
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)
void AddCapturePoint(BfCapturePoint *cp)
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
BfCapturePoint * GetCapturePoint(uint32 entry) 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)
uint32 GetCapturePointEntry() const
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:653
void SetHomePosition(float x, float y, float z, float o)
Definition Creature.h:302
void Respawn(bool force=false)
void SetReactState(ReactStates st)
Definition Creature.h:128
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:82
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:2506
void SetBattlefieldGroup(Battlefield *bf)
Definition Group.cpp:2519
bool AddMember(Player *player)
Definition Group.cpp:386
ObjectGuid GetGUID() const
Definition Group.cpp:2427
bool IsMember(ObjectGuid guid) const
Definition Group.cpp:2459
bool RemoveMember(ObjectGuid guid, RemoveMethod const &method=GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker=ObjectGuid::Empty, char const *reason=nullptr)
Definition Group.cpp:518
bool Create(Player *leader)
Definition Group.cpp:151
Definition Map.h:302
bool AddToMap(T *)
Definition Map.cpp:630
ObjectGuid::LowType GenerateLowGuid()
Definition Map.h:607
GameObject * GetGameObject(ObjectGuid const &guid)
Definition Map.cpp:4425
Creature * GetCreature(ObjectGuid const &guid)
Definition Map.cpp:4392
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:8488
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6163
void SpawnCorpseBones(bool triggerSave=true)
Definition Player.cpp:4555
WorldSession * GetSession() const
Definition Player.h:1705
TeamId GetTeamId() const
Definition Player.h:1819
Battleground * GetBattleground() const
Definition Player.cpp:23024
Group * GetGroup()
Definition Player.h:2159
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options=0)
Definition Player.cpp:1539
void ToggleAFK()
Definition Player.cpp:1509
bool isAFK() const
Definition Player.h:953
void SetBattlegroundOrBattlefieldRaid(Group *group, int8 subgroup=-1)
Definition Player.cpp:23965
void ResurrectPlayer(float restore_percent, bool applySickness=false)
Definition Player.cpp:4374
void SetVisible(bool x)
Definition Unit.cpp:8453
bool IsAlive() const
Definition Unit.h:1247
bool IsInFlight() const
Definition Unit.h:1133
void CombatStop(bool includingCast=false, bool mutualPvP=true)
Definition Unit.cpp:5633
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:968
uint8 GetLevel() const
Definition Unit.h:903
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:969
uint32 GetMapId() const
Definition Position.h:193
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2833
void setActive(bool isActiveObject)
Definition Object.cpp:992
float GetDistance2d(WorldObject const *obj) const
Definition Object.cpp:1142
void SetFarVisible(bool on)
Definition Object.cpp:1015
uint32 GetAreaId() const
Definition Object.h:376
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