/* * 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 . */ #include "GameObject.h" #include "Map.h" #include "ObjectAccessor.h" #include "OutdoorPvPTF.h" #include "Player.h" #include "ScriptMgr.h" #include "WorldStatePackets.h" uint8 const OutdoorPvPTFBuffZonesNum = 5; uint32 const OutdoorPvPTFBuffZones[OutdoorPvPTFBuffZonesNum] = { 3519 /*Terokkar Forest*/, 3791 /*Sethekk Halls*/, 3789 /*Shadow Labyrinth*/, 3792 /*Mana-Tombs*/, 3790 /*Auchenai Crypts*/ }; // locked for 6 hours after capture uint32 const TF_LOCK_TIME = 3600 * 6 * 1000; // update lock timer every 1/4 minute (overkill, but this way it's sure the timer won't "jump" 2 minutes at once.) uint32 const TF_LOCK_TIME_UPDATE = 15000; // blessing of auchindoun, used in TeamCastSpell which uses signed int, so signed int32 const TF_CAPTURE_BUFF = 33377; uint32 const TF_ALLY_QUEST = 11505; uint32 const TF_HORDE_QUEST = 11506; OutdoorPvPTF::OutdoorPvPTF(Map* map) : OutdoorPvP(map) { m_TypeId = OUTDOOR_PVP_TF; m_IsLocked = false; m_LockTimer = TF_LOCK_TIME; m_LockTimerUpdate = 0; m_AllianceTowersControlled = 0; m_HordeTowersControlled = 0; hours_left = 6; second_digit = 0; first_digit = 0; ControlZoneHandlers[TF_ENTRY_TOWER_NW] = std::make_unique(this, 2682, 2683, 2681); ControlZoneHandlers[TF_ENTRY_TOWER_N] = std::make_unique(this, 2685, 2684, 2686); ControlZoneHandlers[TF_ENTRY_TOWER_NE] = std::make_unique(this, 2689, 2688, 2690); ControlZoneHandlers[TF_ENTRY_TOWER_SE] = std::make_unique(this, 2695, 2694, 2696); ControlZoneHandlers[TF_ENTRY_TOWER_S] = std::make_unique(this, 2692, 2691, 2693); } void OutdoorPvPTF::SendRemoveWorldStates(Player* player) { WorldPackets::WorldState::InitWorldStates initWorldStates; initWorldStates.MapID = player->GetMapId(); initWorldStates.AreaID = player->GetZoneId(); initWorldStates.SubareaID = player->GetAreaId(); initWorldStates.Worldstates.emplace_back(TF_UI_TOWER_COUNT_H, 0); initWorldStates.Worldstates.emplace_back(TF_UI_TOWER_COUNT_A, 0); initWorldStates.Worldstates.emplace_back(TF_UI_TOWERS_CONTROLLED_DISPLAY, 0); initWorldStates.Worldstates.emplace_back(TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT, 0); initWorldStates.Worldstates.emplace_back(TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT, 0); initWorldStates.Worldstates.emplace_back(TF_UI_LOCKED_TIME_HOURS, 0); initWorldStates.Worldstates.emplace_back(TF_UI_LOCKED_DISPLAY_NEUTRAL, 0); initWorldStates.Worldstates.emplace_back(TF_UI_LOCKED_DISPLAY_HORDE, 0); initWorldStates.Worldstates.emplace_back(TF_UI_LOCKED_DISPLAY_ALLIANCE, 0); for (auto& itr : ControlZoneHandlers) { TFControlZoneHandler* handler = static_cast(itr.second.get()); initWorldStates.Worldstates.emplace_back(handler->GetWorldStateNeutral(), 0); initWorldStates.Worldstates.emplace_back(handler->GetWorldStateHorde(), 0); initWorldStates.Worldstates.emplace_back(handler->GetWorldStateAlliance(), 0); } player->SendDirectMessage(initWorldStates.Write()); } void OutdoorPvPTF::Update(uint32 diff) { OutdoorPvP::Update(diff); if (m_IsLocked) { // lock timer is down, release lock if (m_LockTimer < diff) { m_LockTimer = TF_LOCK_TIME; m_LockTimerUpdate = 0; m_IsLocked = false; for (ObjectGuid const& controlZoneGUID : _controlZoneGUIDs) { if (GameObject* gameObject = GetMap()->GetGameObject(controlZoneGUID)) { gameObject->HandleCustomTypeCommand(GameObjectType::SetControlZoneValue()); gameObject->ActivateObject(GameObjectActions::MakeActive, 0); } } SetWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, 1); SetWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, 0); SetWorldState(TF_UI_LOCKED_DISPLAY_HORDE, 0); SetWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE, 0); } else { // worldstateui update timer is down, update ui with new time data if (m_LockTimerUpdate < diff) { m_LockTimerUpdate = TF_LOCK_TIME_UPDATE; uint32 minutes_left = m_LockTimer / 60000; hours_left = minutes_left / 60; minutes_left -= hours_left * 60; second_digit = minutes_left % 10; first_digit = minutes_left / 10; SetWorldState(TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT, first_digit); SetWorldState(TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT, second_digit); SetWorldState(TF_UI_LOCKED_TIME_HOURS, hours_left); } else m_LockTimerUpdate -= diff; m_LockTimer -= diff; } } } void OutdoorPvPTF::HandlePlayerEnterZone(Player* player, uint32 zone) { if (player->GetTeam() == ALLIANCE) { if (m_AllianceTowersControlled >= TF_TOWER_NUM) player->CastSpell(player, TF_CAPTURE_BUFF, true); } else if (player->GetTeam() == HORDE) { if (m_HordeTowersControlled >= TF_TOWER_NUM) player->CastSpell(player, TF_CAPTURE_BUFF, true); } OutdoorPvP::HandlePlayerEnterZone(player, zone); } void OutdoorPvPTF::HandlePlayerLeaveZone(Player* player, uint32 zone) { // remove buffs player->RemoveAurasDueToSpell(TF_CAPTURE_BUFF); OutdoorPvP::HandlePlayerLeaveZone(player, zone); } uint32 OutdoorPvPTF::GetAllianceTowersControlled() const { return m_AllianceTowersControlled; } void OutdoorPvPTF::SetAllianceTowersControlled(uint32 count) { m_AllianceTowersControlled = count; } uint32 OutdoorPvPTF::GetHordeTowersControlled() const { return m_HordeTowersControlled; } void OutdoorPvPTF::SetHordeTowersControlled(uint32 count) { m_HordeTowersControlled = count; } bool OutdoorPvPTF::IsLocked() const { return m_IsLocked; } void OutdoorPvPTF::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker) { OutdoorPvP::ProcessEvent(obj, eventId, invoker); SetWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled); SetWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled); // now check if everything is capped if (m_HordeTowersControlled == TF_TOWER_NUM) HandleCapture(TEAM_HORDE); else if (m_AllianceTowersControlled == TF_TOWER_NUM) HandleCapture(TEAM_ALLIANCE); else { TeamCastSpell(TEAM_ALLIANCE, -TF_CAPTURE_BUFF); TeamCastSpell(TEAM_HORDE, -TF_CAPTURE_BUFF); } } void OutdoorPvPTF::HandleCapture(TeamId team) { m_IsLocked = true; for (ObjectGuid const& controlZoneGUID : _controlZoneGUIDs) if (GameObject* gameObject = GetMap()->GetGameObject(controlZoneGUID)) gameObject->ActivateObject(GameObjectActions::MakeInert, 0); TeamApplyBuff(team, TF_CAPTURE_BUFF); SetWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, 0); SetWorldState(TF_UI_LOCKED_DISPLAY_HORDE, team == TEAM_HORDE ? 1 : 0); SetWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE, team == TEAM_ALLIANCE ? 1 : 0); SetWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, 0); } bool OutdoorPvPTF::SetupOutdoorPvP() { m_AllianceTowersControlled = 0; m_HordeTowersControlled = 0; m_IsLocked = false; m_LockTimer = TF_LOCK_TIME; m_LockTimerUpdate = 0; hours_left = 6; second_digit = 0; first_digit = 0; // add the zones affected by the pvp buff for (uint8 i = 0; i < OutdoorPvPTFBuffZonesNum; ++i) RegisterZone(OutdoorPvPTFBuffZones[i]); return true; } void OutdoorPvPTF::OnGameObjectCreate(GameObject* go) { switch (go->GetEntry()) { case TF_ENTRY_TOWER_NW: case TF_ENTRY_TOWER_N: case TF_ENTRY_TOWER_NE: case TF_ENTRY_TOWER_SE: case TF_ENTRY_TOWER_S: _controlZoneGUIDs.insert(go->GetGUID()); break; default: break; } OutdoorPvP::OnGameObjectCreate(go); } TFControlZoneHandler::TFControlZoneHandler(OutdoorPvPTF* pvp, uint32 worldstateHorde, uint32 worldstateAlliance, uint32 worldstateNeutral) : OutdoorPvPControlZoneHandler(pvp), _worldstateHorde(worldstateHorde), _worldstateAlliance(worldstateAlliance), _worldstateNeutral(worldstateNeutral) { } void TFControlZoneHandler::HandleProgressEventHorde(GameObject* controlZone) { controlZone->SetGoArtKit(1); GetOutdoorPvPTF()->SetHordeTowersControlled(GetOutdoorPvPTF()->GetHordeTowersControlled() + 1); GetOutdoorPvP()->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_TAKEN_HORDE); controlZone->GetMap()->SetWorldStateValue(_worldstateHorde, 1, false); controlZone->GetMap()->SetWorldStateValue(_worldstateAlliance, 0, false); controlZone->GetMap()->SetWorldStateValue(_worldstateNeutral, 0, false); if (GuidUnorderedSet const* guidSet = controlZone->GetInsidePlayers()) for (ObjectGuid const& guid : *guidSet) if (Player* player = ObjectAccessor::GetPlayer(*controlZone, guid)) if (player->GetTeam() == HORDE) player->AreaExploredOrEventHappens(TF_HORDE_QUEST); OutdoorPvPControlZoneHandler::HandleProgressEventHorde(controlZone); } void TFControlZoneHandler::HandleProgressEventAlliance(GameObject* controlZone) { controlZone->SetGoArtKit(2); GetOutdoorPvPTF()->SetAllianceTowersControlled(GetOutdoorPvPTF()->GetAllianceTowersControlled() + 1); GetOutdoorPvP()->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_TAKEN_ALLIANCE); controlZone->GetMap()->SetWorldStateValue(_worldstateHorde, 0, false); controlZone->GetMap()->SetWorldStateValue(_worldstateAlliance, 1, false); controlZone->GetMap()->SetWorldStateValue(_worldstateNeutral, 0, false); if (GuidUnorderedSet const* guidSet = controlZone->GetInsidePlayers()) for (ObjectGuid const& guid : *guidSet) if (Player* player = ObjectAccessor::GetPlayer(*controlZone, guid)) if (player->GetTeam() == ALLIANCE) player->AreaExploredOrEventHappens(TF_ALLY_QUEST); OutdoorPvPControlZoneHandler::HandleProgressEventAlliance(controlZone); } void TFControlZoneHandler::HandleNeutralEventHorde(GameObject* controlZone) { GetOutdoorPvPTF()->SetHordeTowersControlled(GetOutdoorPvPTF()->GetHordeTowersControlled() - 1); GetOutdoorPvP()->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_LOSE_HORDE); OutdoorPvPControlZoneHandler::HandleNeutralEventHorde(controlZone); } void TFControlZoneHandler::HandleNeutralEventAlliance(GameObject* controlZone) { GetOutdoorPvPTF()->SetAllianceTowersControlled(GetOutdoorPvPTF()->GetAllianceTowersControlled() - 1); GetOutdoorPvP()->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_LOSE_ALLIANCE); OutdoorPvPControlZoneHandler::HandleNeutralEventAlliance(controlZone); } void TFControlZoneHandler::HandleNeutralEvent(GameObject* controlZone) { controlZone->SetGoArtKit(21); controlZone->GetMap()->SetWorldStateValue(_worldstateHorde, 0, false); controlZone->GetMap()->SetWorldStateValue(_worldstateAlliance, 0, false); controlZone->GetMap()->SetWorldStateValue(_worldstateNeutral, 1, false); OutdoorPvPControlZoneHandler::HandleNeutralEvent(controlZone); } OutdoorPvPTF* TFControlZoneHandler::GetOutdoorPvPTF() const { return static_cast(OutdoorPvPControlZoneHandler::GetOutdoorPvP()); } class OutdoorPvP_terokkar_forest : public OutdoorPvPScript { public: OutdoorPvP_terokkar_forest() : OutdoorPvPScript("outdoorpvp_tf") { } OutdoorPvP* GetOutdoorPvP(Map* map) const override { return new OutdoorPvPTF(map); } }; void AddSC_outdoorpvp_tf() { new OutdoorPvP_terokkar_forest(); }