/* * 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 "OutdoorPvPZM.h" #include "Creature.h" #include "GameObject.h" #include "GossipDef.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Player.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "ScriptMgr.h" #include "WorldSession.h" #include "WorldStatePackets.h" uint8 const OutdoorPvPZMBuffZonesNum = 5; // the buff is cast in these zones uint32 const OutdoorPvPZMBuffZones[OutdoorPvPZMBuffZonesNum] = { 3521, 3607, 3717, 3715, 3716 }; // linked when the central tower is controlled uint32 const ZM_GRAVEYARD_ZONE = 3521; ZMControlZoneHandler::ZMControlZoneHandler(OutdoorPvPZM* pvp, uint32 textBeaconTakenHorde, uint32 textBeaconTakenAlliance, uint32 worldstateNeutralUi, uint32 worldstateNeutralMap, uint32 worldstateHordeUi, uint32 worldstateHordeMap, uint32 worldstateAllianceUi, uint32 worldstateAllianceMap) : OutdoorPvPControlZoneHandler(pvp), _textBeaconTakenHorde(textBeaconTakenHorde), _textBeaconTakenAlliance(textBeaconTakenAlliance), _worldstateNeutralUi(worldstateNeutralUi), _worldstateNeutralMap(worldstateNeutralMap), _worldstateHordeUi(worldstateHordeUi), _worldstateHordeMap(worldstateHordeMap), _worldstateAllianceUi(worldstateAllianceUi), _worldstateAllianceMap(worldstateAllianceMap) { } void ZMControlZoneHandler::HandleProgressEventHorde(GameObject* controlZone) { OutdoorPvPControlZoneHandler::HandleProgressEventHorde(controlZone); GetOutdoorPvpZM()->SetHordeTowersControlled(GetOutdoorPvpZM()->GetHordeTowersControlled() + 1); GetOutdoorPvpZM()->SendDefenseMessage(ZM_GRAVEYARD_ZONE, _textBeaconTakenHorde); GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceMap, 0); GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceUi, 0); GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralMap, 0); GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralUi, 0); GetOutdoorPvpZM()->SetWorldState(_worldstateHordeMap, 1); GetOutdoorPvpZM()->SetWorldState(_worldstateHordeUi, 1); } void ZMControlZoneHandler::HandleProgressEventAlliance(GameObject* controlZone) { OutdoorPvPControlZoneHandler::HandleProgressEventAlliance(controlZone); GetOutdoorPvpZM()->SetAllianceTowersControlled(GetOutdoorPvpZM()->GetAllianceTowersControlled() + 1); GetOutdoorPvpZM()->SendDefenseMessage(ZM_GRAVEYARD_ZONE, _textBeaconTakenAlliance); GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceMap, 1); GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceUi, 1); GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralMap, 0); GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralUi, 0); GetOutdoorPvpZM()->SetWorldState(_worldstateHordeMap, 0); GetOutdoorPvpZM()->SetWorldState(_worldstateHordeUi, 0); } void ZMControlZoneHandler::HandleNeutralEventHorde(GameObject* controlZone) { GetOutdoorPvpZM()->SetHordeTowersControlled(GetOutdoorPvpZM()->GetHordeTowersControlled() - 1); OutdoorPvPControlZoneHandler::HandleNeutralEventHorde(controlZone); } void ZMControlZoneHandler::HandleNeutralEventAlliance(GameObject* controlZone) { GetOutdoorPvpZM()->SetAllianceTowersControlled(GetOutdoorPvpZM()->GetAllianceTowersControlled() - 1); OutdoorPvPControlZoneHandler::HandleNeutralEventAlliance(controlZone); } void ZMControlZoneHandler::HandleNeutralEvent(GameObject* controlZone) { OutdoorPvPControlZoneHandler::HandleNeutralEvent(controlZone); GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceMap, 0); GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceUi, 0); GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralMap, 1); GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralUi, 1); GetOutdoorPvpZM()->SetWorldState(_worldstateHordeMap, 0); GetOutdoorPvpZM()->SetWorldState(_worldstateHordeUi, 0); } OutdoorPvPZM* ZMControlZoneHandler::GetOutdoorPvpZM() { return static_cast(OutdoorPvPControlZoneHandler::GetOutdoorPvP()); } void OutdoorPvPZM::Update(uint32 diff) { OutdoorPvP::Update(diff); if (m_AllianceTowersControlled == ZM_NUM_BEACONS) m_Graveyard->SetBeaconState(ALLIANCE); else if (m_HordeTowersControlled == ZM_NUM_BEACONS) m_Graveyard->SetBeaconState(HORDE); else m_Graveyard->SetBeaconState(0); } void OutdoorPvPZM::HandlePlayerEnterZone(Player* player, uint32 zone) { if (player->GetTeam() == ALLIANCE) { if (m_Graveyard->GetGraveyardState() & ZM_GRAVEYARD_A) player->CastSpell(player, ZM_CAPTURE_BUFF, true); } else if (player->GetTeam() == HORDE) { if (m_Graveyard->GetGraveyardState() & ZM_GRAVEYARD_H) player->CastSpell(player, ZM_CAPTURE_BUFF, true); } OutdoorPvP::HandlePlayerEnterZone(player, zone); } void OutdoorPvPZM::HandlePlayerLeaveZone(Player* player, uint32 zone) { // remove buffs player->RemoveAurasDueToSpell(ZM_CAPTURE_BUFF); // remove flag player->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_A); player->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_H); OutdoorPvP::HandlePlayerLeaveZone(player, zone); } OutdoorPvPZM::OutdoorPvPZM(Map* map) : OutdoorPvP(map) { m_TypeId = OUTDOOR_PVP_ZM; m_AllianceTowersControlled = 0; m_HordeTowersControlled = 0; ControlZoneHandlers[ZM_GO_ENTRY_BEACON_EAST] = std::make_unique( this, TEXT_EAST_BEACON_TAKEN_HORDE, TEXT_EAST_BEACON_TAKEN_ALLIANCE, ZM_UI_TOWER_EAST_N, ZM_MAP_TOWER_EAST_N, ZM_UI_TOWER_EAST_H, ZM_MAP_TOWER_EAST_H, ZM_UI_TOWER_EAST_A, ZM_MAP_TOWER_EAST_A ); ControlZoneHandlers[ZM_GO_ENTRY_BEACON_WEST] = std::make_unique( this, TEXT_WEST_BEACON_TAKEN_HORDE, TEXT_WEST_BEACON_TAKEN_ALLIANCE, ZM_UI_TOWER_WEST_N, ZM_MAP_TOWER_WEST_N, ZM_UI_TOWER_WEST_H, ZM_MAP_TOWER_WEST_H, ZM_UI_TOWER_WEST_A, ZM_MAP_TOWER_WEST_A ); } bool OutdoorPvPZM::SetupOutdoorPvP() { m_AllianceTowersControlled = 0; m_HordeTowersControlled = 0; // add the zones affected by the pvp buff for (uint8 i = 0; i < OutdoorPvPZMBuffZonesNum; ++i) RegisterZone(OutdoorPvPZMBuffZones[i]); m_Graveyard = std::make_unique(this); return true; } void OutdoorPvPZM::HandleKillImpl(Player* player, Unit* killed) { if (killed->GetTypeId() != TYPEID_PLAYER) return; if (player->GetTeam() == ALLIANCE && killed->ToPlayer()->GetTeam() != ALLIANCE) player->CastSpell(player, ZM_AlliancePlayerKillReward, true); else if (player->GetTeam() == HORDE && killed->ToPlayer()->GetTeam() != HORDE) player->CastSpell(player, ZM_HordePlayerKillReward, true); } void OPvPCapturePointZM_Graveyard::Update(uint32 /*diff*/) { m_State = m_OldState; } int32 OPvPCapturePointZM_Graveyard::HandleOpenGo(Player* player, GameObject* go) { switch (go->GetEntry()) { case 182529: case 182527: case 182528: if (player->HasAura(ZM_BATTLE_STANDARD_A) && m_GraveyardState != ZM_GRAVEYARD_A) { m_GraveyardState = ZM_GRAVEYARD_A; m_PvP->TeamApplyBuff(TEAM_ALLIANCE, ZM_CAPTURE_BUFF); player->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_A); m_PvP->SendDefenseMessage(ZM_GRAVEYARD_ZONE, TEXT_TWIN_SPIRE_RUINS_TAKEN_ALLIANCE); } else if (player->HasAura(ZM_BATTLE_STANDARD_H) && m_GraveyardState != ZM_GRAVEYARD_H) { m_GraveyardState = ZM_GRAVEYARD_H; m_PvP->TeamApplyBuff(TEAM_HORDE, ZM_CAPTURE_BUFF); player->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_H); m_PvP->SendDefenseMessage(ZM_GRAVEYARD_ZONE, TEXT_TWIN_SPIRE_RUINS_TAKEN_HORDE); } UpdateTowerState(); return 0; default: return OPvPCapturePoint::HandleOpenGo(player, go); } } OPvPCapturePointZM_Graveyard::OPvPCapturePointZM_Graveyard(OutdoorPvP* pvp) : OPvPCapturePoint(pvp) { m_BothControllingFaction = 0; m_GraveyardState = ZM_GRAVEYARD_N; m_FlagCarrierGUID.Clear(); } void OPvPCapturePointZM_Graveyard::UpdateTowerState() { m_PvP->SetWorldState(ZM_MAP_GRAVEYARD_N, int32((m_GraveyardState & ZM_GRAVEYARD_N) != 0)); m_PvP->SetWorldState(ZM_MAP_GRAVEYARD_H, int32((m_GraveyardState & ZM_GRAVEYARD_H) != 0)); m_PvP->SetWorldState(ZM_MAP_GRAVEYARD_A, int32((m_GraveyardState & ZM_GRAVEYARD_A) != 0)); bool allianceFlagReady = m_BothControllingFaction == ALLIANCE && m_GraveyardState != ZM_GRAVEYARD_A; m_PvP->SetWorldState(ZM_MAP_ALLIANCE_FLAG_READY, int32(allianceFlagReady)); m_PvP->SetWorldState(ZM_MAP_ALLIANCE_FLAG_NOT_READY, int32(!allianceFlagReady)); bool hordeFlagReady = m_BothControllingFaction == HORDE && m_GraveyardState != ZM_GRAVEYARD_H; m_PvP->SetWorldState(ZM_MAP_HORDE_FLAG_READY, int32(hordeFlagReady)); m_PvP->SetWorldState(ZM_MAP_HORDE_FLAG_NOT_READY, int32(!hordeFlagReady)); } void OPvPCapturePointZM_Graveyard::SetBeaconState(uint32 controlling_faction) { // nothing to do here if (m_BothControllingFaction == controlling_faction) return; m_BothControllingFaction = controlling_faction; switch (controlling_faction) { case ALLIANCE: // if ally already controls the gy and taken back both beacons, return, nothing to do for us if (m_GraveyardState & ZM_GRAVEYARD_A) return; // ally doesn't control the gy, but controls the side beacons -> add gossip option, add neutral banner break; case HORDE: // if horde already controls the gy and taken back both beacons, return, nothing to do for us if (m_GraveyardState & ZM_GRAVEYARD_H) return; // horde doesn't control the gy, but controls the side beacons -> add gossip option, add neutral banner break; default: // if the graveyard is not neutral, then leave it that way // if the graveyard is neutral, then we have to dispel the buff from the flag carrier if (m_GraveyardState & ZM_GRAVEYARD_N) { // gy was neutral, thus neutral banner was spawned, it is possible that someone was taking the flag to the gy if (!m_FlagCarrierGUID.IsEmpty()) { // remove flag from carrier, reset flag carrier guid Player* p = ObjectAccessor::FindPlayer(m_FlagCarrierGUID); if (p) { p->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_A); p->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_H); } m_FlagCarrierGUID.Clear(); } } break; } // send worldstateupdate UpdateTowerState(); } bool OPvPCapturePointZM_Graveyard::HandleDropFlag(Player* /*player*/, uint32 spellId) { switch (spellId) { case ZM_BATTLE_STANDARD_A: case ZM_BATTLE_STANDARD_H: m_FlagCarrierGUID.Clear(); return true; default: break; } return false; } uint32 OPvPCapturePointZM_Graveyard::GetGraveyardState() const { return m_GraveyardState; } uint32 OutdoorPvPZM::GetAllianceTowersControlled() const { return m_AllianceTowersControlled; } void OutdoorPvPZM::SetAllianceTowersControlled(uint32 count) { m_AllianceTowersControlled = count; } uint32 OutdoorPvPZM::GetHordeTowersControlled() const { return m_HordeTowersControlled; } void OutdoorPvPZM::SetHordeTowersControlled(uint32 count) { m_HordeTowersControlled = count; } void OutdoorPvPZM::SendRemoveWorldStates(Player* player) { WorldPackets::WorldState::InitWorldStates initWorldStates; initWorldStates.MapID = player->GetMapId(); initWorldStates.AreaID = player->GetZoneId(); initWorldStates.SubareaID = player->GetAreaId(); for (auto& itr : ControlZoneHandlers) { ZMControlZoneHandler* handler = static_cast(itr.second.get()); initWorldStates.Worldstates.emplace_back(handler->GetWorldStateNeutralUI(), 0); initWorldStates.Worldstates.emplace_back(handler->GetWorldStateNeutralMap(), 0); initWorldStates.Worldstates.emplace_back(handler->GetWorldStateHordeUI(), 0); initWorldStates.Worldstates.emplace_back(handler->GetWorldStateHordeMap(), 0); initWorldStates.Worldstates.emplace_back(handler->GetWorldStateAllianceUI(), 0); initWorldStates.Worldstates.emplace_back(handler->GetWorldStateAllianceMap(), 0); } initWorldStates.Worldstates.emplace_back(ZM_MAP_GRAVEYARD_H, 0); initWorldStates.Worldstates.emplace_back(ZM_MAP_GRAVEYARD_A, 0); initWorldStates.Worldstates.emplace_back(ZM_MAP_GRAVEYARD_N, 0); initWorldStates.Worldstates.emplace_back(ZM_MAP_HORDE_FLAG_READY, 0); initWorldStates.Worldstates.emplace_back(ZM_MAP_HORDE_FLAG_NOT_READY, 0); initWorldStates.Worldstates.emplace_back(ZM_MAP_ALLIANCE_FLAG_NOT_READY, 0); initWorldStates.Worldstates.emplace_back(ZM_MAP_ALLIANCE_FLAG_READY, 0); player->SendDirectMessage(initWorldStates.Write()); } class OutdoorPvP_zangarmarsh : public OutdoorPvPScript { public: OutdoorPvP_zangarmarsh() : OutdoorPvPScript("outdoorpvp_zm") { } OutdoorPvP* GetOutdoorPvP(Map* map) const override { return new OutdoorPvPZM(map); } }; enum ZMFieldScoutMisc { GOSSIP_MENU_FIELD_SCOUT_HORDE = 7722, GOSSIP_MENU_FIELD_SCOUT_ALLIANCE = 7724, GOSSIP_OPTION_FIELD_SCOUT_BATTLE_STANDARD = 0, GOSSIP_OPTION_FIELD_SCOUT_VENDOR = 1, }; // 18581 - Alliance Field Scout // 18564 - Horde Field Scout struct npc_zm_field_scout : public ScriptedAI { npc_zm_field_scout(Creature* creature) : ScriptedAI(creature) { } bool CanObtainBanner(Player* player) { OutdoorPvP* pvp = player->GetOutdoorPvP(); if (!pvp) return false; OutdoorPvPZM* zmPvp = reinterpret_cast(pvp); if (!zmPvp) return false; OPvPCapturePointZM_Graveyard* gy = zmPvp->GetGraveyard(); if (!gy) return false; if (!gy->GetFlagCarrierGUID().IsEmpty()) return false; switch (me->GetEntry()) { case ZM_ALLIANCE_FIELD_SCOUT: return player->GetTeam() == ALLIANCE && pvp->GetWorldState(ZM_MAP_ALLIANCE_FLAG_READY); case ZM_HORDE_FIELD_SCOUT: return player->GetTeam() == HORDE && pvp->GetWorldState(ZM_MAP_HORDE_FLAG_READY); default: break; } return true; } bool OnGossipHello(Player* player) override { uint32 gossipMenuId = GOSSIP_MENU_FIELD_SCOUT_HORDE; if (me->GetEntry() == ZM_ALLIANCE_FIELD_SCOUT) gossipMenuId = GOSSIP_MENU_FIELD_SCOUT_ALLIANCE; InitGossipMenuFor(player, gossipMenuId); if (CanObtainBanner(player)) AddGossipItemFor(player, gossipMenuId, GOSSIP_OPTION_FIELD_SCOUT_BATTLE_STANDARD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); AddGossipItemFor(player, gossipMenuId, GOSSIP_OPTION_FIELD_SCOUT_VENDOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID()); return true; } bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override { uint32 const action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId); switch (action) { case GOSSIP_ACTION_INFO_DEF: { player->PlayerTalkClass->SendCloseGossip(); OutdoorPvP* pvp = player->GetOutdoorPvP(); if (!pvp) return true; OutdoorPvPZM* zmPvp = reinterpret_cast(pvp); if (!zmPvp) return true; OPvPCapturePointZM_Graveyard* gy = zmPvp->GetGraveyard(); if (!gy) return true; // if the flag is already taken, then return if (!gy->GetFlagCarrierGUID().IsEmpty()) return true; uint32 battleStandardSpell = ZM_BATTLE_STANDARD_H; if (me->GetEntry() == ZM_ALLIANCE_FIELD_SCOUT) battleStandardSpell = ZM_BATTLE_STANDARD_A; me->CastSpell(player, battleStandardSpell, true); gy->SetFlagCarrierGUID(player->GetGUID()); gy->UpdateTowerState(); break; } case GOSSIP_ACTION_TRADE: player->GetSession()->SendListInventory(me->GetGUID()); break; default: break; } return true; } }; void AddSC_outdoorpvp_zm() { new OutdoorPvP_zangarmarsh(); RegisterCreatureAI(npc_zm_field_scout); }