diff options
Diffstat (limited to 'src')
5 files changed, 597 insertions, 975 deletions
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp index 7f15b69cbd9..d7857885a66 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp @@ -37,254 +37,146 @@ enum StrandOfTheAncientsPvpStats PVP_STAT_DEMOLISHERS_DESTROYED = 232 }; +enum StrandOfTheAncientsEvents +{ + EVENT_HORDE_ASSAULT_STARTED = 21702, + EVENT_ALLIANCE_ASSAULT_STARTED = 23748, + EVENT_TITAN_RELIC_ACTIVATED = 20572 +}; + +enum StrandOfTheAncientsCreatures +{ + NPC_KANRETHAD = 29, + NPC_DEMOLISHER = 28781, + NPC_ANTIPERSONNEL_CANNON = 27894, + NPC_RIGGER_SPARKLIGHT = 29260, + NPC_GORGRIL_RIGSPARK = 29262, + NPC_WORLD_TRIGGER = 22515, + NPC_DEMOLISHER_SA = 28781 +}; + +enum StrandOfTheAncientsSpawnPositions +{ + SPAWN_DEFENDERS = 1399 +}; + +enum StrandOfTheAncientsData +{ + DATA_ATTACKERS = 1, + DATA_STATUS = 2 +}; + +enum StrandOfTheAncientSpells +{ + SPELL_TELEPORT_DEFENDER = 52364, + SPELL_TELEPORT_ATTACKERS = 60178, + SPELL_END_OF_ROUND = 52459, + SPELL_REMOVE_SEAFORIUM = 59077, + SPELL_ALLIANCE_CONTROL_PHASE_SHIFT = 60027, + SPELL_HORDE_CONTROL_PHASE_SHIFT = 60028, + SPELL_CARRYING_SEAFORIUM_CHARGE = 52415 +}; + +Position const spawnPositionOnTransport[] = +{ + { 0.0f, 5.0f, 9.6f, 3.14f }, + { -6.0f, -3.0f, 8.6f, 0.0f } +}; + BattlegroundSA::BattlegroundSA(BattlegroundTemplate const* battlegroundTemplate) : Battleground(battlegroundTemplate) { StartMessageIds[BG_STARTING_EVENT_FOURTH] = 0; // handle by Kanrethad - BgObjects.resize(BG_SA_MAXOBJ); - BgCreatures.resize(AsUnderlyingType(BG_SA_MAXNPC) + AsUnderlyingType(BG_SA_MAX_GY)); + BgObjects.resize(0); + BgCreatures.resize(0); TimerEnabled = false; UpdateWaitTimer = 0; SignaledRoundTwo = false; SignaledRoundTwoHalfMin = false; InitSecondRound = false; - Attackers = TEAM_ALLIANCE; + Attackers = static_cast<TeamId>(urand(TEAM_ALLIANCE, TEAM_HORDE)); TotalTime = 0; EndRoundTimer = 0; ShipsStarted = false; Status = BG_SA_NOT_STARTED; - for (uint8 i = 0; i < MAX_GATES; ++i) - GateStatus[i] = BG_SA_HORDE_GATE_OK; - - for (uint8 i = 0; i < 2; i++) + for (BG_SA_RoundScore& roundScore : RoundScores) { - RoundScores[i].winner = TEAM_ALLIANCE; - RoundScores[i].time = 0; + roundScore.winner = TEAM_ALLIANCE; + roundScore.time = 0; } - //! This is here to prevent an uninitialised variable warning - //! The warning only occurs when SetUpBattleGround fails though. - //! In the future this function should be called BEFORE sending initial worldstates. - memset(&GraveyardStatus, 0, sizeof(GraveyardStatus)); + _boatGUIDs = { }; + _staticBombGUIDs = { }; } -BattlegroundSA::~BattlegroundSA() { } +BattlegroundSA::~BattlegroundSA() = default; void BattlegroundSA::Reset() { TotalTime = 0; - Attackers = ((urand(0, 1)) ? TEAM_ALLIANCE : TEAM_HORDE); - for (uint8 i = 0; i <= 5; i++) - GateStatus[i] = BG_SA_HORDE_GATE_OK; ShipsStarted = false; Status = BG_SA_WARMUP; } bool BattlegroundSA::SetupBattleground() { - return ResetObjs(); + return true; } bool BattlegroundSA::ResetObjs() { - for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if (Player* player = ObjectAccessor::FindPlayer(itr->first)) - SendTransportsRemove(player); - - uint32 atF = BG_SA_Factions[Attackers]; - uint32 defF = BG_SA_Factions[Attackers ? TEAM_ALLIANCE : TEAM_HORDE]; - - for (uint8 i = 0; i < BG_SA_MAXOBJ; i++) - DelObject(i); - - for (uint8 i = 0; i < BG_SA_MAXNPC; i++) - DelCreature(i); - - for (uint8 i = BG_SA_MAXNPC; i < AsUnderlyingType(BG_SA_MAXNPC) + AsUnderlyingType(BG_SA_MAX_GY); i++) - DelCreature(i); - - for (uint8 i = 0; i < MAX_GATES; ++i) - GateStatus[i] = Attackers == TEAM_HORDE ? BG_SA_ALLIANCE_GATE_OK : BG_SA_HORDE_GATE_OK; - - if (!AddCreature(BG_SA_NpcEntries[BG_SA_NPC_KANRETHAD], BG_SA_NPC_KANRETHAD, BG_SA_NpcSpawnlocs[BG_SA_NPC_KANRETHAD])) - { - TC_LOG_ERROR("bg.battleground", "SOTA: couldn't spawn Kanrethad, aborted. Entry: {}", BG_SA_NpcEntries[BG_SA_NPC_KANRETHAD]); - return false; - } - - for (uint8 i = 0; i <= BG_SA_PORTAL_DEFFENDER_RED; i++) - { - if (!AddObject(i, BG_SA_ObjEntries[i], BG_SA_ObjSpawnlocs[i], 0, 0, 0, 0, RESPAWN_ONE_DAY)) - { - TC_LOG_ERROR("bg.battleground", "SOTA: couldn't spawn BG_SA_PORTAL_DEFFENDER_RED, Entry: {}", BG_SA_ObjEntries[i]); - continue; - } - } - - for (uint8 i = BG_SA_BOAT_ONE; i <= BG_SA_BOAT_TWO; i++) - { - uint32 boatid = 0; - switch (i) - { - case BG_SA_BOAT_ONE: - boatid = Attackers ? BG_SA_BOAT_ONE_H : BG_SA_BOAT_ONE_A; - break; - case BG_SA_BOAT_TWO: - boatid = Attackers ? BG_SA_BOAT_TWO_H : BG_SA_BOAT_TWO_A; - break; - default: - break; - } - if (!AddObject(i, boatid, BG_SA_ObjSpawnlocs[i].GetPositionX(), - BG_SA_ObjSpawnlocs[i].GetPositionY(), - BG_SA_ObjSpawnlocs[i].GetPositionZ() + (Attackers ? -3.750f: 0), - BG_SA_ObjSpawnlocs[i].GetOrientation(), 0, 0, 0, 0, RESPAWN_ONE_DAY)) - { - TC_LOG_ERROR("bg.battleground", "SOTA: couldn't spawn one of the BG_SA_BOAT, Entry: {}", boatid); - continue; - } - } - - for (uint8 i = BG_SA_SIGIL_1; i <= BG_SA_LEFT_FLAGPOLE; i++) - { - if (!AddObject(i, BG_SA_ObjEntries[i], BG_SA_ObjSpawnlocs[i], 0, 0, 0, 0, RESPAWN_ONE_DAY)) - { - TC_LOG_ERROR("bg.battleground", "SOTA: couldn't spawn Sigil, Entry: {}", BG_SA_ObjEntries[i]); - continue; - } - } - - // MAD props for Kiper for discovering those values - 4 hours of his work. - GetBGObject(BG_SA_BOAT_ONE)->SetParentRotation(QuaternionData(0.f, 0.f, 1.0f, 0.0002f)); - GetBGObject(BG_SA_BOAT_TWO)->SetParentRotation(QuaternionData(0.f, 0.f, 1.0f, 0.00001f)); - SpawnBGObject(BG_SA_BOAT_ONE, RESPAWN_IMMEDIATELY); - SpawnBGObject(BG_SA_BOAT_TWO, RESPAWN_IMMEDIATELY); - - //Cannons and demolishers - NPCs are spawned - //By capturing GYs. - for (uint8 i = 0; i < BG_SA_DEMOLISHER_5; i++) - { - if (!AddCreature(BG_SA_NpcEntries[i], i, BG_SA_NpcSpawnlocs[i], Attackers == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE, 600)) - { - TC_LOG_ERROR("bg.battleground", "SOTA: couldn't spawn Cannon or demolisher, Entry: {}, Attackers: {}", BG_SA_NpcEntries[i], Attackers == TEAM_ALLIANCE ? "Horde(1)" : "Alliance(0)"); - continue; - } - } - - OverrideGunFaction(); - DemolisherStartState(true); + for (ObjectGuid const& bombGuid : _dynamicBombGUIDs) + if (GameObject* bomb = GetBgMap()->GetGameObject(bombGuid)) + bomb->Delete(); - for (uint8 i = 0; i <= BG_SA_PORTAL_DEFFENDER_RED; i++) - { - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - GetBGObject(i)->SetFaction(defF); - } + _dynamicBombGUIDs.clear(); - GetBGObject(BG_SA_TITAN_RELIC)->SetFaction(atF); - GetBGObject(BG_SA_TITAN_RELIC)->Refresh(); + TeamId const defenders = Attackers == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE; TotalTime = 0; ShipsStarted = false; - //Graveyards - for (uint8 i = 0; i < BG_SA_MAX_GY; i++) - { - WorldSafeLocsEntry const* sg = sObjectMgr->GetWorldSafeLoc(BG_SA_GYEntries[i]); + UpdateWorldState(BG_SA_ALLY_ATTACKS, Attackers == TEAM_ALLIANCE); + UpdateWorldState(BG_SA_HORDE_ATTACKS, Attackers == TEAM_HORDE); - if (!sg) - { - TC_LOG_ERROR("bg.battleground", "SOTA: Can't find GY entry {}", BG_SA_GYEntries[i]); - return false; - } + UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_ALL, Attackers == TEAM_ALLIANCE); + UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_ALL, Attackers == TEAM_ALLIANCE); - if (i == BG_SA_BEACH_GY) - { - GraveyardStatus[i] = Attackers; - AddSpiritGuide(i + BG_SA_MAXNPC, sg->Loc.GetPositionX(), sg->Loc.GetPositionY(), sg->Loc.GetPositionZ(), BG_SA_GYOrientation[i], Attackers); - } - else - { - GraveyardStatus[i] = ((Attackers == TEAM_HORDE)? TEAM_ALLIANCE : TEAM_HORDE); - if (!AddSpiritGuide(i + BG_SA_MAXNPC, sg->Loc.GetPositionX(), sg->Loc.GetPositionY(), sg->Loc.GetPositionZ(), BG_SA_GYOrientation[i], Attackers == TEAM_HORDE ? TEAM_ALLIANCE : TEAM_HORDE)) - TC_LOG_ERROR("bg.battleground", "SOTA: couldn't spawn GY: {}", i); - } - } - - //GY capture points - for (uint8 i = BG_SA_CENTRAL_FLAG; i <= BG_SA_LEFT_FLAG; i++) - { - if (!AddObject(i, (BG_SA_ObjEntries[i] - (Attackers == TEAM_ALLIANCE ? 1 : 0)), BG_SA_ObjSpawnlocs[i], 0, 0, 0, 0, RESPAWN_ONE_DAY)) - { - TC_LOG_ERROR("bg.battleground", "SOTA: couldn't spawn Central Flag Entry: {}", BG_SA_ObjEntries[i] - (Attackers == TEAM_ALLIANCE ? 1 : 0)); - continue; - } - GetBGObject(i)->SetFaction(atF); - } - - UpdateObjectInteractionFlags(); - - for (uint8 i = BG_SA_BOMB; i < BG_SA_MAXOBJ; i++) - { - if (!AddObject(i, BG_SA_ObjEntries[BG_SA_BOMB], BG_SA_ObjSpawnlocs[i], 0, 0, 0, 0, RESPAWN_ONE_DAY)) - { - TC_LOG_ERROR("bg.battleground", "SOTA: couldn't spawn SA Bomb Entry: {}", BG_SA_ObjEntries[BG_SA_BOMB] + i); - continue; - } - GetBGObject(i)->SetFaction(atF); - } + UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_HRD, Attackers == TEAM_HORDE); + UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_HRD, Attackers == TEAM_HORDE); - //Player may enter BEFORE we set up BG - lets update his worldstates anyway... - UpdateWorldState(BG_SA_RIGHT_GY_HORDE, GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_HORDE ? 1 : 0); - UpdateWorldState(BG_SA_LEFT_GY_HORDE, GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_HORDE ? 1 : 0); - UpdateWorldState(BG_SA_CENTER_GY_HORDE, GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_HORDE ? 1 : 0); + UpdateWorldState(BG_SA_HORDE_DEFENCE_TOKEN, defenders == TEAM_HORDE); + UpdateWorldState(BG_SA_ALLIANCE_DEFENCE_TOKEN, defenders == TEAM_ALLIANCE); - UpdateWorldState(BG_SA_RIGHT_GY_ALLIANCE, GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_ALLIANCE ? 1 : 0); - UpdateWorldState(BG_SA_LEFT_GY_ALLIANCE, GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_ALLIANCE ? 1 : 0); - UpdateWorldState(BG_SA_CENTER_GY_ALLIANCE, GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_ALLIANCE ? 1 : 0); + CaptureGraveyard(StrandOfTheAncientsGraveyard::Central, defenders); + CaptureGraveyard(StrandOfTheAncientsGraveyard::West, defenders); + CaptureGraveyard(StrandOfTheAncientsGraveyard::East, defenders); - if (Attackers == TEAM_ALLIANCE) - { - UpdateWorldState(BG_SA_ALLY_ATTACKS, 1); - UpdateWorldState(BG_SA_HORDE_ATTACKS, 0); + UpdateWorldState(BG_SA_ATTACKER_TEAM, Attackers); - UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_ALL, 1); - UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_ALL, 1); - UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_HRD, 0); - UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_HRD, 0); + for (ObjectGuid const& guid : _gateGUIDs) + if (GameObject* gate = GetBgMap()->GetGameObject(guid)) + gate->SetDestructibleState(GO_DESTRUCTIBLE_INTACT, nullptr, true); - UpdateWorldState(BG_SA_HORDE_DEFENCE_TOKEN, 1); - UpdateWorldState(BG_SA_ALLIANCE_DEFENCE_TOKEN, 0); - } - else - { - UpdateWorldState(BG_SA_HORDE_ATTACKS, 1); - UpdateWorldState(BG_SA_ALLY_ATTACKS, 0); + BG_SA_GateState const state = Attackers == TEAM_ALLIANCE ? BG_SA_HORDE_GATE_OK : BG_SA_ALLIANCE_GATE_OK; + UpdateWorldState(BG_SA_PURPLE_GATEWS, state); + UpdateWorldState(BG_SA_RED_GATEWS, state); + UpdateWorldState(BG_SA_BLUE_GATEWS, state); + UpdateWorldState(BG_SA_GREEN_GATEWS, state); + UpdateWorldState(BG_SA_YELLOW_GATEWS, state); + UpdateWorldState(BG_SA_ANCIENT_GATEWS, state); - UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_ALL, 0); - UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_ALL, 0); - UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_HRD, 1); - UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_HRD, 1); + GetBgMap()->UpdateSpawnGroupConditions(); - UpdateWorldState(BG_SA_HORDE_DEFENCE_TOKEN, 0); - UpdateWorldState(BG_SA_ALLIANCE_DEFENCE_TOKEN, 1); - } + if (GameObject* door = GetBgMap()->GetGameObject(_collisionDoorGUID)) + door->ResetDoorOrButton(); - UpdateWorldState(BG_SA_ATTACKER_TEAM, Attackers); - UpdateWorldState(BG_SA_PURPLE_GATEWS, 1); - UpdateWorldState(BG_SA_RED_GATEWS, 1); - UpdateWorldState(BG_SA_BLUE_GATEWS, 1); - UpdateWorldState(BG_SA_GREEN_GATEWS, 1); - UpdateWorldState(BG_SA_YELLOW_GATEWS, 1); - UpdateWorldState(BG_SA_ANCIENT_GATEWS, 1); - - for (int i = BG_SA_BOAT_ONE; i <= BG_SA_BOAT_TWO; i++) - for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if (Player* player = ObjectAccessor::FindPlayer(itr->first)) - SendTransportInit(player); - - // set status manually so preparation is cast correctly in 2nd round too SetStatus(STATUS_WAIT_JOIN); + GetBgMap()->DoOnPlayers([&](Player* player) + { + SendTransportInit(player); + }); TeleportPlayers(); return true; @@ -295,23 +187,27 @@ void BattlegroundSA::StartShips() if (ShipsStarted) return; - GetBGObject(BG_SA_BOAT_ONE)->SetGoState(GO_STATE_TRANSPORT_STOPPED); - GetBGObject(BG_SA_BOAT_TWO)->SetGoState(GO_STATE_TRANSPORT_STOPPED); - - for (int i = BG_SA_BOAT_ONE; i <= BG_SA_BOAT_TWO; i++) + for (ObjectGuid const& guid : _boatGUIDs[Attackers]) { - for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) + if (GameObject* boat = GetBgMap()->GetGameObject(guid)) { - if (Player* p = ObjectAccessor::FindPlayer(itr->first)) + boat->SetGoState(GO_STATE_TRANSPORT_STOPPED); + + // make sure every player knows the transport exists & is moving + for (auto const& [playerGuid, _] : GetPlayers()) { - UpdateData data(p->GetMapId()); - WorldPacket pkt; - GetBGObject(i)->BuildValuesUpdateBlockForPlayer(&data, p); - data.BuildPacket(&pkt); - p->SendDirectMessage(&pkt); + if (Player const* player = ObjectAccessor::FindPlayer(playerGuid)) + { + UpdateData data(player->GetMapId()); + WorldPacket pkt; + boat->BuildValuesUpdateBlockForPlayer(&data, player); + data.BuildPacket(&pkt); + player->SendDirectMessage(&pkt); + } } } } + ShipsStarted = true; } @@ -339,17 +235,16 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff) if (Status == BG_SA_WARMUP) { EndRoundTimer = BG_SA_ROUNDLENGTH; - UpdateWorldState(BG_SA_TIMER, GameTime::GetGameTime() + EndRoundTimer); + UpdateWorldState(BG_SA_TIMER, GameTime::GetGameTime() + (EndRoundTimer / 1000)); if (TotalTime >= BG_SA_WARMUPLENGTH) { - if (Creature* c = GetBGCreature(BG_SA_NPC_KANRETHAD)) + if (Creature* c = FindKanrethad()) SendChatMessage(c, TEXT_ROUND_STARTED); TotalTime = 0; ToggleTimer(); - DemolisherStartState(false); Status = BG_SA_ROUND_ONE; - TriggerGameEvent((Attackers == TEAM_ALLIANCE) ? 23748 : 21702); + TriggerGameEvent((Attackers == TEAM_ALLIANCE) ? EVENT_ALLIANCE_ASSAULT_STARTED : EVENT_HORDE_ASSAULT_STARTED); } if (TotalTime >= BG_SA_BOAT_START) StartShips(); @@ -362,21 +257,20 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff) else EndRoundTimer = BG_SA_ROUNDLENGTH; - UpdateWorldState(BG_SA_TIMER, GameTime::GetGameTime() + EndRoundTimer); + UpdateWorldState(BG_SA_TIMER, GameTime::GetGameTime() + (EndRoundTimer / 1000)); if (TotalTime >= 60000) { - if (Creature* c = GetBGCreature(BG_SA_NPC_KANRETHAD)) + if (Creature* c = FindKanrethad()) SendChatMessage(c, TEXT_ROUND_STARTED); TotalTime = 0; ToggleTimer(); - DemolisherStartState(false); Status = BG_SA_ROUND_TWO; - TriggerGameEvent((Attackers == TEAM_ALLIANCE) ? 23748 : 21702); + TriggerGameEvent((Attackers == TEAM_ALLIANCE) ? EVENT_ALLIANCE_ASSAULT_STARTED : EVENT_HORDE_ASSAULT_STARTED); // status was set to STATUS_WAIT_JOIN manually for Preparation, set it back now SetStatus(STATUS_IN_PROGRESS); - for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if (Player* p = ObjectAccessor::FindPlayer(itr->first)) + for (const auto& [playerGuid, bp] : GetPlayers()) + if (Player* p = ObjectAccessor::FindPlayer(playerGuid)) p->RemoveAurasDueToSpell(SPELL_PREPARATION); } if (TotalTime >= 30000) @@ -396,20 +290,7 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff) { if (TotalTime >= BG_SA_ROUNDLENGTH) { - CastSpellOnTeam(SPELL_END_OF_ROUND, ALLIANCE); - CastSpellOnTeam(SPELL_END_OF_ROUND, HORDE); - RoundScores[0].winner = Attackers; - RoundScores[0].time = BG_SA_ROUNDLENGTH; - TotalTime = 0; - Status = BG_SA_SECOND_WARMUP; - Attackers = (Attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE; - UpdateWaitTimer = 5000; - SignaledRoundTwo = false; - SignaledRoundTwoHalfMin = false; - InitSecondRound = true; - ToggleTimer(); - ResetObjs(); - GetBgMap()->UpdateAreaDependentAuras(); + EndRound(); return; } } @@ -430,8 +311,6 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff) return; } } - if (Status == BG_SA_ROUND_ONE || Status == BG_SA_ROUND_TWO) - UpdateDemolisherSpawns(); } } @@ -455,11 +334,11 @@ void BattlegroundSA::HandleAreaTrigger(Player* /*source*/, uint32 /*trigger*/, b return; } -void BattlegroundSA::TeleportPlayers() +void BattlegroundSA::TeleportPlayers() const { - for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) + for (auto const& [playerGuid, bp] : GetPlayers()) { - if (Player* player = ObjectAccessor::FindPlayer(itr->first)) + if (Player* player = ObjectAccessor::FindPlayer(playerGuid)) { // should remove spirit of redemption if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) @@ -481,83 +360,114 @@ void BattlegroundSA::TeleportPlayers() } } -void BattlegroundSA::TeleportToEntrancePosition(Player* player) +// This function teleports player to entrance position, but it's not implemented correctly +// It is also used on round swap; which should be handled by the following spells: 52365, 52528, 53464, 53465 (Split Teleport (FACTION) (Boat X)) +// This spell however cannot work with current system because of grid limitations. +// On battleground start, this function should work fine, except that it is called to late and we need a NearTeleport to solve this. +void BattlegroundSA::TeleportToEntrancePosition(Player* player) const { if (GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID())) == Attackers) { - if (!ShipsStarted) - { - // player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + ObjectGuid const boatGUID = _boatGUIDs[Attackers][urand(0, 1)]; - if (urand(0, 1)) - player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f); - else - player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f); + if (GameObject* boat = GetBgMap()->GetGameObject(boatGUID)) + { + if (TransportBase* transport = boat->ToTransportBase()) + { + player->Relocate(spawnPositionOnTransport[Attackers]); + transport->AddPassenger(player); + player->m_movementInfo.transport.pos.Relocate(spawnPositionOnTransport[Attackers]); + float x, y, z, o; + spawnPositionOnTransport[Attackers].GetPosition(x, y, z, o); + transport->CalculatePassengerPosition(x, y, z, &o); + player->Relocate(x, y, z, o); + + if (player->IsInWorld()) + player->NearTeleportTo({ x, y, z, o }); + } } + } + else if (WorldSafeLocsEntry const* defenderSpawn = sObjectMgr->GetWorldSafeLoc(SPAWN_DEFENDERS)) + { + if (player->IsInWorld()) + player->TeleportTo(defenderSpawn->Loc); else - player->TeleportTo(607, 1600.381f, -106.263f, 8.8745f, 3.78f); + player->WorldRelocate(defenderSpawn->Loc); } - else - player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f); } void BattlegroundSA::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker /*= nullptr*/) { + switch (eventId) + { + case EVENT_ALLIANCE_ASSAULT_STARTED: + for (ObjectGuid const& bombGuid : _staticBombGUIDs[TEAM_ALLIANCE]) + if (GameObject* bomb = GetBgMap()->GetGameObject(bombGuid)) + bomb->RemoveFlag(GO_FLAG_NOT_SELECTABLE); + break; + case EVENT_HORDE_ASSAULT_STARTED: + for (ObjectGuid const& bombGuid : _staticBombGUIDs[TEAM_HORDE]) + if (GameObject* bomb = GetBgMap()->GetGameObject(bombGuid)) + bomb->RemoveFlag(GO_FLAG_NOT_SELECTABLE); + break; + default: + break; + } + if (GameObject* go = Object::ToGameObject(obj)) { switch (go->GetGoType()) { case GAMEOBJECT_TYPE_GOOBER: if (invoker) - if (eventId == BG_SA_EVENT_TITAN_RELIC_ACTIVATED) + if (eventId == EVENT_TITAN_RELIC_ACTIVATED) TitanRelicActivated(invoker->ToPlayer()); break; case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING: { if (GateInfo const* gate = GetGate(obj->GetEntry())) { - uint8 gateId = gate->GateId; + uint32 gateId = gate->GameObjectId; // damaged if (eventId == go->GetGOInfo()->destructibleBuilding.DamagedEvent) { - GateStatus[gateId] = Attackers == TEAM_HORDE ? BG_SA_ALLIANCE_GATE_DAMAGED : BG_SA_HORDE_GATE_DAMAGED; + BG_SA_GateState gateState = Attackers == TEAM_HORDE ? BG_SA_ALLIANCE_GATE_DAMAGED : BG_SA_HORDE_GATE_DAMAGED; if (Creature* c = obj->FindNearestCreature(NPC_WORLD_TRIGGER, 500.0f)) SendChatMessage(c, gate->DamagedText, invoker); PlaySoundToAll(Attackers == TEAM_ALLIANCE ? SOUND_WALL_ATTACKED_ALLIANCE : SOUND_WALL_ATTACKED_HORDE); + + UpdateWorldState(gate->WorldState, gateState); } // destroyed else if (eventId == go->GetGOInfo()->destructibleBuilding.DestroyedEvent) { - GateStatus[gate->GateId] = Attackers == TEAM_HORDE ? BG_SA_ALLIANCE_GATE_DESTROYED : BG_SA_HORDE_GATE_DESTROYED; - - if (gateId < 5) - DelObject(gateId + 14); - + BG_SA_GateState gateState = Attackers == TEAM_HORDE ? BG_SA_ALLIANCE_GATE_DESTROYED : BG_SA_HORDE_GATE_DESTROYED; if (Creature* c = obj->FindNearestCreature(NPC_WORLD_TRIGGER, 500.0f)) SendChatMessage(c, gate->DestroyedText, invoker); PlaySoundToAll(Attackers == TEAM_ALLIANCE ? SOUND_WALL_DESTROYED_ALLIANCE : SOUND_WALL_DESTROYED_HORDE); + // check if other gate from same line of defense is already destroyed for honor reward bool rewardHonor = true; switch (gateId) { - case BG_SA_GREEN_GATE: - if (IsGateDestroyed(BG_SA_BLUE_GATE)) + case GO_GATE_OF_THE_GREEN_EMERALD: + if (IsGateDestroyed(GetGate(GO_GATE_OF_THE_BLUE_SAPPHIRE))) rewardHonor = false; break; - case BG_SA_BLUE_GATE: - if (IsGateDestroyed(BG_SA_GREEN_GATE)) + case GO_GATE_OF_THE_BLUE_SAPPHIRE: + if (IsGateDestroyed(GetGate(GO_GATE_OF_THE_GREEN_EMERALD))) rewardHonor = false; break; - case BG_SA_RED_GATE: - if (IsGateDestroyed(BG_SA_PURPLE_GATE)) + case GO_GATE_OF_THE_RED_SUN: + if (IsGateDestroyed(GetGate(GO_GATE_OF_THE_PURPLE_AMETHYST))) rewardHonor = false; break; - case BG_SA_PURPLE_GATE: - if (IsGateDestroyed(BG_SA_RED_GATE)) + case GO_GATE_OF_THE_PURPLE_AMETHYST: + if (IsGateDestroyed(GetGate(GO_GATE_OF_THE_RED_SUN))) rewardHonor = false; break; default: @@ -577,12 +487,12 @@ void BattlegroundSA::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* } } - UpdateObjectInteractionFlags(); - } - else - break; + if (rewardHonor) + MakeObjectsInteractable(gate->LineOfDefense); - UpdateWorldState(gate->WorldState, GateStatus[gateId]); + UpdateWorldState(gate->WorldState, gateState); + GetBgMap()->UpdateSpawnGroupConditions(); + } } break; } @@ -604,419 +514,337 @@ void BattlegroundSA::HandleKillUnit(Creature* creature, Unit* killer) } } -/* - You may ask what the fuck does it do? - Prevents owner overwriting guns faction with own. - */ -void BattlegroundSA::OverrideGunFaction() +void BattlegroundSA::DestroyGate(Player* /*player*/, GameObject* /*go*/) { - if (!BgCreatures[0]) - return; +} - for (uint8 i = BG_SA_GUN_1; i <= BG_SA_GUN_10; i++) +void BattlegroundSA::CaptureGraveyard(StrandOfTheAncientsGraveyard graveyard, TeamId teamId) +{ + switch (graveyard) { - if (Creature* gun = GetBGCreature(i)) - gun->SetFaction(BG_SA_Factions[Attackers ? TEAM_ALLIANCE : TEAM_HORDE]); - } + case StrandOfTheAncientsGraveyard::West: + UpdateWorldState(BG_SA_LEFT_GY_ALLIANCE, teamId == TEAM_ALLIANCE); + UpdateWorldState(BG_SA_LEFT_GY_HORDE, teamId == TEAM_HORDE); + break; + case StrandOfTheAncientsGraveyard::East: + UpdateWorldState(BG_SA_RIGHT_GY_ALLIANCE, teamId == TEAM_ALLIANCE); + UpdateWorldState(BG_SA_RIGHT_GY_HORDE, teamId == TEAM_HORDE); + break; + case StrandOfTheAncientsGraveyard::Central: + UpdateWorldState(BG_SA_CENTER_GY_ALLIANCE, teamId == TEAM_ALLIANCE); + UpdateWorldState(BG_SA_CENTER_GY_HORDE, teamId == TEAM_HORDE); - for (uint8 i = BG_SA_DEMOLISHER_1; i <= BG_SA_DEMOLISHER_4; i++) - { - if (Creature* dem = GetBGCreature(i)) - dem->SetFaction(BG_SA_Factions[Attackers]); + CaptureGraveyard(StrandOfTheAncientsGraveyard::East, teamId); + CaptureGraveyard(StrandOfTheAncientsGraveyard::West, teamId); + break; + default: + break; } } -void BattlegroundSA::DemolisherStartState(bool start) +void BattlegroundSA::TitanRelicActivated(Player* clicker) { - if (!BgCreatures[0]) + if (!clicker) return; - // set flags only for the demolishers on the beach, factory ones dont need it - for (uint8 i = BG_SA_DEMOLISHER_1; i <= BG_SA_DEMOLISHER_4; i++) + TeamId clickerTeamId = GetTeamIndexByTeamId(GetPlayerTeam(clicker->GetGUID())); + if (clickerTeamId == Attackers) { - if (Creature* dem = GetBGCreature(i)) + if (clickerTeamId == TEAM_ALLIANCE) + SendBroadcastText(BG_SA_TEXT_ALLIANCE_CAPTURED_TITAN_PORTAL, CHAT_MSG_BG_SYSTEM_ALLIANCE); + else + SendBroadcastText(BG_SA_TEXT_HORDE_CAPTURED_TITAN_PORTAL, CHAT_MSG_BG_SYSTEM_HORDE); + + if (Status == BG_SA_ROUND_ONE) { - if (start) + EndRound(); + // Achievement Storm the Beach (1310) + for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) { - dem->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - dem->SetUninteractible(true); + if (Player* player = ObjectAccessor::FindPlayer(itr->first)) + if (GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID())) == Attackers) + player->UpdateCriteria(CriteriaType::BeSpellTarget, 65246); } - else + + if (Creature* c = FindKanrethad()) + SendChatMessage(c, TEXT_ROUND_1_FINISHED); + } + else if (Status == BG_SA_ROUND_TWO) + { + RoundScores[1].winner = Attackers; + RoundScores[1].time = TotalTime; + ToggleTimer(); + // Achievement Storm the Beach (1310) + for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) { - dem->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - dem->SetUninteractible(false); + if (Player* player = ObjectAccessor::FindPlayer(itr->first)) + if (GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID())) == Attackers && RoundScores[1].winner == Attackers) + player->UpdateCriteria(CriteriaType::BeSpellTarget, 65246); } + + if (RoundScores[0].time == RoundScores[1].time) + EndBattleground(TEAM_OTHER); + else if (RoundScores[0].time < RoundScores[1].time) + EndBattleground(RoundScores[0].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); + else + EndBattleground(RoundScores[1].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); } } } -void BattlegroundSA::DestroyGate(Player* /*player*/, GameObject* /*go*/) +void BattlegroundSA::ToggleTimer() { + TimerEnabled = !TimerEnabled; + UpdateWorldState(BG_SA_ENABLE_TIMER, TimerEnabled); } -WorldSafeLocsEntry const* BattlegroundSA::GetClosestGraveyard(Player* player) +void BattlegroundSA::EndBattleground(Team winner) { - uint32 safeloc = 0; - WorldSafeLocsEntry const* ret; - WorldSafeLocsEntry const* closest; - float dist, nearest; - float x, y, z; - - player->GetPosition(x, y, z); - - TeamId teamId = GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID())); - if (teamId == Attackers) - safeloc = BG_SA_GYEntries[BG_SA_BEACH_GY]; - else - safeloc = BG_SA_GYEntries[BG_SA_DEFENDER_LAST_GY]; - - closest = sObjectMgr->GetWorldSafeLoc(safeloc); - nearest = player->GetExactDistSq(closest->Loc); - - for (uint8 i = BG_SA_RIGHT_CAPTURABLE_GY; i < BG_SA_MAX_GY; i++) - { - if (GraveyardStatus[i] != teamId) - continue; + // honor reward for winning + if (winner == ALLIANCE) + RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); + else if (winner == HORDE) + RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); - ret = sObjectMgr->GetWorldSafeLoc(BG_SA_GYEntries[i]); - dist = player->GetExactDistSq(ret->Loc); - if (dist < nearest) - { - closest = ret; - nearest = dist; - } - } + // complete map_end rewards (even if no team wins) + RewardHonorToTeam(GetBonusHonorFromKill(2), ALLIANCE); + RewardHonorToTeam(GetBonusHonorFromKill(2), HORDE); - return closest; + Battleground::EndBattleground(winner); } -bool BattlegroundSA::CanInteractWithObject(uint32 objectId) +void BattlegroundSA::SendTransportInit(Player* player) { - switch (objectId) - { - case BG_SA_TITAN_RELIC: - if (!IsGateDestroyed(BG_SA_ANCIENT_GATE) || !IsGateDestroyed(BG_SA_YELLOW_GATE)) - return false; - [[fallthrough]]; - case BG_SA_CENTRAL_FLAG: - if (!IsGateDestroyed(BG_SA_RED_GATE) && !IsGateDestroyed(BG_SA_PURPLE_GATE)) - return false; - [[fallthrough]]; - case BG_SA_LEFT_FLAG: - case BG_SA_RIGHT_FLAG: - if (!IsGateDestroyed(BG_SA_GREEN_GATE) && !IsGateDestroyed(BG_SA_BLUE_GATE)) - return false; - break; - default: - ABORT(); - break; - } - - return true; + UpdateData transData(player->GetMapId()); + for (ObjectGuid const& boatGuid : _boatGUIDs[Attackers]) + if (GameObject const* boat = GetBgMap()->GetGameObject(boatGuid)) + boat->BuildCreateUpdateBlockForPlayer(&transData, player); + + WorldPacket packet; + transData.BuildPacket(&packet); + player->SendDirectMessage(&packet); } -void BattlegroundSA::UpdateObjectInteractionFlags(uint32 objectId) +void BattlegroundSA::SendTransportsRemove(Player* player) { - if (GameObject* go = GetBGObject(objectId)) - { - if (CanInteractWithObject(objectId)) - go->RemoveFlag(GO_FLAG_NOT_SELECTABLE); - else - go->SetFlag(GO_FLAG_NOT_SELECTABLE); - } + UpdateData transData(player->GetMapId()); + for (ObjectGuid const& boatGuid : _boatGUIDs[Attackers]) + if (GameObject const* boat = GetBgMap()->GetGameObject(boatGuid)) + boat->BuildOutOfRangeUpdateBlock(&transData); + + WorldPacket packet; + transData.BuildPacket(&packet); + player->SendDirectMessage(&packet); } -void BattlegroundSA::UpdateObjectInteractionFlags() +bool BattlegroundSA::IsGateDestroyed(GateInfo const* gateInfo) const { - for (uint8 i = BG_SA_CENTRAL_FLAG; i <= BG_SA_LEFT_FLAG; ++i) - UpdateObjectInteractionFlags(i); - UpdateObjectInteractionFlags(BG_SA_TITAN_RELIC); + if (!gateInfo) + return false; + + int32 value = GetBgMap()->GetWorldStateValue(gateInfo->WorldState); + return value == BG_SA_ALLIANCE_GATE_DESTROYED || value == BG_SA_HORDE_GATE_DESTROYED; } -void BattlegroundSA::EventPlayerClickedOnFlag(Player* source, GameObject* go) +void BattlegroundSA::HandleCaptureGraveyardAction(GameObject* graveyardBanner, Player* player) { - switch (go->GetEntry()) + if (!graveyardBanner || !player) + return; + + TeamId const teamId = GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID())); + // Only attackers can capture graveyard by gameobject action + if (teamId != Attackers) + return; + + switch (graveyardBanner->GetEntry()) { - case 191307: - case 191308: - if (CanInteractWithObject(BG_SA_LEFT_FLAG)) - CaptureGraveyard(BG_SA_LEFT_CAPTURABLE_GY, source); + case GO_GRAVEYARD_WEST_A: + case GO_GRAVEYARD_WEST_H: + CaptureGraveyard(StrandOfTheAncientsGraveyard::West, teamId); break; - case 191305: - case 191306: - if (CanInteractWithObject(BG_SA_RIGHT_FLAG)) - CaptureGraveyard(BG_SA_RIGHT_CAPTURABLE_GY, source); + case GO_GRAVEYARD_EAST_A: + case GO_GRAVEYARD_EAST_H: + CaptureGraveyard(StrandOfTheAncientsGraveyard::East, teamId); break; - case 191310: - case 191309: - if (CanInteractWithObject(BG_SA_CENTRAL_FLAG)) - CaptureGraveyard(BG_SA_CENTRAL_CAPTURABLE_GY, source); + case GO_GRAVEYARD_CENTRAL_A: + case GO_GRAVEYARD_CENTRAL_H: + CaptureGraveyard(StrandOfTheAncientsGraveyard::Central, teamId); break; default: - return; - }; + break; + } } -void BattlegroundSA::CaptureGraveyard(BG_SA_Graveyards i, Player* Source) +void BattlegroundSA::MakeObjectsInteractable(DefenseLine defenseLine) { - if (GraveyardStatus[i] == Attackers) - return; - - DelCreature(AsUnderlyingType(BG_SA_MAXNPC) + i); - TeamId teamId = GetTeamIndexByTeamId(GetPlayerTeam(Source->GetGUID())); - GraveyardStatus[i] = teamId; - WorldSafeLocsEntry const* sg = sObjectMgr->GetWorldSafeLoc(BG_SA_GYEntries[i]); - if (!sg) + auto makeInteractable = [&](ObjectGuid const& guid) -> void { - TC_LOG_ERROR("bg.battleground", "BattlegroundSA::CaptureGraveyard: non-existant GY entry: {}", BG_SA_GYEntries[i]); - return; - } - - AddSpiritGuide(i + AsUnderlyingType(BG_SA_MAXNPC), sg->Loc.GetPositionX(), sg->Loc.GetPositionY(), sg->Loc.GetPositionZ(), BG_SA_GYOrientation[i], GraveyardStatus[i]); - uint32 npc = 0; - uint32 flag = 0; + if (GameObject* gameObject = GetBgMap()->GetGameObject(guid)) + gameObject->RemoveFlag(GO_FLAG_NOT_SELECTABLE); + }; - switch (i) + switch (defenseLine) { - case BG_SA_LEFT_CAPTURABLE_GY: - flag = BG_SA_LEFT_FLAG; - DelObject(flag); - AddObject(flag, (BG_SA_ObjEntries[flag] - (teamId == TEAM_ALLIANCE ? 0 : 1)), - BG_SA_ObjSpawnlocs[flag], 0, 0, 0, 0, RESPAWN_ONE_DAY); - - npc = BG_SA_NPC_RIGSPARK; - if (Creature* rigspark = AddCreature(BG_SA_NpcEntries[npc], npc, BG_SA_NpcSpawnlocs[npc], Attackers)) - rigspark->AI()->Talk(TEXT_SPARKLIGHT_RIGSPARK_SPAWN); - - for (uint8 j = BG_SA_DEMOLISHER_7; j <= BG_SA_DEMOLISHER_8; j++) - { - AddCreature(BG_SA_NpcEntries[j], j, BG_SA_NpcSpawnlocs[j], (Attackers == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE), 600); - - if (Creature* dem = GetBGCreature(j)) - dem->SetFaction(BG_SA_Factions[Attackers]); - } - - UpdateWorldState(BG_SA_LEFT_GY_ALLIANCE, GraveyardStatus[i] == TEAM_ALLIANCE); - UpdateWorldState(BG_SA_LEFT_GY_HORDE, GraveyardStatus[i] == TEAM_HORDE); - - if (Creature* c = Source->FindNearestCreature(NPC_WORLD_TRIGGER, 500.0f)) - SendChatMessage(c, teamId == TEAM_ALLIANCE ? TEXT_WEST_GRAVEYARD_CAPTURED_A : TEXT_WEST_GRAVEYARD_CAPTURED_H, Source); - + case DefenseLine::First: + makeInteractable(_graveyardWest); + makeInteractable(_graveyardEast); break; - case BG_SA_RIGHT_CAPTURABLE_GY: - flag = BG_SA_RIGHT_FLAG; - DelObject(flag); - AddObject(flag, (BG_SA_ObjEntries[flag] - (teamId == TEAM_ALLIANCE ? 0 : 1)), - BG_SA_ObjSpawnlocs[flag], 0, 0, 0, 0, RESPAWN_ONE_DAY); - - npc = BG_SA_NPC_SPARKLIGHT; - if (Creature* sparklight = AddCreature(BG_SA_NpcEntries[npc], npc, BG_SA_NpcSpawnlocs[npc], Attackers)) - sparklight->AI()->Talk(TEXT_SPARKLIGHT_RIGSPARK_SPAWN); - - for (uint8 j = BG_SA_DEMOLISHER_5; j <= BG_SA_DEMOLISHER_6; j++) - { - AddCreature(BG_SA_NpcEntries[j], j, BG_SA_NpcSpawnlocs[j], Attackers == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE, 600); - - if (Creature* dem = GetBGCreature(j)) - dem->SetFaction(BG_SA_Factions[Attackers]); - } - - UpdateWorldState(BG_SA_RIGHT_GY_ALLIANCE, GraveyardStatus[i] == TEAM_ALLIANCE); - UpdateWorldState(BG_SA_RIGHT_GY_HORDE, GraveyardStatus[i] == TEAM_HORDE); - - if (Creature* c = Source->FindNearestCreature(NPC_WORLD_TRIGGER, 500.0f)) - SendChatMessage(c, teamId == TEAM_ALLIANCE ? TEXT_EAST_GRAVEYARD_CAPTURED_A : TEXT_EAST_GRAVEYARD_CAPTURED_H, Source); - + case DefenseLine::Second: + makeInteractable(_graveyardCentral); break; - case BG_SA_CENTRAL_CAPTURABLE_GY: - flag = BG_SA_CENTRAL_FLAG; - DelObject(flag); - AddObject(flag, (BG_SA_ObjEntries[flag] - (teamId == TEAM_ALLIANCE ? 0 : 1)), - BG_SA_ObjSpawnlocs[flag], 0, 0, 0, 0, RESPAWN_ONE_DAY); - - UpdateWorldState(BG_SA_CENTER_GY_ALLIANCE, GraveyardStatus[i] == TEAM_ALLIANCE); - UpdateWorldState(BG_SA_CENTER_GY_HORDE, GraveyardStatus[i] == TEAM_HORDE); - - if (Creature* c = Source->FindNearestCreature(NPC_WORLD_TRIGGER, 500.0f)) - SendChatMessage(c, teamId == TEAM_ALLIANCE ? TEXT_SOUTH_GRAVEYARD_CAPTURED_A : TEXT_SOUTH_GRAVEYARD_CAPTURED_H, Source); + case DefenseLine::Third: + break; + case DefenseLine::Last: + // make titan orb interactable + if (GameObject* door = GetBgMap()->GetGameObject(_collisionDoorGUID)) + door->UseDoorOrButton(); + makeInteractable(_titanRelicGUID); break; default: - ABORT(); break; - }; + } } -void BattlegroundSA::TitanRelicActivated(Player* clicker) +Creature* BattlegroundSA::FindKanrethad() const { - if (!clicker) - return; - - if (CanInteractWithObject(BG_SA_TITAN_RELIC)) - { - TeamId clickerTeamId = GetTeamIndexByTeamId(GetPlayerTeam(clicker->GetGUID())); - if (clickerTeamId == Attackers) - { - if (clickerTeamId == TEAM_ALLIANCE) - SendBroadcastText(BG_SA_TEXT_ALLIANCE_CAPTURED_TITAN_PORTAL, CHAT_MSG_BG_SYSTEM_ALLIANCE); - else - SendBroadcastText(BG_SA_TEXT_HORDE_CAPTURED_TITAN_PORTAL, CHAT_MSG_BG_SYSTEM_HORDE); - - if (Status == BG_SA_ROUND_ONE) - { - RoundScores[0].winner = Attackers; - RoundScores[0].time = TotalTime; - // Achievement Storm the Beach (1310) - for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - { - if (Player* player = ObjectAccessor::FindPlayer(itr->first)) - if (GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID())) == Attackers) - player->UpdateCriteria(CriteriaType::BeSpellTarget, 65246); - } + return GetBgMap()->GetCreature(_kanrethadGUID); +} - Attackers = (Attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE; - Status = BG_SA_SECOND_WARMUP; - TotalTime = 0; - ToggleTimer(); +void BattlegroundSA::EndRound() +{ + RoundScores[0].winner = Attackers; + RoundScores[0].time = std::min<uint32>(TotalTime, BG_SA_ROUNDLENGTH); - if (Creature* c = GetBGCreature(BG_SA_NPC_KANRETHAD)) - SendChatMessage(c, TEXT_ROUND_1_FINISHED); + Attackers = (Attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE; + Status = BG_SA_SECOND_WARMUP; + TotalTime = 0; + ToggleTimer(); - UpdateWaitTimer = 5000; - SignaledRoundTwo = false; - SignaledRoundTwoHalfMin = false; - InitSecondRound = true; - ResetObjs(); - GetBgMap()->UpdateAreaDependentAuras(); - CastSpellOnTeam(SPELL_END_OF_ROUND, ALLIANCE); - CastSpellOnTeam(SPELL_END_OF_ROUND, HORDE); - } - else if (Status == BG_SA_ROUND_TWO) - { - RoundScores[1].winner = Attackers; - RoundScores[1].time = TotalTime; - ToggleTimer(); - // Achievement Storm the Beach (1310) - for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - { - if (Player* player = ObjectAccessor::FindPlayer(itr->first)) - if (GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID())) == Attackers && RoundScores[1].winner == Attackers) - player->UpdateCriteria(CriteriaType::BeSpellTarget, 65246); - } + UpdateWaitTimer = 5000; + SignaledRoundTwo = false; + SignaledRoundTwoHalfMin = false; + InitSecondRound = true; + ResetObjs(); + GetBgMap()->UpdateAreaDependentAuras(); - if (RoundScores[0].time == RoundScores[1].time) - EndBattleground(TEAM_OTHER); - else if (RoundScores[0].time < RoundScores[1].time) - EndBattleground(RoundScores[0].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); - else - EndBattleground(RoundScores[1].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); - } - } - } -} + CastSpellOnTeam(SPELL_END_OF_ROUND, ALLIANCE); + CastSpellOnTeam(SPELL_END_OF_ROUND, HORDE); -void BattlegroundSA::ToggleTimer() -{ - TimerEnabled = !TimerEnabled; - UpdateWorldState(BG_SA_ENABLE_TIMER, TimerEnabled); + RemoveAuraOnTeam(SPELL_CARRYING_SEAFORIUM_CHARGE, HORDE); + RemoveAuraOnTeam(SPELL_CARRYING_SEAFORIUM_CHARGE, ALLIANCE); } -void BattlegroundSA::EndBattleground(Team winner) +void BattlegroundSA::OnGameObjectCreate(GameObject* gameobject) { - // honor reward for winning - if (winner == ALLIANCE) - RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); - else if (winner == HORDE) - RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); + Battleground::OnGameObjectCreate(gameobject); - // complete map_end rewards (even if no team wins) - RewardHonorToTeam(GetBonusHonorFromKill(2), ALLIANCE); - RewardHonorToTeam(GetBonusHonorFromKill(2), HORDE); + if (gameobject->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) + _gateGUIDs.insert(gameobject->GetGUID()); - Battleground::EndBattleground(winner); -} - -void BattlegroundSA::UpdateDemolisherSpawns() -{ - for (uint8 i = BG_SA_DEMOLISHER_1; i <= BG_SA_DEMOLISHER_8; i++) + switch (gameobject->GetEntry()) { - if (!BgCreatures[i].IsEmpty()) - { - if (Creature* Demolisher = GetBGCreature(i)) - { - if (Demolisher->isDead()) - { - // Demolisher is not in list - if (DemoliserRespawnList.find(i) == DemoliserRespawnList.end()) - { - DemoliserRespawnList[i] = GameTime::GetGameTimeMS() +30000; - } - else - { - if (DemoliserRespawnList[i] < GameTime::GetGameTimeMS()) - { - Demolisher->Relocate(BG_SA_NpcSpawnlocs[i]); - Demolisher->Respawn(); - DemoliserRespawnList.erase(i); - } - } - } - } - } + case BG_SA_BOAT_ONE_A: + _boatGUIDs[TEAM_ALLIANCE][0] = gameobject->GetGUID(); + break; + case BG_SA_BOAT_TWO_A: + _boatGUIDs[TEAM_ALLIANCE][1] = gameobject->GetGUID(); + break; + case BG_SA_BOAT_ONE_H: + _boatGUIDs[TEAM_HORDE][0] = gameobject->GetGUID(); + break; + case BG_SA_BOAT_TWO_H: + _boatGUIDs[TEAM_HORDE][1] = gameobject->GetGUID(); + break; + case GO_SEAFORIUM_BOMB_A: + _staticBombGUIDs[TEAM_ALLIANCE].insert(gameobject->GetGUID()); + if (Status != BG_SA_SECOND_WARMUP && Status != BG_SA_WARMUP) + gameobject->RemoveFlag(GO_FLAG_NOT_SELECTABLE); + break; + case GO_SEAFORIUM_BOMB_H: + _staticBombGUIDs[TEAM_HORDE].insert(gameobject->GetGUID()); + if (Status != BG_SA_SECOND_WARMUP && Status != BG_SA_WARMUP) + gameobject->RemoveFlag(GO_FLAG_NOT_SELECTABLE); + break; + case GO_SEAFORIUM_CHARGE_A: + case GO_SEAFORIUM_CHARGE_H: + _dynamicBombGUIDs.insert(gameobject->GetGUID()); + break; + case GO_GRAVEYARD_EAST_A: + case GO_GRAVEYARD_EAST_H: + _graveyardEast = gameobject->GetGUID(); + break; + case GO_GRAVEYARD_WEST_A: + case GO_GRAVEYARD_WEST_H: + _graveyardWest = gameobject->GetGUID(); + break; + case GO_GRAVEYARD_CENTRAL_A: + case GO_GRAVEYARD_CENTRAL_H: + _graveyardCentral = gameobject->GetGUID(); + break; + case GO_COLLISION_DOOR: + _collisionDoorGUID = gameobject->GetGUID(); + break; + case GO_TITAN_RELIC_A: + case GO_TITAN_RELIC_H: + _titanRelicGUID = gameobject->GetGUID(); + break; + default: + break; } } -void BattlegroundSA::SendTransportInit(Player* player) +void BattlegroundSA::DoAction(uint32 actionId, WorldObject* source, WorldObject* target) { - if (!BgObjects[BG_SA_BOAT_ONE].IsEmpty() || !BgObjects[BG_SA_BOAT_TWO].IsEmpty()) + switch (actionId) { - UpdateData transData(player->GetMapId()); - if (!BgObjects[BG_SA_BOAT_ONE].IsEmpty()) - GetBGObject(BG_SA_BOAT_ONE)->BuildCreateUpdateBlockForPlayer(&transData, player); - - if (!BgObjects[BG_SA_BOAT_TWO].IsEmpty()) - GetBGObject(BG_SA_BOAT_TWO)->BuildCreateUpdateBlockForPlayer(&transData, player); - - WorldPacket packet; - transData.BuildPacket(&packet); - player->SendDirectMessage(&packet); + case ACTION_SOTA_CAPTURE_GRAVEYARD: + HandleCaptureGraveyardAction(Object::ToGameObject(target), Object::ToPlayer(source)); + break; + default: + break; } } -void BattlegroundSA::SendTransportsRemove(Player* player) +void BattlegroundSA::OnCreatureCreate(Creature* creature) { - if (!BgObjects[BG_SA_BOAT_ONE].IsEmpty() || !BgObjects[BG_SA_BOAT_TWO].IsEmpty()) + Battleground::OnCreatureCreate(creature); + + switch (creature->GetEntry()) { - UpdateData transData(player->GetMapId()); - if (!BgObjects[BG_SA_BOAT_ONE].IsEmpty()) - GetBGObject(BG_SA_BOAT_ONE)->BuildOutOfRangeUpdateBlock(&transData); - if (!BgObjects[BG_SA_BOAT_TWO].IsEmpty()) - GetBGObject(BG_SA_BOAT_TWO)->BuildOutOfRangeUpdateBlock(&transData); - WorldPacket packet; - transData.BuildPacket(&packet); - player->SendDirectMessage(&packet); + case NPC_DEMOLISHER: + creature->SetFaction(BG_SA_Factions[Attackers]); + break; + case NPC_ANTIPERSONNEL_CANNON: + creature->SetFaction(BG_SA_Factions[Attackers == TEAM_HORDE ? TEAM_ALLIANCE : TEAM_HORDE]); + break; + case NPC_KANRETHAD: + _kanrethadGUID = creature->GetGUID(); + break; + case NPC_RIGGER_SPARKLIGHT: + case NPC_GORGRIL_RIGSPARK: + creature->AI()->Talk(TEXT_SPARKLIGHT_RIGSPARK_SPAWN); + break; + default: + break; } } -bool BattlegroundSA::IsGateDestroyed(BG_SA_Objects gateId) const +void BattlegroundSA::OnMapSet(BattlegroundMap* map) { - ASSERT(gateId < MAX_GATES); - return GateStatus[gateId] == BG_SA_ALLIANCE_GATE_DESTROYED || GateStatus[gateId] == BG_SA_HORDE_GATE_DESTROYED; + Battleground::OnMapSet(map); + ResetObjs(); } -bool BattlegroundSA::IsSpellAllowed(uint32 spellId, Player const* /*player*/) const +uint32 BattlegroundSA::GetData(uint32 dataId) const { - switch (spellId) + switch (dataId) { - case SPELL_ALLIANCE_CONTROL_PHASE_SHIFT: - return Attackers == TEAM_HORDE; - case SPELL_HORDE_CONTROL_PHASE_SHIFT: - return Attackers == TEAM_ALLIANCE; - case SPELL_PREPARATION: - return Status == BG_SA_WARMUP || Status == BG_SA_SECOND_WARMUP; + case DATA_ATTACKERS: + return Attackers; + case DATA_STATUS: + return Status; default: - break; + return Battleground::GetData(dataId); } - - return true; } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h index 097df5a4e22..a6160aa5041 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h @@ -21,9 +21,6 @@ #include "Battleground.h" #include "Object.h" -#define BG_SA_FLAG_AMOUNT 3 -#define BG_SA_DEMOLISHER_AMOUNT 4 - enum BG_SA_Status { BG_SA_NOT_STARTED = 0, @@ -46,60 +43,32 @@ enum BG_SA_GateState BG_SA_HORDE_GATE_DESTROYED = 6, }; -enum BG_SA_EventIds +enum StrandOfTheAncientsGameObjects { - BG_SA_EVENT_BLUE_GATE_DAMAGED = 19040, - BG_SA_EVENT_BLUE_GATE_DESTROYED = 19045, - - BG_SA_EVENT_GREEN_GATE_DAMAGED = 19041, - BG_SA_EVENT_GREEN_GATE_DESTROYED = 19046, - - BG_SA_EVENT_RED_GATE_DAMAGED = 19042, - BG_SA_EVENT_RED_GATE_DESTROYED = 19047, - - BG_SA_EVENT_PURPLE_GATE_DAMAGED = 19043, - BG_SA_EVENT_PURPLE_GATE_DESTROYED = 19048, + GO_SEAFORIUM_BOMB_H = 194086, // Used by horde players + GO_SEAFORIUM_BOMB_A = 190753, // Used by alliance players + GO_SEAFORIUM_CHARGE_H = 257572, + GO_SEAFORIUM_CHARGE_A = 257565, - BG_SA_EVENT_YELLOW_GATE_DAMAGED = 19044, - BG_SA_EVENT_YELLOW_GATE_DESTROYED = 19049, + GO_GRAVEYARD_WEST_H = 191307, + GO_GRAVEYARD_WEST_A = 191308, - BG_SA_EVENT_ANCIENT_GATE_DAMAGED = 19836, - BG_SA_EVENT_ANCIENT_GATE_DESTROYED = 19837, + GO_GRAVEYARD_EAST_H = 191305, + GO_GRAVEYARD_EAST_A = 191306, - BG_SA_EVENT_TITAN_RELIC_ACTIVATED = 22097 -}; + GO_GRAVEYARD_CENTRAL_H = 191309, + GO_GRAVEYARD_CENTRAL_A = 191310, -enum SASpellIds -{ - SPELL_TELEPORT_DEFENDER = 52364, - SPELL_TELEPORT_ATTACKERS = 60178, - SPELL_END_OF_ROUND = 52459, - SPELL_REMOVE_SEAFORIUM = 59077, - SPELL_ALLIANCE_CONTROL_PHASE_SHIFT = 60027, - SPELL_HORDE_CONTROL_PHASE_SHIFT = 60028 -}; + GO_COLLISION_DOOR = 194162, + GO_TITAN_RELIC_A = 194083, + GO_TITAN_RELIC_H = 194082, -enum SACreatureIds -{ - NPC_KANRETHAD = 29, - NPC_INVISIBLE_STALKER = 15214, - NPC_WORLD_TRIGGER = 22515, - NPC_WORLD_TRIGGER_LARGE_AOI_NOT_IMMUNE_PC_NPC = 23472, - - NPC_ANTI_PERSONNAL_CANNON = 27894, - NPC_DEMOLISHER_SA = 28781, - NPC_RIGGER_SPARKLIGHT = 29260, - NPC_GORGRIL_RIGSPARK = 29262 -}; - -enum SAGameObjectIds -{ GO_GATE_OF_THE_GREEN_EMERALD = 190722, GO_GATE_OF_THE_PURPLE_AMETHYST = 190723, GO_GATE_OF_THE_BLUE_SAPPHIRE = 190724, GO_GATE_OF_THE_RED_SUN = 190726, GO_GATE_OF_THE_YELLOW_MOON = 190727, - GO_CHAMBER_OF_ANCIENT_RELICS = 192549, + GO_CHAMBER_OF_ANCIENT_RELICS = 192549 }; enum BG_SA_Timers @@ -164,326 +133,49 @@ enum SAWorldStates BG_SA_GREEN_GATEWS = 3623, BG_SA_YELLOW_GATEWS = 3638, BG_SA_ANCIENT_GATEWS = 3849, + BG_SA_LEFT_GY_ALLIANCE = 3635, BG_SA_RIGHT_GY_ALLIANCE = 3636, BG_SA_CENTER_GY_ALLIANCE = 3637, + BG_SA_RIGHT_ATT_TOKEN_ALL = 3627, BG_SA_LEFT_ATT_TOKEN_ALL = 3626, BG_SA_LEFT_ATT_TOKEN_HRD = 3629, BG_SA_RIGHT_ATT_TOKEN_HRD = 3628, BG_SA_HORDE_DEFENCE_TOKEN = 3631, BG_SA_ALLIANCE_DEFENCE_TOKEN = 3630, + BG_SA_RIGHT_GY_HORDE = 3632, BG_SA_LEFT_GY_HORDE = 3633, BG_SA_CENTER_GY_HORDE = 3634, + BG_SA_BONUS_TIMER = 3571, + BG_SA_ENABLE_TIMER = 3564, BG_SA_ATTACKER_TEAM = 3690, BG_SA_DESTROYED_ALLIANCE_VEHICLES = 3955, BG_SA_DESTROYED_HORDE_VEHICLES = 3956, }; -enum BG_SA_NPCs -{ - BG_SA_GUN_1 = 0, - BG_SA_GUN_2, - BG_SA_GUN_3, - BG_SA_GUN_4, - BG_SA_GUN_5, - BG_SA_GUN_6, - BG_SA_GUN_7, - BG_SA_GUN_8, - BG_SA_GUN_9, - BG_SA_GUN_10, - BG_SA_DEMOLISHER_1, - BG_SA_DEMOLISHER_2, - BG_SA_DEMOLISHER_3, - BG_SA_DEMOLISHER_4, - BG_SA_DEMOLISHER_5, - BG_SA_DEMOLISHER_6, - BG_SA_DEMOLISHER_7, - BG_SA_DEMOLISHER_8, - BG_SA_NPC_SPARKLIGHT, - BG_SA_NPC_RIGSPARK, - BG_SA_NPC_KANRETHAD, - BG_SA_MAXNPC -}; - enum BG_SA_Boat { - BG_SA_BOAT_ONE_A = 193182, - BG_SA_BOAT_TWO_H = 193183, + BG_SA_BOAT_ONE_A = 208000, + BG_SA_BOAT_TWO_H = 208001, BG_SA_BOAT_ONE_H = 193184, BG_SA_BOAT_TWO_A = 193185 }; -uint32 const BG_SA_NpcEntries[BG_SA_MAXNPC] = -{ - NPC_ANTI_PERSONNAL_CANNON, - NPC_ANTI_PERSONNAL_CANNON, - NPC_ANTI_PERSONNAL_CANNON, - NPC_ANTI_PERSONNAL_CANNON, - NPC_ANTI_PERSONNAL_CANNON, - NPC_ANTI_PERSONNAL_CANNON, - NPC_ANTI_PERSONNAL_CANNON, - NPC_ANTI_PERSONNAL_CANNON, - NPC_ANTI_PERSONNAL_CANNON, - NPC_ANTI_PERSONNAL_CANNON, - // 4 beach demolishers - NPC_DEMOLISHER_SA, - NPC_DEMOLISHER_SA, - NPC_DEMOLISHER_SA, - NPC_DEMOLISHER_SA, - // 4 factory demolishers - NPC_DEMOLISHER_SA, - NPC_DEMOLISHER_SA, - NPC_DEMOLISHER_SA, - NPC_DEMOLISHER_SA, - // Used Demolisher Salesman - NPC_RIGGER_SPARKLIGHT, - NPC_GORGRIL_RIGSPARK, - // Kanrethad - NPC_KANRETHAD -}; - -Position const BG_SA_NpcSpawnlocs[BG_SA_MAXNPC] = -{ - // Cannons - { 1436.429f, 110.05f, 41.407f, 5.4f }, - { 1404.9023f, 84.758f, 41.183f, 5.46f }, - { 1068.693f, -86.951f, 93.81f, 0.02f }, - { 1068.83f, -127.56f, 96.45f, 0.0912f }, - { 1422.115f, -196.433f, 42.1825f, 1.0222f }, - { 1454.887f, -220.454f, 41.956f, 0.9627f }, - { 1232.345f, -187.517f, 66.945f, 0.45f }, - { 1249.634f, -224.189f, 66.72f, 0.635f }, - { 1236.213f, 92.287f, 64.965f, 5.751f }, - { 1215.11f, 57.772f, 64.739f, 5.78f }, - // Demolishers - { 1611.597656f, -117.270073f, 8.719355f, 2.513274f}, - { 1575.562500f, -158.421875f, 5.024450f, 2.129302f}, - { 1618.047729f, 61.424641f, 7.248210f, 3.979351f}, - { 1575.103149f, 98.873344f, 2.830360f, 3.752458f}, - // Demolishers 2 - { 1371.055786f, -317.071136f, 35.007359f, 1.947460f}, - { 1424.034912f, -260.195190f, 31.084425f, 2.820013f}, - { 1353.139893f, 223.745438f, 35.265411f, 4.343684f}, - { 1404.809570f, 197.027237f, 32.046032f, 3.605401f}, - // Npcs - { 1348.644165f, -298.786469f, 31.080130f, 1.710423f}, - { 1358.191040f, 195.527786f, 31.018187f, 4.171337f}, - { 841.921f, -134.194f, 196.838f, 6.23082f } -}; - -enum BG_SA_Objects -{ - BG_SA_GREEN_GATE = 0, - BG_SA_YELLOW_GATE, - BG_SA_BLUE_GATE, - BG_SA_RED_GATE, - BG_SA_PURPLE_GATE, - BG_SA_ANCIENT_GATE, - BG_SA_TITAN_RELIC, - BG_SA_PORTAL_DEFFENDER_BLUE, - BG_SA_PORTAL_DEFFENDER_GREEN, - BG_SA_PORTAL_DEFFENDER_YELLOW, - BG_SA_PORTAL_DEFFENDER_PURPLE, - BG_SA_PORTAL_DEFFENDER_RED, - BG_SA_BOAT_ONE, - BG_SA_BOAT_TWO, - BG_SA_SIGIL_1, - BG_SA_SIGIL_2, - BG_SA_SIGIL_3, - BG_SA_SIGIL_4, - BG_SA_SIGIL_5, - BG_SA_CENTRAL_FLAGPOLE, - BG_SA_RIGHT_FLAGPOLE, - BG_SA_LEFT_FLAGPOLE, - BG_SA_CENTRAL_FLAG, - BG_SA_RIGHT_FLAG, - BG_SA_LEFT_FLAG, - BG_SA_BOMB, - BG_SA_MAXOBJ = BG_SA_BOMB+68 -}; - -Position const BG_SA_ObjSpawnlocs[BG_SA_MAXOBJ] = -{ - { 1411.57f, 108.163f, 28.692f, 5.441f }, - { 1055.452f, -108.1f, 82.134f, 0.034f }, - { 1431.3413f, -219.437f, 30.893f, 0.9736f }, - { 1227.667f, -212.555f, 55.372f, 0.5023f }, - { 1214.681f, 81.21f, 53.413f, 5.745f }, - { 878.555f, -108.2f, 117.845f, 0.0f }, - { 836.5f, -108.8f, 120.219f, 0.0f }, - // Portal - {1468.380005f, -225.798996f, 30.896200f, 0.0f}, //blue - {1394.270020f, 72.551399f, 31.054300f, 0.0f}, //green - {1065.260010f, -89.79501f, 81.073402f, 0.0f}, //yellow - {1216.069946f, 47.904301f, 54.278198f, 0.0f}, //purple - {1255.569946f, -233.548996f, 56.43699f, 0.0f}, //red - // Ships - { 2679.696777f, -826.891235f, 3.712860f, 5.78367f}, //rot2 1 rot3 0.0002f - { 2574.003662f, 981.261475f, 2.603424f, 0.807696f}, - // Sigils - { 1414.054f, 106.72f, 41.442f, 5.441f }, - { 1060.63f, -107.8f, 94.7f, 0.034f }, - { 1433.383f, -216.4f, 43.642f, 0.9736f }, - { 1230.75f, -210.724f, 67.611f, 0.5023f }, - { 1217.8f, 79.532f, 66.58f, 5.745f }, - // Flagpoles - { 1215.114258f, -65.711861f, 70.084267f, -3.124123f}, - {1338.863892f, -153.336533f, 30.895121f, -2.530723f}, - {1309.124268f, 9.410645f, 30.893402f, -1.623156f}, - // Flags - { 1215.108032f, -65.715767f, 70.084267f, -3.124123f}, - { 1338.859253f, -153.327316f, 30.895077f, -2.530723f}, - { 1309.192017f, 9.416233f, 30.893402f, 1.518436f}, - // Bombs - {1333.45f, 211.354f, 31.0538f, 5.03666f}, - {1334.29f, 209.582f, 31.0532f, 1.28088f}, - {1332.72f, 210.049f, 31.0532f, 1.28088f}, - {1334.28f, 210.78f, 31.0538f, 3.85856f}, - {1332.64f, 211.39f, 31.0532f, 1.29266f}, - {1371.41f, 194.028f, 31.5107f, 0.753095f}, - {1372.39f, 194.951f, 31.4679f, 0.753095f}, - {1371.58f, 196.942f, 30.9349f, 1.01777f}, - {1370.43f, 196.614f, 30.9349f, 0.957299f}, - {1369.46f, 196.877f, 30.9351f, 2.45348f}, - {1370.35f, 197.361f, 30.9349f, 1.08689f}, - {1369.47f, 197.941f, 30.9349f, 0.984787f}, - {1592.49f, 47.5969f, 7.52271f, 4.63218f}, - {1593.91f, 47.8036f, 7.65856f, 4.63218f}, - {1593.13f, 46.8106f, 7.54073f, 4.63218f}, - {1589.22f, 36.3616f, 7.45975f, 4.64396f}, - {1588.24f, 35.5842f, 7.55613f, 4.79564f}, - {1588.14f, 36.7611f, 7.49675f, 4.79564f}, - {1595.74f, 35.5278f, 7.46602f, 4.90246f}, - {1596, 36.6475f, 7.47991f, 4.90246f}, - {1597.03f, 36.2356f, 7.48631f, 4.90246f}, - {1597.93f, 37.1214f, 7.51725f, 4.90246f}, - {1598.16f, 35.888f, 7.50018f, 4.90246f}, - {1579.6f, -98.0917f, 8.48478f, 1.37996f}, - {1581.2f, -98.401f, 8.47483f, 1.37996f}, - {1580.38f, -98.9556f, 8.4772f, 1.38781f}, - {1585.68f, -104.966f, 8.88551f, 0.493246f}, - {1586.15f, -106.033f, 9.10616f, 0.493246f}, - {1584.88f, -105.394f, 8.82985f, 0.493246f}, - {1581.87f, -100.899f, 8.46164f, 0.929142f}, - {1581.48f, -99.4657f, 8.46926f, 0.929142f}, - {1583.2f, -91.2291f, 8.49227f, 1.40038f}, - {1581.94f, -91.0119f, 8.49977f, 1.40038f}, - {1582.33f, -91.951f, 8.49353f, 1.1844f}, - {1342.06f, -304.049f, 30.9532f, 5.59507f}, - {1340.96f, -304.536f, 30.9458f, 1.28323f}, - {1341.22f, -303.316f, 30.9413f, 0.486051f}, - {1342.22f, -302.939f, 30.986f, 4.87643f}, - {1382.16f, -287.466f, 32.3063f, 4.80968f}, - {1381, -287.58f, 32.2805f, 4.80968f}, - {1381.55f, -286.536f, 32.3929f, 2.84225f}, - {1382.75f, -286.354f, 32.4099f, 1.00442f}, - {1379.92f, -287.34f, 32.2872f, 3.81615f}, - {1100.52f, -2.41391f, 70.2984f, 0.131054f}, - {1099.35f, -2.13851f, 70.3375f, 4.4586f}, - {1099.59f, -1.00329f, 70.238f, 2.49903f}, - {1097.79f, 0.571316f, 70.159f, 4.00307f}, - {1098.74f, -7.23252f, 70.7972f, 4.1523f}, - {1098.46f, -5.91443f, 70.6715f, 4.1523f}, - {1097.53f, -7.39704f, 70.7959f, 4.1523f}, - {1097.32f, -6.64233f, 70.7424f, 4.1523f}, - {1096.45f, -5.96664f, 70.7242f, 4.1523f}, - {971.725f, 0.496763f, 86.8467f, 2.09233f}, - {973.589f, 0.119518f, 86.7985f, 3.17225f}, - {972.524f, 1.25333f, 86.8351f, 5.28497f}, - {971.993f, 2.05668f, 86.8584f, 5.28497f}, - {973.635f, 2.11805f, 86.8197f, 2.36722f}, - {974.791f, 1.74679f, 86.7942f, 1.5936f}, - {974.771f, 3.0445f, 86.8125f, 0.647199f}, - {979.554f, 3.6037f, 86.7923f, 1.69178f}, - {979.758f, 2.57519f, 86.7748f, 1.76639f}, - {980.769f, 3.48904f, 86.7939f, 1.76639f}, - {979.122f, 2.87109f, 86.7794f, 1.76639f}, - {986.167f, 4.85363f, 86.8439f, 1.5779f}, - {986.176f, 3.50367f, 86.8217f, 1.5779f}, - {987.33f, 4.67389f, 86.8486f, 1.5779f}, - {985.23f, 4.65898f, 86.8368f, 1.5779f}, - {984.556f, 3.54097f, 86.8137f, 1.5779f}, -}; - -/* Ships: - * 193182 - ally - * 193183 - horde - * 193184 - horde - * 193185 - ally - * Banners: - * 191308 - left one, - * 191306 - right one, - * 191310 - central, - * Ally ones, substract 1 - * to get horde ones. - */ - -uint32 const BG_SA_ObjEntries[BG_SA_MAXOBJ + BG_SA_FLAG_AMOUNT] = -{ - 190722, - 190727, - 190724, - 190726, - 190723, - 192549, - 192834, - 192819, - 192819, - 192819, - 192819, - 192819, - 0, // Boat - 0, // Boat - 192687, - 192685, - 192689, - 192690, - 192691, - 191311, - 191311, - 191311, - 191310, - 191306, - 191308, - 190753 -}; - uint32 const BG_SA_Factions[2] = { 1732, 1735, }; -enum BG_SA_Graveyards +enum class StrandOfTheAncientsGraveyard { - BG_SA_BEACH_GY = 0, - BG_SA_DEFENDER_LAST_GY, - BG_SA_RIGHT_CAPTURABLE_GY, - BG_SA_LEFT_CAPTURABLE_GY, - BG_SA_CENTRAL_CAPTURABLE_GY, - BG_SA_MAX_GY -}; - -const uint32 BG_SA_GYEntries[BG_SA_MAX_GY] = -{ - 1350, - 1349, - 1347, - 1346, - 1348, -}; - -float const BG_SA_GYOrientation[BG_SA_MAX_GY] = -{ - 6.202f, - 1.926f, // right capturable GY - 3.917f, // left capturable GY - 3.104f, // center, capturable - 6.148f, // defender last GY + West, + East, + Central }; enum BG_SA_BroadcastTexts @@ -495,24 +187,31 @@ enum BG_SA_BroadcastTexts BG_SA_TEXT_ROUND_TWO_START_HALF_MINUTE = 29449 }; +enum class DefenseLine +{ + First, + Second, + Third, + Last +}; + struct GateInfo { - uint8 GateId; uint32 GameObjectId; uint32 WorldState; uint8 DamagedText; uint8 DestroyedText; + DefenseLine LineOfDefense; }; -#define MAX_GATES 6 -GateInfo const Gates[MAX_GATES] = +GateInfo const Gates[] = { - { BG_SA_GREEN_GATE, GO_GATE_OF_THE_GREEN_EMERALD, BG_SA_GREEN_GATEWS, TEXT_GREEN_GATE_UNDER_ATTACK, TEXT_GREEN_GATE_DESTROYED }, - { BG_SA_YELLOW_GATE, GO_GATE_OF_THE_YELLOW_MOON, BG_SA_YELLOW_GATEWS, TEXT_YELLOW_GATE_UNDER_ATTACK, TEXT_YELLOW_GATE_DESTROYED }, - { BG_SA_BLUE_GATE, GO_GATE_OF_THE_BLUE_SAPPHIRE, BG_SA_BLUE_GATEWS, TEXT_BLUE_GATE_UNDER_ATTACK, TEXT_BLUE_GATE_DESTROYED }, - { BG_SA_RED_GATE, GO_GATE_OF_THE_RED_SUN, BG_SA_RED_GATEWS, TEXT_RED_GATE_UNDER_ATTACK, TEXT_RED_GATE_DESTROYED }, - { BG_SA_PURPLE_GATE, GO_GATE_OF_THE_PURPLE_AMETHYST, BG_SA_PURPLE_GATEWS, TEXT_PURPLE_GATE_UNDER_ATTACK, TEXT_PURPLE_GATE_DESTROYED }, - { BG_SA_ANCIENT_GATE, GO_CHAMBER_OF_ANCIENT_RELICS, BG_SA_ANCIENT_GATEWS, TEXT_ANCIENT_GATE_UNDER_ATTACK, TEXT_ANCIENT_GATE_DESTROYED } + { GO_GATE_OF_THE_GREEN_EMERALD, BG_SA_GREEN_GATEWS, TEXT_GREEN_GATE_UNDER_ATTACK, TEXT_GREEN_GATE_DESTROYED, DefenseLine::First }, + { GO_GATE_OF_THE_YELLOW_MOON, BG_SA_YELLOW_GATEWS, TEXT_YELLOW_GATE_UNDER_ATTACK, TEXT_YELLOW_GATE_DESTROYED, DefenseLine::Third }, + { GO_GATE_OF_THE_BLUE_SAPPHIRE, BG_SA_BLUE_GATEWS, TEXT_BLUE_GATE_UNDER_ATTACK, TEXT_BLUE_GATE_DESTROYED, DefenseLine::First }, + { GO_GATE_OF_THE_RED_SUN, BG_SA_RED_GATEWS, TEXT_RED_GATE_UNDER_ATTACK, TEXT_RED_GATE_DESTROYED, DefenseLine::Second }, + { GO_GATE_OF_THE_PURPLE_AMETHYST, BG_SA_PURPLE_GATEWS, TEXT_PURPLE_GATE_UNDER_ATTACK, TEXT_PURPLE_GATE_DESTROYED, DefenseLine::Second }, + { GO_CHAMBER_OF_ANCIENT_RELICS, BG_SA_ANCIENT_GATEWS, TEXT_ANCIENT_GATE_UNDER_ATTACK, TEXT_ANCIENT_GATE_DESTROYED, DefenseLine::Last } }; struct BG_SA_RoundScore @@ -521,6 +220,11 @@ struct BG_SA_RoundScore uint32 time; }; +enum StrandOfTheAncientSharedActions +{ + ACTION_SOTA_CAPTURE_GRAVEYARD +}; + /// Class for manage Strand of Ancient battleground class BattlegroundSA : public Battleground { @@ -543,21 +247,18 @@ class BattlegroundSA : public Battleground void Reset() override; /// Called when a player kill a unit in bg void HandleKillUnit(Creature* creature, Unit* killer) override; - /// Return the nearest graveyard where player can respawn - WorldSafeLocsEntry const* GetClosestGraveyard(Player* player) override; /// Called when someone activates an event void ProcessEvent(WorldObject* /*obj*/, uint32 /*eventId*/, WorldObject* /*invoker*/ = nullptr) override; - /// Called when a player click on flag (graveyard flag) - void EventPlayerClickedOnFlag(Player* source, GameObject* go) override; /// Called when a player clicked on relic void TitanRelicActivated(Player* clicker); /// Return GateInfo, relative to bg data, according to gameobject entry GateInfo const* GetGate(uint32 entry) { - for (uint8 i = 0; i < MAX_GATES; ++i) - if (Gates[i].GameObjectId == entry) - return &Gates[i]; + for (GateInfo const& gate : Gates) + if (gate.GameObjectId == entry) + return &gate; + return nullptr; } @@ -568,11 +269,12 @@ class BattlegroundSA : public Battleground void RemovePlayer(Player* player, ObjectGuid guid, uint32 team) override; void HandleAreaTrigger(Player* source, uint32 trigger, bool entered) override; - /* Scorekeeping */ - - // Control Phase Shift - bool IsSpellAllowed(uint32 spellId, Player const* player) const override; + void OnGameObjectCreate(GameObject* gameobject) override; + void DoAction(uint32 actionId, WorldObject* source, WorldObject* target) override; + void OnCreatureCreate(Creature* creature) override; + void OnMapSet(BattlegroundMap* map) override; + uint32 GetData(uint32 dataId) const override; private: /** @@ -587,20 +289,8 @@ class BattlegroundSA : public Battleground * \brief Called between the two round * -Teleport all players to good location */ - void TeleportPlayers(); - void TeleportToEntrancePosition(Player* player); - /** - * \brief Called on start and between the two round - * -Update faction of all vehicle - */ - void OverrideGunFaction(); - /// Set selectable or not demolisher, called on battle start, when boats arrive to dock - void DemolisherStartState(bool start); - /// Checks if a player can interact with the given object - bool CanInteractWithObject(uint32 objectId); - /// Updates interaction flags of specific objects - void UpdateObjectInteractionFlags(uint32 objectId); - void UpdateObjectInteractionFlags(); + void TeleportPlayers() const; + void TeleportToEntrancePosition(Player* player) const; /** * \brief Called when a gate is destroy * -Give honor to player witch destroy it @@ -617,19 +307,24 @@ class BattlegroundSA : public Battleground * \param i : id of graveyard * \param Source : Player who capture gy */ - void CaptureGraveyard(BG_SA_Graveyards i, Player* Source); + void CaptureGraveyard(StrandOfTheAncientsGraveyard graveyard, TeamId teamId); /// Switch on/off timer worldstate void ToggleTimer(); - /// Respawn dead demolisher - void UpdateDemolisherSpawns(); - /// Send packet to player for create boats (client part) void SendTransportInit(Player* player); /// Send packet to player for destroy boats (client part) void SendTransportsRemove(Player* player); - bool IsGateDestroyed(BG_SA_Objects gateId) const; + bool IsGateDestroyed(GateInfo const* gateInfo) const; + + void HandleCaptureGraveyardAction(GameObject* graveyardBanner, Player* player); + + void MakeObjectsInteractable(DefenseLine defenseLine); + + Creature* FindKanrethad() const; + + void EndRound(); /// Id of attacker team TeamId Attackers; @@ -640,12 +335,8 @@ class BattlegroundSA : public Battleground uint32 EndRoundTimer; /// For know if boats has start moving or not yet bool ShipsStarted; - /// Status of each gate (Destroy/Damage/Intact) - BG_SA_GateState GateStatus[MAX_GATES]; /// Statu of battle (Start or not, and what round) BG_SA_Status Status; - /// Team witch conntrol each graveyard - TeamId GraveyardStatus[BG_SA_MAX_GY]; /// Score of each round BG_SA_RoundScore RoundScores[2]; /// used for know we are in timer phase or not (used for worldstate update) @@ -658,6 +349,18 @@ class BattlegroundSA : public Battleground bool SignaledRoundTwoHalfMin; /// for know if second round has been init bool InitSecondRound; - std::map<uint32/*id*/, uint32/*timer*/> DemoliserRespawnList; + + // [team][boat_idx] + std::array<std::array<ObjectGuid, 2 /*BOAT_COUNT*/>, PVP_TEAMS_COUNT> _boatGUIDs; + std::array<GuidUnorderedSet, PVP_TEAMS_COUNT> _staticBombGUIDs; // bombs ready to be picked up + GuidUnorderedSet _dynamicBombGUIDs; // bombs thrown by players, ready to explode/disarm + + ObjectGuid _graveyardWest; + ObjectGuid _graveyardEast; + ObjectGuid _graveyardCentral; + GuidUnorderedSet _gateGUIDs; + ObjectGuid _collisionDoorGUID; + ObjectGuid _kanrethadGUID; + ObjectGuid _titanRelicGUID; }; #endif diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 9d073e84c59..06c3ccaf4ad 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1581,7 +1581,7 @@ void Spell::EffectOpenLock() return; // Arathi Basin banner opening. /// @todo Verify correctness of this check - if (gameObjTarget->GetMapId() != 30 && ((goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune) || + if (gameObjTarget->GetMapId() != 30 && gameObjTarget->GetMapId() != 607 && ((goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune) || (goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.requireLOS))) { //CanUseBattlegroundObject() already called in CheckCast() diff --git a/src/server/scripts/Northrend/StrandOfTheAncients/strand_of_the_ancients.cpp b/src/server/scripts/Northrend/StrandOfTheAncients/strand_of_the_ancients.cpp new file mode 100644 index 00000000000..ed268327760 --- /dev/null +++ b/src/server/scripts/Northrend/StrandOfTheAncients/strand_of_the_ancients.cpp @@ -0,0 +1,87 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "BattlegroundSA.h" +#include "GameObject.h" +#include "GameObjectAI.h" +#include "Player.h" +#include "SpellScript.h" +#include "ZoneScript.h" + +// 191305 - Horde Banner +// 191306 - Alliance Banner +// 191307 - Horde Banner +// 191308 - Alliance Banner +// 191309 - Horde Banner +// 191310 - Alliance Banner +struct go_sota_capturable_object : public GameObjectAI +{ + go_sota_capturable_object(GameObject* go) : GameObjectAI(go) { } + + bool OnGossipHello(Player* player) override + { + if (me->GetGoState() != GO_STATE_READY || me->HasFlag(GO_FLAG_NOT_SELECTABLE)) + return true; + + if (ZoneScript* zonescript = me->GetZoneScript()) + { + zonescript->DoAction(ACTION_SOTA_CAPTURE_GRAVEYARD, player, me); + return false; + } + + return true; + } +}; + +// 52410 - Place Seaforium Charge +class spell_place_seaforium_charge : public SpellScript +{ + enum Spells + { + SPELL_PLACE_SEAFORIUM_CHARGE_HORDE = 226090, + SPELL_PLACE_SEAFORIUM_CHARGE_ALLIANCE = 226094 + }; + + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_PLACE_SEAFORIUM_CHARGE_HORDE, SPELL_PLACE_SEAFORIUM_CHARGE_ALLIANCE }); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Player* playerCaster = GetCaster()->ToPlayer()) + { + Team const team = playerCaster->GetBGTeam(); + if (team == ALLIANCE) + playerCaster->CastSpell(playerCaster, SPELL_PLACE_SEAFORIUM_CHARGE_ALLIANCE, true); + else if (team == HORDE) + playerCaster->CastSpell(playerCaster, SPELL_PLACE_SEAFORIUM_CHARGE_HORDE, true); + } + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_place_seaforium_charge::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +void AddSC_strand_of_the_ancients() +{ + RegisterGameObjectAI(go_sota_capturable_object); + RegisterSpellScript(spell_place_seaforium_charge); +} diff --git a/src/server/scripts/Northrend/northrend_script_loader.cpp b/src/server/scripts/Northrend/northrend_script_loader.cpp index c41abc94806..fe2514d804e 100644 --- a/src/server/scripts/Northrend/northrend_script_loader.cpp +++ b/src/server/scripts/Northrend/northrend_script_loader.cpp @@ -210,6 +210,8 @@ void AddSC_wintergrasp(); void AddSC_zuldrak(); void AddSC_crystalsong_forest(); +void AddSC_strand_of_the_ancients(); + // The name of this function should match: // void Add${NameOfDirectory}Scripts() void AddNorthrendScripts() @@ -406,4 +408,6 @@ void AddNorthrendScripts() AddSC_storm_peaks(); AddSC_wintergrasp(); AddSC_zuldrak(); + + AddSC_strand_of_the_ancients(); } |