TrinityCore
Loading...
Searching...
No Matches
battleground_strand_of_the_ancients.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 "BattlegroundScript.h"
19#include "Battleground.h"
20#include "BattlegroundMgr.h"
21#include "BattlegroundScore.h"
22#include "Creature.h"
23#include "CreatureAI.h"
24#include "GameObject.h"
25#include "GameTime.h"
26#include "Map.h"
27#include "ObjectAccessor.h"
28#include "ObjectMgr.h"
29#include "Player.h"
30#include "ScriptMgr.h"
32#include "VehicleDefines.h"
33#include "WorldStateMgr.h"
34
44
56
84
91
105
135
170
178
179static constexpr uint32 BG_SA_Factions[2] =
180{
181 1732,
182 1735,
183};
184
186{
187 West,
188 East,
189 Central
190};
191
200
201enum class DefenseLine
202{
203 First,
204 Second,
205 Third,
206 Last
207};
208
217
227
233
239
246
257
262
268
279
281{
282 { 0.0f, 5.0f, 9.6f, 3.14f },
283 { -6.0f, -3.0f, 8.6f, 0.0f }
284};
285
287{
289 {
290 _timerEnabled = false;
292 _signaledRoundTwo = false;
294 _initSecondRound = false;
296 _totalTime = 0;
297 _endRoundTimer = 0;
298 _shipsStarted = false;
300
301 _roundScores = { };
302
303 for (BG_SA_RoundScore& roundScore : _roundScores)
304 {
305 roundScore.winner = TEAM_ALLIANCE;
306 roundScore.time = 0;
307 }
308
309 _boatGUIDs = { };
310 _staticBombGUIDs = { };
311 }
312
313 void OnInit() override
314 {
317 ResetObjs();
318 }
319
320 void OnUpdate(uint32 diff) override
321 {
324 {
325 if (_updateWaitTimer < diff)
326 {
328 {
329 _signaledRoundTwo = true;
330 _initSecondRound = false;
332 }
333 }
334 else
335 {
336 _updateWaitTimer -= diff;
337 return;
338 }
339 }
340 _totalTime += diff;
341
342 if (_status == BG_SA_WARMUP)
343 {
347 {
348 if (Creature* c = FindKanrethad())
350
351 _totalTime = 0;
352 ToggleTimer();
355 }
357 StartShips();
358 return;
359 }
360 else if (_status == BG_SA_SECOND_WARMUP)
361 {
362 if (_roundScores[0].time < BG_SA_ROUNDLENGTH)
364 else
366
368 if (_totalTime >= 60000)
369 {
370 if (Creature* c = FindKanrethad())
372
373 _totalTime = 0;
374 ToggleTimer();
377 // status was set to STATUS_WAIT_JOIN manually for Preparation, set it back now
379 for (const auto& [playerGuid, bp] : battleground->GetPlayers())
380 if (Player* p = ObjectAccessor::FindPlayer(playerGuid))
381 p->RemoveAurasDueToSpell(SPELL_PREPARATION);
382 }
383 if (_totalTime >= 30000)
384 {
386 {
389 }
390 }
391 StartShips();
392 return;
393 }
395 {
397 {
399 {
400 EndRound();
401 return;
402 }
403 }
404 else if (_status == BG_SA_ROUND_TWO)
405 {
407 {
412 if (_roundScores[0].time == _roundScores[1].time)
414 else if (_roundScores[0].time < _roundScores[1].time)
416 else
418 return;
419 }
420 }
421 }
422 }
423
424 void Reset()
425 {
426 _totalTime = 0;
427 _shipsStarted = false;
429 }
430
432 {
433 for (ObjectGuid const& bombGuid : _dynamicBombGUIDs)
434 if (GameObject* bomb = battlegroundMap->GetGameObject(bombGuid))
435 bomb->Delete();
436
437 _dynamicBombGUIDs.clear();
438
440
441 _totalTime = 0;
442 _shipsStarted = false;
443
446
449
452
455
459
461
462 for (ObjectGuid const& guid : _gateGUIDs)
463 if (GameObject* gate = battlegroundMap->GetGameObject(guid))
464 gate->SetDestructibleState(GO_DESTRUCTIBLE_INTACT, nullptr, true);
465
473
475
477 door->ResetDoorOrButton();
478
481 {
482 SendTransportInit(player);
483 });
484
486 }
487
489 {
490 if (_shipsStarted)
491 return;
492
493 for (ObjectGuid const& guid : _boatGUIDs[_attackers])
494 {
495 if (GameObject* boat = battlegroundMap->GetGameObject(guid))
496 {
497 boat->SetGoState(GO_STATE_TRANSPORT_STOPPED);
498
499 // make sure every player knows the transport exists & is moving
500 for (auto const& [playerGuid, _] : battleground->GetPlayers())
501 if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
502 boat->SendUpdateToPlayer(player);
503 }
504 }
505
506 _shipsStarted = true;
507 }
508
509 void OnPlayerJoined(Player* player, bool inBattleground) override
510 {
511 BattlegroundScript::OnPlayerJoined(player, inBattleground);
512 SendTransportInit(player);
513 if (!inBattleground)
515 }
516
517 void TeleportPlayers() const
518 {
519 for (auto const& [playerGuid, bp] : battleground->GetPlayers())
520 {
521 if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
522 {
523 // should remove spirit of redemption
524 if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
525 player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
526
527 if (!player->IsAlive())
528 {
529 player->ResurrectPlayer(1.0f);
530 player->SpawnCorpseBones();
531 }
532
533 player->ResetAllPowers();
534 player->CombatStopWithPets(true);
535
536 player->CastSpell(player, SPELL_PREPARATION, true);
537
539 }
540 }
541 }
542
543 // This function teleports player to entrance position, but it's not implemented correctly
544 // It is also used on round swap; which should be handled by the following spells: 52365, 52528, 53464, 53465 (Split Teleport (FACTION) (Boat X))
545 // This spell however cannot work with current system because of grid limitations.
546 // On battleground start, this function should work fine, except that it is called to late and we need a NearTeleport to solve this.
548 {
550 {
551 ObjectGuid const boatGUID = _boatGUIDs[_attackers][urand(0, 1)];
552
553 if (GameObject* boat = battlegroundMap->GetGameObject(boatGUID))
554 {
555 if (TransportBase* transport = boat->ToTransportBase())
556 {
557 transport->AddPassenger(player, spawnPositionOnTransport[_attackers]);
558 Position position = transport->GetPositionWithOffset(player->m_movementInfo.transport.pos);
559 player->Relocate(position);
560
561 if (player->IsInWorld())
562 player->NearTeleportTo(position);
563 }
564 }
565 }
566 else if (WorldSafeLocsEntry const* defenderSpawn = sObjectMgr->GetWorldSafeLoc(SPAWN_DEFENDERS))
567 {
568 if (player->IsInWorld())
569 player->TeleportTo(defenderSpawn->Loc);
570 else
571 player->WorldRelocate(defenderSpawn->Loc);
572 }
573 }
574
575 void ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker) override
576 {
577 BattlegroundScript::ProcessEvent(obj, eventId, invoker);
578
579 switch (eventId)
580 {
582 for (ObjectGuid const& bombGuid : _staticBombGUIDs[TEAM_ALLIANCE])
583 if (GameObject* bomb = battlegroundMap->GetGameObject(bombGuid))
584 bomb->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
585 break;
587 for (ObjectGuid const& bombGuid : _staticBombGUIDs[TEAM_HORDE])
588 if (GameObject* bomb = battlegroundMap->GetGameObject(bombGuid))
589 bomb->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
590 break;
591 default:
592 break;
593 }
594
595 if (GameObject* go = Object::ToGameObject(obj))
596 {
597 switch (go->GetGoType())
598 {
600 if (invoker)
601 if (eventId == EVENT_TITAN_RELIC_ACTIVATED)
602 TitanRelicActivated(invoker->ToPlayer());
603 break;
605 {
606 if (GateInfo const* gate = GetGate(obj->GetEntry()))
607 {
608 uint32 gateId = gate->GameObjectId;
609
610 // damaged
611 if (eventId == go->GetGOInfo()->destructibleBuilding.DamagedEvent)
612 {
614
615 if (Creature* c = obj->FindNearestCreature(NPC_WORLD_TRIGGER, 500.0f))
616 battleground->SendChatMessage(c, gate->DamagedText, invoker);
617
619
620 UpdateWorldState(gate->WorldState, gateState);
621 }
622 // destroyed
623 else if (eventId == go->GetGOInfo()->destructibleBuilding.DestroyedEvent)
624 {
626 if (Creature* c = obj->FindNearestCreature(NPC_WORLD_TRIGGER, 500.0f))
627 battleground->SendChatMessage(c, gate->DestroyedText, invoker);
628
630
631 // check if other gate from same line of defense is already destroyed for honor reward
632 bool rewardHonor = true;
633 switch (gateId)
634 {
637 rewardHonor = false;
638 break;
641 rewardHonor = false;
642 break;
645 rewardHonor = false;
646 break;
649 rewardHonor = false;
650 break;
651 default:
652 break;
653 }
654
655 if (invoker)
656 {
657 if (Unit* unit = invoker->ToUnit())
658 {
659 if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
660 {
662 if (rewardHonor)
664 }
665 }
666 }
667
668 if (rewardHonor)
669 MakeObjectsInteractable(gate->LineOfDefense);
670
671 UpdateWorldState(gate->WorldState, gateState);
673 }
674 }
675 break;
676 }
677 default:
678 break;
679 }
680 }
681 }
682
683 void OnUnitKilled(Creature* victim, Unit* killer) override
684 {
685 if (victim->GetEntry() == NPC_DEMOLISHER_SA)
686 {
687 if (Player* killerPlayer = killer->GetCharmerOrOwnerPlayerOrPlayerItself())
690 int32 currentDestroyedVehicles = WorldStateMgr::GetValue(worldStateId, battlegroundMap);
691 UpdateWorldState(worldStateId, currentDestroyedVehicles + 1);
692 }
693 }
694
718
719 void TitanRelicActivated(Player const* clicker)
720 {
721 if (!clicker)
722 return;
723
725 if (clickerTeamId == _attackers)
726 {
727 if (clickerTeamId == TEAM_ALLIANCE)
729 else
731
733 {
734 EndRound();
735 // Achievement Storm the Beach (1310)
736 for (auto itr = battleground->GetPlayers().begin(); itr != battleground->GetPlayers().end(); ++itr)
737 {
738 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
740 player->UpdateCriteria(CriteriaType::BeSpellTarget, 65246);
741 }
742
743 if (Creature* c = FindKanrethad())
745 }
746 else if (_status == BG_SA_ROUND_TWO)
747 {
748 _roundScores[1].winner = _attackers;
749 _roundScores[1].time = _totalTime;
750 ToggleTimer();
751 // Achievement Storm the Beach (1310)
752 for (auto itr = battleground->GetPlayers().begin(); itr != battleground->GetPlayers().end(); ++itr)
753 {
754 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
756 player->UpdateCriteria(CriteriaType::BeSpellTarget, 65246);
757 }
758
759 if (_roundScores[0].time == _roundScores[1].time)
761 else if (_roundScores[0].time < _roundScores[1].time)
763 else
765 }
766 }
767 }
768
774
775 void OnEnd(Team winner) override
776 {
778
779 // honor reward for winning
780 if (winner == ALLIANCE)
782 else if (winner == HORDE)
784
785 // complete map_end rewards (even if no team wins)
788 }
789
790 void SendTransportInit(Player* player) const
791 {
792 for (ObjectGuid const& boatGuid : _boatGUIDs[_attackers])
793 if (GameObject* boat = battlegroundMap->GetGameObject(boatGuid))
794 boat->SendUpdateToPlayer(player);
795 }
796
797 bool IsGateDestroyed(GateInfo const* gateInfo) const
798 {
799 if (!gateInfo)
800 return false;
801
804 }
805
806 void HandleCaptureGraveyardAction(GameObject const* graveyardBanner, Player const* player)
807 {
808 if (!graveyardBanner || !player)
809 return;
810
812 // Only attackers can capture graveyard by gameobject action
813 if (teamId != _attackers)
814 return;
815
816 switch (graveyardBanner->GetEntry())
817 {
821 break;
825 break;
829 break;
830 default:
831 break;
832 }
833 }
834
835 void MakeObjectsInteractable(DefenseLine defenseLine) const
836 {
837 auto makeInteractable = [&](ObjectGuid const& guid) -> void
838 {
839 if (GameObject* gameObject = battlegroundMap->GetGameObject(guid))
840 gameObject->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
841 };
842
843 switch (defenseLine)
844 {
846 makeInteractable(_graveyardWest);
847 makeInteractable(_graveyardEast);
848 break;
850 makeInteractable(_graveyardCentral);
851 break;
853 break;
855 // make titan orb interactable
857 door->UseDoorOrButton();
858
859 makeInteractable(_titanRelicGUID);
860 break;
861 default:
862 break;
863 }
864 }
865
870
894
895 void OnGameObjectCreate(GameObject* gameobject) override
896 {
898
900 _gateGUIDs.insert(gameobject->GetGUID());
901
902 switch (gameobject->GetEntry())
903 {
904 case BG_SA_BOAT_ONE_A:
905 _boatGUIDs[TEAM_ALLIANCE][0] = gameobject->GetGUID();
906 break;
907 case BG_SA_BOAT_TWO_A:
908 _boatGUIDs[TEAM_ALLIANCE][1] = gameobject->GetGUID();
909 break;
910 case BG_SA_BOAT_ONE_H:
911 _boatGUIDs[TEAM_HORDE][0] = gameobject->GetGUID();
912 break;
913 case BG_SA_BOAT_TWO_H:
914 _boatGUIDs[TEAM_HORDE][1] = gameobject->GetGUID();
915 break;
917 _staticBombGUIDs[TEAM_ALLIANCE].insert(gameobject->GetGUID());
920 break;
922 _staticBombGUIDs[TEAM_HORDE].insert(gameobject->GetGUID());
925 break;
928 _dynamicBombGUIDs.insert(gameobject->GetGUID());
929 break;
932 _graveyardEast = gameobject->GetGUID();
933 break;
936 _graveyardWest = gameobject->GetGUID();
937 break;
940 _graveyardCentral = gameobject->GetGUID();
941 break;
943 _collisionDoorGUID = gameobject->GetGUID();
944 break;
945 case GO_TITAN_RELIC_A:
946 case GO_TITAN_RELIC_H:
947 _titanRelicGUID = gameobject->GetGUID();
948 break;
949 default:
950 break;
951 }
952 }
953
954 void DoAction(uint32 actionId, WorldObject* source, WorldObject* target) override
955 {
956 BattlegroundScript::DoAction(actionId, source, target);
957
958 switch (actionId)
959 {
962 break;
963 default:
964 break;
965 }
966 }
967
968 void OnCreatureCreate(Creature* creature) override
969 {
971 switch (creature->GetEntry())
972 {
973 case NPC_DEMOLISHER:
975 break;
978 break;
979 case NPC_KANRETHAD:
980 _kanrethadGUID = creature->GetGUID();
981 break;
985 break;
986 default:
987 break;
988 }
989 }
990
991 uint32 GetData(uint32 dataId) const override
992 {
993 switch (dataId)
994 {
995 case DATA_ATTACKERS:
996 return _attackers;
997 case DATA_STATUS:
998 return _status;
999 default:
1000 return BattlegroundScript::GetData(dataId);
1001 }
1002 }
1003
1004 static GateInfo const* GetGate(uint32 entry)
1005 {
1006 for (GateInfo const& gate : Gates)
1007 if (gate.GameObjectId == entry)
1008 return &gate;
1009
1010 return nullptr;
1011 }
1012
1013private:
1016
1026 std::array<BG_SA_RoundScore, 2> _roundScores;
1037
1038 // [team][boat_idx]
1039 std::array<std::array<ObjectGuid, 2 /*BOAT_COUNT*/>, PVP_TEAMS_COUNT> _boatGUIDs;
1040 std::array<GuidUnorderedSet, PVP_TEAMS_COUNT> _staticBombGUIDs; // bombs ready to be picked up
1041 GuidUnorderedSet _dynamicBombGUIDs; // bombs thrown by players, ready to explode/disarm
1042
1050};
1051
@ SCORE_BONUS_HONOR
@ SPELL_PREPARATION
@ STATUS_WAIT_JOIN
@ STATUS_IN_PROGRESS
@ IN_MILLISECONDS
Definition Common.h:38
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
std::unordered_set< ObjectGuid > GuidUnorderedSet
Definition ObjectGuid.h:435
#define sObjectMgr
Definition ObjectMgr.h:1885
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
#define RegisterBattlegroundMapScript(script_name, mapId)
Definition ScriptMgr.h:1447
@ GAMEOBJECT_TYPE_GOOBER
@ GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
@ TEAM_ALLIANCE
@ TEAM_HORDE
@ GO_DESTRUCTIBLE_INTACT
uint8 constexpr PVP_TEAMS_COUNT
@ TEAM_OTHER
@ ALLIANCE
@ HORDE
@ GO_FLAG_NOT_SELECTABLE
@ CHAT_MSG_BG_SYSTEM_ALLIANCE
@ CHAT_MSG_BG_SYSTEM_HORDE
@ CHAT_MSG_BG_SYSTEM_NEUTRAL
@ GO_STATE_TRANSPORT_STOPPED
@ SPELL_AURA_MOD_SHAPESHIFT
@ SPELL_AURA_SPIRIT_OF_REDEMPTION
GateInfo const Gates[]
void AddSC_battleground_strand_of_the_ancients()
static constexpr Position spawnPositionOnTransport[]
static constexpr uint32 BG_SA_Factions[2]
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
bool IsInWorld() const
Definition BaseEntity.h:158
Battleground * battleground
void TriggerGameEvent(uint32 gameEventId, WorldObject *source=nullptr, WorldObject *target=nullptr) override
BattlegroundMap * battlegroundMap
virtual void OnEnd(Team winner)
virtual void OnUpdate(uint32 diff)
virtual void OnPlayerJoined(Player *player, bool inBattleground)
void UpdateWorldState(int32 worldStateId, int32 value, bool hidden=false) const
void PlaySoundToAll(uint32 SoundID)
void RewardHonorToTeam(uint32 Honor, Team team)
void RemoveAuraOnTeam(uint32 SpellID, Team team)
void SendChatMessage(Creature *source, uint8 textId, WorldObject *target=nullptr)
static TeamId GetTeamIndexByTeamId(Team team)
void SetStatus(BattlegroundStatus Status)
virtual void EndBattleground(Team winner)
void SendBroadcastText(uint32 id, ChatMsg msgType, WorldObject const *target=nullptr)
BattlegroundPlayerMap const & GetPlayers() const
bool UpdatePlayerScore(Player *player, uint32 type, uint32 value, bool doAddHonor=true, Optional< HonorGainSource > source={})
BattlegroundStatus GetStatus() const
Team GetPlayerTeam(ObjectGuid guid) const
uint32 GetBonusHonorFromKill(uint32 kills) const
void UpdatePvpStat(Player *player, uint32 pvpStatId, uint32 value)
void CastSpellOnTeam(uint32 SpellID, Team team)
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
CreatureAI * AI() const
Definition Creature.h:228
void RemoveFlag(GameObjectFlags flags)
Definition GameObject.h:278
GameobjectTypes GetGoType() const
Definition GameObject.h:282
void UpdateSpawnGroupConditions()
Definition Map.cpp:2506
void DoOnPlayers(T &&fn)
Definition Map.h:406
int32 GetWorldStateValue(int32 worldStateId) const
Definition Map.cpp:427
GameObject * GetGameObject(ObjectGuid const &guid)
Definition Map.cpp:3552
void UpdateAreaDependentAuras()
Definition Map.cpp:4078
Creature * GetCreature(ObjectGuid const &guid)
Definition Map.cpp:3542
Player * ToPlayer()
Definition Object.h:126
GameObject * ToGameObject()
Definition Object.h:131
uint32 GetEntry() const
Definition Object.h:89
Unit * ToUnit()
Definition Object.h:116
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={}, uint32 teleportSpellId=0)
Definition Player.cpp:1226
Definition Unit.h:635
void SetFaction(uint32 faction) override
Definition Unit.h:872
void NearTeleportTo(TeleportLocation const &target, bool casting=false)
Definition Unit.cpp:12958
constexpr void WorldRelocate(WorldLocation const &loc)
Definition Position.h:202
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition Object.cpp:1517
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition Object.cpp:1621
MovementInfo m_movementInfo
Definition Object.h:548
virtual void DoAction(uint32 actionId, WorldObject *source=nullptr, WorldObject *target=nullptr)
Definition ZoneScript.h:104
virtual uint32 GetData(uint32) const
Definition ZoneScript.h:99
virtual void OnCreatureCreate(Creature *)
Definition ZoneScript.h:76
virtual void ProcessEvent(WorldObject *obj, uint32 eventId, WorldObject *invoker)
Definition ZoneScript.h:103
virtual void OnGameObjectCreate(GameObject *)
Definition ZoneScript.h:79
time_t GetGameTime()
Definition GameTime.cpp:52
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API int32 GetValue(int32 worldStateId, Map const *map)
@ ACTION_SOTA_CAPTURE_GRAVEYARD
struct MovementInfo::TransportInfo transport
Position GetPositionWithOffset(Position const &offset) const
Definition Position.cpp:61
constexpr void Relocate(float x, float y)
Definition Position.h:74
std::array< GuidUnorderedSet, PVP_TEAMS_COUNT > _staticBombGUIDs
void OnUnitKilled(Creature *victim, Unit *killer) override
bool _shipsStarted
For know if boats has start moving or not yet.
BG_SA_Status _status
Statu of battle (Start or not, and what round)
void ProcessEvent(WorldObject *obj, uint32 eventId, WorldObject *invoker) override
void MakeObjectsInteractable(DefenseLine defenseLine) const
void OnPlayerJoined(Player *player, bool inBattleground) override
bool _timerEnabled
used for know we are in timer phase or not (used for worldstate update)
std::array< std::array< ObjectGuid, 2 >, PVP_TEAMS_COUNT > _boatGUIDs
bool _initSecondRound
for know if second round has been init
void CaptureGraveyard(StrandOfTheAncientsGraveyard graveyard, TeamId teamId)
void DoAction(uint32 actionId, WorldObject *source, WorldObject *target) override
uint32 _totalTime
Totale elapsed time of current round.
void HandleCaptureGraveyardAction(GameObject const *graveyardBanner, Player const *player)
void OnGameObjectCreate(GameObject *gameobject) override
bool _signaledRoundTwo
for know if warning about second round start has been sent
bool _signaledRoundTwoHalfMin
for know if warning about second round start has been sent
std::array< BG_SA_RoundScore, 2 > _roundScores
Score of each round.
uint32 _updateWaitTimer
5secs before starting the 1min countdown for second round
uint8 const defenders