From 51a1a0aca9762947e3b3cdecd881b3f538227f47 Mon Sep 17 00:00:00 2001 From: spp Date: Mon, 14 Dec 2009 03:53:38 +0100 Subject: Wintergrasp: Normalization of names to fit OutdoorPvP system --HG-- branch : trunk --- .../scripts/scripts/northrend/wintergrasp.cpp | 2 +- src/game/BattleGroundHandler.cpp | 6 +- src/game/CMakeLists.txt | 4 +- src/game/Level2.cpp | 18 +- src/game/OutdoorPvP.h | 2 +- src/game/OutdoorPvPMgr.cpp | 4 +- src/game/OutdoorPvPWG.cpp | 1828 +++++++++++++++++++ src/game/OutdoorPvPWG.h | 325 ++++ src/game/Wintergrasp.cpp | 1865 -------------------- src/game/Wintergrasp.h | 305 ---- 10 files changed, 2171 insertions(+), 2188 deletions(-) create mode 100644 src/game/OutdoorPvPWG.cpp create mode 100644 src/game/OutdoorPvPWG.h delete mode 100644 src/game/Wintergrasp.cpp delete mode 100644 src/game/Wintergrasp.h (limited to 'src') diff --git a/src/bindings/scripts/scripts/northrend/wintergrasp.cpp b/src/bindings/scripts/scripts/northrend/wintergrasp.cpp index 53e6fca2af7..89b886083a5 100644 --- a/src/bindings/scripts/scripts/northrend/wintergrasp.cpp +++ b/src/bindings/scripts/scripts/northrend/wintergrasp.cpp @@ -15,7 +15,7 @@ */ #include "precompiled.h" -#include "Wintergrasp.h" +#include "OutdoorPvPWG.h" #define GOSSIP_HELLO_DEMO1 "Build catapult." #define GOSSIP_HELLO_DEMO2 "Build demolisher." diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index bcd446cadfa..8413198272e 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -36,7 +36,7 @@ #include "Opcodes.h" // Temporal fix to wintergrasp spirit guides till 3.2 -#include "Wintergrasp.h" +#include "OutdoorPvPWG.h" #include "OutdoorPvPMgr.h" // WG end @@ -601,7 +601,7 @@ void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data ) { // Wintergrasp Hack till 3.2 and it's implemented as BG if (GetPlayer()->GetZoneId() == 4197) { - OPvPWintergrasp *pvpWG = (OPvPWintergrasp*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); + OutdoorPvPWG *pvpWG = (OutdoorPvPWG*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); if (pvpWG && pvpWG->isWarTime()) pvpWG->SendAreaSpiritHealerQueryOpcode(_player, guid); } @@ -632,7 +632,7 @@ void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data ) { // Wintergrasp Hack till 3.2 and it's implemented as BG if (GetPlayer()->GetZoneId() == 4197) { - OPvPWintergrasp *pvpWG = (OPvPWintergrasp*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); + OutdoorPvPWG *pvpWG = (OutdoorPvPWG*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); if (pvpWG && pvpWG->isWarTime()) pvpWG->AddPlayerToResurrectQueue(guid, _player->GetGUID()); } diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index a657bb99c50..663e827812b 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -192,6 +192,8 @@ SET(game_STAT_SRCS OutdoorPvPTF.h OutdoorPvPZM.cpp OutdoorPvPZM.h + OutdoorPvPWG.cpp + OutdoorPvPWG.h Path.h PetAI.cpp PetAI.h @@ -290,8 +292,6 @@ SET(game_STAT_SRCS GroupReference.h GroupRefManager.h OutdoorPvPImpl.h - Wintergrasp.h - Wintergrasp.cpp ZoneScript.h ) add_definitions(-fopenmp) diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index 836acbb3174..3c2a7bf8f1d 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -40,7 +40,7 @@ #include #include #include "GlobalEvents.h" -#include "Wintergrasp.h" +#include "OutdoorPvPWG.h" #include "OutdoorPvPMgr.h" #include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand @@ -4240,7 +4240,7 @@ bool ChatHandler::HandleNpcSetLinkCommand(const char* args) bool ChatHandler::HandleWintergraspStatusCommand(const char* args) { - OPvPWintergrasp *pvpWG = (OPvPWintergrasp*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); + OutdoorPvPWG *pvpWG = (OutdoorPvPWG*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); if (!pvpWG || !sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) { @@ -4250,7 +4250,7 @@ bool ChatHandler::HandleWintergraspStatusCommand(const char* args) } PSendSysMessage(LANG_BG_WG_STATUS, objmgr.GetTrinityStringForDBCLocale( - pvpWG->GetTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE), + pvpWG->getDefenderTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE), secsToTimeString(pvpWG->GetTimer(), true).c_str(), pvpWG->isWarTime() ? "Yes" : "No", pvpWG->GetNumPlayersH(), @@ -4260,7 +4260,7 @@ bool ChatHandler::HandleWintergraspStatusCommand(const char* args) bool ChatHandler::HandleWintergraspStartCommand(const char* args) { - OPvPWintergrasp *pvpWG = (OPvPWintergrasp*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); + OutdoorPvPWG *pvpWG = (OutdoorPvPWG*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); if (!pvpWG || !sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) { @@ -4275,7 +4275,7 @@ bool ChatHandler::HandleWintergraspStartCommand(const char* args) bool ChatHandler::HandleWintergraspStopCommand(const char* args) { - OPvPWintergrasp *pvpWG = (OPvPWintergrasp*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); + OutdoorPvPWG *pvpWG = (OutdoorPvPWG*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); if (!pvpWG || !sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) { @@ -4293,7 +4293,7 @@ bool ChatHandler::HandleWintergraspEnableCommand(const char* args) if(!*args) return false; - OPvPWintergrasp *pvpWG = (OPvPWintergrasp*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); + OutdoorPvPWG *pvpWG = (OutdoorPvPWG*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); if (!pvpWG || !sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) { @@ -4335,7 +4335,7 @@ bool ChatHandler::HandleWintergraspTimerCommand(const char* args) if(!*args) return false; - OPvPWintergrasp *pvpWG = (OPvPWintergrasp*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); + OutdoorPvPWG *pvpWG = (OutdoorPvPWG*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); if (!pvpWG) { @@ -4367,7 +4367,7 @@ bool ChatHandler::HandleWintergraspTimerCommand(const char* args) bool ChatHandler::HandleWintergraspSwitchTeamCommand(const char* args) { - OPvPWintergrasp *pvpWG = (OPvPWintergrasp*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); + OutdoorPvPWG *pvpWG = (OutdoorPvPWG*)sOutdoorPvPMgr.GetOutdoorPvPToZoneId(4197); if (!pvpWG) { @@ -4378,6 +4378,6 @@ bool ChatHandler::HandleWintergraspSwitchTeamCommand(const char* args) uint32 timer = pvpWG->GetTimer(); pvpWG->forceChangeTeam(); pvpWG->setTimer(timer); - PSendSysMessage(LANG_BG_WG_SWITCH_FACTION, GetTrinityString(pvpWG->GetTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE)); + PSendSysMessage(LANG_BG_WG_SWITCH_FACTION, GetTrinityString(pvpWG->getDefenderTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE)); return true; } diff --git a/src/game/OutdoorPvP.h b/src/game/OutdoorPvP.h index 99f97451728..a68f0b84cf8 100644 --- a/src/game/OutdoorPvP.h +++ b/src/game/OutdoorPvP.h @@ -33,7 +33,7 @@ enum OutdoorPvPTypes OUTDOOR_PVP_ZM, OUTDOOR_PVP_SI, OUTDOOR_PVP_EP, - OPVP_WINTERGRASP, + OUTDOOR_PVP_WG, OUTDOOR_PVP_NR, }; diff --git a/src/game/OutdoorPvPMgr.cpp b/src/game/OutdoorPvPMgr.cpp index 4df07914b36..75f08e04e4e 100644 --- a/src/game/OutdoorPvPMgr.cpp +++ b/src/game/OutdoorPvPMgr.cpp @@ -23,7 +23,7 @@ #include "OutdoorPvPZM.h" #include "OutdoorPvPSI.h" #include "OutdoorPvPEP.h" -#include "Wintergrasp.h" +#include "OutdoorPvPWG.h" #include "Player.h" #include "Policies/SingletonImp.h" @@ -125,7 +125,7 @@ void OutdoorPvPMgr::InitOutdoorPvP() sLog.outDebug("OutdoorPvP : EP successfully initiated."); } - pOP = new OPvPWintergrasp; + pOP = new OutdoorPvPWG; // respawn, init variables if(!pOP->SetupOutdoorPvP()) { diff --git a/src/game/OutdoorPvPWG.cpp b/src/game/OutdoorPvPWG.cpp new file mode 100644 index 00000000000..28cf16645e6 --- /dev/null +++ b/src/game/OutdoorPvPWG.cpp @@ -0,0 +1,1828 @@ +/* + * Copyright (C) 2008-2009 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OutdoorPvPWG.h" +#include "SpellAuras.h" +#include "Vehicle.h" +#include "ObjectMgr.h" +#include "World.h" +#include "Chat.h" +#include "MapManager.h" + +void _LoadTeamPair(TeamPairMap &pairMap, const TeamPair *pair) +{ + while((*pair)[0]) + { + pairMap[(*pair)[0]] = (*pair)[1]; + pairMap[(*pair)[1]] = (*pair)[0]; + ++pair; + } +} + +void _RespawnCreatureIfNeeded(Creature *cr, uint32 entry) +{ + if (cr) + { + cr->SetOriginalEntry(entry); + if (entry != cr->GetEntry() || !cr->isAlive()) + cr->Respawn(true); + cr->SetVisibility(VISIBILITY_ON); + } +} + +OutdoorPvPWG::OutdoorPvPWG() +{ + m_TypeId = OUTDOOR_PVP_WG; + + m_LastResurrectTime = 0; // Temporal copy of BG system till 3.2 +} + +bool OutdoorPvPWG::SetupOutdoorPvP() +{ + if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) + { + sWorld.setState(WORLDSTATE_WINTERGRASP_CONTROLING_FACTION, TEAM_NEUTRAL); + return false; + } + + m_defender = TeamId(rand()%2); + sWorld.setState(WORLDSTATE_WINTERGRASP_CONTROLING_FACTION, getDefenderTeam()); + m_changeDefender = false; + m_workshopCount[TEAM_ALLIANCE] = 0; + m_workshopCount[TEAM_HORDE] = 0; + m_tenacityStack = 0; + m_gate = NULL; + + std::list engGuids; + std::list spiritGuids; + + // Store Eng, spirit guide guids and questgiver for later use + QueryResult *result = WorldDatabase.PQuery("SELECT guid, id FROM creature WHERE creature.map=571" + " AND creature.id IN (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);", + CRE_ENG_A, CRE_ENG_H, CRE_SPI_A, CRE_SPI_H, 31101, 31051, 31102, 31052, + 31107, 31109, 31151, 31153, 31106, 31108, 31053, 31054, 31091, 31036); + if (!result) + sLog.outError("Cannot find siege workshop master or spirit guides in creature!"); + else + { + do + { + Position posHorde, posAlli; + Field *fields = result->Fetch(); + switch(fields[1].GetUInt32()) + { + case CRE_ENG_A: + case CRE_ENG_H: + engGuids.push_back(fields[0].GetUInt32()); + break; + case CRE_SPI_A: + case CRE_SPI_H: + spiritGuids.push_back(fields[0].GetUInt32()); + break; + case 31051: + posHorde.Relocate(5081.7, 2173.73, 365.878, 0.855211); + posAlli.Relocate(5296.56, 2789.87, 409.275, 0.733038); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31101: + posHorde.Relocate(5296.56, 2789.87, 409.275, 0.733038); + posAlli.Relocate(5016.57, 3677.53, 362.982, 5.7525); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31052: + posHorde.Relocate(5100.07, 2168.89, 365.779, 1.97222); + posAlli.Relocate(5298.43, 2738.76, 409.316, 3.97174); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31102: + posHorde.Relocate(5298.43, 2738.76, 409.316, 3.97174); + posAlli.Relocate(5030.44, 3659.82, 363.194, 1.83336); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31109: + posHorde.Relocate(5080.4, 2199, 359.489, 2.96706); + posAlli.Relocate(5234.97, 2883.4, 409.275, 4.29351); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31107: + posHorde.Relocate(5234.97, 2883.4, 409.275, 4.29351); + posAlli.Relocate(5008.64, 3659.91, 361.07, 4.0796); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31153: + posHorde.Relocate(5088.49, 2188.18, 365.647, 5.25344); + posAlli.Relocate(5366.13, 2833.4, 409.323, 3.14159); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31151: + posHorde.Relocate(5366.13, 2833.4, 409.323, 3.14159); + posAlli.Relocate(5032.33, 3680.7, 363.018, 3.43167); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31108: + posHorde.Relocate(5095.67, 2193.28, 365.924, 4.93928); + posAlli.Relocate(5295.56, 2926.67, 409.275, 0.872665); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31106: + posHorde.Relocate(5295.56, 2926.67, 409.275, 0.872665); + posAlli.Relocate(5032.66, 3674.28, 363.053, 2.9447); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31054: + posHorde.Relocate(5088.61, 2167.66, 365.689, 0.680678); + posAlli.Relocate(5371.4, 3026.51, 409.206, 3.25003); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31053: + posHorde.Relocate(5371.4, 3026.51, 409.206, 3.25003); + posAlli.Relocate(5032.44, 3668.66, 363.11, 2.87402); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31036: + posHorde.Relocate(5078.28, 2183.7, 365.029, 1.46608); + posAlli.Relocate(5359.13, 2837.99, 409.364, 4.69893); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + case 31091: + posHorde.Relocate(5359.13, 2837.99, 409.364, 4.69893); + posAlli.Relocate(5022.43, 3659.91, 361.61, 1.35426); + LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); + break; + default: + break; + } + }while(result->NextRow()); + delete result; + } + + // Select POI + AreaPOIList areaPOIs; + float minX = 9999, minY = 9999, maxX = -9999, maxY = -9999; + for (uint32 i = 0; i < sAreaPOIStore.GetNumRows(); ++i) + { + const AreaPOIEntry * poiInfo = sAreaPOIStore.LookupEntry(i); + if (poiInfo && poiInfo->zoneId == ZONE_WINTERGRASP) + { + areaPOIs.push_back(poiInfo); + if (minX > poiInfo->x) minX = poiInfo->x; + if (minY > poiInfo->y) minY = poiInfo->y; + if (maxX < poiInfo->x) maxX = poiInfo->x; + if (maxY < poiInfo->y) maxY = poiInfo->y; + } + } + minX -= 20; minY -= 20; maxX += 20; maxY += 20; + + // Coords: 4290.330078, 1790.359985 - 5558.379883, 4048.889893 + result = WorldDatabase.PQuery("SELECT guid FROM gameobject,gameobject_template" + " WHERE gameobject.map=571" + " AND gameobject.position_x>%f AND gameobject.position_y>%f" + " AND gameobject.position_x<%f AND gameobject.position_y<%f" + " AND gameobject_template.type=33" + " AND gameobject.id=gameobject_template.entry", + minX, minY, maxX, maxY); + if (!result) + return false; + + do + { + Field *fields = result->Fetch(); + + uint32 guid = fields[0].GetUInt32(); + GameObjectData const * goData = objmgr.GetGOData(guid); + if (!goData) // this should not happen + continue; + + float x = goData->posX, y = goData->posY; + float minDist = 100; + AreaPOIList::iterator poi = areaPOIs.end(); + for (AreaPOIList::iterator itr = areaPOIs.begin(); itr != areaPOIs.end(); ++itr) + { + if (!(*itr)->icon[1]) // note: may for other use + continue; + + float dist = (abs((*itr)->x - x) + abs((*itr)->y - y)); + if (minDist > dist) + { + minDist = dist; + poi = itr; + } + } + + if (poi == areaPOIs.end()) + continue; + + // add building to the list + TeamId teamId = x > POS_X_CENTER ? getDefenderTeam() : getAttackerTeam(); + m_buildingStates[guid] = new BuildingState((*poi)->worldState, teamId, getDefenderTeam() != TEAM_ALLIANCE); + if ((*poi)->id == 2246) + m_gate = m_buildingStates[guid]; + areaPOIs.erase(poi); + + // add capture point + uint32 capturePointEntry = 0; + + switch(goData->id) + { + case 192028: // NW + case 192030: // W + case 192032: // SW + capturePointEntry = 190475; + break; + case 192029: // NE + case 192031: // E + case 192033: // SE + capturePointEntry = 190487; + break; + } + + if (capturePointEntry) + { + uint32 engGuid = 0; + uint32 spiritGuid = 0; + // Find closest Eng to Workshop + float minDist = 100; + for (std::list::iterator itr = engGuids.begin(); itr != engGuids.end(); ++itr) + { + const CreatureData *creData = objmgr.GetCreatureData(*itr); + if (!creData) + continue; + + float dist = (abs(creData->posX - x) + abs(creData->posY - y)); + if (minDist > dist) + { + minDist = dist; + engGuid = *itr; + } + } + + if (!engGuid) + { + sLog.outError("Cannot find nearby siege workshop master!"); + continue; + } + else + engGuids.remove(engGuid); + // Find closest Spirit Guide to Workshop + minDist = 255; + for (std::list::iterator itr = spiritGuids.begin(); itr != spiritGuids.end(); ++itr) + { + const CreatureData *creData = objmgr.GetCreatureData(*itr); + if (!creData) + continue; + + float dist = (abs(creData->posX - x) + abs(creData->posY - y)); + if (minDist > dist) + { + minDist = dist; + spiritGuid = *itr; + } + } + + // Inside fortress won't be capturable + OPvPCapturePointWG *workshop = new OPvPCapturePointWG(this, m_buildingStates[guid]); + if (goData->posX < POS_X_CENTER && !workshop->SetCapturePointData(capturePointEntry, goData->mapid, goData->posX + 40 * cos(goData->orientation + M_PI / 2), goData->posY + 40 * sin(goData->orientation + M_PI / 2), goData->posZ)) + { + delete workshop; + sLog.outError("Cannot add capture point!"); + continue; + } + + const CreatureData *creData = objmgr.GetCreatureData(engGuid); + if (!creData) + continue; + + workshop->m_engEntry = const_cast(&creData->id); + const_cast(creData)->displayid = 0; + workshop->m_engGuid = engGuid; + + // Back spirit is linked to one of the inside workshops, 1 workshop wont have spirit + if (spiritGuid) + { + spiritGuids.remove(spiritGuid); + + const CreatureData *spiritData = objmgr.GetCreatureData(spiritGuid); + if (!spiritData) + continue; + + workshop->m_spiEntry = const_cast(&spiritData->id); + const_cast(spiritData)->displayid = 0; + workshop->m_spiGuid = spiritGuid; + } + else + workshop->m_spiGuid = 0; + workshop->m_workshopGuid = guid; + AddCapturePoint(workshop); + m_buildingStates[guid]->type = BUILDING_WORKSHOP; + workshop->SetTeamByBuildingState(); + } + }while(result->NextRow()); + delete result; + + engGuids.clear(); + spiritGuids.clear(); + + if (!m_gate) + { + sLog.outError("Cannot find wintergrasp fortress gate!"); + return false; + } + + // Load Graveyard + GraveYardMap::const_iterator graveLow = objmgr.mGraveYardMap.lower_bound(ZONE_WINTERGRASP); + GraveYardMap::const_iterator graveUp = objmgr.mGraveYardMap.upper_bound(ZONE_WINTERGRASP); + for (AreaPOIList::iterator itr = areaPOIs.begin(); itr != areaPOIs.end();) + { + if ((*itr)->icon[1] == 8) + { + // find or create grave yard + const WorldSafeLocsEntry *loc = objmgr.GetClosestGraveYard((*itr)->x, (*itr)->y, (*itr)->z, (*itr)->mapId, 0); + if (!loc) + { + ++itr; + continue; + } + + GraveYardMap::const_iterator graveItr; + for (graveItr = graveLow; graveItr != graveUp; ++graveItr) + if (graveItr->second.safeLocId == loc->ID) + break; + if (graveItr == graveUp) + { + GraveYardData graveData; + graveData.safeLocId = loc->ID; + graveData.team = 0; + graveItr = objmgr.mGraveYardMap.insert(std::make_pair(ZONE_WINTERGRASP, graveData)); + } + + for (BuildingStateMap::iterator stateItr = m_buildingStates.begin(); stateItr != m_buildingStates.end(); ++stateItr) + { + if (stateItr->second->worldState == (*itr)->worldState) + { + stateItr->second->graveTeam = const_cast(&graveItr->second.team); + break; + } + } + areaPOIs.erase(itr++); + } + else + ++itr; + } + + //Titan Relic + objmgr.AddGOData(192829, 571, 5440, 2840.8, 420.43 + 10, 0); + + _LoadTeamPair(m_goDisplayPair, OutdoorPvPWGGODisplayPair); + _LoadTeamPair(m_creEntryPair, OutdoorPvPWGCreEntryPair); + + m_wartime = false; + m_timer = sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_START_TIME) * MINUTE * IN_MILISECONDS; + + m_towerDamagedCount[TEAM_ALLIANCE] = 0; + m_towerDestroyedCount[TEAM_ALLIANCE] = 0; + m_towerDamagedCount[TEAM_HORDE] = 0; + m_towerDestroyedCount[TEAM_HORDE] = 0; + + RemoveOfflinePlayerWGAuras(); + + RegisterZone(ZONE_WINTERGRASP); + return true; +} + +void OutdoorPvPWG::ProcessEvent(GameObject *obj, uint32 eventId) +{ + if (obj->GetEntry() == 192829) // Titan Relic + { + if (obj->GetGOInfo()->goober.eventId == eventId && isWarTime() && m_gate && m_gate->damageState == DAMAGE_DESTROYED) + { + m_changeDefender = true; + m_timer = 0; + } + } + else if (obj->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) + { + BuildingStateMap::const_iterator itr = m_buildingStates.find(obj->GetDBTableGUIDLow()); + if (itr == m_buildingStates.end()) + return; + + std::string msgStr; + switch(eventId) + { // TODO - Localized msgs of GO names + case 19672: case 19675: // Flamewatch Tower + msgStr = "Flamewatch"; + break; + case 18553: case 19677: // Shadowsight Tower + msgStr = "Shadowsight"; + break; + case 19673: case 19676: // Winter's Edge Tower + msgStr = "Winter's Edge"; + break; + case 19776: case 19778: // E Workshop damaged + msgStr = "Sunken Ring"; + break; + case 19777: case 19779: // W Workshop damaged + msgStr = "Broken Temple"; + break; + case 19782: case 19786: // NW Workshop damaged + msgStr = "north-western"; + break; + case 19783: case 19787: // NE Workshop damaged + msgStr = "north-eastern"; + break; + case 19784: case 19788: // SW Workshop damaged + msgStr = "Westpark"; + break; + case 19785: case 19789: // SE Workshop damaged + msgStr = "Eastpark"; + break; + case 19657: case 19661: // NW Wintergrasp Keep Tower damaged + msgStr = "north-western"; + break; + case 19658: case 19663: // NE Wintergrasp Keep Tower damaged + msgStr = "north-eastern"; + break; + case 19659: case 19662: // SW Wintergrasp Keep Tower damaged + msgStr = "south-western"; + break; + case 19660: case 19664: // SE Wintergrasp Keep Tower damaged + msgStr = "south-eastern"; + break; + default: + msgStr = ""; + } + + BuildingState *state = itr->second; + if (eventId == obj->GetGOInfo()->building.damagedEvent) + { + state->damageState = DAMAGE_DAMAGED; + switch(state->type) + { + case BUILDING_WORKSHOP: + msgStr = fmtstring(objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_WORKSHOP_DAMAGED), msgStr.c_str(), objmgr.GetTrinityStringForDBCLocale(getDefenderTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE)); + sWorld.SendZoneText(ZONE_WINTERGRASP, msgStr.c_str()); + break; + case BUILDING_WALL: + sWorld.SendZoneText(ZONE_WINTERGRASP, objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_FORTRESS_UNDER_ATTACK)); + break; + case BUILDING_TOWER: + ++m_towerDamagedCount[state->GetTeam()]; + msgStr = fmtstring(objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_TOWER_DAMAGED), msgStr.c_str()); + sWorld.SendZoneText(ZONE_WINTERGRASP, msgStr.c_str()); + break; + } + } + else if (eventId == obj->GetGOInfo()->building.destroyedEvent) + { + state->damageState = DAMAGE_DESTROYED; + + switch(state->type) + { + case BUILDING_WORKSHOP: + ModifyWorkshopCount(state->GetTeam(), false); + msgStr = fmtstring(objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_WORKSHOP_DESTROYED), msgStr.c_str(), objmgr.GetTrinityStringForDBCLocale(getDefenderTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE)); + sWorld.SendZoneText(ZONE_WINTERGRASP, msgStr.c_str()); + break; + case BUILDING_WALL: + sWorld.SendZoneText(ZONE_WINTERGRASP, objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_FORTRESS_UNDER_ATTACK)); + break; + case BUILDING_TOWER: + --m_towerDamagedCount[state->GetTeam()]; + ++m_towerDestroyedCount[state->GetTeam()]; + if (state->GetTeam() == getAttackerTeam()) + { + TeamCastSpell(getAttackerTeam(), -SPELL_TOWER_CONTROL); + TeamCastSpell(getDefenderTeam(), -SPELL_TOWER_CONTROL); + uint32 attStack = 3 - m_towerDestroyedCount[getAttackerTeam()]; + + if (m_towerDestroyedCount[getAttackerTeam()]) + { + for (PlayerSet::iterator itr = m_players[getDefenderTeam()].begin(); itr != m_players[getDefenderTeam()].end(); ++itr) + if ((*itr)->getLevel() > 69) + (*itr)->SetAuraStack(SPELL_TOWER_CONTROL, (*itr), m_towerDestroyedCount[getAttackerTeam()]); + } + + if (attStack) + { + for (PlayerSet::iterator itr = m_players[getAttackerTeam()].begin(); itr != m_players[getAttackerTeam()].end(); ++itr) + if ((*itr)->getLevel() > 69) + (*itr)->SetAuraStack(SPELL_TOWER_CONTROL, (*itr), attStack); + } + else + { + if (m_timer < 600000) + m_timer = 0; + else + m_timer = m_timer - 600000; // - 10 mins + } + } + msgStr = fmtstring(objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_TOWER_DESTROYED), msgStr.c_str()); + sWorld.SendZoneText(ZONE_WINTERGRASP, msgStr.c_str()); + break; + } + BroadcastStateChange(state); + } + } +} + +void OutdoorPvPWG::RemoveOfflinePlayerWGAuras() +{ + // if server crashed while in battle there could be players with rank or tenacity + CharacterDatabase.PExecute("DELETE FROM character_aura WHERE spell IN (%u, %u, %u, %u, %u)", + SPELL_RECRUIT, SPELL_CORPORAL, SPELL_LIEUTENANT, SPELL_TENACITY, SPELL_TOWER_CONTROL); +} + +void OutdoorPvPWG::ModifyWorkshopCount(TeamId team, bool add) +{ + if (team == TEAM_NEUTRAL) + return; + + if (add) + ++m_workshopCount[team]; + else if (m_workshopCount[team]) + --m_workshopCount[team]; + else + sLog.outError("OutdoorPvPWG::ModifyWorkshopCount: negative workshop count!"); + + SendUpdateWorldState(MaxVehNumWorldState[team], m_workshopCount[team] * MAX_VEHICLE_PER_WORKSHOP); +} + +uint32 OutdoorPvPWG::GetCreatureEntry(uint32 guidlow, const CreatureData *data) +{ + if (getDefenderTeam() == TEAM_ALLIANCE) + { + TeamPairMap::const_iterator itr = m_creEntryPair.find(data->id); + if (itr != m_creEntryPair.end()) + { + const_cast(data)->displayid = 0; + return itr->second; + } + } + return data->id; +} + +OutdoorPvPWGCreType OutdoorPvPWG::GetCreatureType(uint32 entry) const +{ + // VEHICLES, GUARDS and TURRETS gives kill credit + // OTHER Not in wartime + // TURRET Only during wartime + // SPECIAL like "OTHER" but no despawn conditions + // Entries like Case A: Case: B have their own despawn function + switch(entry) + { + case 27881: // Catapult + case 28094: // Demolisher + case 28312: // Alliance Siege Engine + case 32627: // Horde Siege Engine + case 28319: // Siege turret + case 32629: // Siege turret + return CREATURE_SIEGE_VEHICLE; + case 28366: // Wintergrasp Tower cannon + return CREATURE_TURRET; + case CRE_ENG_A: // Alliance Engineer + case CRE_ENG_H: // Horde Engineer + return CREATURE_ENGINEER; + case 30739:case 30740: // Champions + case 32307:case 32308: // Guards + return CREATURE_GUARD; + case CRE_SPI_A: // Dwarven Spirit Guide + case CRE_SPI_H: // Taunka Spirit Guide + return CREATURE_SPIRIT_GUIDE; + case 6491: // Spirit Healers + return CREATURE_SPIRIT_HEALER; + case 31101:case 31051: // Hoodoo Master & Sorceress + case 31102:case 31052: // Vieron Blazefeather & Bowyer + case 31107:case 31109: // Lieutenant & Senior Demolitionist + case 31151:case 31153: // Tactical Officer + case 31106:case 31108: // Siegesmith & Siege Master + case 31053:case 31054: // Primalist & Anchorite + case 31091:case 31036: // Commander + return CREATURE_QUESTGIVER; + case 32615:case 32626: // Warbringer && Brigadier General + case 32296:case 32294: // Quartermaster + case 30870:case 30869: // Flight Masters + return CREATURE_SPECIAL; + default: + return CREATURE_OTHER; // Revenants, Elementals, etc + } +} + +void OutdoorPvPWG::OnCreatureCreate(Creature *creature, bool add) +{ + uint32 entry = creature->GetEntry(); + switch(GetCreatureType(entry)) + { + case CREATURE_SIEGE_VEHICLE: + { + if (!creature->isSummon()) + return; + + TeamId team; + if (add) + { + if (creature->getFaction() == WintergraspFaction[TEAM_ALLIANCE]) + team = TEAM_ALLIANCE; + else if (creature->getFaction() == WintergraspFaction[TEAM_HORDE]) + team = TEAM_HORDE; + else + return; + + if (uint32 engLowguid = GUID_LOPART(((TempSummon*)creature)->GetSummonerGUID())) + { + if (OPvPCapturePointWG *workshop = GetWorkshopByEngGuid(engLowguid)) + { + if (CanBuildVehicle(workshop)) + { + m_vehicles[team].insert(creature); + //workshop->m_vehicles.insert(creature); + } + else + { + creature->setDeathState(DEAD); + creature->SetRespawnTime(DAY); + return; + } + } + } + + if (m_tenacityStack > 0 && team == TEAM_ALLIANCE) + creature->SetAuraStack(SPELL_TENACITY_VEHICLE, creature, m_tenacityStack); + else if (m_tenacityStack < 0 && team == TEAM_HORDE) + creature->SetAuraStack(SPELL_TENACITY_VEHICLE, creature, -m_tenacityStack); + } + else // the faction may be changed in uncharm + { + // TODO: now you have to wait until the corpse of vehicle disappear to build a new one + if (m_vehicles[TEAM_ALLIANCE].erase(creature)) + team = TEAM_ALLIANCE; + else if (m_vehicles[TEAM_HORDE].erase(creature)) + team = TEAM_HORDE; + else + return; + } + SendUpdateWorldState(VehNumWorldState[team], m_vehicles[team].size()); + break; + } + case CREATURE_QUESTGIVER: + m_questgivers[creature->GetDBTableGUIDLow()] = creature; + break; + case CREATURE_ENGINEER: + for (OutdoorPvP::OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + { + if (OPvPCapturePointWG *workshop = dynamic_cast(itr->second)) + if (workshop->m_engGuid == creature->GetDBTableGUIDLow()) + { + workshop->m_engineer = add ? creature : NULL; + break; + } + } + break; + case CREATURE_SPIRIT_GUIDE: + for (OutdoorPvP::OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + { + if (OPvPCapturePointWG *workshop = dynamic_cast(itr->second)) + if (workshop->m_spiGuid == creature->GetDBTableGUIDLow()) + { + workshop->m_spiritguide = add ? creature : NULL; + break; + } + } + creature->CastSpell(creature, SPELL_SPIRITUAL_IMMUNITY, true); + case CREATURE_SPIRIT_HEALER: + case CREATURE_TURRET: + case CREATURE_OTHER: + if (add) + UpdateCreatureInfo(creature); + default: + if (add) + m_creatures.insert(creature); + else + m_creatures.erase(creature); + break; + } +} + +void OutdoorPvPWG::OnGameObjectCreate(GameObject *go, bool add) +{ + OutdoorPvP::OnGameObjectCreate(go, add); + + if (UpdateGameObjectInfo(go)) + { + if (add) m_gobjects.insert(go); + else m_gobjects.erase(go); + } + //do we need to store building? + else if (go->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) + { + BuildingStateMap::const_iterator itr = m_buildingStates.find(go->GetDBTableGUIDLow()); + if (itr != m_buildingStates.end()) + { + itr->second->building = add ? go : NULL; + if (go->GetGOInfo()->displayId == 7878 || go->GetGOInfo()->displayId == 7900) + itr->second->type = BUILDING_TOWER; + if (!add || itr->second->damageState == DAMAGE_INTACT && !itr->second->health) + itr->second->health = go->GetGOValue()->building.health; + else + { + go->GetGOValue()->building.health = itr->second->health; + if (itr->second->damageState == DAMAGE_DAMAGED) + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED); + else if (itr->second->damageState == DAMAGE_DESTROYED) + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); + } + } + } +} + +void OutdoorPvPWG::UpdateAllWorldObject() +{ + // update cre and go factions + for (GameObjectSet::iterator itr = m_gobjects.begin(); itr != m_gobjects.end(); ++itr) + UpdateGameObjectInfo(*itr); + for (CreatureSet::iterator itr = m_creatures.begin(); itr != m_creatures.end(); ++itr) + UpdateCreatureInfo(*itr); + for (QuestGiverMap::iterator itr = m_questgivers.begin(); itr != m_questgivers.end(); ++itr) + UpdateQuestGiverPosition((*itr).first, (*itr).second); + + // rebuild and update building states + RebuildAllBuildings(); + + // update capture points + for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + if (OPvPCapturePointWG *workshop = dynamic_cast(itr->second)) + workshop->SetTeamByBuildingState(); +} + +void OutdoorPvPWG::RebuildAllBuildings() +{ + for (BuildingStateMap::const_iterator itr = m_buildingStates.begin(); itr != m_buildingStates.end(); ++itr) + { + if (itr->second->building) + { + UpdateGameObjectInfo(itr->second->building); + itr->second->building->Rebuild(); + itr->second->health = itr->second->building->GetGOValue()->building.health; + } + else + itr->second->health = 0; + + if (itr->second->damageState == DAMAGE_DESTROYED) + { + if (itr->second->type == BUILDING_WORKSHOP) + ModifyWorkshopCount(itr->second->GetTeam(), true); + } + + itr->second->damageState = DAMAGE_INTACT; + itr->second->SetTeam(getDefenderTeam() == TEAM_ALLIANCE ? OTHER_TEAM(itr->second->defaultTeam) : itr->second->defaultTeam); + } + m_towerDamagedCount[TEAM_ALLIANCE] = 0; + m_towerDestroyedCount[TEAM_ALLIANCE] = 0; + m_towerDamagedCount[TEAM_HORDE] = 0; + m_towerDestroyedCount[TEAM_HORDE] = 0; +} + +void OutdoorPvPWG::SendInitWorldStatesTo(Player *player) const +{ + WorldPacket data(SMSG_INIT_WORLD_STATES, (4+4+4+2+(m_buildingStates.size()*8))); + data << uint32(571); + data << uint32(ZONE_WINTERGRASP); + data << uint32(0); + data << uint16(4+5+4+m_buildingStates.size()); + + data << uint32(3803) << uint32(getDefenderTeam() == TEAM_ALLIANCE ? 1 : 0); + data << uint32(3802) << uint32(getDefenderTeam() != TEAM_ALLIANCE ? 1 : 0); + data << uint32(3801) << uint32(isWarTime() ? 0 : 1); + data << uint32(3710) << uint32(isWarTime() ? 1 : 0); + + for (uint32 i = 0; i < 5; ++i) + data << ClockWorldState[i] << m_clock[i]; + + data << uint32(3490) << uint32(m_vehicles[TEAM_HORDE].size()); + data << uint32(3491) << m_workshopCount[TEAM_HORDE] * MAX_VEHICLE_PER_WORKSHOP; + data << uint32(3680) << uint32(m_vehicles[TEAM_ALLIANCE].size()); + data << uint32(3681) << m_workshopCount[TEAM_ALLIANCE] * MAX_VEHICLE_PER_WORKSHOP; + + for (BuildingStateMap::const_iterator itr = m_buildingStates.begin(); itr != m_buildingStates.end(); ++itr) + itr->second->FillData(data); + + if (player) + player->GetSession()->SendPacket(&data); + else + BroadcastPacket(data); +} + +void OutdoorPvPWG::BroadcastStateChange(BuildingState *state) const +{ + if (m_sendUpdate) + for (uint32 team = 0; team < 2; ++team) + for (PlayerSet::const_iterator p_itr = m_players[team].begin(); p_itr != m_players[team].end(); ++p_itr) + state->SendUpdate(*p_itr); +} + +// Called at Start and Battle End +bool OutdoorPvPWG::UpdateCreatureInfo(Creature *creature) +{ + if (!creature) + return false; + uint32 entry = creature->GetEntry(); + switch(GetCreatureType(entry)) + { + case CREATURE_TURRET: + if (isWarTime()) + { + if (!creature->isAlive()) + creature->Respawn(true); + creature->setFaction(WintergraspFaction[getDefenderTeam()]); + creature->SetVisibility(VISIBILITY_ON); + } + else + { + if (creature->IsVehicle() && creature->GetVehicleKit()) + creature->GetVehicleKit()->RemoveAllPassengers(); + creature->SetVisibility(VISIBILITY_OFF); + creature->setFaction(35); + } + return false; + case CREATURE_OTHER: + if (isWarTime()) + { + creature->SetVisibility(VISIBILITY_OFF); + creature->setFaction(35); + } + else + { + creature->RestoreFaction(); + creature->SetVisibility(VISIBILITY_ON); + } + return false; + case CREATURE_SPIRIT_GUIDE: + if (isWarTime()) + { + creature->SetVisibility(VISIBILITY_ON); + //creature->setDeathState(ALIVE); + } + else + { + creature->SetVisibility(VISIBILITY_OFF); + //creature->setDeathState(DEAD); + } + return false; + case CREATURE_SPIRIT_HEALER: + creature->SetVisibility(isWarTime() ? VISIBILITY_OFF : VISIBILITY_ON); + return false; + case CREATURE_ENGINEER: + return false; + case CREATURE_SIEGE_VEHICLE: + //creature->DisappearAndDie(); + return false; + case CREATURE_GUARD: + case CREATURE_SPECIAL: + { + TeamPairMap::const_iterator itr = m_creEntryPair.find(creature->GetCreatureData()->id); + if (itr != m_creEntryPair.end()) + { + entry = getDefenderTeam() == TEAM_ALLIANCE ? itr->second : itr->first; + _RespawnCreatureIfNeeded(creature, entry); + } + return false; + } + default: + return false; + } +} + +bool OutdoorPvPWG::UpdateQuestGiverPosition(uint32 guid, Creature *creature) +{ + assert(guid); + Position pos = m_qgPosMap[std::pair(guid, getDefenderTeam() == TEAM_HORDE)]; + + if (creature && creature->IsInWorld()) + { + // if not questgiver or position is the same, do nothing + if (creature->GetPositionX() == pos.GetPositionX() && + creature->GetPositionY() == pos.GetPositionY() && + creature->GetPositionZ() == pos.GetPositionZ()) + return false; + + if (creature->isAlive() && creature->isInCombat()) + { + creature->CombatStop(true); + creature->getHostilRefManager().deleteReferences(); + } + creature->SetHomePosition(pos); + creature->DestroyForNearbyPlayers(); + if (!creature->GetMap()->IsLoaded(pos.GetPositionX(), pos.GetPositionY())) + creature->GetMap()->LoadGrid(pos.GetPositionX(), pos.GetPositionY()); + creature->GetMap()->CreatureRelocation(creature, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); + if (!creature->isAlive()) + creature->Respawn(true); + } + else + objmgr.MoveCreData(guid, 571, pos); + + return true; +} + +// Return false = Need to rebuild at battle End/Start +// true = no need to rebuild (ie: Banners or teleporters) +bool OutdoorPvPWG::UpdateGameObjectInfo(GameObject *go) const +{ + uint32 attFaction = 35; + uint32 defFaction = 35; + + if (isWarTime()) + { + attFaction = WintergraspFaction[getAttackerTeam()]; + defFaction = WintergraspFaction[getDefenderTeam()]; + } + + switch(go->GetGOInfo()->displayId) + { + case 8244: // Defender's Portal - Vehicle Teleporter + go->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[getDefenderTeam()]); + return true; + case 7967: // Titan relic + go->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[getAttackerTeam()]); + return true; + + case 8165: // Wintergrasp Keep Door + case 7877: // Wintergrasp Fortress Wall + case 7878: // Wintergrasp Keep Tower + case 7906: // Wintergrasp Fortress Gate + case 7909: // Wintergrasp Wall + go->SetUInt32Value(GAMEOBJECT_FACTION, defFaction); + return false; + case 7900: // Flamewatch Tower - Shadowsight Tower - Winter's Edge Tower + go->SetUInt32Value(GAMEOBJECT_FACTION, attFaction); + return false; + case 8208: // Goblin Workshop + OPvPCapturePointWG *workshop = GetWorkshopByGOGuid(go->GetGUID()); + if (workshop) + go->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[workshop->m_buildingState->GetTeam()]); + return false; + } + + // Note: this is only for test, still need db support + TeamPairMap::const_iterator itr = m_goDisplayPair.find(go->GetGOInfo()->displayId); + if (itr != m_goDisplayPair.end()) + { + go->SetUInt32Value(GAMEOBJECT_DISPLAYID, getDefenderTeam() == TEAM_ALLIANCE ? + itr->second : itr->first); + return true; + } + return false; +} + +void OutdoorPvPWG::HandlePlayerEnterZone(Player * plr, uint32 zone) +{ + if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) + return; + + if (isWarTime()) + { + if (plr->getLevel() > 69) + { + if (!plr->HasAura(SPELL_RECRUIT) && !plr->HasAura(SPELL_CORPORAL) + && !plr->HasAura(SPELL_LIEUTENANT)) + plr->CastSpell(plr, SPELL_RECRUIT, true); + if (plr->GetTeamId() == getAttackerTeam()) + { + if (m_towerDestroyedCount[getAttackerTeam()] < 3) + plr->SetAuraStack(SPELL_TOWER_CONTROL, plr, 3 - m_towerDestroyedCount[getAttackerTeam()]); + } + else + { + if (m_towerDestroyedCount[getAttackerTeam()]) + plr->SetAuraStack(SPELL_TOWER_CONTROL, plr, m_towerDestroyedCount[getAttackerTeam()]); + } + } + } + + SendInitWorldStatesTo(plr); + OutdoorPvP::HandlePlayerEnterZone(plr, zone); + UpdateTenacityStack(); +} + +// Reapply Auras if needed +void OutdoorPvPWG::HandlePlayerResurrects(Player * plr, uint32 zone) +{ + if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) + return; + + if (isWarTime()) + { + if (plr->getLevel() > 69) + { + // Tenacity + if (plr->GetTeamId() == TEAM_ALLIANCE && m_tenacityStack > 0 || + plr->GetTeamId() == TEAM_HORDE && m_tenacityStack < 0) + { + if (plr->HasAura(SPELL_TENACITY)) + plr->RemoveAurasDueToSpell(SPELL_TENACITY); + + int32 newStack = m_tenacityStack < 0 ? -m_tenacityStack : m_tenacityStack; + if (newStack > 20) + newStack = 20; + plr->SetAuraStack(SPELL_TENACITY, plr, newStack); + } + + // Tower Control + if (plr->GetTeamId() == getAttackerTeam()) + { + if (m_towerDestroyedCount[getAttackerTeam()] < 3) + plr->SetAuraStack(SPELL_TOWER_CONTROL, plr, 3 - m_towerDestroyedCount[getAttackerTeam()]); + } + else + { + if (m_towerDestroyedCount[getAttackerTeam()]) + plr->SetAuraStack(SPELL_TOWER_CONTROL, plr, m_towerDestroyedCount[getAttackerTeam()]); + } + } + } + OutdoorPvP::HandlePlayerResurrects(plr, zone); +} + +void OutdoorPvPWG::HandlePlayerLeaveZone(Player * plr, uint32 zone) +{ + if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) + return; + + if (!plr->GetSession()->PlayerLogout()) + { + if (plr->GetVehicle()) // dismiss in change zone case + plr->GetVehicle()->Dismiss(); + plr->RemoveAurasDueToSpell(SPELL_RECRUIT); + plr->RemoveAurasDueToSpell(SPELL_CORPORAL); + plr->RemoveAurasDueToSpell(SPELL_LIEUTENANT); + plr->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + plr->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY); + } + plr->RemoveAurasDueToSpell(SPELL_TENACITY); + OutdoorPvP::HandlePlayerLeaveZone(plr, zone); + UpdateTenacityStack(); +} + +void OutdoorPvPWG::PromotePlayer(Player *killer) const +{ + Aura *aur; + if (aur = killer->GetAura(SPELL_RECRUIT)) + { + if (aur->GetStackAmount() >= 5) + { + killer->RemoveAura(SPELL_RECRUIT); + killer->CastSpell(killer, SPELL_CORPORAL, true); + ChatHandler(killer).PSendSysMessage(LANG_BG_WG_RANK1); + } + else + killer->CastSpell(killer, SPELL_RECRUIT, true); + } + else if (aur = killer->GetAura(SPELL_CORPORAL)) + { + if (aur->GetStackAmount() >= 5) + { + killer->RemoveAura(SPELL_CORPORAL); + killer->CastSpell(killer, SPELL_LIEUTENANT, true); + ChatHandler(killer).PSendSysMessage(LANG_BG_WG_RANK2); + } + else + killer->CastSpell(killer, SPELL_CORPORAL, true); + } +} + +void OutdoorPvPWG::HandleKill(Player *killer, Unit *victim) +{ + if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED) || !isWarTime()) + return; + + bool ok = false; + if (victim->GetTypeId() == TYPEID_PLAYER) + { + if (victim->getLevel() >= 70) + ok = true; + killer->RewardPlayerAndGroupAtEvent(CRE_PVP_KILL, victim); + } + else + { + switch(GetCreatureType(victim->GetEntry())) + { + case CREATURE_SIEGE_VEHICLE: + killer->RewardPlayerAndGroupAtEvent(CRE_PVP_KILL_V, victim); + ok = true; + break; + case CREATURE_GUARD: + killer->RewardPlayerAndGroupAtEvent(CRE_PVP_KILL, victim); + ok = true; + break; + case CREATURE_TURRET: + ok = true; + break; + } + } + + if (ok) + { + if (Group *pGroup = killer->GetGroup()) + { + for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + if (itr->getSource()->IsAtGroupRewardDistance(killer) && itr->getSource()->getLevel() > 69) + PromotePlayer(itr->getSource()); + } + else if (killer->getLevel() > 69) + PromotePlayer(killer); + } +} + +// Recalculates Tenacity and applies it to Players / Vehicles +void OutdoorPvPWG::UpdateTenacityStack() +{ + if (!isWarTime()) + return; + + TeamId team = TEAM_NEUTRAL; + uint32 allianceNum = 0; + uint32 hordeNum = 0; + int32 newStack = 0; + + for (PlayerSet::iterator itr = m_players[TEAM_ALLIANCE].begin(); itr != m_players[TEAM_ALLIANCE].end(); ++itr) + if ((*itr)->getLevel() > 69) + ++allianceNum; + + for (PlayerSet::iterator itr = m_players[TEAM_HORDE].begin(); itr != m_players[TEAM_HORDE].end(); ++itr) + if ((*itr)->getLevel() > 69) + ++hordeNum; + + if (allianceNum && hordeNum) + { + if (allianceNum < hordeNum) + newStack = int32((float(hordeNum) / float(allianceNum) - 1)*4); // positive, should cast on alliance + else if (allianceNum > hordeNum) + newStack = int32((1 - float(allianceNum) / float(hordeNum))*4); // negative, should cast on horde + } + + if (newStack == m_tenacityStack) + return; + + if (m_tenacityStack > 0 && newStack <= 0) // old buff was on alliance + team = TEAM_ALLIANCE; + else if (m_tenacityStack < 0 && newStack >= 0) // old buff was on horde + team = TEAM_HORDE; + + m_tenacityStack = newStack; + + // Remove old buff + if (team != TEAM_NEUTRAL) + { + for (PlayerSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) + if ((*itr)->getLevel() > 69) + (*itr)->RemoveAurasDueToSpell(SPELL_TENACITY); + + for (CreatureSet::const_iterator itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) + (*itr)->RemoveAurasDueToSpell(SPELL_TENACITY_VEHICLE); + } + + // Apply new buff + if (newStack) + { + team = newStack > 0 ? TEAM_ALLIANCE : TEAM_HORDE; + if (newStack < 0) + newStack = -newStack; + if (newStack > 20) + newStack = 20; + + for (PlayerSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) + if ((*itr)->getLevel() > 69) + (*itr)->SetAuraStack(SPELL_TENACITY, (*itr), newStack); + + for (CreatureSet::const_iterator itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) + (*itr)->SetAuraStack(SPELL_TENACITY_VEHICLE, (*itr), newStack); + } +} + +void OutdoorPvPWG::UpdateClockDigit(uint32 &timer, uint32 digit, uint32 mod) +{ + uint32 value = timer%mod; + timer /= mod; + if (m_clock[digit] != value) + { + m_clock[digit] = value; + SendUpdateWorldState(ClockWorldState[digit], value); + } +} + +void OutdoorPvPWG::UpdateClock() +{ + uint32 timer = m_timer / 1000; + UpdateClockDigit(timer, 0, 10); + UpdateClockDigit(timer, 1, 6); + UpdateClockDigit(timer, 2, 10); + UpdateClockDigit(timer, 3, 6); + if (!isWarTime()) + UpdateClockDigit(timer, 4, 10); +} + +bool OutdoorPvPWG::Update(uint32 diff) +{ + if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) + return false; + + if (m_timer > diff) + { + m_timer -= diff; + + if (isWarTime()) + { + OutdoorPvP::Update(diff); // update capture points + + /*********************************************************/ + /*** BATTLEGROUND RESSURECTION SYSTEM ***/ + /*********************************************************/ + + //this should be handled by spell system + m_LastResurrectTime += diff; + if (m_LastResurrectTime >= RESURRECTION_INTERVAL) + { + if (GetReviveQueueSize()) + { + for (std::map >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr) + { + Creature *sh = NULL; + for (std::vector::const_iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2) + { + Player *plr = objmgr.GetPlayer(*itr2); + if (!plr) + continue; + + if (!sh && plr->IsInWorld()) + { + sh = plr->GetMap()->GetCreature(itr->first); + // only for visual effect + if (sh) + // Spirit Heal, effect 117 + sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true); + } + + // Resurrection visual + plr->CastSpell(plr, SPELL_RESURRECTION_VISUAL, true); + m_ResurrectQueue.push_back(*itr2); + } + (itr->second).clear(); + } + + m_ReviveQueue.clear(); + m_LastResurrectTime = 0; + } + else + // queue is clear and time passed, just update last resurrection time + m_LastResurrectTime = 0; + } + else if (m_LastResurrectTime > 500) // Resurrect players only half a second later, to see spirit heal effect on NPC + { + for (std::vector::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr) + { + Player *plr = objmgr.GetPlayer(*itr); + if (!plr) + continue; + plr->ResurrectPlayer(1.0f); + plr->CastSpell(plr, 6962, true); + plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true); + ObjectAccessor::Instance().ConvertCorpseForPlayer(*itr); + } + m_ResurrectQueue.clear(); + } + } + UpdateClock(); + } + else + { + m_sendUpdate = false; + int32 entry = LANG_BG_WG_DEFENDED; + + if (m_changeDefender) + { + m_changeDefender = false; + m_defender = getAttackerTeam(); + entry = LANG_BG_WG_CAPTURED; + } + + if (isWarTime()) + { + if (m_timer != 1) // 1 = forceStopBattle + sWorld.SendZoneText(ZONE_WINTERGRASP, fmtstring(objmgr.GetTrinityStringForDBCLocale(entry), objmgr.GetTrinityStringForDBCLocale(getDefenderTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE))); + EndBattle(); + } + else + { + if (m_timer != 1) // 1 = forceStartBattle + sWorld.SendZoneText(ZONE_WINTERGRASP, objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_BATTLE_STARTS)); + StartBattle(); + } + + UpdateAllWorldObject(); + UpdateClock(); + + SendInitWorldStatesTo(); + m_sendUpdate = true; + } + + return false; +} + +void OutdoorPvPWG::forceStartBattle() +{ // Uptime will do all the work + m_wartime = false; + + if (m_timer != 1) + { + m_timer = 1; + sWorld.SendZoneText(ZONE_WINTERGRASP, objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_BATTLE_FORCE_START)); + } +} + +void OutdoorPvPWG::forceStopBattle() +{ // Uptime will do all the work. + + if (!isWarTime()) + m_wartime = true; + + if (m_timer != 1) + { + m_timer = 1; + sWorld.SendZoneText(ZONE_WINTERGRASP, objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_BATTLE_FORCE_STOP)); + } +} + +void OutdoorPvPWG::forceChangeTeam() +{ + m_changeDefender = true; + m_timer = 1; + sWorld.SendZoneText(ZONE_WINTERGRASP, fmtstring(objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_SWITCH_FACTION), objmgr.GetTrinityStringForDBCLocale(getAttackerTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE))); + if (isWarTime()) + forceStartBattle(); + else + forceStopBattle(); +} + +// Can be forced by gm's while in battle so have to reset in case it was wartime +void OutdoorPvPWG::StartBattle() +{ + m_wartime = true; + m_timer = sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_BATTLE_TIME) * MINUTE * IN_MILISECONDS; + + // Remove Essence of Wintergrasp to all players + sWorld.setState(WORLDSTATE_WINTERGRASP_CONTROLING_FACTION, TEAM_NEUTRAL); + sWorld.UpdateAreaDependentAuras(); + + // destroyed all vehicles + for (uint32 team = 0; team < 2; ++team) + { + while(!m_vehicles[team].empty()) + { + Creature *veh = *m_vehicles[team].begin(); + m_vehicles[team].erase(m_vehicles[team].begin()); + veh->setDeathState(JUST_DIED); + } + } + + // Remove All Wintergrasp auras. Add Recruit rank and Tower Control + for (PlayerSet::iterator itr = m_players[getAttackerTeam()].begin(); itr != m_players[getAttackerTeam()].end(); ++itr) + { + (*itr)->RemoveAurasDueToSpell(SPELL_RECRUIT); + (*itr)->RemoveAurasDueToSpell(SPELL_CORPORAL); + (*itr)->RemoveAurasDueToSpell(SPELL_LIEUTENANT); + (*itr)->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + (*itr)->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY); + if ((*itr)->getLevel() > 69) + { + (*itr)->SetAuraStack(SPELL_TOWER_CONTROL, (*itr), 3); + (*itr)->CastSpell(*itr, SPELL_RECRUIT, true); + } + } + + // Remove All Wintergrasp auras. Add Recruit rank + for (PlayerSet::iterator itr = m_players[getDefenderTeam()].begin(); itr != m_players[getDefenderTeam()].end(); ++itr) + { + (*itr)->RemoveAurasDueToSpell(SPELL_RECRUIT); + (*itr)->RemoveAurasDueToSpell(SPELL_CORPORAL); + (*itr)->RemoveAurasDueToSpell(SPELL_LIEUTENANT); + (*itr)->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + (*itr)->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY); + if ((*itr)->getLevel() > 69) + (*itr)->CastSpell(*itr, SPELL_RECRUIT, true); + } + UpdateTenacityStack(); +} + +void OutdoorPvPWG::EndBattle() +{ + // Cast Essence of Wintergrasp to all players (CheckCast will determine who to cast) + sWorld.setState(WORLDSTATE_WINTERGRASP_CONTROLING_FACTION, getDefenderTeam()); + sWorld.UpdateAreaDependentAuras(); + + for (uint32 team = 0; team < 2; ++team) + { + // destroyed all vehicles + while(!m_vehicles[team].empty()) + { + Creature *veh = *m_vehicles[team].begin(); + m_vehicles[team].erase(m_vehicles[team].begin()); + veh->setDeathState(JUST_DIED); + } + + if (m_players[team].empty()) + continue; + + for (PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) + { + // When WG ends the zone is cleaned including corpses, revive all players if dead + if ((*itr)->isDead()) + { + (*itr)->ResurrectPlayer(1.0f); + ObjectAccessor::Instance().ConvertCorpseForPlayer((*itr)->GetGUID()); + } + (*itr)->RemoveAurasDueToSpell(SPELL_TENACITY); + (*itr)->CombatStop(true); + (*itr)->getHostilRefManager().deleteReferences(); + } + + if (m_timer == 1) // Battle End was forced so no reward. + { + for (PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) + { + (*itr)->RemoveAurasDueToSpell(SPELL_RECRUIT); + (*itr)->RemoveAurasDueToSpell(SPELL_CORPORAL); + (*itr)->RemoveAurasDueToSpell(SPELL_LIEUTENANT); + (*itr)->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + (*itr)->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY); + } + continue; + } + + // calculate rewards + uint32 intactNum = 0; + uint32 damagedNum = 0; + for (OutdoorPvP::OPvPCapturePointMap::const_iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + if (OPvPCapturePointWG *workshop = dynamic_cast(itr->second)) + if (workshop->m_buildingState->GetTeam() == team) + if (workshop->m_buildingState->damageState == DAMAGE_DAMAGED) + ++damagedNum; + else if (workshop->m_buildingState->damageState == DAMAGE_INTACT) + ++intactNum; + + uint32 spellRewardId = team == getDefenderTeam() ? SPELL_VICTORY_REWARD : SPELL_DEFEAT_REWARD; + uint32 baseHonor = 0; + uint32 marks = 0; + uint32 playersWithRankNum = 0; + uint32 honor = 0; + + if (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_CUSTOM_HONOR)) + { + // Calculate Level 70+ with Corporal or Lieutenant rank + for (PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) + if ((*itr)->getLevel() > 69 && ((*itr)->HasAura(SPELL_LIEUTENANT) || (*itr)->HasAura(SPELL_CORPORAL))) + ++playersWithRankNum; + + baseHonor = team == getDefenderTeam() ? sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_WIN_BATTLE) : sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_LOSE_BATTLE); + baseHonor += (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_DAMAGED_TOWER) * m_towerDamagedCount[OTHER_TEAM(team)]); + baseHonor += (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_DESTROYED_TOWER) * m_towerDestroyedCount[OTHER_TEAM(team)]); + baseHonor += (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_INTACT_BUILDING) * intactNum); + baseHonor += (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_DAMAGED_BUILDING) * damagedNum); + if (playersWithRankNum) + baseHonor /= playersWithRankNum; + } + + for (PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) + { + + if ((*itr)->getLevel() < 70) + continue; // No rewards for level <70 + + // give rewards + if (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_CUSTOM_HONOR)) + { + if (team == getDefenderTeam()) + { + if ((*itr)->HasAura(SPELL_LIEUTENANT)) + { + marks = 3; + honor = baseHonor; + } + else if ((*itr)->HasAura(SPELL_CORPORAL)) + { + marks = 2; + honor = baseHonor; + } + else + { + marks = 1; + honor = 0; + } + } + else + { + if ((*itr)->HasAura(SPELL_LIEUTENANT)) + { + marks = 1; + honor = baseHonor; + } + else if ((*itr)->HasAura(SPELL_CORPORAL)) + { + marks = 1; + honor = baseHonor; + } + else + { + marks = 0; + honor = 0; + } + } + (*itr)->RewardHonor(NULL, 1, honor); + RewardMarkOfHonor(*itr, marks); + (*itr)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, spellRewardId); + } + else + { + if ((*itr)->HasAura(SPELL_LIEUTENANT) || (*itr)->HasAura(SPELL_CORPORAL)) + { + // TODO - Honor from SpellReward should be shared by team players + // TODO - Marks should be given depending on Rank but 3 are given + // each time so Won't give any to recruits + (*itr)->CastSpell(*itr, spellRewardId, true); + for (uint32 i = 0; i < intactNum; ++i) + (*itr)->CastSpell(*itr, SPELL_INTACT_BUILDING, true); + for (uint32 i = 0; i < damagedNum; ++i) + (*itr)->CastSpell(*itr, SPELL_DAMAGED_BUILDING, true); + for (uint32 i = 0; i < m_towerDamagedCount[OTHER_TEAM(team)]; ++i) + (*itr)->CastSpell(*itr, SPELL_DAMAGED_TOWER, true); + for (uint32 i = 0; i < m_towerDestroyedCount[OTHER_TEAM(team)]; ++i) + (*itr)->CastSpell(*itr, SPELL_DESTROYED_TOWER, true); + } + } + if (team == getDefenderTeam()) + { + if ((*itr)->HasAura(SPELL_LIEUTENANT) || (*itr)->HasAura(SPELL_CORPORAL)) + { + (*itr)->AreaExploredOrEventHappens(A_VICTORY_IN_WG); + (*itr)->AreaExploredOrEventHappens(H_VICTORY_IN_WG); + } + } + (*itr)->RemoveAurasDueToSpell(SPELL_RECRUIT); + (*itr)->RemoveAurasDueToSpell(SPELL_CORPORAL); + (*itr)->RemoveAurasDueToSpell(SPELL_LIEUTENANT); + (*itr)->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + (*itr)->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY); + } + } + + m_wartime = false; + m_timer = sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_INTERVAL) * MINUTE * IN_MILISECONDS; + //3.2.0: TeamCastSpell(getAttackerTeam(), SPELL_TELEPORT_DALARAN); + RemoveOfflinePlayerWGAuras(); +} + +bool OutdoorPvPWG::CanBuildVehicle(OPvPCapturePointWG *workshop) const +{ + TeamId team = workshop->m_buildingState->GetTeam(); + if (team == TEAM_NEUTRAL) + return false; + + return isWarTime() + && workshop->m_buildingState->damageState != DAMAGE_DESTROYED + && m_vehicles[team].size() < m_workshopCount[team] * MAX_VEHICLE_PER_WORKSHOP; +} + +uint32 OutdoorPvPWG::GetData(uint32 id) +{ + // if can build more vehicles + if (OPvPCapturePointWG *workshop = GetWorkshopByEngGuid(id)) + return CanBuildVehicle(workshop) ? 1 : 0; + + return 0; +} + +void OutdoorPvPWG::RewardMarkOfHonor(Player *plr, uint32 count) +{ + // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens + if (plr->HasAura(SPELL_AURA_PLAYER_INACTIVE)) + return; + if (count == 0) + return; + + ItemPosCountVec dest; + uint32 no_space_count = 0; + uint8 msg = plr->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, WG_MARK_OF_HONOR, count, &no_space_count); + + if (msg == EQUIP_ERR_ITEM_NOT_FOUND) + { + sLog.outErrorDb("Wintergrasp reward item (Entry %u) not exist in `item_template`.", WG_MARK_OF_HONOR); + return; + } + + if (msg != EQUIP_ERR_OK) // convert to possible store amount + count -= no_space_count; + + if (count != 0 && !dest.empty()) // can add some + if (Item* item = plr->StoreNewItem(dest, WG_MARK_OF_HONOR, true, 0)) + plr->SendNewItem(item, count, true, false); +} + +void OutdoorPvPWG::LoadQuestGiverMap(uint32 guid, Position posHorde, Position posAlli) +{ + m_qgPosMap[std::pair(guid, true)] = posHorde, + m_qgPosMap[std::pair(guid, false)] = posAlli, + m_questgivers[guid] = NULL; + if (getDefenderTeam() == TEAM_ALLIANCE) + objmgr.MoveCreData(guid, 571, posAlli); +} + +OPvPCapturePointWG *OutdoorPvPWG::GetWorkshop(uint32 lowguid) const +{ + if (OPvPCapturePoint *cp = GetCapturePoint(lowguid)) + return dynamic_cast(cp); + return NULL; +} + +OPvPCapturePointWG *OutdoorPvPWG::GetWorkshopByEngGuid(uint32 lowguid) const +{ + for (OutdoorPvP::OPvPCapturePointMap::const_iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + if (OPvPCapturePointWG *workshop = dynamic_cast(itr->second)) + if (workshop->m_engGuid == lowguid) + return workshop; + return NULL; +} + +OPvPCapturePointWG *OutdoorPvPWG::GetWorkshopByGOGuid(uint32 lowguid) const +{ + for (OutdoorPvP::OPvPCapturePointMap::const_iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + if (OPvPCapturePointWG *workshop = dynamic_cast(itr->second)) + if (workshop->m_workshopGuid == lowguid) + return workshop; + return NULL; +} + +/*######################################################## + * Copy of Battleground system to make Spirit Guides Work + *#######################################################*/ +void OutdoorPvPWG::SendAreaSpiritHealerQueryOpcode(Player *pl, const uint64& guid) +{ + WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12); + uint32 time_ = 30000 - GetLastResurrectTime(); // resurrect every 30 seconds + if (time_ == uint32(-1)) + time_ = 0; + data << guid << time_; + pl->GetSession()->SendPacket(&data); +} + +void OutdoorPvPWG::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid) +{ + m_ReviveQueue[npc_guid].push_back(player_guid); + + Player *plr = objmgr.GetPlayer(player_guid); + if (!plr) + return; + + plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true); +} + +void OutdoorPvPWG::RemovePlayerFromResurrectQueue(uint64 player_guid) +{ + for (std::map >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr) + { + for (std::vector::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2) + { + if (*itr2 == player_guid) + { + (itr->second).erase(itr2); + + Player *plr = objmgr.GetPlayer(player_guid); + if (!plr) + return; + + plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT); + + return; + } + } + } +} + +void OutdoorPvPWG::RelocateDeadPlayers(Creature *cr) +{ + if (!cr || GetCreatureType(cr->GetEntry()) != CREATURE_SPIRIT_GUIDE) + return; + + // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard + std::vector ghost_list = m_ReviveQueue[cr->GetGUID()]; + if (!ghost_list.empty()) + { + WorldSafeLocsEntry const *ClosestGrave = NULL; + for (std::vector::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr) + { + Player* plr = objmgr.GetPlayer(*itr); + if (!plr) + continue; + + if (!ClosestGrave) + ClosestGrave = objmgr.GetClosestGraveYard(plr->GetPositionX(), plr->GetPositionY(), plr->GetPositionZ(), plr->GetMapId(), plr->GetTeam()); + + if (ClosestGrave) + plr->TeleportTo(plr->GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation()); + } + } +} + +/*###### +##OPvPCapturePointWG +######*/ + +OPvPCapturePointWG::OPvPCapturePointWG(OutdoorPvPWG *opvp, BuildingState *state) +: OPvPCapturePoint(opvp), m_buildingState(state), m_wintergrasp(opvp) +, m_engineer(NULL), m_engGuid(0), m_spiritguide(NULL), m_spiGuid(0) +{ +} + +void OPvPCapturePointWG::SetTeamByBuildingState() +{ + if (m_buildingState->GetTeam() == TEAM_ALLIANCE) + { + m_value = m_maxValue; + m_State = OBJECTIVESTATE_ALLIANCE; + } + else if (m_buildingState->GetTeam() == TEAM_HORDE) + { + m_value = -m_maxValue; + m_State = OBJECTIVESTATE_HORDE; + } + else + { + m_value = 0; + m_State = OBJECTIVESTATE_NEUTRAL; + } + + if (m_team != m_buildingState->GetTeam()) + { + TeamId oldTeam = m_team; + m_team = m_buildingState->GetTeam(); + ChangeTeam(oldTeam); + } + + SendChangePhase(); +} + +void OPvPCapturePointWG::ChangeTeam(TeamId oldTeam) +{ + uint32 entry = 0; + uint32 guide_entry = 0; + + if (oldTeam != TEAM_NEUTRAL) + m_wintergrasp->ModifyWorkshopCount(oldTeam, false); + + if (m_team != TEAM_NEUTRAL) + { + entry = m_team == TEAM_ALLIANCE ? CRE_ENG_A : CRE_ENG_H; + guide_entry = m_team == TEAM_ALLIANCE ? CRE_SPI_A : CRE_SPI_H; + m_wintergrasp->ModifyWorkshopCount(m_team, true); + } + + if (m_capturePoint) + GameObject::SetGoArtKit(CapturePointArtKit[m_team], m_capturePoint, m_capturePointGUID); + + m_buildingState->SetTeam(m_team); + // TODO: this may be sent twice + m_wintergrasp->BroadcastStateChange(m_buildingState); + + if (m_buildingState->building) + m_buildingState->building->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[m_team]); + + if (entry) + { + if (m_engGuid) + { + *m_engEntry = entry; + _RespawnCreatureIfNeeded(m_engineer, entry); + } + if (m_spiGuid) + { + *m_spiEntry = guide_entry; + _RespawnCreatureIfNeeded(m_spiritguide, guide_entry); + m_wintergrasp->RelocateDeadPlayers(m_spiritguide); + } + } + else if (m_engineer) + m_engineer->SetVisibility(VISIBILITY_OFF); + + sLog.outDebug("Wintergrasp workshop now belongs to %u.", (uint32)m_buildingState->GetTeam()); +} diff --git a/src/game/OutdoorPvPWG.h b/src/game/OutdoorPvPWG.h new file mode 100644 index 00000000000..63381b15f7b --- /dev/null +++ b/src/game/OutdoorPvPWG.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2008-2009 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OUTDOOR_PVP_WG_ +#define OUTDOOR_PVP_WG_ + +#include "OutdoorPvPImpl.h" + +#define ZONE_WINTERGRASP 4197 +#define POS_X_CENTER 5100 +#define MAX_VEHICLE_PER_WORKSHOP 4 + +const uint32 WintergraspFaction[3] = {1732, 1735, 35}; +const uint32 WG_MARK_OF_HONOR = 43589; +const uint32 VehNumWorldState[2] = {3680,3490}; +const uint32 MaxVehNumWorldState[2] = {3681,3491}; +const uint32 ClockWorldState[5] = {3785,3784,3782,3976,3975}; + +enum OutdoorPvPWGSpell +{ + // Wartime auras + SPELL_RECRUIT = 37795, + SPELL_CORPORAL = 33280, + SPELL_LIEUTENANT = 55629, + SPELL_TENACITY = 58549, + SPELL_TENACITY_VEHICLE = 59911, + SPELL_TOWER_CONTROL = 62064, + SPELL_SPIRITUAL_IMMUNITY = 58729, + + // Reward spells + SPELL_VICTORY_REWARD = 56902, + SPELL_DEFEAT_REWARD = 58494, + SPELL_DAMAGED_TOWER = 59135, + SPELL_DESTROYED_TOWER = 59136, + SPELL_DAMAGED_BUILDING = 59201, + SPELL_INTACT_BUILDING = 59203, + +// SPELL_TELEPORT_DALARAN = 53360, +// SPELL_VICTORY_AURA = 60044, +}; + +/* Not used / Not implemented + +const uint16 GameEventWintergraspDefender[2] = {50, 51}; + +enum OutdoorPvP_WG_Sounds +{ + OutdoorPvP_WG_SOUND_KEEP_CLAIMED = 8192, + OutdoorPvP_WG_SOUND_KEEP_CAPTURED_ALLIANCE = 8173, + OutdoorPvP_WG_SOUND_KEEP_CAPTURED_HORDE = 8213, + OutdoorPvP_WG_SOUND_KEEP_ASSAULTED_ALLIANCE = 8212, + OutdoorPvP_WG_SOUND_KEEP_ASSAULTED_HORDE = 8174, + OutdoorPvP_WG_SOUND_NEAR_VICTORY = 8456 +}; + +enum DataId +{ + DATA_ENGINEER_DIE, +}; + +enum OutdoorPvP_WG_KeepStatus +{ + OutdoorPvP_WG_KEEP_TYPE_NEUTRAL = 0, + OutdoorPvP_WG_KEEP_TYPE_CONTESTED = 1, + OutdoorPvP_WG_KEEP_STATUS_ALLY_CONTESTED = 1, + OutdoorPvP_WG_KEEP_STATUS_HORDE_CONTESTED = 2, + OutdoorPvP_WG_KEEP_TYPE_OCCUPIED = 3, + OutdoorPvP_WG_KEEP_STATUS_ALLY_OCCUPIED = 3, + OutdoorPvP_WG_KEEP_STATUS_HORDE_OCCUPIED = 4 +}; +*/ + +enum OutdoorPvPWGCreType +{ + CREATURE_OTHER, + CREATURE_SIEGE_VEHICLE, + CREATURE_TURRET, + CREATURE_ENGINEER, + CREATURE_GUARD, + CREATURE_SPECIAL, + CREATURE_SPIRIT_GUIDE, + CREATURE_SPIRIT_HEALER, + CREATURE_QUESTGIVER, +}; + +enum OutdoorPvPWGBuildingType +{ + BUILDING_WALL, + BUILDING_WORKSHOP, + BUILDING_TOWER, +}; + +enum OutdoorPvPWGDamageState +{ // Do not change order + DAMAGE_INTACT, + DAMAGE_DAMAGED, + DAMAGE_DESTROYED, +}; + +typedef uint32 TeamPair[2]; + +enum OutdoorPvPWGQuest +{ + A_VICTORY_IN_WG = 13181, + H_VICTORY_IN_WG = 13183, + CRE_PVP_KILL = 31086, //Quest Objective - Fixme: this should be handled by DB + CRE_PVP_KILL_V = 31093, //Quest Objective - Fixme: this should be handled by DB +}; + +enum OutdoorPvPWGCreEntry +{ + CRE_ENG_A = 30499, + CRE_ENG_H = 30400, + CRE_SPI_A = 31842, + CRE_SPI_H = 31841, +}; + +const TeamPair OutdoorPvPWGCreEntryPair[] = +{ + {32307, 32308}, // Guards + {30739, 30740}, // Champions + {32296, 32294}, // Quartermaster + {32615, 32626}, // Warbringer & Brigadier General + {0,0} // Do not delete Used in LoadTeamPair +}; + +const TeamPair OutdoorPvPWGGODisplayPair[] = +{ + {5651, 5652}, + {8256, 8257}, + {0,0} // Do not delete Used in LoadTeamPair +}; + +const uint32 AreaPOIIconId[3][3] = {{7,8,9},{4,5,6},{1,2,3}}; +typedef std::list AreaPOIList; + +struct BuildingState +{ + explicit BuildingState(uint32 _worldState, TeamId _team, bool asDefault) + : worldState(_worldState), health(0) + , defaultTeam(asDefault ? _team : OTHER_TEAM(_team)), team(_team), damageState(DAMAGE_INTACT) + , building(NULL), type(BUILDING_WALL), graveTeam(NULL) + {} + uint32 worldState; + uint32 health; + TeamId defaultTeam; + OutdoorPvPWGDamageState damageState; + GameObject *building; + uint32 *graveTeam; + OutdoorPvPWGBuildingType type; + + void SendUpdate(Player *player) const + { + player->SendUpdateWorldState(worldState, AreaPOIIconId[team][damageState]); + } + + void FillData(WorldPacket &data) const + { + data << worldState << AreaPOIIconId[team][damageState]; + } + + TeamId GetTeam() const { return team; } + void SetTeam(TeamId t) + { + team = t; + if(graveTeam) + if (uint32 newTeam = TeamId2Team[t]) + *graveTeam = newTeam; + } + +private: + TeamId team; +}; + +typedef std::map TeamPairMap; + +class OPvPCapturePointWG; + +class OutdoorPvPWG : public OutdoorPvP +{ + protected: + typedef std::map BuildingStateMap; + typedef std::set CreatureSet; + typedef std::set GameObjectSet; + typedef std::map, Position> QuestGiverPositionMap; + typedef std::map QuestGiverMap; + public: + OutdoorPvPWG(); + bool SetupOutdoorPvP(); + + uint32 GetCreatureEntry(uint32 guidlow, const CreatureData *data); + + void OnCreatureCreate(Creature *creature, bool add); + void OnGameObjectCreate(GameObject *go, bool add); + + void ProcessEvent(GameObject *obj, uint32 eventId); + + void HandlePlayerEnterZone(Player *plr, uint32 zone); + void HandlePlayerLeaveZone(Player *plr, uint32 zone); + void HandlePlayerResurrects(Player * plr, uint32 zone); + void HandleKill(Player *killer, Unit *victim); + + bool Update(uint32 diff); + + void BroadcastStateChange(BuildingState *state) const; + + uint32 GetData(uint32 id); + void SetData(uint32 id, uint32 value) {}; + + void ModifyWorkshopCount(TeamId team, bool add); + uint32 GetTimer() const { return m_timer / 1000; }; + bool isWarTime() const { return m_wartime; }; + void setTimer(uint32 timer) { if (timer >= 0) m_timer = timer; }; + uint32 GetNumPlayersA() const { return m_players[TEAM_ALLIANCE].size(); }; + uint32 GetNumPlayersH() const { return m_players[TEAM_HORDE].size(); }; + TeamId getDefenderTeam() const { return m_defender; }; + TeamId getAttackerTeam() const { return OTHER_TEAM(m_defender); }; + void forceChangeTeam(); + void forceStopBattle(); + void forceStartBattle(); + + // Temporal BG specific till 3.2 + void SendAreaSpiritHealerQueryOpcode(Player *pl, const uint64& guid); + void AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid); + void RemovePlayerFromResurrectQueue(uint64 player_guid); + void RelocateDeadPlayers(Creature *cr); + // BG end + protected: + // Temporal BG specific till 3.2 + std::vector m_ResurrectQueue; // Player GUID + uint32 m_LastResurrectTime; + // Spirit Guide guid + Player list GUIDS + std::map > m_ReviveQueue; + + uint32 GetLastResurrectTime() const { return m_LastResurrectTime; } + uint32 GetReviveQueueSize() const { return m_ReviveQueue.size(); } + // BG end + + TeamId m_defender; + int32 m_tenacityStack; + + BuildingStateMap m_buildingStates; + BuildingState *m_gate; + + CreatureSet m_creatures; + CreatureSet m_vehicles[2]; + GameObjectSet m_gobjects; + QuestGiverMap m_questgivers; + + TeamPairMap m_creEntryPair, m_goDisplayPair; + QuestGiverPositionMap m_qgPosMap; + + bool m_wartime; + bool m_changeDefender; + uint32 m_timer; + uint32 m_clock[5]; + uint32 m_workshopCount[2]; + uint32 m_towerDestroyedCount[2]; + uint32 m_towerDamagedCount[2]; + + OPvPCapturePointWG *GetWorkshop(uint32 lowguid) const; + OPvPCapturePointWG *GetWorkshopByEngGuid(uint32 lowguid) const; + OPvPCapturePointWG *GetWorkshopByGOGuid(uint32 lowguid) const; + + void StartBattle(); + void EndBattle(); + + void UpdateClock(); + void UpdateClockDigit(uint32 &timer, uint32 digit, uint32 mod); + void PromotePlayer(Player *player) const; + void UpdateTenacityStack(); + void UpdateAllWorldObject(); + bool UpdateCreatureInfo(Creature *creature); + bool UpdateGameObjectInfo(GameObject *go) const; + + bool CanBuildVehicle(OPvPCapturePointWG *workshop) const; + OutdoorPvPWGCreType GetCreatureType(uint32 entry) const; + + void RebuildAllBuildings(); + + void SendInitWorldStatesTo(Player *player = NULL) const; + void RemoveOfflinePlayerWGAuras(); + void RewardMarkOfHonor(Player *player, uint32 count); + void MoveQuestGiver(uint32 guid); + void LoadQuestGiverMap(uint32 guid, Position posHorde, Position posAlli); + bool UpdateQuestGiverPosition(uint32 guid, Creature *creature); +}; + +class OPvPCapturePointWG : public OPvPCapturePoint +{ + public: + explicit OPvPCapturePointWG(OutdoorPvPWG *opvp, BuildingState *state); + void SetTeamByBuildingState(); + void ChangeState() {} + void ChangeTeam(TeamId oldteam); + + uint32 *m_spiEntry; + uint32 m_spiGuid; + Creature *m_spiritguide; + + uint32 *m_engEntry; + uint32 m_engGuid; + Creature *m_engineer; + uint32 m_workshopGuid; + BuildingState *m_buildingState; + protected: + OutdoorPvPWG *m_wintergrasp; +}; + +#endif diff --git a/src/game/Wintergrasp.cpp b/src/game/Wintergrasp.cpp deleted file mode 100644 index 81f3f600426..00000000000 --- a/src/game/Wintergrasp.cpp +++ /dev/null @@ -1,1865 +0,0 @@ -/* - * Copyright (C) 2008-2009 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Wintergrasp.h" -#include "SpellAuras.h" -#include "Vehicle.h" -#include "ObjectMgr.h" -#include "World.h" -#include "Chat.h" -#include "MapManager.h" - -typedef uint32 TeamPair[2]; - -enum WintergraspQuest -{ - A_VICTORY_IN_WG = 13181, - H_VICTORY_IN_WG = 13183, - CRE_PVP_KILL = 31086, //Quest Objective - CRE_PVP_KILL_V = 31093, //Quest Objective -}; - -enum CreatureEntry -{ - CRE_ENG_A = 30499, - CRE_ENG_H = 30400, - CRE_SPI_A = 31842, - CRE_SPI_H = 31841, -}; - -const TeamPair CreatureEntryPair[] = -{ - {32307, 32308}, // Guards - {30739, 30740}, // Champions - {32296, 32294}, // Quartermaster - {32615, 32626}, // Warbringer & Brigadier General - {0,0} // Do not delete Used in LoadTeamPair -}; - -const TeamPair GODisplayPair[] = -{ - {5651, 5652}, - {8256, 8257}, - {0,0} // Do not delete Used in LoadTeamPair -}; - -void LoadTeamPair(TeamPairMap &pairMap, const TeamPair *pair) -{ - while((*pair)[0]) - { - pairMap[(*pair)[0]] = (*pair)[1]; - pairMap[(*pair)[1]] = (*pair)[0]; - ++pair; - } -} - -void RespawnCreatureIfNeeded(Creature *cr, uint32 entry) -{ - if (cr) - { - cr->SetOriginalEntry(entry); - if (entry != cr->GetEntry() || !cr->isAlive()) - cr->Respawn(true); - cr->SetVisibility(VISIBILITY_ON); - } -} - -#define REMOVE_WARTIME_AURAS(p) (p)->RemoveAura(SPELL_RECRUIT);\ - (p)->RemoveAura(SPELL_CORPORAL);(p)->RemoveAura(SPELL_LIEUTENANT);\ - (p)->RemoveAura(SPELL_TOWER_CONTROL);\ - (p)->RemoveAura(SPELL_SPIRITUAL_IMMUNITY) - -// Visual defines, easier to understand code -#define getDefenderTeam() m_defender -#define getAttackerTeam() OTHER_TEAM(m_defender) - -typedef std::list AreaPOIList; - -OPvPWintergrasp::OPvPWintergrasp() -{ - m_TypeId = OPVP_WINTERGRASP; - - m_LastResurrectTime = 0; // Temporal copy of BG system till 3.2 -} - -bool OPvPWintergrasp::SetupOutdoorPvP() -{ - if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) - { - sWorld.setState(WORLDSTATE_WINTERGRASP_CONTROLING_FACTION, TEAM_NEUTRAL); - return false; - } - - m_defender = TeamId(rand()%2); - sWorld.setState(WORLDSTATE_WINTERGRASP_CONTROLING_FACTION, getDefenderTeam()); - m_changeDefender = false; - m_workshopCount[TEAM_ALLIANCE] = 0; - m_workshopCount[TEAM_HORDE] = 0; - m_tenacityStack = 0; - m_gate = NULL; - - std::list engGuids; - std::list spiritGuids; - - // Store Eng, spirit guide guids and questgiver for later use - QueryResult *result = WorldDatabase.PQuery("SELECT guid, id FROM creature WHERE creature.map=571" - " AND creature.id IN (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);", - CRE_ENG_A, CRE_ENG_H, CRE_SPI_A, CRE_SPI_H, 31101, 31051, 31102, 31052, - 31107, 31109, 31151, 31153, 31106, 31108, 31053, 31054, 31091, 31036); - if (!result) - sLog.outError("Cannot find siege workshop master or spirit guides in creature!"); - else - { - do - { - Position posHorde, posAlli; - Field *fields = result->Fetch(); - switch(fields[1].GetUInt32()) - { - case CRE_ENG_A: - case CRE_ENG_H: - engGuids.push_back(fields[0].GetUInt32()); - break; - case CRE_SPI_A: - case CRE_SPI_H: - spiritGuids.push_back(fields[0].GetUInt32()); - break; - case 31051: - posHorde.Relocate(5081.7, 2173.73, 365.878, 0.855211); - posAlli.Relocate(5296.56, 2789.87, 409.275, 0.733038); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31101: - posHorde.Relocate(5296.56, 2789.87, 409.275, 0.733038); - posAlli.Relocate(5016.57, 3677.53, 362.982, 5.7525); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31052: - posHorde.Relocate(5100.07, 2168.89, 365.779, 1.97222); - posAlli.Relocate(5298.43, 2738.76, 409.316, 3.97174); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31102: - posHorde.Relocate(5298.43, 2738.76, 409.316, 3.97174); - posAlli.Relocate(5030.44, 3659.82, 363.194, 1.83336); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31109: - posHorde.Relocate(5080.4, 2199, 359.489, 2.96706); - posAlli.Relocate(5234.97, 2883.4, 409.275, 4.29351); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31107: - posHorde.Relocate(5234.97, 2883.4, 409.275, 4.29351); - posAlli.Relocate(5008.64, 3659.91, 361.07, 4.0796); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31153: - posHorde.Relocate(5088.49, 2188.18, 365.647, 5.25344); - posAlli.Relocate(5366.13, 2833.4, 409.323, 3.14159); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31151: - posHorde.Relocate(5366.13, 2833.4, 409.323, 3.14159); - posAlli.Relocate(5032.33, 3680.7, 363.018, 3.43167); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31108: - posHorde.Relocate(5095.67, 2193.28, 365.924, 4.93928); - posAlli.Relocate(5295.56, 2926.67, 409.275, 0.872665); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31106: - posHorde.Relocate(5295.56, 2926.67, 409.275, 0.872665); - posAlli.Relocate(5032.66, 3674.28, 363.053, 2.9447); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31054: - posHorde.Relocate(5088.61, 2167.66, 365.689, 0.680678); - posAlli.Relocate(5371.4, 3026.51, 409.206, 3.25003); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31053: - posHorde.Relocate(5371.4, 3026.51, 409.206, 3.25003); - posAlli.Relocate(5032.44, 3668.66, 363.11, 2.87402); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31036: - posHorde.Relocate(5078.28, 2183.7, 365.029, 1.46608); - posAlli.Relocate(5359.13, 2837.99, 409.364, 4.69893); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - case 31091: - posHorde.Relocate(5359.13, 2837.99, 409.364, 4.69893); - posAlli.Relocate(5022.43, 3659.91, 361.61, 1.35426); - LoadQuestGiverMap(fields[0].GetUInt32(), posHorde, posAlli); - break; - default: - break; - } - }while(result->NextRow()); - delete result; - } - - // Select POI - AreaPOIList areaPOIs; - float minX = 9999, minY = 9999, maxX = -9999, maxY = -9999; - for (uint32 i = 0; i < sAreaPOIStore.GetNumRows(); ++i) - { - const AreaPOIEntry * poiInfo = sAreaPOIStore.LookupEntry(i); - if (poiInfo && poiInfo->zoneId == ZONE_WINTERGRASP) - { - areaPOIs.push_back(poiInfo); - if (minX > poiInfo->x) minX = poiInfo->x; - if (minY > poiInfo->y) minY = poiInfo->y; - if (maxX < poiInfo->x) maxX = poiInfo->x; - if (maxY < poiInfo->y) maxY = poiInfo->y; - } - } - minX -= 20; minY -= 20; maxX += 20; maxY += 20; - - // Coords: 4290.330078, 1790.359985 - 5558.379883, 4048.889893 - result = WorldDatabase.PQuery("SELECT guid FROM gameobject,gameobject_template" - " WHERE gameobject.map=571" - " AND gameobject.position_x>%f AND gameobject.position_y>%f" - " AND gameobject.position_x<%f AND gameobject.position_y<%f" - " AND gameobject_template.type=33" - " AND gameobject.id=gameobject_template.entry", - minX, minY, maxX, maxY); - if (!result) - return false; - - do - { - Field *fields = result->Fetch(); - - uint32 guid = fields[0].GetUInt32(); - GameObjectData const * goData = objmgr.GetGOData(guid); - if (!goData) // this should not happen - continue; - - float x = goData->posX, y = goData->posY; - float minDist = 100; - AreaPOIList::iterator poi = areaPOIs.end(); - for (AreaPOIList::iterator itr = areaPOIs.begin(); itr != areaPOIs.end(); ++itr) - { - if (!(*itr)->icon[1]) // note: may for other use - continue; - - float dist = (abs((*itr)->x - x) + abs((*itr)->y - y)); - if (minDist > dist) - { - minDist = dist; - poi = itr; - } - } - - if (poi == areaPOIs.end()) - continue; - - // add building to the list - TeamId teamId = x > POS_X_CENTER ? getDefenderTeam() : getAttackerTeam(); - m_buildingStates[guid] = new BuildingState((*poi)->worldState, teamId, getDefenderTeam() != TEAM_ALLIANCE); - if ((*poi)->id == 2246) - m_gate = m_buildingStates[guid]; - areaPOIs.erase(poi); - - // add capture point - uint32 capturePointEntry = 0; - - switch(goData->id) - { - case 192028: // NW - case 192030: // W - case 192032: // SW - capturePointEntry = 190475; - break; - case 192029: // NE - case 192031: // E - case 192033: // SE - capturePointEntry = 190487; - break; - } - - if (capturePointEntry) - { - uint32 engGuid = 0; - uint32 spiritGuid = 0; - // Find closest Eng to Workshop - float minDist = 100; - for (std::list::iterator itr = engGuids.begin(); itr != engGuids.end(); ++itr) - { - const CreatureData *creData = objmgr.GetCreatureData(*itr); - if (!creData) - continue; - - float dist = (abs(creData->posX - x) + abs(creData->posY - y)); - if (minDist > dist) - { - minDist = dist; - engGuid = *itr; - } - } - - if (!engGuid) - { - sLog.outError("Cannot find nearby siege workshop master!"); - continue; - } - else - engGuids.remove(engGuid); - // Find closest Spirit Guide to Workshop - minDist = 255; - for (std::list::iterator itr = spiritGuids.begin(); itr != spiritGuids.end(); ++itr) - { - const CreatureData *creData = objmgr.GetCreatureData(*itr); - if (!creData) - continue; - - float dist = (abs(creData->posX - x) + abs(creData->posY - y)); - if (minDist > dist) - { - minDist = dist; - spiritGuid = *itr; - } - } - - // Inside fortress won't be capturable - SiegeWorkshop *workshop = new SiegeWorkshop(this, m_buildingStates[guid]); - if (goData->posX < POS_X_CENTER && !workshop->SetCapturePointData(capturePointEntry, goData->mapid, goData->posX + 40 * cos(goData->orientation + M_PI / 2), goData->posY + 40 * sin(goData->orientation + M_PI / 2), goData->posZ)) - { - delete workshop; - sLog.outError("Cannot add capture point!"); - continue; - } - - const CreatureData *creData = objmgr.GetCreatureData(engGuid); - if (!creData) - continue; - - workshop->m_engEntry = const_cast(&creData->id); - const_cast(creData)->displayid = 0; - workshop->m_engGuid = engGuid; - - // Back spirit is linked to one of the inside workshops, 1 workshop wont have spirit - if (spiritGuid) - { - spiritGuids.remove(spiritGuid); - - const CreatureData *spiritData = objmgr.GetCreatureData(spiritGuid); - if (!spiritData) - continue; - - workshop->m_spiEntry = const_cast(&spiritData->id); - const_cast(spiritData)->displayid = 0; - workshop->m_spiGuid = spiritGuid; - } - else - workshop->m_spiGuid = 0; - workshop->m_workshopGuid = guid; - AddCapturePoint(workshop); - m_buildingStates[guid]->type = BUILDING_WORKSHOP; - workshop->SetTeamByBuildingState(); - } - }while(result->NextRow()); - delete result; - - engGuids.clear(); - spiritGuids.clear(); - - if (!m_gate) - { - sLog.outError("Cannot find wintergrasp fortress gate!"); - return false; - } - - // Load Graveyard - GraveYardMap::const_iterator graveLow = objmgr.mGraveYardMap.lower_bound(ZONE_WINTERGRASP); - GraveYardMap::const_iterator graveUp = objmgr.mGraveYardMap.upper_bound(ZONE_WINTERGRASP); - for (AreaPOIList::iterator itr = areaPOIs.begin(); itr != areaPOIs.end();) - { - if ((*itr)->icon[1] == 8) - { - // find or create grave yard - const WorldSafeLocsEntry *loc = objmgr.GetClosestGraveYard((*itr)->x, (*itr)->y, (*itr)->z, (*itr)->mapId, 0); - if (!loc) - { - ++itr; - continue; - } - - GraveYardMap::const_iterator graveItr; - for (graveItr = graveLow; graveItr != graveUp; ++graveItr) - if (graveItr->second.safeLocId == loc->ID) - break; - if (graveItr == graveUp) - { - GraveYardData graveData; - graveData.safeLocId = loc->ID; - graveData.team = 0; - graveItr = objmgr.mGraveYardMap.insert(std::make_pair(ZONE_WINTERGRASP, graveData)); - } - - for (BuildingStateMap::iterator stateItr = m_buildingStates.begin(); stateItr != m_buildingStates.end(); ++stateItr) - { - if (stateItr->second->worldState == (*itr)->worldState) - { - stateItr->second->graveTeam = const_cast(&graveItr->second.team); - break; - } - } - areaPOIs.erase(itr++); - } - else - ++itr; - } - - //for (AreaPOIList::iterator itr = areaPOIs.begin(); itr != areaPOIs.end(); ++itr) - // sLog.outError("not assigned %u %f %f", (*itr)->id, (*itr)->x, (*itr)->y); - - //gameeventmgr.StartInternalEvent(GameEventWintergraspDefender[getDefenderTeam()]); - - //Titan Relic eventid = 19982 - objmgr.AddGOData(192829, 571, 5440, 2840.8, 420.43 + 10, 0); - - LoadTeamPair(m_goDisplayPair, GODisplayPair); - LoadTeamPair(m_creEntryPair, CreatureEntryPair); - - m_wartime = false; - m_timer = sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_START_TIME) * MINUTE * IN_MILISECONDS; - - m_towerDamagedCount[TEAM_ALLIANCE] = 0; - m_towerDestroyedCount[TEAM_ALLIANCE] = 0; - m_towerDamagedCount[TEAM_HORDE] = 0; - m_towerDestroyedCount[TEAM_HORDE] = 0; - - RemoveOfflinePlayerWGAuras(); - - RegisterZone(ZONE_WINTERGRASP); - return true; -} - -void OPvPWintergrasp::ProcessEvent(GameObject *obj, uint32 eventId) -{ - if (obj->GetEntry() == 192829) - { - if (obj->GetGOInfo()->goober.eventId == eventId && isWarTime() && m_gate && m_gate->damageState == DAMAGE_DESTROYED) - { - m_changeDefender = true; - m_timer = 0; - } - } - else if (obj->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) - { - BuildingStateMap::const_iterator itr = m_buildingStates.find(obj->GetDBTableGUIDLow()); - if (itr == m_buildingStates.end()) - return; - - std::string msgStr; - switch(eventId) - { // TODO - Localized msgs of GO names - case 19672: case 19675: // Flamewatch Tower - msgStr = "Flamewatch"; - break; - case 18553: case 19677: // Shadowsight Tower - msgStr = "Shadowsight"; - break; - case 19673: case 19676: // Winter's Edge Tower - msgStr = "Winter's Edge"; - break; - case 19776: case 19778: // E Workshop damaged - msgStr = "Sunken Ring"; - break; - case 19777: case 19779: // W Workshop damaged - msgStr = "Broken Temple"; - break; - case 19782: case 19786: // NW Workshop damaged - msgStr = "north-western"; - break; - case 19783: case 19787: // NE Workshop damaged - msgStr = "north-eastern"; - break; - case 19784: case 19788: // SW Workshop damaged - msgStr = "Westpark"; - break; - case 19785: case 19789: // SE Workshop damaged - msgStr = "Eastpark"; - break; - case 19657: case 19661: // NW Wintergrasp Keep Tower damaged - msgStr = "north-western"; - break; - case 19658: case 19663: // NE Wintergrasp Keep Tower damaged - msgStr = "north-eastern"; - break; - case 19659: case 19662: // SW Wintergrasp Keep Tower damaged - msgStr = "south-western"; - break; - case 19660: case 19664: // SE Wintergrasp Keep Tower damaged - msgStr = "south-eastern"; - break; - default: - msgStr = ""; - } - - BuildingState *state = itr->second; - if (eventId == obj->GetGOInfo()->building.damagedEvent) - { - state->damageState = DAMAGE_DAMAGED; - switch(state->type) - { - case BUILDING_WORKSHOP: - msgStr = fmtstring(objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_WORKSHOP_DAMAGED), msgStr.c_str(), objmgr.GetTrinityStringForDBCLocale(getDefenderTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE)); - sWorld.SendZoneText(ZONE_WINTERGRASP, msgStr.c_str()); - break; - case BUILDING_WALL: - sWorld.SendZoneText(ZONE_WINTERGRASP, objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_FORTRESS_UNDER_ATTACK)); - break; - case BUILDING_TOWER: - ++m_towerDamagedCount[state->GetTeam()]; - msgStr = fmtstring(objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_TOWER_DAMAGED), msgStr.c_str()); - sWorld.SendZoneText(ZONE_WINTERGRASP, msgStr.c_str()); - break; - } - } - else if (eventId == obj->GetGOInfo()->building.destroyedEvent) - { - state->damageState = DAMAGE_DESTROYED; - - switch(state->type) - { - case BUILDING_WORKSHOP: - ModifyWorkshopCount(state->GetTeam(), false); - msgStr = fmtstring(objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_WORKSHOP_DESTROYED), msgStr.c_str(), objmgr.GetTrinityStringForDBCLocale(getDefenderTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE)); - sWorld.SendZoneText(ZONE_WINTERGRASP, msgStr.c_str()); - break; - case BUILDING_WALL: - sWorld.SendZoneText(ZONE_WINTERGRASP, objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_FORTRESS_UNDER_ATTACK)); - break; - case BUILDING_TOWER: - --m_towerDamagedCount[state->GetTeam()]; - ++m_towerDestroyedCount[state->GetTeam()]; - if (state->GetTeam() == getAttackerTeam()) - { - TeamCastSpell(getAttackerTeam(), -SPELL_TOWER_CONTROL); - TeamCastSpell(getDefenderTeam(), -SPELL_TOWER_CONTROL); - uint32 attStack = 3 - m_towerDestroyedCount[getAttackerTeam()]; - - if (m_towerDestroyedCount[getAttackerTeam()]) - { - for (PlayerSet::iterator itr = m_players[getDefenderTeam()].begin(); itr != m_players[getDefenderTeam()].end(); ++itr) - if ((*itr)->getLevel() > 69) - (*itr)->SetAuraStack(SPELL_TOWER_CONTROL, (*itr), m_towerDestroyedCount[getAttackerTeam()]); - } - - if (attStack) - { - for (PlayerSet::iterator itr = m_players[getAttackerTeam()].begin(); itr != m_players[getAttackerTeam()].end(); ++itr) - if ((*itr)->getLevel() > 69) - (*itr)->SetAuraStack(SPELL_TOWER_CONTROL, (*itr), attStack); - } - else - { - if (m_timer < 600000) - m_timer = 0; - else - m_timer = m_timer - 600000; // - 10 mins - } - } - msgStr = fmtstring(objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_TOWER_DESTROYED), msgStr.c_str()); - sWorld.SendZoneText(ZONE_WINTERGRASP, msgStr.c_str()); - break; - } - BroadcastStateChange(state); - } - } -} - -void OPvPWintergrasp::RemoveOfflinePlayerWGAuras() -{ - // if server crashed while in battle there could be players with rank or tenacity - CharacterDatabase.PExecute("DELETE FROM character_aura WHERE spell IN (%u, %u, %u, %u, %u)", - SPELL_RECRUIT, SPELL_CORPORAL, SPELL_LIEUTENANT, SPELL_TENACITY, SPELL_TOWER_CONTROL); -} - -void OPvPWintergrasp::ModifyWorkshopCount(TeamId team, bool add) -{ - if (team == TEAM_NEUTRAL) - return; - - if (add) - ++m_workshopCount[team]; - else if (m_workshopCount[team]) - --m_workshopCount[team]; - else - sLog.outError("OPvPWintergrasp::ModifyWorkshopCount: negative workshop count!"); - - SendUpdateWorldState(MaxVehNumWorldState[team], m_workshopCount[team] * MAX_VEHICLE_PER_WORKSHOP); -} - -uint32 OPvPWintergrasp::GetCreatureEntry(uint32 guidlow, const CreatureData *data) -{ - if (getDefenderTeam() == TEAM_ALLIANCE) - { - TeamPairMap::const_iterator itr = m_creEntryPair.find(data->id); - if (itr != m_creEntryPair.end()) - { - const_cast(data)->displayid = 0; - return itr->second; - } - } - return data->id; -} - -WintergraspCreType OPvPWintergrasp::GetCreatureType(uint32 entry) const -{ - // VEHICLES, GUARDS and TURRETS gives kill credit - // OTHER Not in wartime - // TURRET Only during wartime - // SPECIAL like "OTHER" but no despawn conditions - // Entries like Case A: Case: B have their own despawn function - switch(entry) - { - case 27881: // Catapult - case 28094: // Demolisher - case 28312: // Alliance Siege Engine - case 32627: // Horde Siege Engine - case 28319: // Siege turret - case 32629: // Siege turret - return CREATURE_SIEGE_VEHICLE; - case 28366: // Wintergrasp Tower cannon - return CREATURE_TURRET; - case CRE_ENG_A: // Alliance Engineer - case CRE_ENG_H: // Horde Engineer - return CREATURE_ENGINEER; - case 30739:case 30740: // Champions - case 32307:case 32308: // Guards - return CREATURE_GUARD; - case CRE_SPI_A: // Dwarven Spirit Guide - case CRE_SPI_H: // Taunka Spirit Guide - return CREATURE_SPIRIT_GUIDE; - case 6491: // Spirit Healers - return CREATURE_SPIRIT_HEALER; - case 31101:case 31051: // Hoodoo Master & Sorceress - case 31102:case 31052: // Vieron Blazefeather & Bowyer - case 31107:case 31109: // Lieutenant & Senior Demolitionist - case 31151:case 31153: // Tactical Officer - case 31106:case 31108: // Siegesmith & Siege Master - case 31053:case 31054: // Primalist & Anchorite - case 31091:case 31036: // Commander - return CREATURE_QUESTGIVER; - case 32615:case 32626: // Warbringer && Brigadier General - case 32296:case 32294: // Quartermaster - case 30870:case 30869: // Flight Masters - return CREATURE_SPECIAL; - default: - return CREATURE_OTHER; // Revenants, Elementals, etc - } -} - -void OPvPWintergrasp::OnCreatureCreate(Creature *creature, bool add) -{ - uint32 entry = creature->GetEntry(); - switch(GetCreatureType(entry)) - { - case CREATURE_SIEGE_VEHICLE: - { - if (!creature->isSummon()) - return; - - TeamId team; - if (add) - { - if (creature->getFaction() == WintergraspFaction[TEAM_ALLIANCE]) - team = TEAM_ALLIANCE; - else if (creature->getFaction() == WintergraspFaction[TEAM_HORDE]) - team = TEAM_HORDE; - else - return; - - if (uint32 engLowguid = GUID_LOPART(((TempSummon*)creature)->GetSummonerGUID())) - { - if (SiegeWorkshop *workshop = GetWorkshopByEngGuid(engLowguid)) - { - if (CanBuildVehicle(workshop)) - { - m_vehicles[team].insert(creature); - //workshop->m_vehicles.insert(creature); - } - else - { - creature->setDeathState(DEAD); - creature->SetRespawnTime(DAY); - return; - } - } - } - - if (m_tenacityStack > 0 && team == TEAM_ALLIANCE) - creature->SetAuraStack(SPELL_TENACITY_VEHICLE, creature, m_tenacityStack); - else if (m_tenacityStack < 0 && team == TEAM_HORDE) - creature->SetAuraStack(SPELL_TENACITY_VEHICLE, creature, -m_tenacityStack); - } - else // the faction may be changed in uncharm - { - // TODO: now you have to wait until the corpse of vehicle disappear to build a new one - if (m_vehicles[TEAM_ALLIANCE].erase(creature)) - team = TEAM_ALLIANCE; - else if (m_vehicles[TEAM_HORDE].erase(creature)) - team = TEAM_HORDE; - else - return; - } - SendUpdateWorldState(VehNumWorldState[team], m_vehicles[team].size()); - break; - } - case CREATURE_QUESTGIVER: - m_questgivers[creature->GetDBTableGUIDLow()] = creature; - break; - case CREATURE_ENGINEER: - for (OutdoorPvP::OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - { - if (SiegeWorkshop *workshop = dynamic_cast(itr->second)) - if (workshop->m_engGuid == creature->GetDBTableGUIDLow()) - { - workshop->m_engineer = add ? creature : NULL; - break; - } - } - break; - case CREATURE_SPIRIT_GUIDE: - for (OutdoorPvP::OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - { - if (SiegeWorkshop *workshop = dynamic_cast(itr->second)) - if (workshop->m_spiGuid == creature->GetDBTableGUIDLow()) - { - workshop->m_spiritguide = add ? creature : NULL; - break; - } - } - creature->CastSpell(creature, SPELL_SPIRITUAL_IMMUNITY, true); - case CREATURE_SPIRIT_HEALER: - case CREATURE_TURRET: - case CREATURE_OTHER: - if (add) - UpdateCreatureInfo(creature); - default: - if (add) - m_creatures.insert(creature); - else - m_creatures.erase(creature); - break; - } -} - -void OPvPWintergrasp::OnGameObjectCreate(GameObject *go, bool add) -{ - OutdoorPvP::OnGameObjectCreate(go, add); - - if (UpdateGameObjectInfo(go)) - { - if (add) m_gobjects.insert(go); - else m_gobjects.erase(go); - } - //do we need to store building? - else if (go->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) - { - BuildingStateMap::const_iterator itr = m_buildingStates.find(go->GetDBTableGUIDLow()); - if (itr != m_buildingStates.end()) - { - itr->second->building = add ? go : NULL; - if (go->GetGOInfo()->displayId == 7878 || go->GetGOInfo()->displayId == 7900) - itr->second->type = BUILDING_TOWER; - if (!add || itr->second->damageState == DAMAGE_INTACT && !itr->second->health) - itr->second->health = go->GetGOValue()->building.health; - else - { - go->GetGOValue()->building.health = itr->second->health; - if (itr->second->damageState == DAMAGE_DAMAGED) - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED); - else if (itr->second->damageState == DAMAGE_DESTROYED) - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); - } - } - } -} - -void OPvPWintergrasp::UpdateAllWorldObject() -{ - // update cre and go factions - for (GameObjectSet::iterator itr = m_gobjects.begin(); itr != m_gobjects.end(); ++itr) - UpdateGameObjectInfo(*itr); - for (CreatureSet::iterator itr = m_creatures.begin(); itr != m_creatures.end(); ++itr) - UpdateCreatureInfo(*itr); - for (QuestGiverMap::iterator itr = m_questgivers.begin(); itr != m_questgivers.end(); ++itr) - UpdateQuestGiverPosition((*itr).first, (*itr).second); - - // rebuild and update building states - RebuildAllBuildings(); - - // update capture points - for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - if (SiegeWorkshop *workshop = dynamic_cast(itr->second)) - workshop->SetTeamByBuildingState(); -} - -void OPvPWintergrasp::RebuildAllBuildings() -{ - for (BuildingStateMap::const_iterator itr = m_buildingStates.begin(); itr != m_buildingStates.end(); ++itr) - { - if (itr->second->building) - { - UpdateGameObjectInfo(itr->second->building); - itr->second->building->Rebuild(); - itr->second->health = itr->second->building->GetGOValue()->building.health; - } - else - itr->second->health = 0; - - if (itr->second->damageState == DAMAGE_DESTROYED) - { - if (itr->second->type == BUILDING_WORKSHOP) - ModifyWorkshopCount(itr->second->GetTeam(), true); - } - - itr->second->damageState = DAMAGE_INTACT; - itr->second->SetTeam(getDefenderTeam() == TEAM_ALLIANCE ? OTHER_TEAM(itr->second->defaultTeam) : itr->second->defaultTeam); - } - m_towerDamagedCount[TEAM_ALLIANCE] = 0; - m_towerDestroyedCount[TEAM_ALLIANCE] = 0; - m_towerDamagedCount[TEAM_HORDE] = 0; - m_towerDestroyedCount[TEAM_HORDE] = 0; -} - -void OPvPWintergrasp::SendInitWorldStatesTo(Player *player) const -{ - WorldPacket data(SMSG_INIT_WORLD_STATES, (4+4+4+2+(m_buildingStates.size()*8))); - data << uint32(571); - data << uint32(ZONE_WINTERGRASP); - data << uint32(0); - data << uint16(4+5+4+m_buildingStates.size()); - - data << uint32(3803) << uint32(getDefenderTeam() == TEAM_ALLIANCE ? 1 : 0); - data << uint32(3802) << uint32(getDefenderTeam() != TEAM_ALLIANCE ? 1 : 0); - data << uint32(3801) << uint32(isWarTime() ? 0 : 1); - data << uint32(3710) << uint32(isWarTime() ? 1 : 0); - - for (uint32 i = 0; i < 5; ++i) - data << ClockWorldState[i] << m_clock[i]; - - data << uint32(3490) << uint32(m_vehicles[TEAM_HORDE].size()); - data << uint32(3491) << m_workshopCount[TEAM_HORDE] * MAX_VEHICLE_PER_WORKSHOP; - data << uint32(3680) << uint32(m_vehicles[TEAM_ALLIANCE].size()); - data << uint32(3681) << m_workshopCount[TEAM_ALLIANCE] * MAX_VEHICLE_PER_WORKSHOP; - - for (BuildingStateMap::const_iterator itr = m_buildingStates.begin(); itr != m_buildingStates.end(); ++itr) - itr->second->FillData(data); - - if (player) - player->GetSession()->SendPacket(&data); - else - BroadcastPacket(data); -} - -void OPvPWintergrasp::BroadcastStateChange(BuildingState *state) const -{ - if (m_sendUpdate) - for (uint32 team = 0; team < 2; ++team) - for (PlayerSet::const_iterator p_itr = m_players[team].begin(); p_itr != m_players[team].end(); ++p_itr) - state->SendUpdate(*p_itr); -} - -// Called at Start and Battle End -bool OPvPWintergrasp::UpdateCreatureInfo(Creature *creature) -{ - if (!creature) - return false; - uint32 entry = creature->GetEntry(); - switch(GetCreatureType(entry)) - { - case CREATURE_TURRET: - if (isWarTime()) - { - if (!creature->isAlive()) - creature->Respawn(true); - creature->setFaction(WintergraspFaction[getDefenderTeam()]); - creature->SetVisibility(VISIBILITY_ON); - } - else - { - if (creature->IsVehicle() && creature->GetVehicleKit()) - creature->GetVehicleKit()->RemoveAllPassengers(); - creature->SetVisibility(VISIBILITY_OFF); - creature->setFaction(35); - } - return false; - case CREATURE_OTHER: - if (isWarTime()) - { - creature->SetVisibility(VISIBILITY_OFF); - creature->setFaction(35); - } - else - { - creature->RestoreFaction(); - creature->SetVisibility(VISIBILITY_ON); - } - return false; - case CREATURE_SPIRIT_GUIDE: - if (isWarTime()) - { - creature->SetVisibility(VISIBILITY_ON); - //creature->setDeathState(ALIVE); - } - else - { - creature->SetVisibility(VISIBILITY_OFF); - //creature->setDeathState(DEAD); - } - return false; - case CREATURE_SPIRIT_HEALER: - creature->SetVisibility(isWarTime() ? VISIBILITY_OFF : VISIBILITY_ON); - return false; - case CREATURE_ENGINEER: - return false; - case CREATURE_SIEGE_VEHICLE: - //creature->DisappearAndDie(); - return false; - case CREATURE_GUARD: - case CREATURE_SPECIAL: - { - TeamPairMap::const_iterator itr = m_creEntryPair.find(creature->GetCreatureData()->id); - if (itr != m_creEntryPair.end()) - { - entry = getDefenderTeam() == TEAM_ALLIANCE ? itr->second : itr->first; - RespawnCreatureIfNeeded(creature, entry); - } - return false; - } - default: - return false; - } -} - -bool OPvPWintergrasp::UpdateQuestGiverPosition(uint32 guid, Creature *creature) -{ - assert(guid); - Position pos = m_qgPosMap[std::pair(guid, getDefenderTeam() == TEAM_HORDE)]; - - if (creature && creature->IsInWorld()) - { - // if not questgiver or position is the same, do nothing - if (creature->GetPositionX() == pos.GetPositionX() && - creature->GetPositionY() == pos.GetPositionY() && - creature->GetPositionZ() == pos.GetPositionZ()) - return false; - - if (creature->isAlive() && creature->isInCombat()) - { - creature->CombatStop(true); - creature->getHostilRefManager().deleteReferences(); - } - creature->SetHomePosition(pos); - creature->DestroyForNearbyPlayers(); - if (!creature->GetMap()->IsLoaded(pos.GetPositionX(), pos.GetPositionY())) - creature->GetMap()->LoadGrid(pos.GetPositionX(), pos.GetPositionY()); - creature->GetMap()->CreatureRelocation(creature, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); - if (!creature->isAlive()) - creature->Respawn(true); - } - else - objmgr.MoveCreData(guid, 571, pos); - - return true; -} - -// Return false = Need to rebuild at battle End/Start -// true = no need to rebuild (ie: Banners or teleporters) -bool OPvPWintergrasp::UpdateGameObjectInfo(GameObject *go) const -{ - uint32 attFaction = 35; - uint32 defFaction = 35; - - if (isWarTime()) - { - attFaction = WintergraspFaction[getAttackerTeam()]; - defFaction = WintergraspFaction[getDefenderTeam()]; - } - - switch(go->GetGOInfo()->displayId) - { - case 8244: // Defender's Portal - Vehicle Teleporter - go->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[getDefenderTeam()]); - return true; - case 7967: // Titan relic - go->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[getAttackerTeam()]); - return true; - - case 8165: // Wintergrasp Keep Door - case 7877: // Wintergrasp Fortress Wall - case 7878: // Wintergrasp Keep Tower - case 7906: // Wintergrasp Fortress Gate - case 7909: // Wintergrasp Wall - go->SetUInt32Value(GAMEOBJECT_FACTION, defFaction); - return false; - case 7900: // Flamewatch Tower - Shadowsight Tower - Winter's Edge Tower - go->SetUInt32Value(GAMEOBJECT_FACTION, attFaction); - return false; - case 8208: // Goblin Workshop - SiegeWorkshop *workshop = GetWorkshopByGOGuid(go->GetGUID()); - if (workshop) - go->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[workshop->m_buildingState->GetTeam()]); - return false; - } - - // Note: this is only for test, still need db support - TeamPairMap::const_iterator itr = m_goDisplayPair.find(go->GetGOInfo()->displayId); - if (itr != m_goDisplayPair.end()) - { - go->SetUInt32Value(GAMEOBJECT_DISPLAYID, getDefenderTeam() == TEAM_ALLIANCE ? - itr->second : itr->first); - return true; - } - return false; -} - -void OPvPWintergrasp::HandlePlayerEnterZone(Player * plr, uint32 zone) -{ - if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) - return; - - if (isWarTime()) - { - if (plr->getLevel() > 69) - { - if (!plr->HasAura(SPELL_RECRUIT) && !plr->HasAura(SPELL_CORPORAL) - && !plr->HasAura(SPELL_LIEUTENANT)) - plr->CastSpell(plr, SPELL_RECRUIT, true); - if (plr->GetTeamId() == getAttackerTeam()) - { - if (m_towerDestroyedCount[getAttackerTeam()] < 3) - plr->SetAuraStack(SPELL_TOWER_CONTROL, plr, 3 - m_towerDestroyedCount[getAttackerTeam()]); - } - else - { - if (m_towerDestroyedCount[getAttackerTeam()]) - plr->SetAuraStack(SPELL_TOWER_CONTROL, plr, m_towerDestroyedCount[getAttackerTeam()]); - } - } - } - - SendInitWorldStatesTo(plr); - OutdoorPvP::HandlePlayerEnterZone(plr, zone); - UpdateTenacityStack(); -} - -// Reapply Auras if needed -void OPvPWintergrasp::HandlePlayerResurrects(Player * plr, uint32 zone) -{ - if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) - return; - - if (isWarTime()) - { - if (plr->getLevel() > 69) - { - // Tenacity - if (plr->GetTeamId() == TEAM_ALLIANCE && m_tenacityStack > 0 || - plr->GetTeamId() == TEAM_HORDE && m_tenacityStack < 0) - { - if (plr->HasAura(SPELL_TENACITY)) - plr->RemoveAurasDueToSpell(SPELL_TENACITY); - - int32 newStack = m_tenacityStack < 0 ? -m_tenacityStack : m_tenacityStack; - if (newStack > 20) - newStack = 20; - plr->SetAuraStack(SPELL_TENACITY, plr, newStack); - } - - // Tower Control - if (plr->GetTeamId() == getAttackerTeam()) - { - if (m_towerDestroyedCount[getAttackerTeam()] < 3) - plr->SetAuraStack(SPELL_TOWER_CONTROL, plr, 3 - m_towerDestroyedCount[getAttackerTeam()]); - } - else - { - if (m_towerDestroyedCount[getAttackerTeam()]) - plr->SetAuraStack(SPELL_TOWER_CONTROL, plr, m_towerDestroyedCount[getAttackerTeam()]); - } - } - } - OutdoorPvP::HandlePlayerResurrects(plr, zone); -} - -void OPvPWintergrasp::HandlePlayerLeaveZone(Player * plr, uint32 zone) -{ - if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) - return; - - if (!plr->GetSession()->PlayerLogout()) - { - if (plr->GetVehicle()) // dismiss in change zone case - plr->GetVehicle()->Dismiss(); - REMOVE_WARTIME_AURAS(plr); - } - plr->RemoveAurasDueToSpell(SPELL_TENACITY); - OutdoorPvP::HandlePlayerLeaveZone(plr, zone); - UpdateTenacityStack(); -} - -void OPvPWintergrasp::PromotePlayer(Player *killer) const -{ - Aura *aur; - if (aur = killer->GetAura(SPELL_RECRUIT)) - { - if (aur->GetStackAmount() >= 5) - { - killer->RemoveAura(SPELL_RECRUIT); - killer->CastSpell(killer, SPELL_CORPORAL, true); - ChatHandler(killer).PSendSysMessage(LANG_BG_WG_RANK1); - } - else - killer->CastSpell(killer, SPELL_RECRUIT, true); - } - else if (aur = killer->GetAura(SPELL_CORPORAL)) - { - if (aur->GetStackAmount() >= 5) - { - killer->RemoveAura(SPELL_CORPORAL); - killer->CastSpell(killer, SPELL_LIEUTENANT, true); - ChatHandler(killer).PSendSysMessage(LANG_BG_WG_RANK2); - } - else - killer->CastSpell(killer, SPELL_CORPORAL, true); - } -} - -void OPvPWintergrasp::HandleKill(Player *killer, Unit *victim) -{ - if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED) || !isWarTime()) - return; - - bool ok = false; - if (victim->GetTypeId() == TYPEID_PLAYER) - { - if (victim->getLevel() >= 70) - ok = true; - killer->RewardPlayerAndGroupAtEvent(CRE_PVP_KILL, victim); - } - else - { - switch(GetCreatureType(victim->GetEntry())) - { - case CREATURE_SIEGE_VEHICLE: - killer->RewardPlayerAndGroupAtEvent(CRE_PVP_KILL_V, victim); - ok = true; - break; - case CREATURE_GUARD: - killer->RewardPlayerAndGroupAtEvent(CRE_PVP_KILL, victim); - ok = true; - break; - case CREATURE_TURRET: - ok = true; - break; - } - } - - if (ok) - { - if (Group *pGroup = killer->GetGroup()) - { - for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - if (itr->getSource()->IsAtGroupRewardDistance(killer) && itr->getSource()->getLevel() > 69) - PromotePlayer(itr->getSource()); - } - else if (killer->getLevel() > 69) - PromotePlayer(killer); - } -} - -// Recalculates Tenacity and applies it to Players / Vehicles -void OPvPWintergrasp::UpdateTenacityStack() -{ - if (!isWarTime()) - return; - - TeamId team = TEAM_NEUTRAL; - uint32 allianceNum = 0; - uint32 hordeNum = 0; - int32 newStack = 0; - - for (PlayerSet::iterator itr = m_players[TEAM_ALLIANCE].begin(); itr != m_players[TEAM_ALLIANCE].end(); ++itr) - if ((*itr)->getLevel() > 69) - ++allianceNum; - - for (PlayerSet::iterator itr = m_players[TEAM_HORDE].begin(); itr != m_players[TEAM_HORDE].end(); ++itr) - if ((*itr)->getLevel() > 69) - ++hordeNum; - - if (allianceNum && hordeNum) - { - if (allianceNum < hordeNum) - newStack = int32((float(hordeNum) / float(allianceNum) - 1)*4); // positive, should cast on alliance - else if (allianceNum > hordeNum) - newStack = int32((1 - float(allianceNum) / float(hordeNum))*4); // negative, should cast on horde - } - - if (newStack == m_tenacityStack) - return; - - if (m_tenacityStack > 0 && newStack <= 0) // old buff was on alliance - team = TEAM_ALLIANCE; - else if (m_tenacityStack < 0 && newStack >= 0) // old buff was on horde - team = TEAM_HORDE; - - m_tenacityStack = newStack; - - // Remove old buff - if (team != TEAM_NEUTRAL) - { - for (PlayerSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) - if ((*itr)->getLevel() > 69) - (*itr)->RemoveAurasDueToSpell(SPELL_TENACITY); - - for (CreatureSet::const_iterator itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) - (*itr)->RemoveAurasDueToSpell(SPELL_TENACITY_VEHICLE); - } - - // Apply new buff - if (newStack) - { - team = newStack > 0 ? TEAM_ALLIANCE : TEAM_HORDE; - if (newStack < 0) - newStack = -newStack; - if (newStack > 20) - newStack = 20; - - for (PlayerSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) - if ((*itr)->getLevel() > 69) - (*itr)->SetAuraStack(SPELL_TENACITY, (*itr), newStack); - - for (CreatureSet::const_iterator itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) - (*itr)->SetAuraStack(SPELL_TENACITY_VEHICLE, (*itr), newStack); - } -} - -void OPvPWintergrasp::UpdateClockDigit(uint32 &timer, uint32 digit, uint32 mod) -{ - uint32 value = timer%mod; - timer /= mod; - if (m_clock[digit] != value) - { - m_clock[digit] = value; - SendUpdateWorldState(ClockWorldState[digit], value); - } -} - -void OPvPWintergrasp::UpdateClock() -{ - uint32 timer = m_timer / 1000; - UpdateClockDigit(timer, 0, 10); - UpdateClockDigit(timer, 1, 6); - UpdateClockDigit(timer, 2, 10); - UpdateClockDigit(timer, 3, 6); - if (!isWarTime()) - UpdateClockDigit(timer, 4, 10); -} - -bool OPvPWintergrasp::Update(uint32 diff) -{ - if (!sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_ENABLED)) - return false; - - if (m_timer > diff) - { - m_timer -= diff; - - if (isWarTime()) - { - OutdoorPvP::Update(diff); // update capture points - - /*********************************************************/ - /*** BATTLEGROUND RESSURECTION SYSTEM ***/ - /*********************************************************/ - - //this should be handled by spell system - m_LastResurrectTime += diff; - if (m_LastResurrectTime >= RESURRECTION_INTERVAL) - { - if (GetReviveQueueSize()) - { - for (std::map >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr) - { - Creature *sh = NULL; - for (std::vector::const_iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2) - { - Player *plr = objmgr.GetPlayer(*itr2); - if (!plr) - continue; - - if (!sh && plr->IsInWorld()) - { - sh = plr->GetMap()->GetCreature(itr->first); - // only for visual effect - if (sh) - // Spirit Heal, effect 117 - sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true); - } - - // Resurrection visual - plr->CastSpell(plr, SPELL_RESURRECTION_VISUAL, true); - m_ResurrectQueue.push_back(*itr2); - } - (itr->second).clear(); - } - - m_ReviveQueue.clear(); - m_LastResurrectTime = 0; - } - else - // queue is clear and time passed, just update last resurrection time - m_LastResurrectTime = 0; - } - else if (m_LastResurrectTime > 500) // Resurrect players only half a second later, to see spirit heal effect on NPC - { - for (std::vector::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr) - { - Player *plr = objmgr.GetPlayer(*itr); - if (!plr) - continue; - plr->ResurrectPlayer(1.0f); - plr->CastSpell(plr, 6962, true); - plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true); - ObjectAccessor::Instance().ConvertCorpseForPlayer(*itr); - } - m_ResurrectQueue.clear(); - } - } - UpdateClock(); - } - else - { - m_sendUpdate = false; - int32 entry = LANG_BG_WG_DEFENDED; - - if (m_changeDefender) - { - m_changeDefender = false; - m_defender = getAttackerTeam(); - entry = LANG_BG_WG_CAPTURED; - } - - if (isWarTime()) - { - if (m_timer != 1) // 1 = forceStopBattle - sWorld.SendZoneText(ZONE_WINTERGRASP, fmtstring(objmgr.GetTrinityStringForDBCLocale(entry), objmgr.GetTrinityStringForDBCLocale(getDefenderTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE))); - EndBattle(); - } - else - { - if (m_timer != 1) // 1 = forceStartBattle - sWorld.SendZoneText(ZONE_WINTERGRASP, objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_BATTLE_STARTS)); - StartBattle(); - } - - UpdateAllWorldObject(); - UpdateClock(); - - SendInitWorldStatesTo(); - m_sendUpdate = true; - } - - return false; -} - -void OPvPWintergrasp::forceStartBattle() -{ // Uptime will do all the work - m_wartime = false; - - if (m_timer != 1) - { - m_timer = 1; - sWorld.SendZoneText(ZONE_WINTERGRASP, objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_BATTLE_FORCE_START)); - } -} - -void OPvPWintergrasp::forceStopBattle() -{ // Uptime will do all the work. - - if (!isWarTime()) - m_wartime = true; - - if (m_timer != 1) - { - m_timer = 1; - sWorld.SendZoneText(ZONE_WINTERGRASP, objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_BATTLE_FORCE_STOP)); - } -} - -void OPvPWintergrasp::forceChangeTeam() -{ - m_changeDefender = true; - m_timer = 1; - sWorld.SendZoneText(ZONE_WINTERGRASP, fmtstring(objmgr.GetTrinityStringForDBCLocale(LANG_BG_WG_SWITCH_FACTION), objmgr.GetTrinityStringForDBCLocale(getAttackerTeam() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE))); - if (isWarTime()) - forceStartBattle(); - else - forceStopBattle(); -} - -// Can be forced by gm's while in battle so have to reset in case it was wartime -void OPvPWintergrasp::StartBattle() -{ - m_wartime = true; - m_timer = sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_BATTLE_TIME) * MINUTE * IN_MILISECONDS; - - // Remove Essence of Wintergrasp to all players - sWorld.setState(WORLDSTATE_WINTERGRASP_CONTROLING_FACTION, TEAM_NEUTRAL); - sWorld.UpdateAreaDependentAuras(); - - // destroyed all vehicles - for (uint32 team = 0; team < 2; ++team) - { - while(!m_vehicles[team].empty()) - { - Creature *veh = *m_vehicles[team].begin(); - m_vehicles[team].erase(m_vehicles[team].begin()); - veh->setDeathState(JUST_DIED); - } - } - - // Remove All Wintergrasp auras. Add Recruit rank and Tower Control - for (PlayerSet::iterator itr = m_players[getAttackerTeam()].begin(); itr != m_players[getAttackerTeam()].end(); ++itr) - { - REMOVE_WARTIME_AURAS(*itr); - if ((*itr)->getLevel() > 69) - { - (*itr)->SetAuraStack(SPELL_TOWER_CONTROL, (*itr), 3); - (*itr)->CastSpell(*itr, SPELL_RECRUIT, true); - } - } - - // Remove All Wintergrasp auras. Add Recruit rank - for (PlayerSet::iterator itr = m_players[getDefenderTeam()].begin(); itr != m_players[getDefenderTeam()].end(); ++itr) - { - REMOVE_WARTIME_AURAS(*itr); - if ((*itr)->getLevel() > 69) - (*itr)->CastSpell(*itr, SPELL_RECRUIT, true); - } - UpdateTenacityStack(); -} - -void OPvPWintergrasp::EndBattle() -{ - // Cast Essence of Wintergrasp to all players (CheckCast will determine who to cast) - sWorld.setState(WORLDSTATE_WINTERGRASP_CONTROLING_FACTION, getDefenderTeam()); - sWorld.UpdateAreaDependentAuras(); - - for (uint32 team = 0; team < 2; ++team) - { - // destroyed all vehicles - while(!m_vehicles[team].empty()) - { - Creature *veh = *m_vehicles[team].begin(); - m_vehicles[team].erase(m_vehicles[team].begin()); - veh->setDeathState(JUST_DIED); - } - - if (m_players[team].empty()) - continue; - - for (PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) - { - // When WG ends the zone is cleaned including corpses, revive all players if dead - if ((*itr)->isDead()) - { - (*itr)->ResurrectPlayer(1.0f); - ObjectAccessor::Instance().ConvertCorpseForPlayer((*itr)->GetGUID()); - } - (*itr)->RemoveAurasDueToSpell(SPELL_TENACITY); - (*itr)->CombatStop(true); - (*itr)->getHostilRefManager().deleteReferences(); - } - - if (m_timer == 1) // Battle End was forced so no reward. - { - for (PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) - { - REMOVE_WARTIME_AURAS(*itr); - } - continue; - } - - // calculate rewards - uint32 intactNum = 0; - uint32 damagedNum = 0; - for (OutdoorPvP::OPvPCapturePointMap::const_iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - if (SiegeWorkshop *workshop = dynamic_cast(itr->second)) - if (workshop->m_buildingState->GetTeam() == team) - if (workshop->m_buildingState->damageState == DAMAGE_DAMAGED) - ++damagedNum; - else if (workshop->m_buildingState->damageState == DAMAGE_INTACT) - ++intactNum; - - uint32 spellRewardId = team == getDefenderTeam() ? SPELL_VICTORY_REWARD : SPELL_DEFEAT_REWARD; - uint32 baseHonor = 0; - uint32 marks = 0; - uint32 playersWithRankNum = 0; - uint32 honor = 0; - - if (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_CUSTOM_HONOR)) - { - // Calculate Level 70+ with Corporal or Lieutenant rank - for (PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) - if ((*itr)->getLevel() > 69 && ((*itr)->HasAura(SPELL_LIEUTENANT) || (*itr)->HasAura(SPELL_CORPORAL))) - ++playersWithRankNum; - - baseHonor = team == getDefenderTeam() ? sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_WIN_BATTLE) : sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_LOSE_BATTLE); - baseHonor += (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_DAMAGED_TOWER) * m_towerDamagedCount[OTHER_TEAM(team)]); - baseHonor += (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_DESTROYED_TOWER) * m_towerDestroyedCount[OTHER_TEAM(team)]); - baseHonor += (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_INTACT_BUILDING) * intactNum); - baseHonor += (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_DAMAGED_BUILDING) * damagedNum); - if (playersWithRankNum) - baseHonor /= playersWithRankNum; - } - - for (PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) - { - - if ((*itr)->getLevel() < 70) - continue; // No rewards for level <70 - - // give rewards - if (sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_CUSTOM_HONOR)) - { - if (team == getDefenderTeam()) - { - if ((*itr)->HasAura(SPELL_LIEUTENANT)) - { - marks = 3; - honor = baseHonor; - } - else if ((*itr)->HasAura(SPELL_CORPORAL)) - { - marks = 2; - honor = baseHonor; - } - else - { - marks = 1; - honor = 0; - } - } - else - { - if ((*itr)->HasAura(SPELL_LIEUTENANT)) - { - marks = 1; - honor = baseHonor; - } - else if ((*itr)->HasAura(SPELL_CORPORAL)) - { - marks = 1; - honor = baseHonor; - } - else - { - marks = 0; - honor = 0; - } - } - (*itr)->RewardHonor(NULL, 1, honor); - RewardMarkOfHonor(*itr, marks); - (*itr)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, spellRewardId); - } - else - { - if ((*itr)->HasAura(SPELL_LIEUTENANT) || (*itr)->HasAura(SPELL_CORPORAL)) - { - // TODO - Honor from SpellReward should be shared by team players - // TODO - Marks should be given depending on Rank but 3 are given - // each time so Won't give any to recruits - (*itr)->CastSpell(*itr, spellRewardId, true); - for (uint32 i = 0; i < intactNum; ++i) - (*itr)->CastSpell(*itr, SPELL_INTACT_BUILDING, true); - for (uint32 i = 0; i < damagedNum; ++i) - (*itr)->CastSpell(*itr, SPELL_DAMAGED_BUILDING, true); - for (uint32 i = 0; i < m_towerDamagedCount[OTHER_TEAM(team)]; ++i) - (*itr)->CastSpell(*itr, SPELL_DAMAGED_TOWER, true); - for (uint32 i = 0; i < m_towerDestroyedCount[OTHER_TEAM(team)]; ++i) - (*itr)->CastSpell(*itr, SPELL_DESTROYED_TOWER, true); - } - } - if (team == getDefenderTeam()) - { - if ((*itr)->HasAura(SPELL_LIEUTENANT) || (*itr)->HasAura(SPELL_CORPORAL)) - { - (*itr)->AreaExploredOrEventHappens(A_VICTORY_IN_WG); - (*itr)->AreaExploredOrEventHappens(H_VICTORY_IN_WG); - } - } - REMOVE_WARTIME_AURAS(*itr); - } - } - - m_wartime = false; - m_timer = sWorld.getConfig(CONFIG_OUTDOORPVP_WINTERGRASP_INTERVAL) * MINUTE * IN_MILISECONDS; - //3.2.0: TeamCastSpell(getAttackerTeam(), SPELL_TELEPORT_DALARAN); - RemoveOfflinePlayerWGAuras(); -} - -void OPvPWintergrasp::SetData(uint32 id, uint32 value) -{ - //if (id == DATA_ENGINEER_DIE) - // if (SiegeWorkshop *workshop = GetWorkshopByEngGuid(value)) - // workshop->DespawnAllVehicles(); -} - -bool OPvPWintergrasp::CanBuildVehicle(SiegeWorkshop *workshop) const -{ - TeamId team = workshop->m_buildingState->GetTeam(); - if (team == TEAM_NEUTRAL) - return false; - - return isWarTime() - && workshop->m_buildingState->damageState != DAMAGE_DESTROYED - && m_vehicles[team].size() < m_workshopCount[team] * MAX_VEHICLE_PER_WORKSHOP; -} - -uint32 OPvPWintergrasp::GetData(uint32 id) -{ - // if can build more vehicles - if (SiegeWorkshop *workshop = GetWorkshopByEngGuid(id)) - return CanBuildVehicle(workshop) ? 1 : 0; - - return 0; -} - -void OPvPWintergrasp::RewardMarkOfHonor(Player *plr, uint32 count) -{ - // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens - if (plr->HasAura(SPELL_AURA_PLAYER_INACTIVE)) - return; - if (count == 0) - return; - - ItemPosCountVec dest; - uint32 no_space_count = 0; - uint8 msg = plr->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, WG_MARK_OF_HONOR, count, &no_space_count); - - if (msg == EQUIP_ERR_ITEM_NOT_FOUND) - { - sLog.outErrorDb("Wintergrasp reward item (Entry %u) not exist in `item_template`.", WG_MARK_OF_HONOR); - return; - } - - if (msg != EQUIP_ERR_OK) // convert to possible store amount - count -= no_space_count; - - if (count != 0 && !dest.empty()) // can add some - if (Item* item = plr->StoreNewItem(dest, WG_MARK_OF_HONOR, true, 0)) - plr->SendNewItem(item, count, true, false); -} - -void OPvPWintergrasp::LoadQuestGiverMap(uint32 guid, Position posHorde, Position posAlli) -{ - m_qgPosMap[std::pair(guid, true)] = posHorde, - m_qgPosMap[std::pair(guid, false)] = posAlli, - m_questgivers[guid] = NULL; - if (getDefenderTeam() == TEAM_ALLIANCE) - objmgr.MoveCreData(guid, 571, posAlli); -} - -SiegeWorkshop *OPvPWintergrasp::GetWorkshop(uint32 lowguid) const -{ - if (OPvPCapturePoint *cp = GetCapturePoint(lowguid)) - return dynamic_cast(cp); - return NULL; -} - -SiegeWorkshop *OPvPWintergrasp::GetWorkshopByEngGuid(uint32 lowguid) const -{ - for (OutdoorPvP::OPvPCapturePointMap::const_iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - if (SiegeWorkshop *workshop = dynamic_cast(itr->second)) - if (workshop->m_engGuid == lowguid) - return workshop; - return NULL; -} - -SiegeWorkshop *OPvPWintergrasp::GetWorkshopByGOGuid(uint32 lowguid) const -{ - for (OutdoorPvP::OPvPCapturePointMap::const_iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - if (SiegeWorkshop *workshop = dynamic_cast(itr->second)) - if (workshop->m_workshopGuid == lowguid) - return workshop; - return NULL; -} - -/*######################################################## - * Copy of Battleground system to make Spirit Guides Work - *#######################################################*/ -void OPvPWintergrasp::SendAreaSpiritHealerQueryOpcode(Player *pl, const uint64& guid) -{ - WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12); - uint32 time_ = 30000 - GetLastResurrectTime(); // resurrect every 30 seconds - if (time_ == uint32(-1)) - time_ = 0; - data << guid << time_; - pl->GetSession()->SendPacket(&data); -} - -void OPvPWintergrasp::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid) -{ - m_ReviveQueue[npc_guid].push_back(player_guid); - - Player *plr = objmgr.GetPlayer(player_guid); - if (!plr) - return; - - plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true); -} - -void OPvPWintergrasp::RemovePlayerFromResurrectQueue(uint64 player_guid) -{ - for (std::map >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr) - { - for (std::vector::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2) - { - if (*itr2 == player_guid) - { - (itr->second).erase(itr2); - - Player *plr = objmgr.GetPlayer(player_guid); - if (!plr) - return; - - plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT); - - return; - } - } - } -} - -void OPvPWintergrasp::RelocateDeadPlayers(Creature *cr) -{ - if (!cr || GetCreatureType(cr->GetEntry()) != CREATURE_SPIRIT_GUIDE) - return; - - // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard - std::vector ghost_list = m_ReviveQueue[cr->GetGUID()]; - if (!ghost_list.empty()) - { - WorldSafeLocsEntry const *ClosestGrave = NULL; - for (std::vector::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr) - { - Player* plr = objmgr.GetPlayer(*itr); - if (!plr) - continue; - - if (!ClosestGrave) - ClosestGrave = objmgr.GetClosestGraveYard(plr->GetPositionX(), plr->GetPositionY(), plr->GetPositionZ(), plr->GetMapId(), plr->GetTeam()); - - if (ClosestGrave) - plr->TeleportTo(plr->GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation()); - } - } -} - -/*###### -##SiegeWorkshop -######*/ - -SiegeWorkshop::SiegeWorkshop(OPvPWintergrasp *opvp, BuildingState *state) -: OPvPCapturePoint(opvp), m_buildingState(state), m_wintergrasp(opvp) -, m_engineer(NULL), m_engGuid(0), m_spiritguide(NULL), m_spiGuid(0) -{ -} - -void SiegeWorkshop::SetTeamByBuildingState() -{ - if (m_buildingState->GetTeam() == TEAM_ALLIANCE) - { - m_value = m_maxValue; - m_State = OBJECTIVESTATE_ALLIANCE; - } - else if (m_buildingState->GetTeam() == TEAM_HORDE) - { - m_value = -m_maxValue; - m_State = OBJECTIVESTATE_HORDE; - } - else - { - m_value = 0; - m_State = OBJECTIVESTATE_NEUTRAL; - } - - if (m_team != m_buildingState->GetTeam()) - { - TeamId oldTeam = m_team; - m_team = m_buildingState->GetTeam(); - ChangeTeam(oldTeam); - } - - SendChangePhase(); -} - -void SiegeWorkshop::ChangeTeam(TeamId oldTeam) -{ - uint32 entry = 0; - uint32 guide_entry = 0; - - if (oldTeam != TEAM_NEUTRAL) - m_wintergrasp->ModifyWorkshopCount(oldTeam, false); - - if (m_team != TEAM_NEUTRAL) - { - entry = m_team == TEAM_ALLIANCE ? CRE_ENG_A : CRE_ENG_H; - guide_entry = m_team == TEAM_ALLIANCE ? CRE_SPI_A : CRE_SPI_H; - m_wintergrasp->ModifyWorkshopCount(m_team, true); - } - - if (m_capturePoint) - GameObject::SetGoArtKit(CapturePointArtKit[m_team], m_capturePoint, m_capturePointGUID); - - m_buildingState->SetTeam(m_team); - // TODO: this may be sent twice - m_wintergrasp->BroadcastStateChange(m_buildingState); - - if (m_buildingState->building) - m_buildingState->building->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[m_team]); - - if (entry) - { - if (m_engGuid) - { - *m_engEntry = entry; - RespawnCreatureIfNeeded(m_engineer, entry); - } - if (m_spiGuid) - { - *m_spiEntry = guide_entry; - RespawnCreatureIfNeeded(m_spiritguide, guide_entry); - m_wintergrasp->RelocateDeadPlayers(m_spiritguide); - } - } - else if (m_engineer) - m_engineer->SetVisibility(VISIBILITY_OFF); - - sLog.outDebug("Wintergrasp workshop now belongs to %u.", (uint32)m_buildingState->GetTeam()); -} diff --git a/src/game/Wintergrasp.h b/src/game/Wintergrasp.h deleted file mode 100644 index cc34520ae34..00000000000 --- a/src/game/Wintergrasp.h +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2008-2009 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_WINTERGRASP_H -#define TRINITY_WINTERGRASP_H - -#include "OutdoorPvPImpl.h" - -#define ZONE_WINTERGRASP 4197 -#define POS_X_CENTER 5100 -#define MAX_VEHICLE_PER_WORKSHOP 4 - -const uint32 WintergraspFaction[3] = {1732, 1735, 35}; -const uint32 WG_MARK_OF_HONOR = 43589; -const uint32 VehNumWorldState[2] = {3680,3490}; -const uint32 MaxVehNumWorldState[2] = {3681,3491}; -const uint32 ClockWorldState[5] = {3785,3784,3782,3976,3975}; - -enum WintergraspSpell -{ - // Wartime auras - SPELL_RECRUIT = 37795, - SPELL_CORPORAL = 33280, - SPELL_LIEUTENANT = 55629, - SPELL_TENACITY = 58549, - SPELL_TENACITY_VEHICLE = 59911, - SPELL_TOWER_CONTROL = 62064, - SPELL_SPIRITUAL_IMMUNITY = 58729, - - // Reward spells - SPELL_VICTORY_REWARD = 56902, - SPELL_DEFEAT_REWARD = 58494, - SPELL_DAMAGED_TOWER = 59135, - SPELL_DESTROYED_TOWER = 59136, - SPELL_DAMAGED_BUILDING = 59201, - SPELL_INTACT_BUILDING = 59203, - -// SPELL_TELEPORT_DALARAN = 53360, -// SPELL_VICTORY_AURA = 60044, -}; - -/* Not used / Not implemented - -const uint16 GameEventWintergraspDefender[2] = {50, 51}; - -enum OutdoorPvP_WG_Sounds -{ - OutdoorPvP_WG_SOUND_KEEP_CLAIMED = 8192, - OutdoorPvP_WG_SOUND_KEEP_CAPTURED_ALLIANCE = 8173, - OutdoorPvP_WG_SOUND_KEEP_CAPTURED_HORDE = 8213, - OutdoorPvP_WG_SOUND_KEEP_ASSAULTED_ALLIANCE = 8212, - OutdoorPvP_WG_SOUND_KEEP_ASSAULTED_HORDE = 8174, - OutdoorPvP_WG_SOUND_NEAR_VICTORY = 8456 -}; - -enum DataId -{ - DATA_ENGINEER_DIE, -}; - -enum OutdoorPvP_WG_KeepStatus -{ - OutdoorPvP_WG_KEEP_TYPE_NEUTRAL = 0, - OutdoorPvP_WG_KEEP_TYPE_CONTESTED = 1, - OutdoorPvP_WG_KEEP_STATUS_ALLY_CONTESTED = 1, - OutdoorPvP_WG_KEEP_STATUS_HORDE_CONTESTED = 2, - OutdoorPvP_WG_KEEP_TYPE_OCCUPIED = 3, - OutdoorPvP_WG_KEEP_STATUS_ALLY_OCCUPIED = 3, - OutdoorPvP_WG_KEEP_STATUS_HORDE_OCCUPIED = 4 -}; -*/ - -enum WintergraspCreType -{ - CREATURE_OTHER, - CREATURE_SIEGE_VEHICLE, - CREATURE_TURRET, - CREATURE_ENGINEER, - CREATURE_GUARD, - CREATURE_SPECIAL, - CREATURE_SPIRIT_GUIDE, - CREATURE_SPIRIT_HEALER, - CREATURE_QUESTGIVER, -}; - -enum BuildingType -{ - BUILDING_WALL, - BUILDING_WORKSHOP, - BUILDING_TOWER, -}; - -enum DamageState -{ // Do not change order - DAMAGE_INTACT, - DAMAGE_DAMAGED, - DAMAGE_DESTROYED, -}; - -const uint32 AreaPOIIconId[3][3] = {{7,8,9},{4,5,6},{1,2,3}}; - -struct BuildingState -{ - explicit BuildingState(uint32 _worldState, TeamId _team, bool asDefault) - : worldState(_worldState), health(0) - , defaultTeam(asDefault ? _team : OTHER_TEAM(_team)), team(_team), damageState(DAMAGE_INTACT) - , building(NULL), type(BUILDING_WALL), graveTeam(NULL) - {} - uint32 worldState; - uint32 health; - TeamId defaultTeam; - DamageState damageState; - GameObject *building; - uint32 *graveTeam; - BuildingType type; - - void SendUpdate(Player *player) const - { - player->SendUpdateWorldState(worldState, AreaPOIIconId[team][damageState]); - } - - void FillData(WorldPacket &data) const - { - data << worldState << AreaPOIIconId[team][damageState]; - } - - TeamId GetTeam() const { return team; } - void SetTeam(TeamId t) - { - team = t; - if(graveTeam) - if (uint32 newTeam = TeamId2Team[t]) - *graveTeam = newTeam; - } - -private: - TeamId team; -}; - -typedef std::map TeamPairMap; - -class SiegeWorkshop; - -class OPvPWintergrasp : public OutdoorPvP -{ - protected: - typedef std::map BuildingStateMap; - typedef std::set CreatureSet; - typedef std::set GameObjectSet; - typedef std::map, Position> QuestGiverPositionMap; - typedef std::map QuestGiverMap; - public: - OPvPWintergrasp(); - bool SetupOutdoorPvP(); - - uint32 GetCreatureEntry(uint32 guidlow, const CreatureData *data); - //uint32 GetGameObjectEntry(uint32 guidlow, uint32 entry); - - void OnCreatureCreate(Creature *creature, bool add); - void OnGameObjectCreate(GameObject *go, bool add); - - void ProcessEvent(GameObject *obj, uint32 eventId); - - void HandlePlayerEnterZone(Player *plr, uint32 zone); - void HandlePlayerLeaveZone(Player *plr, uint32 zone); - void HandlePlayerResurrects(Player * plr, uint32 zone); - void HandleKill(Player *killer, Unit *victim); - - bool Update(uint32 diff); - - void BroadcastStateChange(BuildingState *state) const; - - uint32 GetData(uint32 id); - void SetData(uint32 id, uint32 value); - - void ModifyWorkshopCount(TeamId team, bool add); - uint32 GetTimer() const { return m_timer / 1000; }; - TeamId GetTeam() const { return m_defender; }; - bool isWarTime() const { return m_wartime; }; - void setTimer(uint32 timer) - { - if (timer >= 0) - m_timer = timer; - }; - uint32 GetNumPlayersA() const - { - return m_players[TEAM_ALLIANCE].size(); - } - - uint32 GetNumPlayersH() const - { - return m_players[TEAM_HORDE].size(); - } - void forceChangeTeam(); - void forceStopBattle(); - void forceStartBattle(); - - // Temporal BG specific till 3.2 - void SendAreaSpiritHealerQueryOpcode(Player *pl, const uint64& guid); - void AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid); - void RemovePlayerFromResurrectQueue(uint64 player_guid); - void RelocateDeadPlayers(Creature *cr); - // BG end - protected: - // Temporal BG specific till 3.2 - std::vector m_ResurrectQueue; // Player GUID - uint32 m_LastResurrectTime; - // Spirit Guide guid + Player list GUIDS - std::map > m_ReviveQueue; - - uint32 GetLastResurrectTime() const { return m_LastResurrectTime; } - uint32 GetReviveQueueSize() const { return m_ReviveQueue.size(); } - // BG end - - TeamId m_defender; - int32 m_tenacityStack; - - BuildingStateMap m_buildingStates; - BuildingState *m_gate; - - CreatureSet m_creatures; - CreatureSet m_vehicles[2]; - GameObjectSet m_gobjects; - QuestGiverMap m_questgivers; - - TeamPairMap m_creEntryPair, m_goDisplayPair; - QuestGiverPositionMap m_qgPosMap; - - bool m_wartime; - bool m_changeDefender; - uint32 m_timer; - uint32 m_clock[5]; - uint32 m_workshopCount[2]; - uint32 m_towerDestroyedCount[2]; - uint32 m_towerDamagedCount[2]; - - SiegeWorkshop *GetWorkshop(uint32 lowguid) const; - SiegeWorkshop *GetWorkshopByEngGuid(uint32 lowguid) const; - SiegeWorkshop *GetWorkshopByGOGuid(uint32 lowguid) const; - - void StartBattle(); - void EndBattle(); - - void UpdateClock(); - void UpdateClockDigit(uint32 &timer, uint32 digit, uint32 mod); - void PromotePlayer(Player *player) const; - void UpdateTenacityStack(); - void UpdateAllWorldObject(); - bool UpdateCreatureInfo(Creature *creature); - bool UpdateGameObjectInfo(GameObject *go) const; - - bool CanBuildVehicle(SiegeWorkshop *workshop) const; - WintergraspCreType GetCreatureType(uint32 entry) const; - - void RebuildAllBuildings(); - - void SendInitWorldStatesTo(Player *player = NULL) const; - void RemoveOfflinePlayerWGAuras(); - void RewardMarkOfHonor(Player *player, uint32 count); - void MoveQuestGiver(uint32 guid); - void LoadQuestGiverMap(uint32 guid, Position posHorde, Position posAlli); - bool UpdateQuestGiverPosition(uint32 guid, Creature *creature); -}; - -class SiegeWorkshop : public OPvPCapturePoint -{ - public: - explicit SiegeWorkshop(OPvPWintergrasp *opvp, BuildingState *state); - void SetTeamByBuildingState(); - void ChangeState() {} - void ChangeTeam(TeamId oldteam); - //void DespawnAllVehicles(); - - //bool CanBuildVehicle() const { return m_vehicles.size() < MAX_VEHICLE_PER_WORKSHOP && m_buildingState->damageState != DAMAGE_DESTROYED; } - - uint32 *m_spiEntry; - uint32 m_spiGuid; - Creature *m_spiritguide; - - uint32 *m_engEntry; - uint32 m_engGuid; - Creature *m_engineer; - uint32 m_workshopGuid; - //CreatureSet m_vehicles; - BuildingState *m_buildingState; - protected: - OPvPWintergrasp *m_wintergrasp; -}; - -#endif -- cgit v1.2.3